diff options
Diffstat (limited to 'source/blender/blenkernel')
260 files changed, 37899 insertions, 32863 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 89f3431fec8..baec7e77328 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -85,18 +85,13 @@ struct CCGKey; struct MVert; struct MEdge; struct MFace; -struct MTFace; struct Object; struct Scene; struct Mesh; struct MLoopNorSpaceArray; struct BMEditMesh; -struct KeyBlock; struct ModifierData; -struct MCol; -struct ColorBand; -struct GPUVertexAttribs; -struct GPUDrawObject; +struct Depsgraph; struct PBVH; /* number of sub-elements each mesh element has (for interpolation) */ @@ -122,40 +117,9 @@ typedef struct DMFlagMat { typedef enum DerivedMeshType { DM_TYPE_CDDM, - DM_TYPE_EDITBMESH, DM_TYPE_CCGDM } DerivedMeshType; -typedef enum DMDrawOption { - /* the element is hidden or otherwise non-drawable */ - DM_DRAW_OPTION_SKIP = 0, - /* normal drawing */ - DM_DRAW_OPTION_NORMAL = 1, - /* draw, but don't set the color from mcol */ - DM_DRAW_OPTION_NO_MCOL = 2, - /* used in drawMappedFaces, use GL stipple for the face */ - DM_DRAW_OPTION_STIPPLE = 3, -} DMDrawOption; - -/* Drawing callback types */ -typedef int (*DMSetMaterial)(int mat_nr, void *attribs); -typedef int (*DMCompareDrawOptions)(void *userData, int cur_index, int next_index); -typedef void (*DMSetDrawInterpOptions)(void *userData, int index, float t); -typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index); -typedef DMDrawOption (*DMSetDrawOptionsMappedTex)(void *userData, int origindex, int mat_nr); -typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTexPoly *mtexpoly, const bool has_vcol, int matnr); - -typedef enum DMDrawFlag { - DM_DRAW_USE_COLORS = (1 << 0), - DM_DRAW_ALWAYS_SMOOTH = (1 << 1), - DM_DRAW_USE_ACTIVE_UV = (1 << 2), - DM_DRAW_USE_TEXPAINT_UV = (1 << 3), - DM_DRAW_SKIP_HIDDEN = (1 << 4), - DM_DRAW_SKIP_SELECT = (1 << 5), - DM_DRAW_SELECT_USE_EDITMODE = (1 << 6), - DM_DRAW_NEED_NORMALS = (1 << 7) -} DMDrawFlag; - typedef enum DMForeachFlag { DM_FOREACH_NOP = 0, DM_FOREACH_USE_NORMAL = (1 << 0), /* foreachMappedVert, foreachMappedLoop, foreachMappedFaceCenter */ @@ -164,14 +128,9 @@ typedef enum DMForeachFlag { typedef enum DMDirtyFlag { /* dm has valid tessellated faces, but tessellated CDDATA need to be updated. */ DM_DIRTY_TESS_CDLAYERS = 1 << 0, - /* One of the MCOL layers have been updated, force updating of GPUDrawObject's colors buffer. - * This is necessary with modern, VBO draw code, as e.g. in vpaint mode me->mcol may be updated - * without actually rebuilding dm (hence by default keeping same GPUDrawObject, and same colors - * buffer, which prevents update during a stroke!). */ - DM_DIRTY_MCOL_UPDATE_DRAW = 1 << 1, /* check this with modifier dependsOnNormals callback to see if normals need recalculation */ - DM_DIRTY_NORMALS = 1 << 2, + DM_DIRTY_NORMALS = 1 << 1, } DMDirtyFlag; typedef struct DerivedMesh DerivedMesh; @@ -182,9 +141,7 @@ struct DerivedMesh { int needsFree; /* checked on ->release, is set to 0 for cached results */ int deformedOnly; /* set by modifier stack if only deformed from original */ BVHCache *bvhCache; - struct GPUDrawObject *drawObject; DerivedMeshType type; - float auto_bump_scale; DMDirtyFlag dirty; int totmat; /* total materials. Will be valid only before object drawing. */ struct Material **mat; /* material array. Will be valid only before object drawing */ @@ -384,117 +341,6 @@ struct DerivedMesh { */ struct PBVH *(*getPBVH)(struct Object *ob, DerivedMesh *dm); - /* Drawing Operations */ - - /** Draw all vertices as bgl points (no options) */ - void (*drawVerts)(DerivedMesh *dm); - - /** Draw edges in the UV mesh (if exists) */ - void (*drawUVEdges)(DerivedMesh *dm); - - /** Draw all edges as lines (no options) - * - * Also called for *final* editmode DerivedMeshes - */ - void (*drawEdges)(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges); - - /** Draw all loose edges (edges w/ no adjoining faces) */ - void (*drawLooseEdges)(DerivedMesh *dm); - - /** Draw all faces - * o Set face normal or vertex normal based on inherited face flag - * o Use inherited face material index to call setMaterial - * o Only if setMaterial returns true - * - * Also called for *final* editmode DerivedMeshes - */ - void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4], - bool fast, DMSetMaterial setMaterial); - - /** Draw all faces using MTFace - * - Drawing options too complicated to enumerate, look at code. - */ - void (*drawFacesTex)(DerivedMesh *dm, - DMSetDrawOptionsTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag); - - /** Draw all faces with GLSL materials - * o setMaterial is called for every different material nr - * o Only if setMaterial returns true - */ - void (*drawFacesGLSL)(DerivedMesh *dm, DMSetMaterial setMaterial); - - /** Draw mapped faces (no color, or texture) - * - Only if !setDrawOptions or - * setDrawOptions(userData, mapped-face-index, r_drawSmooth) - * returns true - * - * If drawSmooth is set to true then vertex normals should be set and - * glShadeModel called with GL_SMOOTH. Otherwise the face normal should - * be set and glShadeModel called with GL_FLAT. - * - * The setDrawOptions is allowed to not set drawSmooth (for example, when - * lighting is disabled), in which case the implementation should draw as - * smooth shaded. - */ - void (*drawMappedFaces)(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - DMSetMaterial setMaterial, - DMCompareDrawOptions compareDrawOptions, - void *userData, - DMDrawFlag flag); - - /** Draw mapped faces using MTFace - * - Drawing options too complicated to enumerate, look at code. - */ - void (*drawMappedFacesTex)(DerivedMesh *dm, - DMSetDrawOptionsMappedTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag); - - /** Draw mapped faces with GLSL materials - * - setMaterial is called for every different material nr - * - setDrawOptions is called for every face - * - Only if setMaterial and setDrawOptions return true - */ - void (*drawMappedFacesGLSL)(DerivedMesh *dm, - DMSetMaterial setMaterial, - DMSetDrawOptions setDrawOptions, - void *userData); - - /** Draw mapped edges as lines - * - Only if !setDrawOptions or setDrawOptions(userData, mapped-edge) - * returns true - */ - void (*drawMappedEdges)(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - void *userData); - - /** Draw mapped edges as lines with interpolation values - * - Only if !setDrawOptions or - * setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t) - * returns true - * - * NOTE: This routine is optional! - */ - void (*drawMappedEdgesInterp)(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - DMSetDrawInterpOptions setDrawInterpOptions, - void *userData); - - /** Draw all faces with materials - * - setMaterial is called for every different material nr - * - setFace is called to verify if a face must be hidden - */ - void (*drawMappedFacesMat)(DerivedMesh *dm, - void (*setMaterial)(void *userData, int matnr, void *attribs), - bool (*setFace)(void *userData, int index), void *userData); - - struct GPUDrawObject *(*gpuObjectNew)(DerivedMesh *dm); - void (*copy_gpu_data)(DerivedMesh *dm, int type, void *varray_p, - const int *mat_orig_to_new, const void *user_data); - /** Release reference to the DerivedMesh. This function decides internally * if the DerivedMesh will be freed, or cached for later use. */ void (*release)(DerivedMesh *dm); @@ -526,17 +372,6 @@ int DM_release(DerivedMesh *dm); */ void DM_to_mesh(DerivedMesh *dm, struct Mesh *me, struct Object *ob, CustomDataMask mask, bool take_ownership); -struct BMEditMesh *DM_to_editbmesh( - struct DerivedMesh *dm, - struct BMEditMesh *existing, const bool do_tessellate); - -/* conversion to bmesh only */ -void DM_to_bmesh_ex(struct DerivedMesh *dm, struct BMesh *bm, const bool calc_face_normal); -struct BMesh *DM_to_bmesh(struct DerivedMesh *dm, const bool calc_face_normal); - - -/** Utility function to convert a DerivedMesh to a shape key block */ -void DM_to_meshkey(DerivedMesh *dm, struct Mesh *me, struct KeyBlock *kb); void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask); @@ -546,19 +381,19 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask); * freed, see BKE_customdata.h for the different options */ void DM_add_vert_layer( - struct DerivedMesh *dm, int type, int alloctype, + struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); void DM_add_edge_layer( - struct DerivedMesh *dm, int type, int alloctype, + struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); void DM_add_tessface_layer( - struct DerivedMesh *dm, int type, int alloctype, + struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); void DM_add_loop_layer( - DerivedMesh *dm, int type, int alloctype, + DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); void DM_add_poly_layer( - struct DerivedMesh *dm, int type, int alloctype, + struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer); /* custom data access functions @@ -624,16 +459,8 @@ void DM_free_poly_data(struct DerivedMesh *dm, int index, int count); void DM_DupPolys(DerivedMesh *source, DerivedMesh *target); void DM_ensure_normals(DerivedMesh *dm); -void DM_ensure_tessface(DerivedMesh *dm); void DM_ensure_looptri_data(DerivedMesh *dm); -void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num); - -void DM_update_tessface_data(DerivedMesh *dm); -void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate); - -void DM_update_materials(DerivedMesh *dm, struct Object *ob); -struct MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr); void DM_interp_vert_data( struct DerivedMesh *source, struct DerivedMesh *dest, @@ -654,8 +481,6 @@ void DM_interp_tessface_data( float *weights, FaceVertWeight *vert_weights, int count, int dest_index); -void DM_swap_tessface_data(struct DerivedMesh *dm, int index, const int *corner_indices); - void DM_interp_loop_data( struct DerivedMesh *source, struct DerivedMesh *dest, int *src_indices, @@ -666,146 +491,51 @@ void DM_interp_poly_data( int *src_indices, float *weights, int count, int dest_index); -/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */ -void vDM_ColorBand_store(const struct ColorBand *coba, const char alert_color[4]); - -/* UNUSED */ -#if 0 -/** Simple function to get me->totvert amount of vertices/normals, - * correctly deformed and subsurfered. Needed especially when vertexgroups are involved. - * In use now by vertex/weight paint and particles */ -DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob); -#endif -void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos); -/* */ -DerivedMesh *mesh_get_derived_final( - struct Scene *scene, struct Object *ob, - CustomDataMask dataMask); -DerivedMesh *mesh_get_derived_deform( - struct Scene *scene, struct Object *ob, - CustomDataMask dataMask); +void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos); DerivedMesh *mesh_create_derived_for_modifier( - struct Scene *scene, struct Object *ob, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ModifierData *md, int build_shapekey_layers); DerivedMesh *mesh_create_derived_render( - struct Scene *scene, struct Object *ob, - CustomDataMask dataMask); - -DerivedMesh *getEditDerivedBMesh( - struct BMEditMesh *em, struct Object *ob, CustomDataMask data_mask, - float (*vertexCos)[3]); - -DerivedMesh *mesh_create_derived_index_render( - struct Scene *scene, struct Object *ob, - CustomDataMask dataMask, int index); + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); /* same as above but wont use render settings */ DerivedMesh *mesh_create_derived(struct Mesh *me, float (*vertCos)[3]); -DerivedMesh *mesh_create_derived_view( - struct Scene *scene, struct Object *ob, - CustomDataMask dataMask); DerivedMesh *mesh_create_derived_no_deform( - struct Scene *scene, struct Object *ob, - float (*vertCos)[3], + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, float (*vertCos)[3], CustomDataMask dataMask); DerivedMesh *mesh_create_derived_no_deform_render( - struct Scene *scene, struct Object *ob, - float (*vertCos)[3], - CustomDataMask dataMask); -/* for gameengine */ -DerivedMesh *mesh_create_derived_no_virtual( - struct Scene *scene, struct Object *ob, float (*vertCos)[3], - CustomDataMask dataMask); -DerivedMesh *mesh_create_derived_physics( - struct Scene *scene, struct Object *ob, float (*vertCos)[3], + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, float (*vertCos)[3], CustomDataMask dataMask); -DerivedMesh *editbmesh_get_derived_base( - struct Object *ob, struct BMEditMesh *em, CustomDataMask data_mask); -DerivedMesh *editbmesh_get_derived_cage( - struct Scene *scene, struct Object *, +struct Mesh *editbmesh_get_eval_cage( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *, struct BMEditMesh *em, CustomDataMask dataMask); -DerivedMesh *editbmesh_get_derived_cage_and_final( - struct Scene *scene, struct Object *, +struct Mesh *editbmesh_get_eval_cage_and_final( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *, struct BMEditMesh *em, CustomDataMask dataMask, - DerivedMesh **r_final); - -DerivedMesh *object_get_derived_final(struct Object *ob, const bool for_render); + struct Mesh **r_final); float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *r_numVerts))[3]; -bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm); +bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, bool has_prev_mesh); void makeDerivedMesh( - struct Scene *scene, struct Object *ob, struct BMEditMesh *em, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct BMEditMesh *em, CustomDataMask dataMask, const bool build_shapekey_layers); -void weight_to_rgb(float r_rgb[3], const float weight); -/** Update the weight MCOL preview layer. - * If weights are NULL, use object's active vgroup(s). - * Else, weights must be an array of weight float values. - * If indices is NULL, it must be of numVerts length. - * Else, it must be of num length, as indices, which contains vertices' idx to apply weights to. - * (other vertices are assumed zero weight). - */ -void DM_update_weight_mcol( - struct Object *ob, struct DerivedMesh *dm, int const draw_flag, - float *weights, int num, const int *indices); - -/** convert layers requested by a GLSL material to actually available layers in - * the DerivedMesh, with both a pointer for arrays and an offset for editmesh */ -typedef struct DMVertexAttribs { - struct { - struct MLoopUV *array; - int em_offset, gl_index, gl_texco, gl_info_index; - } tface[MAX_MTFACE]; - - struct { - struct MLoopCol *array; - int em_offset, gl_index, gl_info_index; - } mcol[MAX_MCOL]; - - struct { - float (*array)[4]; - int em_offset, gl_index, gl_info_index; - } tang[MAX_MTFACE]; - - struct { - float (*array)[3]; - int em_offset, gl_index, gl_texco, gl_info_index; - } orco; - - int tottface, totmcol, tottang, totorco; -} DMVertexAttribs; - -void DM_vertex_attributes_from_gpu( - DerivedMesh *dm, - struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs); - -void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop); -void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs); - -void DM_calc_tangents_names_from_gpu( - const struct GPUVertexAttribs *gattribs, - char (*tangent_names)[MAX_NAME], int *tangent_names_count); void DM_add_named_tangent_layer_for_uv( CustomData *uv_data, CustomData *tan_data, int numLoopData, const char *layer_name); -#define DM_TANGENT_MASK_ORCO (1 << 9) -void DM_calc_loop_tangents_step_0( - const CustomData *loopData, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count, - bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, - char *ract_uv_name, char *rren_uv_name, short *rtangent_mask); void DM_calc_loop_tangents( DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME], int tangent_names_count); -void DM_calc_auto_bump_scale(DerivedMesh *dm); -/** Set object's bounding box based on DerivedMesh min/max data */ -void DM_set_object_boundbox(struct Object *ob, DerivedMesh *dm); +void DM_calc_auto_bump_scale(DerivedMesh *dm); void DM_init_origspace(DerivedMesh *dm); @@ -818,20 +548,4 @@ void DM_debug_print_cdlayers(CustomData *cdata); bool DM_is_valid(DerivedMesh *dm); #endif -BLI_INLINE int DM_origindex_mface_mpoly( - const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) ATTR_NONNULL(1); - -BLI_INLINE int DM_origindex_mface_mpoly( - const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) -{ - const int j = index_mf_to_mpoly[i]; - return (j != ORIGINDEX_NONE) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : ORIGINDEX_NONE; -} - -struct MVert *DM_get_vert_array(struct DerivedMesh *dm, bool *r_allocated); -struct MEdge *DM_get_edge_array(struct DerivedMesh *dm, bool *r_allocated); -struct MLoop *DM_get_loop_array(struct DerivedMesh *dm, bool *r_allocated); -struct MPoly *DM_get_poly_array(struct DerivedMesh *dm, bool *r_allocated); -struct MFace *DM_get_tessface_array(struct DerivedMesh *dm, bool *r_allocated); - #endif /* __BKE_DERIVEDMESH_H__ */ diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index f1858fc18ed..79e0860cb98 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -163,9 +163,6 @@ struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, con bool BKE_pose_channels_is_valid(const struct bPose *pose); #endif -/* Copy the data from the action-pose (src) into the pose */ -void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); - /* sets constraint flags */ void BKE_pose_update_constraint_flags(struct bPose *pose); @@ -204,6 +201,7 @@ void BKE_pose_remove_group_index(struct bPose *pose, const int index); 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_copyesult_pchan_result(struct bPoseChannel *pchanto, const struct bPoseChannel *pchanfrom); bool BKE_pose_copy_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void BKE_pose_rest(struct bPose *pose); @@ -211,6 +209,7 @@ void BKE_pose_rest(struct bPose *pose); /* Tag pose for recalc. Also tag all related data to be recalc. */ void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose); + #ifdef __cplusplus }; #endif diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 05717e3c8af..0d8a50c5325 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -35,10 +35,11 @@ struct bAnimVizSettings; struct bMotionPath; struct bPoseChannel; -struct EvaluationContext; +struct Depsgraph; struct ListBase; struct Main; struct Object; +struct ParticleSystem; struct Path; struct ReportList; struct Scene; @@ -48,13 +49,20 @@ struct Scene; void animviz_settings_init(struct bAnimVizSettings *avs); +struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src); + void animviz_free_motionpath_cache(struct bMotionPath *mpath); void animviz_free_motionpath(struct bMotionPath *mpath); struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan); void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets); -void animviz_calc_motionpaths(struct Main *bmain, struct Scene *scene, ListBase *targets); +void animviz_calc_motionpaths(struct Depsgraph *depsgraph, + struct Main *bmain, + struct Scene *scene, + ListBase *targets, + bool restore, + bool current_frame_only); /* ---------------------------------------------------- */ /* Curve Paths */ @@ -66,25 +74,28 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl /* ---------------------------------------------------- */ /* Dupli-Geometry */ -struct ListBase *object_duplilist_ex( - struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob, bool update); -struct ListBase *object_duplilist( - struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob); +struct ListBase *object_duplilist(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob); void free_object_duplilist(struct ListBase *lb); int count_duplilist(struct Object *ob); -typedef struct DupliExtraData { - float obmat[4][4]; - unsigned int lay; -} DupliExtraData; +typedef struct DupliObject { + struct DupliObject *next, *prev; + struct Object *ob; + float mat[4][4]; + float orco[3], uv[2]; + + short type; /* from Object.transflag */ + char no_draw; + + /* Persistent identifier for a dupli object, for inter-frame matching of + * objects with motion blur, or inter-update matching for syncing. */ + int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */ -typedef struct DupliApplyData { - int num_objects; - DupliExtraData *extra; -} DupliApplyData; + /* Particle this dupli was generated from. */ + struct ParticleSystem *particle_system; -DupliApplyData *duplilist_apply(struct Object *ob, struct Scene *scene, struct ListBase *duplilist); -void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data); -void duplilist_free_apply_data(DupliApplyData *apply_data); + /* Random ID for shading */ + unsigned int random_id; +} DupliObject; #endif diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 40b4bf8e7f5..df362ff8b04 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -31,22 +31,23 @@ * \author Joshua Leung */ -struct ID; -struct ListBase; -struct Main; struct AnimData; +struct ChannelDriver; +struct Depsgraph; struct FCurve; -struct KeyingSet; +struct ID; struct KS_Path; +struct KeyingSet; +struct ListBase; +struct Main; struct PathResolvedRNA; -struct bContext; - struct PointerRNA; struct PropertyRNA; struct ReportList; +struct Scene; struct bAction; struct bActionGroup; -struct AnimMapper; +struct bContext; /* ************************************* */ /* AnimData API */ @@ -68,10 +69,10 @@ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct b void BKE_animdata_free(struct ID *id, const bool do_id_user); /* Copy AnimData */ -struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const bool do_action); +struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag); /* Copy AnimData */ -bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const bool do_action); +bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const int flag); /* Copy AnimData Actions */ void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid); @@ -120,7 +121,7 @@ void BKE_keyingsets_free(struct ListBase *list); /* Path Fixing API */ /* Get a "fixed" version of the given path (oldPath) */ -char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName, +char *BKE_animsys_fix_rna_path_rename(struct ID *owner_id, char *old_path, const char *prefix, const char *oldName, const char *newName, int oldSubscript, int newSubscript, bool verify_paths); /* Fix all the paths for the given ID + Action */ @@ -133,7 +134,7 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, st bool verify_paths); /* Fix all the paths for the entire database... */ -void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName); +void BKE_animdata_fix_paths_rename_all(struct ID *ref_id, const char *prefix, const char *oldName, const char *newName); /* Fix the path after removing elements that are not ID (e.g., node) */ void BKE_animdata_fix_paths_remove(struct ID *id, const char *path); @@ -151,7 +152,7 @@ char *BKE_animdata_driver_path_hack(struct bContext *C, struct PointerRNA *ptr, char *base_path); /* ************************************* */ -/* Batch AnimData API */ +/* GPUBatch AnimData API */ /* Define for callback looper used in BKE_animdata_main_cb */ typedef void (*ID_AnimData_Edit_Callback)(struct ID *id, struct AnimData *adt, void *user_data); @@ -176,14 +177,13 @@ void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void /* In general, these ones should be called to do all animation evaluation */ /* Evaluation loop for evaluating animation data */ -void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct AnimData *adt, float ctime, short recalc); +void BKE_animsys_evaluate_animdata(struct Depsgraph *depsgraph, struct Scene *scene, struct ID *id, struct AnimData *adt, float ctime, short recalc); /* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */ -void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime); +void BKE_animsys_evaluate_all_animation(struct Main *main, struct Depsgraph *depsgraph, struct Scene *scene, float ctime); /* TODO(sergey): This is mainly a temp public function. */ -struct FCurve; -bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval); +bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct FCurve *fcu, float curval); /* ------------ Specialized API --------------- */ /* There are a few special tools which require these following functions. They are NOT to be used @@ -194,19 +194,21 @@ bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap */ /* Evaluate Action (F-Curve Bag) */ -void animsys_evaluate_action(struct PointerRNA *ptr, struct bAction *act, struct AnimMapper *remap, float ctime); +void animsys_evaluate_action(struct Depsgraph *depsgraph, struct PointerRNA *ptr, struct bAction *act, float ctime); /* Evaluate Action Group */ -void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, struct bActionGroup *agrp, struct AnimMapper *remap, float ctime); +void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, struct bActionGroup *agrp, float ctime); /* ************************************* */ /* ------------ Evaluation API --------------- */ -struct EvaluationContext; +struct Depsgraph; + +void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id); +void BKE_animsys_eval_driver(struct Depsgraph *depsgraph, struct ID *id, int driver_index, struct ChannelDriver *driver_orig); -void BKE_animsys_eval_animdata(struct EvaluationContext *eval_ctx, struct ID *id); -void BKE_animsys_eval_driver(struct EvaluationContext *eval_ctx, struct ID *id, struct FCurve *fcurve); +void BKE_animsys_update_driver_array(struct ID *id); /* ************************************* */ diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index ac8f861fa56..6162c7b6bf6 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -23,6 +23,7 @@ /** \file BKE_appdir.h * \ingroup bli */ +struct ListBase; /* note on naming: typical _get() suffix is omitted here, * since its the main purpose of the API. */ @@ -35,6 +36,7 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con bool BKE_appdir_app_template_any(void); bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len); +void BKE_appdir_app_templates(struct ListBase *templates); /* Initialize path to program executable */ void BKE_appdir_program_path_init(const char *argv0); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index dea5afa1ac2..23a9afbda31 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -33,7 +33,9 @@ * \author nzc */ +struct bPose; struct Bone; +struct Depsgraph; struct GHash; struct Main; struct bArmature; @@ -97,17 +99,19 @@ float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3 void BKE_armature_where_is(struct bArmature *arm); void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); void BKE_pose_clear_pointers(struct bPose *pose); -void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm); -void BKE_pose_rebuild_ex(struct Object *ob, struct bArmature *arm, const bool sort_bones); -void BKE_pose_where_is(struct Scene *scene, struct Object *ob); -void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); +void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose); +void BKE_pchan_rebuild_bbone_handles(struct bPose *pose, struct bPoseChannel *pchan); +void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm, const bool do_id_user); +void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); +void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); /* get_objectspace_bone_matrix has to be removed still */ void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], int root, int posed); void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]); void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat[3][3]); -void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll); +void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll); +void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll); /* Common Conversions Between Co-ordinate Spaces */ void BKE_armature_mat_world_to_pose(struct Object *ob, float inmat[4][4], float outmat[4][4]); @@ -117,7 +121,7 @@ void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan, const float inloc void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]); void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4], float arm_mat[4][4]); -void BKE_armature_mat_pose_to_bone_ex(struct Object *ob, struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]); +void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, struct Object *ob, struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]); void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, float mat[3][3], bool use_compat); void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, float mat[4][4], bool use_comat); @@ -138,8 +142,33 @@ typedef struct Mat4 { float mat[4][4]; } Mat4; -void equalize_bbone_bezier(float *data, int desired); -void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]); +typedef struct BBoneSplineParameters { + int segments; + float length; + + /* Non-uniform scale correction. */ + bool do_scale; + float scale[3]; + + /* Handle control bone data. */ + bool use_prev, prev_bbone; + bool use_next, next_bbone; + + float prev_h[3], next_h[3]; + float prev_mat[4][4], next_mat[4][4]; + + /* Control values. */ + float ease1, ease2; + float roll1, roll2; + float scaleIn, scaleOut; + float curveInX, curveInY, curveOutX, curveOutY; +} BBoneSplineParameters; + +void BKE_pchan_get_bbone_handles(struct bPoseChannel *pchan, struct bPoseChannel **r_prev, struct bPoseChannel **r_next); + +void b_bone_spline_setup(struct bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV]); + +int BKE_compute_b_bone_spline(struct BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]); /* like EBONE_VISIBLE */ #define PBONE_VISIBLE(arm, bone) ( \ @@ -151,11 +180,27 @@ void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array #define PBONE_SELECTABLE(arm, bone) \ (PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE)) + +/* context.selected_pose_bones */ +#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan) \ + for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \ + if (PBONE_VISIBLE(((bArmature *)(_ob)->data), (_pchan)->bone) && ((_pchan)->bone->flag & BONE_SELECTED)) { +#define FOREACH_PCHAN_SELECTED_IN_OBJECT_END \ + } \ + } ((void)0) +/* context.visible_pose_bones */ +#define FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN(_ob, _pchan) \ + for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \ + if (PBONE_VISIBLE(((bArmature *)(_ob)->data), (_pchan)->bone)) { +#define FOREACH_PCHAN_VISIBLE_IN_OBJECT_END \ + } \ + } ((void)0) + + /* Evaluation helpers */ struct bKinematicConstraint; struct bPose; struct bSplineIKConstraint; -struct EvaluationContext; struct bPoseChannel *BKE_armature_ik_solver_find_root( struct bPoseChannel *pchan, @@ -165,46 +210,63 @@ struct bPoseChannel *BKE_armature_splineik_solver_find_root( struct bSplineIKConstraint *data); void BKE_pose_splineik_init_tree(struct Scene *scene, struct Object *ob, float ctime); -void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime); - -void BKE_pose_eval_init(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob); - -void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob); - -void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob, - int pchan_index); - -void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob, - int pchan_index); - -void BKE_pose_bone_done(struct EvaluationContext *eval_ctx, - struct Object *ob, - int pchan_index); - -void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob, - int rootchan_index); - -void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob, - int rootchan_index); - -void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob); - -void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx, - struct Object *ob); +void BKE_splineik_execute_tree( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, struct bPoseChannel *pchan_root, float ctime); + +void BKE_pose_eval_init( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); + +void BKE_pose_eval_init_ik( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); + +void BKE_pose_eval_bone( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + int pchan_index); + +void BKE_pose_constraints_evaluate( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + int pchan_index); + +void BKE_pose_bone_done( + struct Depsgraph *depsgraph, + struct Object *ob, + int pchan_index); + +void BKE_pose_iktree_evaluate( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + int rootchan_index); + +void BKE_pose_splineik_evaluate( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + int rootchan_index); + +void BKE_pose_eval_cleanup( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); + +void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, + struct Object *object); +void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, + struct Object *object); + +void BKE_pose_eval_proxy_copy_bone( + struct Depsgraph *depsgraph, + struct Object *object, + int pchan_index); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_blender_user_menu.h b/source/blender/blenkernel/BKE_blender_user_menu.h new file mode 100644 index 00000000000..ff314314646 --- /dev/null +++ b/source/blender/blenkernel/BKE_blender_user_menu.h @@ -0,0 +1,49 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_BLENDER_USER_MENU_H__ +#define __BKE_BLENDER_USER_MENU_H__ + +/** \file BKE_blender_user_menu.h + * \ingroup bke + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ListBase; +struct bUserMenu; +struct bUserMenuItem; + +struct bUserMenu *BKE_blender_user_menu_find( + struct ListBase *lb, char space_type, const char *context); +struct bUserMenu *BKE_blender_user_menu_ensure( + struct ListBase *lb, char space_type, const char *context); + +struct bUserMenuItem *BKE_blender_user_menu_item_add(struct ListBase *lb, int type); +void BKE_blender_user_menu_item_free(struct bUserMenuItem *umi); +void BKE_blender_user_menu_item_free_list(struct ListBase *lb); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_BLENDER_USER_MENU_H__ */ diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 16115203294..b695132416e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,11 +27,11 @@ /* these lines are grep'd, watch out for our not-so-awesome regex * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ -#define BLENDER_VERSION 279 -#define BLENDER_SUBVERSION 6 -/* Several breakages with 270, e.g. constraint deg vs rad */ -#define BLENDER_MINVERSION 270 -#define BLENDER_MINSUBVERSION 6 +#define BLENDER_VERSION 280 +#define BLENDER_SUBVERSION 30 +/* Several breakages with 280, e.g. collections vs layers */ +#define BLENDER_MINVERSION 280 +#define BLENDER_MINSUBVERSION 0 /* used by packaging tools */ /* can be left blank, otherwise a,b,c... etc with no quotes */ diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h index 9ff164f60be..305b7d07e4d 100644 --- a/source/blender/blenkernel/BKE_blendfile.h +++ b/source/blender/blenkernel/BKE_blendfile.h @@ -61,6 +61,13 @@ struct UserDef *BKE_blendfile_userdef_read_from_memory( bool BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports); bool BKE_blendfile_userdef_write_app_template(const char *filepath, struct ReportList *reports); +struct WorkspaceConfigFileData *BKE_blendfile_workspace_config_read( + const char *filepath, + const void *filebuf, int filelength, + struct ReportList *reports); +bool BKE_blendfile_workspace_config_write(struct Main *bmain, const char *filepath, struct ReportList *reports); +void BKE_blendfile_workspace_config_data_free(struct WorkspaceConfigFileData *workspace_config); + /* partial blend file writing */ void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set); void BKE_blendfile_write_partial_begin(struct Main *bmain_src); diff --git a/source/blender/blenkernel/BKE_bmfont.h b/source/blender/blenkernel/BKE_bmfont.h deleted file mode 100644 index 3be84c83892..00000000000 --- a/source/blender/blenkernel/BKE_bmfont.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef __BKE_BMFONT_H__ -#define __BKE_BMFONT_H__ - -/** \file BKE_bmfont.h - * \ingroup bke - * \since March 2001 - * \author nzc - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct bmGlyph; -struct ImBuf; -struct bmFont; - -void printfGlyph(struct bmGlyph *glyph); -void calcAlpha(struct ImBuf *ibuf); -void readBitmapFontVersion0(struct ImBuf *ibuf, - unsigned char *rect, - int step); -void detectBitmapFont(struct ImBuf *ibuf); -int locateGlyph(struct bmFont *bmfont, unsigned short unicode); -void matrixGlyph(struct ImBuf *ibuf, unsigned short unicode, - float *centerx, float *centery, - float *sizex, float *sizey, - float *transx, float *transy, - float *movex, float *movey, float *advance); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 9fc399c428f..91743bfa567 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -28,12 +28,17 @@ */ enum eCurveMappingPreset; +struct bContext; struct Brush; +struct Paint; struct ImBuf; struct ImagePool; struct Main; struct Scene; +struct ToolSettings; struct UnifiedPaintSettings; +struct Material; + // enum eCurveMappingPreset; #include "DNA_object_enums.h" @@ -45,14 +50,17 @@ void BKE_brush_system_exit(void); /* datablock functions */ void BKE_brush_init(struct Brush *brush); struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode); +struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name); +void BKE_brush_init_gpencil_settings(struct Brush *brush); struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode); void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag); struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush); void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local); -void BKE_brush_unlink(struct Main *bmain, struct Brush *brush); void BKE_brush_free(struct Brush *brush); void BKE_brush_sculpt_reset(struct Brush *brush); +void BKE_brush_gpencil_presets(struct bContext *C); +void BKE_brush_update_material(struct Main *bmain, struct Material *ma, struct Brush *exclude_brush); /* image icon function */ struct ImBuf *get_brush_icon(struct Brush *brush); @@ -117,6 +125,14 @@ void BKE_brush_scale_size( float new_unprojected_radius, float old_unprojected_radius); +/* Accessors */ +#define BKE_brush_tool_get(brush, p) \ + (CHECK_TYPE_ANY(brush, struct Brush *, const struct Brush *), \ + *(const char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset)) +#define BKE_brush_tool_set(brush, p, tool) { \ + CHECK_TYPE_ANY(brush, struct Brush *); \ + *(char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset) = tool; } ((void)0) + /* debugging only */ void BKE_brush_debug_print_state(struct Brush *br); diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index c6057442fec..018f535a4cb 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -40,6 +40,7 @@ struct DerivedMesh; struct BMEditMesh; +struct Mesh; struct MVert; struct MFace; @@ -101,7 +102,7 @@ typedef struct BVHTreeFromMesh { */ BVHTree *bvhtree_from_editmesh_verts( BVHTreeFromEditMesh *data, struct BMEditMesh *em, - float epsilon, int tree_type, int axis); + float epsilon, int tree_type, int axis, BVHCache **bvh_cache); BVHTree *bvhtree_from_editmesh_verts_ex( BVHTreeFromEditMesh *data, struct BMEditMesh *em, const BLI_bitmap *mask, int verts_num_active, @@ -114,7 +115,7 @@ BVHTree *bvhtree_from_mesh_verts_ex( BVHTree *bvhtree_from_editmesh_edges( BVHTreeFromEditMesh *data, struct BMEditMesh *em, - float epsilon, int tree_type, int axis); + float epsilon, int tree_type, int axis, BVHCache **bvh_cache); BVHTree *bvhtree_from_editmesh_edges_ex( BVHTreeFromEditMesh *data, struct BMEditMesh *em, const BLI_bitmap *edges_mask, int edges_num_active, @@ -150,8 +151,8 @@ BVHTree *bvhtree_from_mesh_looptri_ex( const BLI_bitmap *mask, int looptri_num_active, float epsilon, int tree_type, int axis); -BVHTree *bvhtree_from_mesh_get( - struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, +BVHTree *BKE_bvhtree_from_mesh_get( + struct BVHTreeFromMesh *data, struct Mesh *mesh, const int type, const int tree_type); /** @@ -182,14 +183,18 @@ enum { BVHTREE_FROM_FACES = 2, BVHTREE_FROM_LOOPTRI = 3, - BVHTREE_FROM_EM_LOOPTRI = 4, + BVHTREE_FROM_LOOSEVERTS = 4, + BVHTREE_FROM_LOOSEEDGES = 5, + + BVHTREE_FROM_EM_VERTS = 6, + BVHTREE_FROM_EM_EDGES = 7, + BVHTREE_FROM_EM_LOOPTRI = 8, }; -BVHTree *bvhcache_find(BVHCache *cache, int type); +bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree); bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree); void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type); -void bvhcache_init(BVHCache **cache_p); void bvhcache_free(BVHCache **cache_p); diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index e9712681090..43768b67f8f 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -35,6 +35,7 @@ extern "C" { #endif struct CacheFile; +struct Depsgraph; struct Main; struct Scene; @@ -57,7 +58,7 @@ void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file); -void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, const float ctime, const float fps); +void BKE_cachefile_update_frame(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, const float ctime, const float fps); bool BKE_cachefile_filepath_get( const struct Main *bmain, const struct CacheFile *cache_file, float frame, @@ -65,7 +66,7 @@ bool BKE_cachefile_filepath_get( float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps); -void BKE_cachefile_clean(struct Scene *scene, struct CacheFile *cache_file); +void BKE_cachefile_clean(struct Main *bmain, struct CacheFile *cache_file); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index 8eb8ef22b49..d8e2139be83 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -39,11 +39,13 @@ extern "C" { #include "DNA_vec_types.h" struct Camera; +struct Depsgraph; struct Main; struct Object; struct RegionView3D; struct RenderData; struct Scene; +struct ViewLayer; struct rctf; struct View3D; struct GPUFXSettings; @@ -60,7 +62,6 @@ void BKE_camera_free(struct Camera *ca); /* Camera Usage */ float BKE_camera_object_dof_distance(struct Object *ob); -void BKE_camera_object_mode(struct RenderData *rd, struct Object *ob); int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey); float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y); @@ -91,11 +92,6 @@ typedef struct CameraParams { float clipsta; float clipend; - /* fields */ - int use_fields; - int field_second; - int field_odd; - /* computed viewplane */ float ycor; float viewdx; @@ -112,7 +108,7 @@ typedef struct CameraParams { void BKE_camera_params_init(CameraParams *params); void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera); -void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d); +void BKE_camera_params_from_view3d(CameraParams *params, struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d); void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy); void BKE_camera_params_compute_matrix(CameraParams *params); @@ -128,12 +124,13 @@ void BKE_camera_view_frame( float r_vec[4][3]); bool BKE_camera_view_frame_fit_to_scene( - struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct Object *camera_ob, + struct Depsgraph *depsgraph, + struct Scene *scene, struct Object *camera_ob, float r_co[3], float *r_scale); bool BKE_camera_view_frame_fit_to_coords( - const struct Scene *scene, + const struct Depsgraph *depsgraph, const float (*cos)[3], int num_cos, - const struct Object *camera_ob, + struct Object *camera_ob, float r_co[3], float *r_scale); void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings); @@ -141,11 +138,16 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set /* Camera multi-view API */ struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname); -void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]); -void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]); -float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname); -void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname); -bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, struct Object *camera); +void BKE_camera_multiview_view_matrix(struct RenderData *rd, const struct Object *camera, const bool is_left, float r_viewmat[4][4]); +void BKE_camera_multiview_model_matrix(struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4]); +float BKE_camera_multiview_shift_x(struct RenderData *rd, const struct Object *camera, const char *viewname); +void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, const struct Object *camera, const char *viewname); +bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, const struct Object *camera); + +/* Camera background image API */ +struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam); +void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic); +void BKE_camera_background_image_clear(struct Camera *cam); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h index 761b679983d..f2c0b96aa80 100644 --- a/source/blender/blenkernel/BKE_cdderivedmesh.h +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -36,6 +36,7 @@ #define __BKE_CDDERIVEDMESH_H__ #include "BKE_DerivedMesh.h" +#include "BKE_customdata.h" struct DerivedMesh; struct BMEditMesh; @@ -53,20 +54,15 @@ struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, * data to not overwrite the original */ struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh); +/* creates a CDDerivedMesh from the given Mesh with custom allocation type. */ +struct DerivedMesh *CDDM_from_mesh_ex(struct Mesh *mesh, eCDAllocType alloctype, CustomDataMask mask); + + struct DerivedMesh *CDDM_from_bmesh(struct BMesh *bm, const bool use_mdisps); /* creates a CDDerivedMesh from the given BMEditMesh */ DerivedMesh *CDDM_from_editbmesh(struct BMEditMesh *em, const bool use_mdisps, const bool use_tessface); -/* merge verts */ -/* Enum for merge_mode of CDDM_merge_verts. - * Refer to cdderivedmesh.c for details. */ -enum { - CDDM_MERGE_VERTS_DUMP_IF_MAPPED, - CDDM_MERGE_VERTS_DUMP_IF_EQUAL, -}; -DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode); - /* creates a CDDerivedMesh from the given curve object */ struct DerivedMesh *CDDM_from_curve(struct Object *ob); @@ -78,8 +74,6 @@ DerivedMesh *CDDM_from_curve_displist(struct Object *ob, struct ListBase *dispba * custom element data. */ struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm); -struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm); -struct DerivedMesh *CDDM_copy_with_tessface(struct DerivedMesh *dm); /* creates a CDDerivedMesh with the same layer stack configuration as the * given DerivedMesh and containing the requested numbers of elements. @@ -95,11 +89,6 @@ struct DerivedMesh *CDDM_from_template( int numVerts, int numEdges, int numFaces, int numLoops, int numPolys); -/* converts mfaces to mpolys. note things may break if there are not valid - * medges surrounding each mface. - */ -void CDDM_tessfaces_to_faces(struct DerivedMesh *dm); - /* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert * layer is a referenced layer, it will be duplicate to not overwrite the * original @@ -112,22 +101,11 @@ void CDDM_apply_vert_normals(struct DerivedMesh *cddm, short (*vertNormals)[3]); void CDDM_calc_normals_mapping_ex(struct DerivedMesh *dm, const bool only_face_normals); void CDDM_calc_normals_mapping(struct DerivedMesh *dm); void CDDM_calc_normals(struct DerivedMesh *dm); -void CDDM_calc_normals_tessface(struct DerivedMesh *dm); void CDDM_calc_loop_normals(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle); void CDDM_calc_loop_normals_spacearr(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle, struct MLoopNorSpaceArray *r_lnors_spacearr); -/* calculates edges for a CDDerivedMesh (from face data) - * this completely replaces the current edge data in the DerivedMesh - * builds edges from the tessellated face data. - */ -void CDDM_calc_edges_tessface(struct DerivedMesh *dm); - -/* same as CDDM_calc_edges_tessface only makes edges from ngon faces instead of tessellation - * faces*/ -void CDDM_calc_edges(struct DerivedMesh *dm); - /* reconstitute face triangulation */ void CDDM_recalc_tessellation(struct DerivedMesh *dm); void CDDM_recalc_tessellation_ex(struct DerivedMesh *dm, const bool do_face_nor_cpy); diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 6b76ec33c06..87094e77953 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -37,10 +37,11 @@ struct Object; struct Scene; +struct Mesh; struct MFace; -struct DerivedMesh; struct ClothModifierData; struct CollisionModifierData; +struct Depsgraph; #define DO_INLINE MALWAYS_INLINE @@ -116,6 +117,7 @@ typedef struct ClothVertex { float goal; /* goal, from SB */ float impulse[3]; /* used in collision.c */ float xrest[3]; /* rest position of the vertex */ + float dcvel[3]; /* delta velocities to be applied by collision response */ unsigned int impulse_count; /* same as above */ float avg_spring_len; /* average length of connected springs */ float struct_stiff; @@ -132,11 +134,17 @@ ClothVertex; typedef struct ClothSpring { int ij; /* Pij from the paper, one end of the spring. */ int kl; /* Pkl from the paper, one end of the spring. */ - int mn; - float restlen; /* The original length of the spring. */ - int type; /* types defined in BKE_cloth.h ("springType") */ - int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */ - float stiffness; /* stiffness factor from the vertex groups */ + int mn; /* For hair springs: third vertex index; For bending springs: edge index; */ + int *pa; /* Array of vert indices for poly a (for bending springs). */ + int *pb; /* Array of vert indices for poly b (for bending springs). */ + int la; /* Length of *pa. */ + int lb; /* Length of *pb. */ + float restlen; /* The original length of the spring. */ + float restang; /* The original angle of the bending springs. */ + int type; /* Types defined in BKE_cloth.h ("springType"). */ + int flags; /* Defined in BKE_cloth.h, e.g. deactivated due to tearing. */ + float lin_stiffness; /* Linear stiffness factor from the vertex groups. */ + float ang_stiffness; /* Angular stiffness factor from the vertex groups. */ float editrestlen; /* angular bending spring target and derivatives */ @@ -162,15 +170,21 @@ ClothSpring; /* These are the bits used in SimSettings.flags. */ typedef enum { CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ),// object is only collision object, no cloth simulation is done - CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled + CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), /* DEPRECATED, for versioning only. */ CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled - CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */ + CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* DEPRECATED, for versioning only. */ CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12), /* edit cache in editmode */ - CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS = (1 << 13), /* don't allow spring compression */ + CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS = (1 << 13), /* don't allow spring compression */ CLOTH_SIMSETTINGS_FLAG_SEW = (1 << 14), /* pull ends of loose edges together */ CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH = (1 << 15), /* make simulation respect deformations in the base object */ } CLOTH_SIMSETTINGS_FLAGS; +/* ClothSimSettings.bending_model. */ +typedef enum { + CLOTH_BENDING_LINEAR = 0, + CLOTH_BENDING_ANGULAR = 1, +} CLOTH_BENDING_MODEL; + /* COLLISION FLAGS */ typedef enum { CLOTH_COLLSETTINGS_FLAG_ENABLED = ( 1 << 1 ), /* enables cloth - object collisions */ @@ -179,12 +193,12 @@ typedef enum { /* Spring types as defined in the paper.*/ typedef enum { - CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1), - CLOTH_SPRING_TYPE_SHEAR = (1 << 2), - CLOTH_SPRING_TYPE_BENDING = (1 << 3), - CLOTH_SPRING_TYPE_GOAL = (1 << 4), - CLOTH_SPRING_TYPE_SEWING = (1 << 5), - CLOTH_SPRING_TYPE_BENDING_ANG = (1 << 6), + CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1), + CLOTH_SPRING_TYPE_SHEAR = (1 << 2), + CLOTH_SPRING_TYPE_BENDING = (1 << 3), + CLOTH_SPRING_TYPE_GOAL = (1 << 4), + CLOTH_SPRING_TYPE_SEWING = (1 << 5), + CLOTH_SPRING_TYPE_BENDING_HAIR = (1 << 6), } CLOTH_SPRING_TYPES; /* SPRING FLAGS */ @@ -209,10 +223,9 @@ typedef struct ColliderContacts { } ColliderContacts; // needed for implicit.c -int cloth_bvh_objcollision (struct Object *ob, struct ClothModifierData *clmd, float step, float dt ); -int cloth_points_objcollision(struct Object *ob, struct ClothModifierData *clmd, float step, float dt); +int cloth_bvh_collision(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt); -void cloth_find_point_contacts(struct Object *ob, struct ClothModifierData *clmd, float step, float dt, +void cloth_find_point_contacts(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt, ColliderContacts **r_collider_contacts, int *r_totcolliders); void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders); @@ -226,16 +239,18 @@ void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders); void cloth_free_modifier_extern (struct ClothModifierData *clmd ); void cloth_free_modifier (struct ClothModifierData *clmd ); void cloth_init (struct ClothModifierData *clmd ); -void clothModifier_do (struct ClothModifierData *clmd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3]); +void clothModifier_do( + struct ClothModifierData *clmd, struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, struct Mesh *me, float (*vertexCos)[3]); int cloth_uses_vgroup(struct ClothModifierData *clmd); // needed for collision.c -void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving); -void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving); +void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving, bool self); // needed for button_object.c -void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr ); +void cloth_clear_cache( + struct Object *ob, struct ClothModifierData *clmd, float framenr ); void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]); diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h new file mode 100644 index 00000000000..d78133499ce --- /dev/null +++ b/source/blender/blenkernel/BKE_collection.h @@ -0,0 +1,200 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_COLLECTION_H__ +#define __BKE_COLLECTION_H__ + +/** \file blender/blenkernel/BKE_collection.h + * \ingroup bke + */ + +#include "BLI_compiler_compat.h" +#include "BLI_ghash.h" +#include "BLI_iterator.h" +#include "DNA_listBase.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structs */ + +struct Base; +struct BLI_Iterator; +struct Collection; +struct Depsgraph; +struct ID; +struct Main; +struct Object; +struct Scene; +struct ViewLayer; + +typedef struct CollectionParent { + struct CollectionParent *next, *prev; + struct Collection *collection; +} CollectionParent; + +/* Collections */ + +struct Collection *BKE_collection_add(struct Main *bmain, struct Collection *parent, const char *name); +void BKE_collection_free(struct Collection *collection); +bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy); + +struct Collection *BKE_collection_copy(struct Main *bmain, struct Collection *parent, struct Collection *collection); +struct Collection *BKE_collection_copy_master(struct Main *bmain, struct Collection *collection, const int flag); +void BKE_collection_copy_data(struct Main *bmain, struct Collection *collection_dst, const struct Collection *collection_src, const int flag); +void BKE_collection_copy_full(struct Main *bmain, struct Collection *collection); +void BKE_collection_make_local(struct Main *bmain, struct Collection *collection, const bool lib_local); + +/* Master Collection for Scene */ + +struct Collection *BKE_collection_master(const struct Scene *scene); +struct Collection *BKE_collection_master_add(void); + +/* Collection Objects */ + +bool BKE_collection_has_object(struct Collection *collection, struct Object *ob); +bool BKE_collection_has_object_recursive(struct Collection *collection, struct Object *ob); +struct Collection *BKE_collection_object_find(struct Main *bmain, struct Collection *collection, struct Object *ob); +bool BKE_collection_is_empty(struct Collection *collection); + +bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob); +void BKE_collection_object_add_from(struct Main *bmain, struct Scene *scene, struct Object *ob_src, struct Object *ob_dst); +bool BKE_collection_object_remove(struct Main *bmain, struct Collection *collection, struct Object *object, const bool free_us); +void BKE_collection_object_move(struct Main *bmain, struct Scene *scene, struct Collection *collection_dst, struct Collection *collection_src, struct Object *ob); + +bool BKE_scene_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us); +void BKE_collections_object_remove_nulls(struct Main *bmain); +void BKE_collections_child_remove_nulls(struct Main *bmain, struct Collection *old_collection); + +/* Dependencies. */ + +bool BKE_collection_is_in_scene(struct Collection *collection); +void BKE_collections_after_lib_link(struct Main *bmain); +bool BKE_collection_object_cyclic_check(struct Main *bmain, struct Object *object, struct Collection *collection); + +/* Object list cache. */ + +struct ListBase BKE_collection_object_cache_get(struct Collection *collection); +void BKE_collection_object_cache_free(struct Collection *collection); + +struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer, struct Collection *collection); + +/* Editing. */ + +struct Collection *BKE_collection_from_index(struct Scene *scene, const int index); +void BKE_collection_new_name_get(struct Collection *collection_parent, char *rname); +const char *BKE_collection_ui_name_get(struct Collection *collection); +bool BKE_collection_objects_select(struct ViewLayer *view_layer, struct Collection *collection, bool deselect); + +/* Collection children */ + +bool BKE_collection_child_add(struct Main *bmain, + struct Collection *parent, + struct Collection *child); + +bool BKE_collection_child_remove(struct Main *bmain, + struct Collection *parent, + struct Collection *child); + +bool BKE_collection_move(struct Main *bmain, + struct Collection *to_parent, + struct Collection *from_parent, + struct Collection *relative, + bool relative_after, + struct Collection *collection); + +bool BKE_collection_find_cycle(struct Collection *new_ancestor, + struct Collection *collection); + + +/* Iteration callbacks. */ + +typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data); +typedef void (*BKE_scene_collections_Cb)(struct Collection *ob, void *data); + +void BKE_scene_collections_callback(struct Scene *scene, BKE_scene_collections_Cb callback, void *data); +void BKE_scene_objects_callback(struct Scene *scene, BKE_scene_objects_Cb callback, void *data); + +/* Iteratorion over objects in collection. */ + +#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(_collection, _object, _mode) \ + { \ + int _base_flag = (_mode == DAG_EVAL_VIEWPORT) ? \ + BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; \ + int _base_id = 0; \ + for (Base *_base = (Base*)BKE_collection_object_cache_get(_collection).first; \ + _base; \ + _base = _base->next, _base_id++) \ + { \ + if (_base->flag & _base_flag) { \ + Object *_object = _base->object; \ + +#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END \ + } \ + } \ + } + +#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object) \ + for (Base *_base = (Base*)BKE_collection_object_cache_get(_collection).first; \ + _base; \ + _base = _base->next) \ + { \ + Object *_object = _base->object; \ + BLI_assert(_object != NULL); + +#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END \ + } ((void)0) + +/* Iteration over collections in scene. */ + +void BKE_scene_collections_iterator_begin(struct BLI_Iterator *iter, void *data_in); +void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter); +void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter); + +void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in); +void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter); +void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter); + +#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance) \ + ITER_BEGIN(BKE_scene_collections_iterator_begin, \ + BKE_scene_collections_iterator_next, \ + BKE_scene_collections_iterator_end, \ + scene, Collection *, _instance) + +#define FOREACH_SCENE_COLLECTION_END \ + ITER_END + +#define FOREACH_SCENE_OBJECT_BEGIN(scene, _instance) \ + ITER_BEGIN(BKE_scene_objects_iterator_begin, \ + BKE_scene_objects_iterator_next, \ + BKE_scene_objects_iterator_end, \ + scene, Object *, _instance) + +#define FOREACH_SCENE_OBJECT_END \ + ITER_END + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_COLLECTION_H__ */ diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 98dc7d69c0d..9bd1f5385da 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -44,11 +44,12 @@ #include "BLI_kdopbvh.h" struct CollisionModifierData; -struct Group; +struct Collection; struct MFace; struct MVert; struct Object; struct Scene; +struct Depsgraph; struct MVertTri; //////////////////////////////////////// @@ -62,6 +63,7 @@ typedef enum { COLLISION_USE_COLLFACE = (1 << 2), COLLISION_IS_EDGES = (1 << 3), #endif + COLLISION_INACTIVE = (1 << 4), } COLLISION_FLAGS; @@ -72,7 +74,7 @@ typedef enum { typedef struct CollPair { unsigned int face1; // cloth face unsigned int face2; // object face - double distance; // magnitude of vector + float distance; float normal[3]; float vector[3]; // unnormalized collision vector: p2-p1 float pa[3], pb[3]; // collision point p1 on face1, p2 on face2 @@ -143,14 +145,29 @@ void collision_move_object(struct CollisionModifierData *collmd, float step, flo void collision_get_collider_velocity(float vel_old[3], float vel_new[3], struct CollisionModifierData *collmd, struct CollPair *collpair); -///////////////////////////////////////////////// -// used in effect.c -///////////////////////////////////////////////// -/* explicit control over layer mask and dupli recursion */ -struct Object **get_collisionobjects_ext(struct Scene *scene, struct Object *self, struct Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli); +/* Collision relations for dependency graph build. */ + +typedef struct CollisionRelation { + struct CollisionRelation *next, *prev; + struct Object *ob; +} CollisionRelation; + +struct ListBase *BKE_collision_relations_create( + struct Depsgraph *depsgraph, + struct Collection *collection, + unsigned int modifier_type); +void BKE_collision_relations_free(struct ListBase *relations); + +/* Collision object lists for physics simulation evaluation. */ -struct Object **get_collisionobjects(struct Scene *scene, struct Object *self, struct Group *group, unsigned int *numcollobj, unsigned int modifier_type); +struct Object **BKE_collision_objects_create( + struct Depsgraph *depsgraph, + struct Object *self, + struct Collection *collection, + unsigned int *numcollobj, + unsigned int modifier_type); +void BKE_collision_objects_free(struct Object **objects); typedef struct ColliderCache { struct ColliderCache *next, *prev; @@ -158,8 +175,11 @@ typedef struct ColliderCache { struct CollisionModifierData *collmd; } ColliderCache; -struct ListBase *get_collider_cache(struct Scene *scene, struct Object *self, struct Group *group); -void free_collider_cache(struct ListBase **colliders); +struct ListBase *BKE_collider_cache_create( + struct Depsgraph *scene, + struct Object *self, + struct Collection *collection); +void BKE_collider_cache_free(struct ListBase **colliders); ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 293ac30f0f9..e7672001a15 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -40,6 +40,7 @@ struct ListBase; struct Object; struct Scene; struct bPoseChannel; +struct Depsgraph; /* ---------------------------------------------------------------------------- */ #ifdef __cplusplus @@ -48,6 +49,7 @@ extern "C" { /* special struct for use in constraint evaluation */ typedef struct bConstraintOb { + struct Depsgraph *depsgraph;/* to get evaluated armature. */ struct Scene *scene; /* for system time, part of deglobalization, code nicer later with local time (ton) */ struct Object *ob; /* if pchan, then armature that it comes from, otherwise constraint owner */ struct bPoseChannel *pchan; /* pose channel that owns the constraints being evaluated */ @@ -104,7 +106,7 @@ typedef struct bConstraintTypeInfo { /* evaluation */ /* set the ct->matrix for the given constraint target (at the given ctime) */ - void (*get_target_matrix)(struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime); + void (*get_target_matrix)(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime); /* evaluate the constraint for the given time */ void (*evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets); } bConstraintTypeInfo; @@ -119,6 +121,8 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type); /* Constraint function prototypes */ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list); +struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src, const int flag, const bool do_extern); + void BKE_constraints_free(struct ListBase *list); void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user); void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern); @@ -127,11 +131,15 @@ void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void void BKE_constraint_free_data(struct bConstraint *con); void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user); +bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct); + /* Constraint API function prototypes */ struct bConstraint *BKE_constraints_active_get(struct ListBase *list); void BKE_constraints_active_set(ListBase *list, struct bConstraint *con); struct bConstraint *BKE_constraints_find_name(struct ListBase *list, const char *name); +struct bConstraint *BKE_constraint_find_from_target(struct Object *ob, struct bConstraintTarget *tgt); + struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type); struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type); @@ -143,15 +151,16 @@ void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *s bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan); /* Constraint Evaluation function prototypes */ -struct bConstraintOb *BKE_constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); +struct bConstraintOb *BKE_constraints_make_evalob(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, void *subdata, short datatype); void BKE_constraints_clear_evalob(struct bConstraintOb *cob); void BKE_constraint_mat_convertspace( struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale); -void BKE_constraint_target_matrix_get(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); -void BKE_constraint_targets_for_solving_get(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); -void BKE_constraints_solve(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); +void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, struct Scene *scene, struct bConstraint *con, + int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); +void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); +void BKE_constraints_solve(struct Depsgraph *depsgraph, struct ListBase *conlist, struct bConstraintOb *cob, float ctime); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 4db365b7307..9379853af29 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -40,15 +40,21 @@ extern "C" { struct ARegion; struct bScreen; struct CacheFile; +struct Collection; +struct Depsgraph; +struct LayerCollection; struct ListBase; struct Main; struct Object; +struct Base; struct PointerRNA; struct ReportList; struct Scene; +struct ViewLayer; struct ScrArea; struct SpaceLink; struct View3D; +struct ViewRender; struct RegionView3D; struct StructRNA; struct ToolSettings; @@ -59,16 +65,17 @@ struct bPoseChannel; struct bGPdata; struct bGPDlayer; struct bGPDframe; -struct bGPDpalette; -struct bGPDpalettecolor; -struct bGPDbrush; +struct Brush; struct wmWindow; struct wmWindowManager; +struct RenderEngineType; struct SpaceText; struct SpaceImage; struct SpaceClip; struct ID; +#include "DNA_object_enums.h" + /* Structs */ struct bContext; @@ -110,7 +117,12 @@ enum { CTX_MODE_PAINT_VERTEX, CTX_MODE_PAINT_TEXTURE, CTX_MODE_PARTICLE, - CTX_MODE_OBJECT + CTX_MODE_OBJECT, + CTX_MODE_GPENCIL_PAINT, + CTX_MODE_GPENCIL_EDIT, + CTX_MODE_GPENCIL_SCULPT, + CTX_MODE_GPENCIL_WEIGHT, + CTX_MODE_NUM /* must be last */ }; /* Context */ @@ -140,12 +152,15 @@ void CTX_py_dict_set(bContext *C, void *value); struct wmWindowManager *CTX_wm_manager(const bContext *C); struct wmWindow *CTX_wm_window(const bContext *C); +struct WorkSpace *CTX_wm_workspace(const bContext *C); struct bScreen *CTX_wm_screen(const bContext *C); struct ScrArea *CTX_wm_area(const bContext *C); struct SpaceLink *CTX_wm_space_data(const bContext *C); struct ARegion *CTX_wm_region(const bContext *C); void *CTX_wm_region_data(const bContext *C); struct ARegion *CTX_wm_menu(const bContext *C); +struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C); +struct wmMsgBus *CTX_wm_message_bus(const bContext *C); struct ReportList *CTX_wm_reports(const bContext *C); struct View3D *CTX_wm_view3d(const bContext *C); @@ -158,14 +173,13 @@ struct SpaceFile *CTX_wm_space_file(const bContext *C); struct SpaceSeq *CTX_wm_space_seq(const bContext *C); struct SpaceOops *CTX_wm_space_outliner(const bContext *C); struct SpaceNla *CTX_wm_space_nla(const bContext *C); -struct SpaceTime *CTX_wm_space_time(const bContext *C); struct SpaceNode *CTX_wm_space_node(const bContext *C); -struct SpaceLogic *CTX_wm_space_logic(const bContext *C); struct SpaceIpo *CTX_wm_space_graph(const bContext *C); struct SpaceAction *CTX_wm_space_action(const bContext *C); struct SpaceInfo *CTX_wm_space_info(const bContext *C); struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C); struct SpaceClip *CTX_wm_space_clip(const bContext *C); +struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C); void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm); void CTX_wm_window_set(bContext *C, struct wmWindow *win); @@ -173,6 +187,7 @@ void CTX_wm_screen_set(bContext *C, struct bScreen *screen); /* to be removed */ void CTX_wm_area_set(bContext *C, struct ScrArea *sa); void CTX_wm_region_set(bContext *C, struct ARegion *region); void CTX_wm_menu_set(bContext *C, struct ARegion *menu); +void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup); const char *CTX_wm_operator_poll_msg_get(struct bContext *C); void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg); @@ -209,11 +224,6 @@ short CTX_data_type_get(struct bContextDataResult *result); bool CTX_data_equals(const char *member, const char *str); bool CTX_data_dir(const char *member); -#if 0 -void CTX_data_pointer_set(bContextDataResult *result, void *data); -void CTX_data_list_add(bContextDataResult *result, void *data); -#endif - #define CTX_DATA_BEGIN(C, Type, instance, member) \ { \ ListBase ctx_data_list; \ @@ -243,9 +253,16 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas struct Main *CTX_data_main(const bContext *C); struct Scene *CTX_data_scene(const bContext *C); +struct LayerCollection *CTX_data_layer_collection(const bContext *C); +struct Collection *CTX_data_collection(const bContext *C); +struct ViewLayer *CTX_data_view_layer(const bContext *C); +struct RenderEngineType *CTX_data_engine_type(const bContext *C); struct ToolSettings *CTX_data_tool_settings(const bContext *C); const char *CTX_data_mode_string(const bContext *C); +int CTX_data_mode_enum_ex( + const struct Object *obedit, const struct Object *ob, + const eObjectMode object_mode); int CTX_data_mode_enum(const bContext *C); void CTX_data_main_set(bContext *C, struct Main *bmain); @@ -288,18 +305,23 @@ int CTX_data_editable_bones(const bContext *C, ListBase *list); struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C); int CTX_data_selected_pose_bones(const bContext *C, ListBase *list); +int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list); int CTX_data_visible_pose_bones(const bContext *C, ListBase *list); struct bGPdata *CTX_data_gpencil_data(const bContext *C); struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C); struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C); -struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C); -struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C); -struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C); +struct Brush *CTX_data_active_gpencil_brush(const bContext *C); int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); +struct Depsgraph *CTX_data_depsgraph(const bContext *C); + +/* Will Return NULL if depsgraph is not allocated yet. + * Only used by handful of operators which are run on file load. + */ +struct Depsgraph *CTX_data_depsgraph_on_load(const bContext *C); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h index ee6c5c57678..e9745ed50fa 100644 --- a/source/blender/blenkernel/BKE_crazyspace.h +++ b/source/blender/blenkernel/BKE_crazyspace.h @@ -38,23 +38,24 @@ struct Scene; struct Object; struct BMEditMesh; struct Mesh; +struct Depsgraph; /* crazyspace.c */ float (*BKE_crazyspace_get_mapped_editverts( - struct Scene *scene, struct Object *obedit))[3]; + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *obedit))[3]; void BKE_crazyspace_set_quats_editmesh( struct BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4], const bool use_select); void BKE_crazyspace_set_quats_mesh( struct Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]); int BKE_crazyspace_get_first_deform_matrices_editbmesh( - struct Scene *, struct Object *, struct BMEditMesh *em, + struct Depsgraph *depsgraph, struct Scene *, struct Object *, struct BMEditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]); int BKE_sculpt_get_first_deform_matrices( - struct Scene *scene, struct Object *ob, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]); void BKE_crazyspace_build_sculpt( - struct Scene *scene, struct Object *ob, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 5b7e5f9eebb..12e3492368b 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -36,6 +36,7 @@ struct BezTriple; struct Curve; struct EditNurb; +struct Depsgraph; struct GHash; struct ListBase; struct Main; @@ -122,13 +123,14 @@ void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex); void BKE_curve_editNurb_free(struct Curve *cu); struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu); -float *BKE_curve_make_orco(struct Scene *scene, struct Object *ob, int *r_numVerts); +float *BKE_curve_make_orco(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, int *r_numVerts); float *BKE_curve_surf_make_orco(struct Object *ob); void BKE_curve_bevelList_free(struct ListBase *bev); void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, bool for_render); -void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBase *disp, - const bool for_render, const bool use_render_resolution); +void BKE_curve_bevel_make( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *disp, + const bool for_render, const bool use_render_resolution); void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride); void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride); @@ -220,10 +222,17 @@ void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles); /* **** Depsgraph evaluation **** */ -struct EvaluationContext; - -void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx, - struct Curve *curve); +void BKE_curve_eval_geometry( + struct Depsgraph *depsgraph, + struct Curve *curve); + +/* Draw Cache */ +enum { + BKE_CURVE_BATCH_DIRTY_ALL = 0, + BKE_CURVE_BATCH_DIRTY_SELECT, +}; +void BKE_curve_batch_cache_dirty_tag(struct Curve *cu, int mode); +void BKE_curve_batch_cache_free(struct Curve *cu); /* curve_decimate.c */ unsigned int BKE_curve_decimate_bezt_array( diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index e75997cd394..23bc7ddd6fd 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -67,12 +67,14 @@ extern const CustomDataMask CD_MASK_EVERYTHING; * CD_NUMTYPES elements, that indicate if a layer can be copied. */ /* add/copy/merge allocation types */ -#define CD_ASSIGN 0 /* use the data pointer */ -#define CD_CALLOC 1 /* allocate blank memory */ -#define CD_DEFAULT 2 /* allocate and set to default */ -#define CD_REFERENCE 3 /* use data pointers, set layer flag NOFREE */ -#define CD_DUPLICATE 4 /* do a full copy of all layers, only allowed if source - * has same number of elements */ +typedef enum eCDAllocType { + CD_ASSIGN = 0, /* use the data pointer */ + CD_CALLOC = 1, /* allocate blank memory */ + CD_DEFAULT = 2, /* allocate and set to default */ + CD_REFERENCE = 3, /* use data pointers, set layer flag NOFREE */ + CD_DUPLICATE = 4, /* do a full copy of all layers, only allowed if source + * has same number of elements */ +} eCDAllocType; #define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type)) @@ -120,16 +122,18 @@ void CustomData_data_add(int type, void *data1, const void *data2); /* initializes a CustomData object with the same layer setup as source. * mask is a bitfield where (mask & (1 << (layer type))) indicates * if a layer should be copied or not. alloctype must be one of the above. */ -void CustomData_copy(const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, int alloctype, int totelem); +void CustomData_copy( + const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, eCDAllocType alloctype, int totelem); /* BMESH_TODO, not really a public function but readfile.c needs it */ void CustomData_update_typemap(struct CustomData *data); /* same as the above, except that this will preserve existing layers, and only * add the layers that were not there yet */ -bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, int alloctype, int totelem); +bool CustomData_merge( + const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, eCDAllocType alloctype, int totelem); /* Reallocate custom data to a new element count. * Only affects on data layers which are owned by the CustomData itself, @@ -144,7 +148,7 @@ void CustomData_realloc(struct CustomData *data, int totelem); * consistent with the new layout.*/ bool CustomData_bmesh_merge( const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, int alloctype, struct BMesh *bm, const char htype); + CustomDataMask mask, eCDAllocType alloctype, struct BMesh *bm, const char htype); /** NULL's all members and resets the typemap. */ void CustomData_reset(struct CustomData *data); @@ -164,11 +168,13 @@ void CustomData_free_temporary(struct CustomData *data, int totelem); * backed by an external data array. the different allocation types are * defined above. returns the data of the layer. */ -void *CustomData_add_layer(struct CustomData *data, int type, int alloctype, - void *layer, int totelem); +void *CustomData_add_layer( + struct CustomData *data, int type, eCDAllocType alloctype, + void *layer, int totelem); /*same as above but accepts a name */ -void *CustomData_add_layer_named(struct CustomData *data, int type, int alloctype, - void *layer, int totelem, const char *name); +void *CustomData_add_layer_named( + struct CustomData *data, int type, eCDAllocType alloctype, + void *layer, int totelem, const char *name); /* frees the active or first data layer with the give type. * returns 1 on success, 0 if no layer with the given type is found @@ -218,13 +224,20 @@ void CustomData_copy_data(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count); void CustomData_copy_data_named(const struct CustomData *source, - struct CustomData *dest, int source_index, - int dest_index, int count); + struct CustomData *dest, int source_index, + int dest_index, int count); void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count); void CustomData_bmesh_copy_data(const struct CustomData *source, struct CustomData *dest, void *src_block, void **dest_block); +/* Copies data of a single layer of a given type. */ +void CustomData_copy_layer_type_data(const struct CustomData *source, + struct CustomData *destination, + int type, + int source_index, int destination_index, + int count); + /* frees data in a CustomData object * return 1 on success, 0 on failure */ @@ -376,15 +389,14 @@ void CustomData_validate_layer_name(const struct CustomData *data, int type, con bool CustomData_verify_versions(struct CustomData *data, int index); /*BMesh specific customdata stuff*/ -void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, - struct CustomData *ldata, int totloop, int totpoly); -void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total); -void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata); -void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata); +void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop); +void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total); +void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata); +void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, struct CustomData *ldata); void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype); #ifndef NDEBUG -bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback); +bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback); #endif /* External file storage */ diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h index 2ee9d8d2408..7d0bb67c54d 100644 --- a/source/blender/blenkernel/BKE_data_transfer.h +++ b/source/blender/blenkernel/BKE_data_transfer.h @@ -38,6 +38,7 @@ extern "C" { #include "BKE_customdata.h" +struct Depsgraph; struct Object; struct Scene; struct SpaceTransform; @@ -129,11 +130,12 @@ enum { }; void BKE_object_data_transfer_layout( - struct Scene *scene, struct Object *ob_src, struct Object *ob_dst, const int data_types, const bool use_delete, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_src, + struct Object *ob_dst, const int data_types, const bool use_delete, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]); bool BKE_object_data_transfer_mesh( - struct Scene *scene, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_src, struct Object *ob_dst, const int data_types, const bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, struct SpaceTransform *space_transform, const bool auto_transform, @@ -141,9 +143,9 @@ bool BKE_object_data_transfer_mesh( const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, struct ReportList *reports); -bool BKE_object_data_transfer_dm( - struct Scene *scene, - struct Object *ob_src, struct Object *ob_dst, struct DerivedMesh *dm_dst, +bool BKE_object_data_transfer_ex( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob_src, struct Object *ob_dst, struct Mesh *me_dst, const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, struct SpaceTransform *space_transform, const bool auto_transform, diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index a20c5a4240c..a29f4197299 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -116,4 +116,6 @@ void BKE_defvert_extract_vgroup_to_polyweights( struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops, struct MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup); +void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight); + #endif /* __BKE_DEFORM_H__ */ diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h deleted file mode 100644 index 4af4f696b07..00000000000 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * ***** 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) 2004 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __BKE_DEPSGRAPH_H__ -#define __BKE_DEPSGRAPH_H__ - -/** \file BKE_depsgraph.h - * \ingroup bke - */ - -/* Dependency Graph - * - * The dependency graph tracks relations between datablocks, and is used to - * determine which datablocks need to be update based on dependencies and - * visibility. - * - * It does not itself execute changes in objects, but rather sorts the objects - * in the appropriate order and sets flags indicating they should be updated. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct ID; -struct Main; -struct Object; -struct Scene; - -/* Dependency graph evaluation context - * - * This structure stores all the local dependency graph data, - * which is needed for it's evaluation, - */ -typedef struct EvaluationContext { - int mode; /* evaluation mode */ - float ctime; /* evaluation time */ -} EvaluationContext; - -typedef enum eEvaluationMode { - DAG_EVAL_VIEWPORT = 0, /* evaluate for OpenGL viewport */ - DAG_EVAL_PREVIEW = 1, /* evaluate for render with preview settings */ - DAG_EVAL_RENDER = 2, /* evaluate for render purposes */ -} eEvaluationMode; - -/* DagNode->eval_flags */ -enum { - /* Regardless to curve->path animation flag path is to be evaluated anyway, - * to meet dependencies with such a things as curve modifier and other guys - * who're using curve deform, where_on_path and so. - */ - DAG_EVAL_NEED_CURVE_PATH = 1, - /* Scene evaluation would need to have object's data on CPU, - * meaning no GPU shortcuts is allowed. - */ - DAG_EVAL_NEED_CPU = 2, -}; - -/* Global initialization/deinitialization */ -void DAG_init(void); -void DAG_exit(void); - -/* Build and Update - * - * DAG_scene_relations_update will rebuild the dependency graph for a given - * scene if needed, and sort objects in the scene. - * - * DAG_relations_tag_update will clear all dependency graphs and mark them to - * be rebuilt later. The graph is not rebuilt immediately to avoid slowdowns - * when this function is call multiple times from different operators. - * - * DAG_scene_relations_rebuild forces an immediaterebuild of the dependency - * graph, this is only needed in rare cases - */ - -void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce); -void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce); -void DAG_relations_tag_update(struct Main *bmain); -void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene); -void DAG_scene_free(struct Scene *sce); - -/* Update Tagging - * - * DAG_scene_update_flags will mark all objects that depend on time (animation, - * physics, ..) to be recalculated, used when changing the current frame. - * - * DAG_on_visible_update will mark all objects that are visible for the first - * time to be updated, for example on file load or changing layer visibility. - * - * DAG_id_tag_update will mark a given datablock to be updated. The flag indicates - * a specific subset to be update (only object transform and data for now). - * - * DAG_id_type_tag marks a particular datablock type as having changing. This does - * not cause any updates but is used by external render engines to detect if for - * example a datablock was removed. */ - -void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const bool do_time, const bool do_invisible_flush); -void DAG_on_visible_update(struct Main *bmain, const bool do_time); - -void DAG_id_tag_update(struct ID *id, short flag); -void DAG_id_tag_update_ex(struct Main *bmain, struct ID *id, short flag); -void DAG_id_type_tag(struct Main *bmain, short idtype); -int DAG_id_type_tagged(struct Main *bmain, short idtype); - -/* Flushing Tags - * - * DAG_scene_flush_update flushes object recalculation flags immediately to other - * dependencies. Do not use outside of depsgraph.c, this will be removed. - * - * DAG_ids_flush_tagged will flush datablock update flags flags to dependencies, - * use this right before updating to mark all the needed datablocks for update. - * - * DAG_ids_check_recalc and DAG_ids_clear_recalc are used for external render - * engines to detect changes. */ - -void DAG_scene_flush_update(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time); -void DAG_ids_flush_tagged(struct Main *bmain); -void DAG_ids_check_recalc(struct Main *bmain, struct Scene *scene, bool time); -void DAG_ids_clear_recalc(struct Main *bmain); - -/* Armature: sorts the bones according to dependencies between them */ - -void DAG_pose_sort(struct Object *ob); - -/* Editors: callbacks to notify editors of datablock changes */ - -void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id), - void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated), - void (*scene_pre_func)(struct Main *bmain, struct Scene *scene, bool time)); - -void DAG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time); - -/* ** Threaded update ** */ - -/* Initialize the DAG for threaded update. */ -void DAG_threaded_update_begin(struct Scene *scene, - void (*func)(void *node, void *user_data), - void *user_data); - -void DAG_threaded_update_handle_node_updated(void *node_v, - void (*func)(void *node, void *user_data), - void *user_data); - -/* Debugging: print dependency graph for scene or armature object to console */ - -void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob); - -/* ************************ DAG querying ********************* */ - -struct Object *DAG_get_node_object(void *node_v); -const char *DAG_get_node_name(struct Scene *scene, void *node_v); -short DAG_get_eval_flags_for_object(struct Scene *scene, void *object); -bool DAG_is_acyclic(struct Scene *scene); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index a9cfa7b14ed..02c86642b11 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -57,8 +57,8 @@ enum { /* prototypes */ -struct DerivedMesh; -struct EvaluationContext; +struct Depsgraph; +struct Mesh; struct ListBase; struct Main; struct Object; @@ -87,23 +87,25 @@ void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface, int *to void BKE_displist_free(struct ListBase *lb); bool BKE_displist_has_faces(struct ListBase *lb); -void BKE_displist_make_surf(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct DerivedMesh **r_dm_final, - const bool for_render, const bool for_orco, const bool use_render_resolution); -void BKE_displist_make_curveTypes(struct Scene *scene, struct Object *ob, const bool for_orco); -void BKE_displist_make_curveTypes_forRender(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct DerivedMesh **r_dm_final, - const bool for_orco, const bool use_render_resolution); -void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase); -void BKE_displist_make_mball(struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); -void BKE_displist_make_mball_forRender(struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase); +void BKE_displist_make_surf( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase, + struct Mesh **r_final, const bool for_render, const bool for_orco, const bool use_render_resolution); +void BKE_displist_make_curveTypes( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, const bool for_orco); +void BKE_displist_make_curveTypes_forRender( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase, + struct Mesh **r_final, const bool for_orco, const bool use_render_resolution); +void BKE_displist_make_curveTypes_forOrco( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase); +void BKE_displist_make_mball( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); +void BKE_displist_make_mball_forRender( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase); bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4); void BKE_displist_fill(struct ListBase *dispbase, struct ListBase *to, const float normal_proj[3], const bool flipnormal); -float BKE_displist_calc_taper(struct Scene *scene, struct Object *taperobj, int cur, int tot); - -/* add Orco layer to the displist object which has got derived mesh and return orco */ -float *BKE_displist_make_orco(struct Scene *scene, struct Object *ob, struct DerivedMesh *dm_final, - const bool for_render, const bool use_render_resolution); +float BKE_displist_calc_taper(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *taperobj, int cur, int tot); void BKE_displist_minmax(struct ListBase *dispbase, float min[3], float max[3]); diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h index c265672da88..cffadeb5fd9 100644 --- a/source/blender/blenkernel/BKE_dynamicpaint.h +++ b/source/blender/blenkernel/BKE_dynamicpaint.h @@ -27,11 +27,14 @@ * \ingroup bke */ -struct EvaluationContext; +struct Depsgraph; +struct DynamicPaintCanvasSettings; +struct DynamicPaintModifierData; struct Main; struct Scene; +struct ViewLayer; -/* Actual surface point */ +/* Actual surface point */ typedef struct PaintSurfaceData { void *format_data; /* special data for each surface "format" */ void *type_data; /* data used by specific surface type */ @@ -42,7 +45,7 @@ typedef struct PaintSurfaceData { } PaintSurfaceData; -/* Paint type surface point */ +/* Paint type surface point */ typedef struct PaintPoint { /* Wet paint is handled at effect layer only @@ -53,7 +56,7 @@ typedef struct PaintPoint { float color[4]; } PaintPoint; -/* height field waves */ +/* height field waves */ typedef struct PaintWavePoint { float height; @@ -62,9 +65,9 @@ typedef struct PaintWavePoint { short state; } PaintWavePoint; -struct DerivedMesh *dynamicPaint_Modifier_do( - struct Main *bmain, struct EvaluationContext *eval_ctx, struct DynamicPaintModifierData *pmd, struct Scene *scene, - struct Object *ob, struct DerivedMesh *dm); +struct Mesh *dynamicPaint_Modifier_do( + struct DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, struct Mesh *me); void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd); void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tsmd); @@ -88,9 +91,8 @@ struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings /* image sequence baking */ int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, short *do_update); int dynamicPaint_calculateFrame( - struct Main *bmain, - struct EvaluationContext *eval_ctx, struct DynamicPaintSurface *surface, struct Scene *scene, - struct Object *cObject, int frame); + struct DynamicPaintSurface *surface, struct Depsgraph *depsgraph, + struct Scene *scene, struct Object *cObject, int frame); void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, char *filename, short output_layer); /* PaintPoint state */ diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 2cae86d4c3b..de4efaf37b0 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -40,6 +40,8 @@ struct Mesh; struct Scene; struct DerivedMesh; struct MeshStatVis; +struct Depsgraph; +struct EditMeshData; /** * This structure is used for mesh edit-mode. @@ -62,8 +64,9 @@ typedef struct BMEditMesh { struct BMLoop *(*looptris)[3]; int tottri; + struct Mesh *mesh_eval_final, *mesh_eval_cage; + /*derivedmesh stuff*/ - struct DerivedMesh *derivedFinal, *derivedCage; CustomDataMask lastDataMask; unsigned char (*derivedVertColor)[4]; int derivedVertColorLen; @@ -88,17 +91,18 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em); BMEditMesh *BKE_editmesh_from_object(struct Object *ob); void BKE_editmesh_free_derivedmesh(BMEditMesh *em); void BKE_editmesh_free(BMEditMesh *em); -void BKE_editmesh_update_linked_customdata(BMEditMesh *em); void BKE_editmesh_color_free(BMEditMesh *em); void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype); float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]; +void BKE_editmesh_lnorspace_update(BMEditMesh *em); /* editderivedmesh.c */ /* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */ -void BKE_editmesh_statvis_calc(BMEditMesh *em, struct DerivedMesh *dm, - const struct MeshStatVis *statvis); +void BKE_editmesh_statvis_calc( + BMEditMesh *em, struct EditMeshData *emd, const struct MeshStatVis *statvis); -float (*BKE_editmesh_vertexCos_get(struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3]; +float (*BKE_editmesh_vertexCos_get( + struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3]; #endif /* __BKE_EDITMESH_H__ */ diff --git a/source/blender/blenkernel/BKE_bullet.h b/source/blender/blenkernel/BKE_editmesh_cache.h index 84fcd20374f..aaaa79a0857 100644 --- a/source/blender/blenkernel/BKE_bullet.h +++ b/source/blender/blenkernel/BKE_editmesh_cache.h @@ -15,29 +15,22 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __BKE_BULLET_H__ -#define __BKE_BULLET_H__ -/** \file BKE_bullet.h +#ifndef __BKE_EDITMESH_CACHE_H__ +#define __BKE_EDITMESH_CACHE_H__ + +/** \file BKE_editmesh_cache.h * \ingroup bke */ -struct BulletSoftBody; - +struct BMEditMesh; +struct EditMeshData; -/* allocates and initializes general main data */ -extern struct BulletSoftBody *bsbNew(void); +void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, struct EditMeshData *emd); +void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMeshData *emd); -/* frees internal data and softbody itself */ -extern void bsbFree(struct BulletSoftBody *sb); +void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd); -#endif +#endif /* __BKE_EDITMESH_CACHE_H__ */ diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h new file mode 100644 index 00000000000..9553fbc1a5c --- /dev/null +++ b/source/blender/blenkernel/BKE_editmesh_tangent.h @@ -0,0 +1,40 @@ +/* + * ***** 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. + * + * Contributor(s): Joseph Eagar. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_EDITMESH_TANGENT_H__ +#define __BKE_EDITMESH_TANGENT_H__ + +/** \file BKE_editmesh_tangent.h + * \ingroup bke + */ + +void BKE_editmesh_loop_tangent_calc( + BMEditMesh *em, bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_len, + const float (*poly_normals)[3], + const float (*loop_normals)[3], + const float (*vert_orco)[3], + CustomData *dm_loopdata_out, + const uint dm_loopdata_out_len, + short *tangent_mask_curr_p); + +#endif /* __BKE_EDITMESH_TANGENT_H__ */ diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index bb5048a00f0..3d4154c572b 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -40,12 +40,14 @@ struct Object; struct Scene; struct ListBase; -struct Group; +struct Collection; struct ParticleSimulationData; struct ParticleData; struct ParticleKey; +struct Depsgraph; +struct ViewLayer; -struct EffectorWeights *BKE_add_effector_weights(struct Group *group); +struct EffectorWeights *BKE_add_effector_weights(struct Collection *collection); struct PartDeflect *object_add_collision_fields(int type); /* Input to effector code */ @@ -93,6 +95,7 @@ typedef struct EffectorData { typedef struct EffectorCache { struct EffectorCache *next, *prev; + struct Depsgraph *depsgraph; struct Scene *scene; struct Object *ob; struct ParticleSystem *psys; @@ -109,11 +112,35 @@ typedef struct EffectorCache { int flag; } EffectorCache; -void free_partdeflect(struct PartDeflect *pd); -struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool for_simulation); -void pdEndEffectors(struct ListBase **effectors); -void pdPrecalculateEffectors(struct ListBase *effectors); -void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse); +typedef struct EffectorRelation { + struct EffectorRelation *next, *prev; + + struct Object *ob; + struct ParticleSystem *psys; + struct PartDeflect *pd; +} EffectorRelation; + +void free_partdeflect(struct PartDeflect *pd); + +struct ListBase *BKE_effector_relations_create( + struct Depsgraph *depsgraph, + struct ViewLayer *view_layer, + struct Collection *collection); +void BKE_effector_relations_free(struct ListBase *lb); + +struct ListBase *BKE_effectors_create( + struct Depsgraph *depsgraph, + struct Object *ob_src, + struct ParticleSystem *psys_src, + struct EffectorWeights *weights); +void BKE_effectors_apply( + struct ListBase *effectors, + struct ListBase *colliders, + struct EffectorWeights *weights, + struct EffectedPoint *point, + float *force, + float *impulse); +void BKE_effectors_free(struct ListBase *lb); void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point); void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point); diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 055a3d40aba..0b7ffb338d8 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -108,7 +108,11 @@ bool driver_get_variable_property( struct ChannelDriver *driver, struct DriverTarget *dtar, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); -float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime); +bool BKE_driver_has_simple_expression(struct ChannelDriver *driver); +void BKE_driver_invalidate_expression(struct ChannelDriver *driver, bool expr_changed, bool varname_changed); + +float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, + struct ChannelDriver *driver_orig, const float evaltime); /* ************** F-Curve Modifiers *************** */ @@ -269,6 +273,17 @@ bool BKE_fcurve_is_protected(struct FCurve *fcu); /* The curve is an infinite cycle via Cycles modifier */ bool BKE_fcurve_is_cyclic(struct FCurve *fcu); +/* Type of infinite cycle for a curve. */ +typedef enum eFCU_Cycle_Type { + FCU_CYCLE_NONE = 0, + /* The cycle repeats identically to the base range. */ + FCU_CYCLE_PERFECT, + /* The cycle accumulates the change between start and end keys. */ + FCU_CYCLE_OFFSET +} eFCU_Cycle_Type; + +eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu); + /* -------- Curve Sanity -------- */ void calchandles_fcurve(struct FCurve *fcu); @@ -282,7 +297,8 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]); /* evaluate fcurve */ float evaluate_fcurve(struct FCurve *fcu, float evaltime); -float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime); +float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, + struct ChannelDriver *driver_orig, float evaltime); /* evaluate fcurve and store value */ float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime); diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h index af5b146906a..4883f2392b0 100644 --- a/source/blender/blenkernel/BKE_fluidsim.h +++ b/source/blender/blenkernel/BKE_fluidsim.h @@ -36,10 +36,11 @@ struct Object; struct Scene; struct FluidsimSettings; struct MVert; +struct Depsgraph; /* old interface */ -void initElbeemMesh(struct Scene *scene, struct Object *ob, +void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords, int modifierIndex); diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h index ab527e9b393..32bd1c1be7d 100644 --- a/source/blender/blenkernel/BKE_freestyle.h +++ b/source/blender/blenkernel/BKE_freestyle.h @@ -49,8 +49,8 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings; /* FreestyleConfig */ void BKE_freestyle_config_init(FreestyleConfig *config); -void BKE_freestyle_config_free(FreestyleConfig *config); -void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag); +void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user); +void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag); /* FreestyleConfig.modules */ FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 6ed32fc43ac..410c8bb3a65 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -102,7 +102,6 @@ typedef struct Global { /* G.f */ #define G_RENDER_OGL (1 << 0) #define G_SWAP_EXCHANGE (1 << 1) -/* also uses G_FILE_AUTOPLAY */ /* #define G_RENDER_SHADOW (1 << 3) */ /* temp flag, removed */ #define G_BACKBUFSEL (1 << 4) #define G_PICKSEL (1 << 5) @@ -154,16 +153,6 @@ enum { #define G_AUTOPACK (1 << 0) #define G_FILE_COMPRESS (1 << 1) -#define G_FILE_AUTOPLAY (1 << 2) - -#ifdef DNA_DEPRECATED_ALLOW -#define G_FILE_ENABLE_ALL_FRAMES (1 << 3) /* deprecated */ -#define G_FILE_SHOW_DEBUG_PROPS (1 << 4) /* deprecated */ -#define G_FILE_SHOW_FRAMERATE (1 << 5) /* deprecated */ -/* #define G_FILE_SHOW_PROFILE (1 << 6) */ /* deprecated */ -/* #define G_FILE_LOCK (1 << 7) */ /* deprecated */ -/* #define G_FILE_SIGN (1 << 8) */ /* deprecated */ -#endif /* DNA_DEPRECATED_ALLOW */ #define G_FILE_USERPREFS (1 << 9) #define G_FILE_NO_UI (1 << 10) diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 92e16f02e25..3b8df66668a 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -26,30 +26,50 @@ #ifndef __BKE_GPENCIL_H__ #define __BKE_GPENCIL_H__ -/** \file BKE_gpencil.h - * \ingroup bke - * \author Joshua Leung - */ - + /** \file BKE_gpencil.h + * \ingroup bke + * \author Joshua Leung + */ + +struct CurveMapping; +struct Depsgraph; +struct GpencilModifierData; struct ToolSettings; struct ListBase; struct bGPdata; struct bGPDlayer; struct bGPDframe; +struct bGPDspoint; struct bGPDstroke; +struct Material; struct bGPDpalette; struct bGPDpalettecolor; struct Main; +struct BoundBox; +struct Brush; +struct Object; +struct bDeformGroup; +struct SimplifyGpencilModifierData; +struct ArrayGpencilModifierData; +struct LatticeGpencilModifierData; + +struct MDeformVert; +struct MDeformWeight; /* ------------ Grease-Pencil API ------------------ */ +void BKE_gpencil_free_point_weights(struct MDeformVert *dvert); +void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps); void BKE_gpencil_free_stroke(struct bGPDstroke *gps); bool BKE_gpencil_free_strokes(struct bGPDframe *gpf); void BKE_gpencil_free_frames(struct bGPDlayer *gpl); void BKE_gpencil_free_layers(struct ListBase *list); -void BKE_gpencil_free_brushes(struct ListBase *list); -void BKE_gpencil_free_palettes(struct ListBase *list); -void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes); +bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf); +void BKE_gpencil_free_derived_frames(struct bGPdata *gpd); +void BKE_gpencil_free(struct bGPdata *gpd, bool free_all); + +void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd); +void BKE_gpencil_batch_cache_free(struct bGPdata *gpd); void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps); @@ -60,21 +80,37 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]) struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src); struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src); -void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag); +void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst); +struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src); + +void BKE_gpencil_copy_data(struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag); +struct bGPdata *BKE_gpencil_copy(struct Main *bmain, const struct bGPdata *gpd); struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy); void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local); void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); -struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive); -struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src); -struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive); +/* materials */ +void BKE_gpencil_material_index_remove(struct bGPdata *gpd, int index); +void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len); +int BKE_gpencil_get_material_index(struct Object *ob, struct Material *ma); + +/* statistics functions */ +void BKE_gpencil_stats_update(struct bGPdata *gpd); + +/* Utilities for creating and populating GP strokes */ +/* - Number of values defining each point in the built-in data + * buffers for primitives (e.g. 2D Monkey) + */ +#define GP_PRIM_DATABUF_SIZE 5 -struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive); -struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src); -void BKE_gpencil_brush_init_presets(struct ToolSettings *ts); +void BKE_gpencil_stroke_add_points( + struct bGPDstroke *gps, + const float *array, const int totpoints, + const float mat[4][4]); +struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness); /* Stroke and Fill - Alpha Visibility Threshold */ #define GPENCIL_ALPHA_OPACITY_THRESH 0.001f @@ -103,20 +139,44 @@ struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd); void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active); void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl); -struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts); -void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active); -void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush); - -struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd); -void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active); -void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette); -void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd); - -struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette); -void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active); -void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor); -struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name); -void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname); -void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name); +struct Material *BKE_gpencil_get_material_from_brush(struct Brush *brush); +struct Material *BKE_gpencil_material_ensure(struct Main *bmain, struct Object *ob); + +/* object boundbox */ +bool BKE_gpencil_data_minmax( + struct Object *ob, const struct bGPdata *gpd, + float r_min[3], float r_max[3]); +bool BKE_gpencil_stroke_minmax( + const struct bGPDstroke *gps, const bool use_select, + float r_min[3], float r_max[3]); +bool BKE_gpencil_stroke_select_check( + const struct bGPDstroke *gps); + +struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob); +void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]); + +/* vertex groups */ +void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps); +void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup); +void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst); + +/* GPencil geometry evaluation */ +void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd); + +/* stroke geometry utilities */ +void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]); +void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor); +void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps); +void BKE_gpencil_subdivide(struct bGPDstroke *gps, int level, int flag); + +void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]); + +bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf); +bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence); + +void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe); +float BKE_gpencil_multiframe_falloff_calc(struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff); #endif /* __BKE_GPENCIL_H__ */ diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h new file mode 100644 index 00000000000..91f368613cb --- /dev/null +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -0,0 +1,270 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_GPENCIL_MODIFIER_H__ +#define __BKE_GPENCIL_MODIFIER_H__ + +/** \file BKE_gpencil_modifier.h + * \ingroup bke + */ + +#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */ +#include "BLI_compiler_attrs.h" +#include "BKE_customdata.h" + +struct ID; +struct Depsgraph; +struct DerivedMesh; +struct bContext; /* NOTE: bakeModifier() - called from UI - needs to create new datablocks, hence the need for this */ +struct Mesh; +struct Object; +struct Scene; +struct ViewLayer; +struct ListBase; +struct bArmature; +struct Main; +struct GpencilModifierData; +struct BMEditMesh; +struct DepsNodeHandle; +struct bGPDlayer; +struct bGPDframe; +struct bGPDstroke; +struct ModifierUpdateDepsgraphContext; + +#define GPENCIL_MODIFIER_ACTIVE(_md, _is_render) (((_md->mode & eGpencilModifierMode_Realtime) && (_is_render == false)) || \ + ((_md->mode & eGpencilModifierMode_Render) && (_is_render == true))) +#define GPENCIL_MODIFIER_EDIT(_md, _is_edit) (((_md->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit)) + +typedef enum { + /* Should not be used, only for None modifier type */ + eGpencilModifierTypeType_None, + + /* grease pencil modifiers */ + eGpencilModifierTypeType_Gpencil, +} GpencilModifierTypeType; + +typedef enum { + eGpencilModifierTypeFlag_SupportsMapping = (1 << 0), + eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1), + + /* For modifiers that support editmode this determines if the + * modifier should be enabled by default in editmode. This should + * only be used by modifiers that are relatively speedy and + * also generally used in editmode, otherwise let the user enable + * it by hand. + */ + eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2), + + /* For modifiers that require original data and so cannot + * be placed after any non-deformative modifier. + */ + eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3), + + /* max one per type */ + eGpencilModifierTypeFlag_Single = (1 << 4), + + /* can't be added manually by user */ + eGpencilModifierTypeFlag_NoUserAdd = (1 << 5), + /* can't be applied */ + eGpencilModifierTypeFlag_NoApply = (1 << 6), +} GpencilModifierTypeFlag; + +/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */ +typedef void(*GreasePencilObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag); +typedef void(*GreasePencilIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag); +typedef void(*GreasePencilTexWalkFunc)(void *userData, struct Object *ob, struct GpencilModifierData *md, const char *propname); + +typedef struct GpencilModifierTypeInfo { + /* The user visible name for this modifier */ + char name[32]; + + /* The DNA struct name for the modifier data type, used to + * write the DNA data out. + */ + char struct_name[32]; + + /* The size of the modifier data type, used by allocation. */ + int struct_size; + + GpencilModifierTypeType type; + GpencilModifierTypeFlag flags; + + + /********************* Non-optional functions *********************/ + + /* Copy instance data for this modifier type. Should copy all user + * level settings to the target modifier. + */ + void (*copyData)(const struct GpencilModifierData *md, struct GpencilModifierData *target); + + /* Callback for GP "stroke" modifiers that operate on the + * shape and parameters of the provided strokes (e.g. Thickness, Noise, etc.) + * + * The gpl parameter contains the GP layer that the strokes come from. + * While access is provided to this data, you should not directly access + * the gpl->frames data from the modifier. Instead, use the gpf parameter + * instead. + * + * The gps parameter contains the GP stroke to operate on. This is usually a copy + * of the original (unmodified and saved to files) stroke data. + */ + void (*deformStroke)(struct GpencilModifierData *md, struct Depsgraph *depsgraph, + struct Object *ob, struct bGPDlayer *gpl, struct bGPDstroke *gps); + + /* Callback for GP "geometry" modifiers that create extra geometry + * in the frame (e.g. Array) + * + * The gpf parameter contains the GP frame/strokes to operate on. This is + * usually a copy of the original (unmodified and saved to files) stroke data. + * Modifiers should only add any generated strokes to this frame (and not one accessed + * via the gpl parameter). + * + * The modifier_index parameter indicates where the modifier is + * in the modifier stack in relation to other modifiers. + */ + void (*generateStrokes)(struct GpencilModifierData *md, struct Depsgraph *depsgraph, + struct Object *ob, struct bGPDlayer *gpl, struct bGPDframe *gpf); + + /* Bake-down GP modifier's effects into the GP datablock. + * + * This gets called when the user clicks the "Apply" button in the UI. + * As such, this callback needs to go through all layers/frames in the + * datablock, mutating the geometry and/or creating new datablocks/objects + */ + void (*bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph, + struct GpencilModifierData *md, struct Object *ob); + + + /********************* Optional functions *********************/ + + /* Callback for GP "time" modifiers that offset keyframe time + * Returns the frame number to be used after apply the modifier. This is + * usually an offset of the animation for duplicated datablocks. + * + * This function is optional. + */ + int (*remapTime)(struct GpencilModifierData *md, struct Depsgraph *depsgraph, + struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl, int cfra); + + /* Initialize new instance data for this modifier type, this function + * should set modifier variables to their default values. + * + * This function is optional. + */ + void (*initData)(struct GpencilModifierData *md); + + /* Free internal modifier data variables, this function should + * not free the md variable itself. + * + * This function is optional. + */ + void (*freeData)(struct GpencilModifierData *md); + + /* Return a boolean value indicating if this modifier is able to be + * calculated based on the modifier data. This is *not* regarding the + * md->flag, that is tested by the system, this is just if the data + * validates (for example, a lattice will return false if the lattice + * object is not defined). + * + * This function is optional (assumes never disabled if not present). + */ + bool (*isDisabled)(struct GpencilModifierData *md, int userRenderParams); + + /* Add the appropriate relations to the dependency graph. + * + * This function is optional. + */ + void (*updateDepsgraph)(struct GpencilModifierData *md, + const struct ModifierUpdateDepsgraphContext *ctx); + + /* Should return true if the modifier needs to be recalculated on time + * changes. + * + * This function is optional (assumes false if not present). + */ + bool (*dependsOnTime)(struct GpencilModifierData *md); + + + /* Should call the given walk function on with a pointer to each Object + * pointer that the modifier data stores. This is used for linking on file + * load and for unlinking objects or forwarding object references. + * + * This function is optional. + */ + void (*foreachObjectLink)(struct GpencilModifierData *md, struct Object *ob, + GreasePencilObjectWalkFunc walk, void *userData); + + /* Should call the given walk function with a pointer to each ID + * pointer (i.e. each datablock pointer) that the modifier data + * stores. This is used for linking on file load and for + * unlinking datablocks or forwarding datablock references. + * + * This function is optional. If it is not present, foreachObjectLink + * will be used. + */ + void (*foreachIDLink)(struct GpencilModifierData *md, struct Object *ob, + GreasePencilIDWalkFunc walk, void *userData); + + /* Should call the given walk function for each texture that the + * modifier data stores. This is used for finding all textures in + * the context for the UI. + * + * This function is optional. If it is not present, it will be + * assumed the modifier has no textures. + */ + void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob, + GreasePencilTexWalkFunc walk, void *userData); +} GpencilModifierTypeInfo; + +/* Initialize modifier's global data (type info and some common global storages). */ +void BKE_gpencil_modifier_init(void); + +const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type); +struct GpencilModifierData *BKE_gpencil_modifier_new(int type); +void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag); +void BKE_gpencil_modifier_free(struct GpencilModifierData *md); +bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd); +bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md); +struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob, GpencilModifierType type); +struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name); +void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst); +void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md, struct GpencilModifierData *target); +void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag); +void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData); +void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); + +bool BKE_gpencil_has_geometry_modifiers(struct Object *ob); +bool BKE_gpencil_has_time_modifiers(struct Object *ob); + +void BKE_gpencil_stroke_modifiers( + struct Depsgraph *depsgraph, struct Object *ob, + struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps, bool is_render); +void BKE_gpencil_geometry_modifiers( + struct Depsgraph *depsgraph, struct Object *ob, + struct bGPDlayer *gpl, struct bGPDframe *gpf, bool is_render); +int BKE_gpencil_time_modifier( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, + struct bGPDlayer *gpl, int cfra, bool is_render); + +void BKE_gpencil_lattice_init(struct Object *ob); +void BKE_gpencil_lattice_clear(struct Object *ob); + +#endif /* __BKE_GPENCIL_MODIFIER_H__ */ diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h deleted file mode 100644 index 9824814990f..00000000000 --- a/source/blender/blenkernel/BKE_group.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef __BKE_GROUP_H__ -#define __BKE_GROUP_H__ - -/** \file BKE_group.h - * \ingroup bke - * \since March 2001 - * \author nzc - */ - -struct Base; -struct EvaluationContext; -struct Group; -struct Main; -struct Object; -struct Scene; - -void BKE_group_free(struct Group *group); -struct Group *BKE_group_add(struct Main *bmain, const char *name); -void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag); -struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group); -void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local); -bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); -bool BKE_group_object_unlink( - struct Main *bmain, struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); -struct Group *BKE_group_object_find(struct Main *bmain, struct Group *group, struct Object *ob); -bool BKE_group_object_exists(struct Group *group, struct Object *ob); -bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group); -bool BKE_group_is_animated(struct Group *group, struct Object *parent); - -void BKE_group_handle_recalc_and_update( - struct Main *bmain, struct EvaluationContext *eval_ctx, - struct Scene *scene, struct Object *parent, struct Group *group); - -#endif /* __BKE_GROUP_H__ */ diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 686dba21283..7a5262e0a14 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -36,18 +36,53 @@ typedef void (*DrawInfoFreeFP)(void *drawinfo); +enum { + /** ID preview: obj is #ID. */ + ICON_DATA_ID = 0, + /** Preview: obj is #PreviewImage */ + ICON_DATA_PREVIEW, + /** 2D triangles: obj is #Icon_Geom */ + ICON_DATA_GEOM, + /** Studiolight */ + ICON_DATA_STUDIOLIGHT, + /** GPencil Layer color preview (annotations): obj is #bGPDlayer */ + ICON_DATA_GPLAYER, +}; + struct Icon { void *drawinfo; + /** + * Data defined by #obj_type + * \note for #ICON_DATA_GEOM the memory is owned by the icon, + * could be made into a flag if we want that to be optional. + */ void *obj; + char obj_type; + /** Internal use only. */ + char flag; /** #ID_Type or 0 when not used for ID preview. */ short id_type; DrawInfoFreeFP drawinfo_free; }; +/** Used for #ICON_DATA_GEOM, assigned to #Icon.obj. */ +struct Icon_Geom { + int icon_id; + int coords_len; + int coords_range[2]; + const unsigned char (*coords)[2]; + const unsigned char (*colors)[4]; + /* when not NULL, the memory of coords and colors is a sub-region of this pointer. */ + const void *mem; +}; + typedef struct Icon Icon; +struct ImBuf; struct PreviewImage; struct ID; +struct StudioLight; +struct bGPDlayer; enum eIconSizes; @@ -56,6 +91,9 @@ void BKE_icons_init(int first_dyn_id); /* return icon id for library object or create new icon if not found */ int BKE_icon_id_ensure(struct ID *id); +/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */ +int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl); + int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview); /* retrieve icon for id */ @@ -68,7 +106,8 @@ void BKE_icon_set(const int icon_id, struct Icon *icon); /* remove icon and free data if library object becomes invalid */ void BKE_icon_id_delete(struct ID *id); -void BKE_icon_delete(const int icon_id); +bool BKE_icon_delete(const int icon_id); +bool BKE_icon_delete_unmanaged(const int icon_id); /* report changes - icon needs to be recalculated */ void BKE_icon_changed(const int icon_id); @@ -120,6 +159,16 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read( void BKE_previewimg_cached_release(const char *name); void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv); +int BKE_icon_geom_ensure(struct Icon_Geom *geom); +struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len); +struct Icon_Geom *BKE_icon_geom_from_file(const char *filename); + +struct ImBuf *BKE_icon_geom_rasterize( + const struct Icon_Geom *geom, + const unsigned int size_x, const unsigned int size_y); + +int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type); + #define ICON_RENDER_DEFAULT_HEIGHT 32 #endif /* __BKE_ICONS_H__ */ diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 48a00462dd1..6df31db7b83 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -32,6 +32,10 @@ #include "BLI_compiler_attrs.h" +#ifdef __cplusplus +extern "C" { +#endif + struct IDProperty; struct ID; @@ -91,6 +95,7 @@ void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *s void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); void IDP_ReplaceInGroup_ex(struct IDProperty *group, struct IDProperty *prop, struct IDProperty *prop_exist); void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite) ATTR_NONNULL(); +void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag) ATTR_NONNULL(); bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); bool IDP_InsertToGroup(struct IDProperty *group, struct IDProperty *previous, struct IDProperty *pnew) ATTR_NONNULL(1 /* group */, 3 /* pnew */); @@ -118,6 +123,8 @@ void IDP_ClearProperty(IDProperty *prop); void IDP_RelinkProperty(struct IDProperty *prop); +void IDP_Reset(IDProperty *prop, const IDProperty *reference); + #define IDP_Int(prop) ((prop)->data.val) #define IDP_Array(prop) ((prop)->data.pointer) /* C11 const correctness for casts */ @@ -154,4 +161,8 @@ void IDP_repr_fn( void *user_data); void IDP_print(const struct IDProperty *prop); +#ifdef __cplusplus +} +#endif + #endif /* __BKE_IDPROP_H__ */ diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index bd9aeb1ab11..4bcb8e0c15d 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -114,8 +114,6 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const struc struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]); struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]); -void BKE_image_de_interlace(struct Image *ima, int odd); - void BKE_image_make_local(struct Main *bmain, struct Image *ima, const bool lib_local); void BKE_image_tag_time(struct Image *ima); @@ -213,9 +211,9 @@ struct Image *BKE_image_verify_viewer(struct Main *bmain, int type, const char * void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser); /* called on frame change or before render */ -void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr); -void BKE_image_user_check_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr); -int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, int fieldnr, bool *r_is_in_range); +void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra); +void BKE_image_user_check_frame_calc(struct ImageUser *iuser, int cfra); +int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range); void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path); void BKE_image_update_frame(const struct Main *bmain, int cfra); @@ -271,7 +269,7 @@ bool BKE_image_scale(struct Image *image, int width, int height); bool BKE_image_has_alpha(struct Image *image); /* check if texture has gpu texture code */ -bool BKE_image_has_bindcode(struct Image *ima); +bool BKE_image_has_opengl_texture(struct Image *ima); void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *width, int *height); void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float size[2]); @@ -296,6 +294,12 @@ void BKE_image_file_format_set(struct Image *image, int ftype, const struct ImbF bool BKE_image_has_loaded_ibuf(struct Image *image); struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name); struct ImBuf *BKE_image_get_first_ibuf(struct Image *image); + +struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name); +bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int slot); +struct RenderSlot *BKE_image_get_renderslot(struct Image *ima, int slot); +bool BKE_image_clear_renderslot(struct Image *ima, struct ImageUser *iuser, int slot); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 2f953e57d71..73a6f5047b2 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -80,29 +80,19 @@ struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]); void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src); char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb); -// needed for the GE -typedef struct WeightsArrayCache { - int num_defgroup_weights; - float **defgroup_weights; -} WeightsArrayCache; - -float **BKE_keyblock_get_per_block_weights(struct Object *ob, struct Key *key, struct WeightsArrayCache *cache); -void BKE_keyblock_free_per_block_weights(struct Key *key, float **per_keyblock_weights, struct WeightsArrayCache *cache); -void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb, - float **per_keyblock_weights, const int mode); - /* conversion functions */ /* Note: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */ void BKE_keyblock_update_from_lattice(struct Lattice *lt, struct KeyBlock *kb); void BKE_keyblock_convert_from_lattice(struct Lattice *lt, struct KeyBlock *kb); void BKE_keyblock_convert_to_lattice(struct KeyBlock *kb, struct Lattice *lt); +int BKE_keyblock_curve_element_count(struct ListBase *nurb); void BKE_keyblock_update_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb); void BKE_keyblock_convert_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb); void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct ListBase *nurb); void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb); -void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct KeyBlock *kb); +void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb); void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me); void BKE_keyblock_mesh_calc_normals( struct KeyBlock *kb, struct Mesh *mesh, float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3]); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index 3673e657b33..aa655c66477 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -50,8 +50,6 @@ struct Lamp *BKE_lamp_localize(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local); void BKE_lamp_free(struct Lamp *la); -void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime); - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index f7d006785d2..2e093ba11a2 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -38,11 +38,13 @@ struct Lattice; struct Main; +struct Mesh; struct Object; struct Scene; -struct DerivedMesh; struct BPoint; struct MDeformVert; +struct Depsgraph; +struct bGPDstroke; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); void BKE_lattice_init(struct Lattice *lt); @@ -53,7 +55,6 @@ void BKE_lattice_free(struct Lattice *lt); void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); -struct LatticeDeformData; struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) ATTR_WARN_UNUSED_RESULT; void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight); void end_latt_deform(struct LatticeDeformData *lattice_deform_data); @@ -61,23 +62,28 @@ void end_latt_deform(struct LatticeDeformData *lattice_deform_data); bool object_deform_mball(struct Object *ob, struct ListBase *dispbase); void outside_lattice(struct Lattice *lt); -void curve_deform_verts(struct Scene *scene, struct Object *cuOb, struct Object *target, - struct DerivedMesh *dm, float (*vertexCos)[3], - int numVerts, const char *vgroup, short defaxis); -void curve_deform_vector(struct Scene *scene, struct Object *cuOb, struct Object *target, - float orco[3], float vec[3], float mat[3][3], int no_rot_axis); - -void lattice_deform_verts(struct Object *laOb, struct Object *target, - struct DerivedMesh *dm, float (*vertexCos)[3], - int numVerts, const char *vgroup, float influence); -void armature_deform_verts(struct Object *armOb, struct Object *target, - struct DerivedMesh *dm, float (*vertexCos)[3], - float (*defMats)[3][3], int numVerts, int deformflag, - float (*prevCos)[3], const char *defgrp_name); +void curve_deform_verts( + struct Object *cuOb, struct Object *target, + struct Mesh *mesh, float (*vertexCos)[3], + int numVerts, const char *vgroup, short defaxis); +void curve_deform_vector( + struct Object *cuOb, struct Object *target, + float orco[3], float vec[3], float mat[3][3], int no_rot_axis); + +void lattice_deform_verts( + struct Object *laOb, struct Object *target, + struct Mesh *mesh, float (*vertexCos)[3], + int numVerts, const char *vgroup, float influence); +void armature_deform_verts( + struct Object *armOb, struct Object *target, + const struct Mesh *mesh, float (*vertexCos)[3], + float (*defMats)[3][3], int numVerts, int deformflag, + float (*prevCos)[3], const char *defgrp_name, + struct bGPDstroke *gps); float (*BKE_lattice_vertexcos_get(struct Object *ob, int *r_numVerts))[3]; void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3]); -void BKE_lattice_modifiers_calc(struct Scene *scene, struct Object *ob); +void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); struct MDeformVert *BKE_lattice_deform_verts_get(struct Object *lattice); struct BPoint *BKE_lattice_active_point_get(struct Lattice *lt); @@ -90,6 +96,8 @@ void BKE_lattice_center_bounds(struct Lattice *lt, float cent[3]); void BKE_lattice_translate(struct Lattice *lt, float offset[3], bool do_keys); void BKE_lattice_transform(struct Lattice *lt, float mat[4][4], bool do_keys); +bool BKE_lattice_is_any_selected(const struct Lattice *lt); + int BKE_lattice_index_from_uvw(struct Lattice *lt, const int u, const int v, const int w); void BKE_lattice_index_to_uvw(struct Lattice *lt, const int index, int *r_u, int *r_v, int *r_w); int BKE_lattice_index_flip(struct Lattice *lt, const int index, @@ -99,9 +107,17 @@ void BKE_lattice_bitmap_from_flag(struct Lattice *lt, unsigned int *bitmap, cons /* **** Depsgraph evaluation **** */ -struct EvaluationContext; +struct Depsgraph; -void BKE_lattice_eval_geometry(struct EvaluationContext *eval_ctx, +void BKE_lattice_eval_geometry(struct Depsgraph *depsgraph, struct Lattice *latt); +/* Draw Cache */ +enum { + BKE_LATTICE_BATCH_DIRTY_ALL = 0, + BKE_LATTICE_BATCH_DIRTY_SELECT, +}; +void BKE_lattice_batch_cache_dirty_tag(struct Lattice *lt, int mode); +void BKE_lattice_batch_cache_free(struct Lattice *lt); + #endif /* __BKE_LATTICE_H__ */ diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h new file mode 100644 index 00000000000..2d736b41d1a --- /dev/null +++ b/source/blender/blenkernel/BKE_layer.h @@ -0,0 +1,396 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_LAYER_H__ +#define __BKE_LAYER_H__ + +/** \file blender/blenkernel/BKE_layer.h + * \ingroup bke + */ + +#include "BKE_collection.h" + +#include "DNA_listBase.h" +#include "DNA_scene_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TODO_LAYER_OVERRIDE /* CollectionOverride */ +#define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */ +#define TODO_LAYER /* generic todo */ + +#define ROOT_PROP "root" + +struct Base; +struct Collection; +struct Depsgraph; +struct ID; +struct IDProperty; +struct LayerCollection; +struct ListBase; +struct Main; +struct Object; +struct RenderEngine; +struct Scene; +struct ViewLayer; +struct WorkSpace; + +struct ViewLayer *BKE_view_layer_default_view(const struct Scene *scene); +struct ViewLayer *BKE_view_layer_default_render(const struct Scene *scene); +struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *layer_name); +struct ViewLayer *BKE_view_layer_add(struct Scene *scene, const char *name); + +/* DEPRECATED */ +struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene); + +void BKE_view_layer_free(struct ViewLayer *view_layer); +void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user); + +void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag); + +struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer); +struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene, struct LayerCollection *lc); +struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob); +void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer); + +void BKE_view_layer_base_select(struct Base *selbase); +void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, struct Base *selbase); + +void BKE_view_layer_copy_data( + struct Scene *scene_dst, const struct Scene *scene_src, + struct ViewLayer *view_layer_dst, const struct ViewLayer *view_layer_src, + const int flag); + +void BKE_view_layer_rename(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, const char *name); + +struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer); +bool BKE_layer_collection_activate(struct ViewLayer *view_layer, struct LayerCollection *lc); +struct LayerCollection *BKE_layer_collection_activate_parent(struct ViewLayer *view_layer, struct LayerCollection *lc); + +int BKE_layer_collection_count(struct ViewLayer *view_layer); + +struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer, const int index); +int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc); + +void BKE_main_collection_sync(const struct Main *bmain); +void BKE_scene_collection_sync(const struct Scene *scene); +void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer); + +void BKE_main_collection_sync_remap(const struct Main *bmain); + +struct LayerCollection *BKE_layer_collection_first_from_scene_collection( + struct ViewLayer *view_layer, const struct Collection *collection); +bool BKE_view_layer_has_collection( + struct ViewLayer *view_layer, const struct Collection *collection); +bool BKE_scene_has_object( + struct Scene *scene, struct Object *ob); + +/* selection and hiding */ + +bool BKE_layer_collection_objects_select( + struct ViewLayer *view_layer, struct LayerCollection *lc, bool deselect); +bool BKE_layer_collection_has_selected_objects( + struct ViewLayer *view_layer, struct LayerCollection *lc); + +void BKE_base_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, bool extend); +void BKE_layer_collection_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct LayerCollection *lc, bool extend); + +/* override */ + +void BKE_override_view_layer_datablock_add( + struct ViewLayer *view_layer, int id_type, const char *data_path, const struct ID *owner_id); +void BKE_override_view_layer_int_add( + struct ViewLayer *view_layer, int id_type, const char *data_path, const int value); + +void BKE_override_layer_collection_boolean_add( + struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value); + +/* evaluation */ + +void BKE_layer_eval_view_layer( + struct Depsgraph *depsgraph, + struct Scene *scene, + struct ViewLayer *view_layer); + +void BKE_layer_eval_view_layer_indexed( + struct Depsgraph *depsgraph, + struct Scene *scene, + int view_layer_index); + +/* iterators */ + +void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in); +void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter); +void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter); + +void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in); +void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter); +void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter); + +void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in); +void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter); +void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter); + +struct ObjectsInModeIteratorData { + int object_mode; + struct ViewLayer *view_layer; + struct Base *base_active; +}; + +void BKE_view_layer_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in); +void BKE_view_layer_renderable_objects_iterator_next(BLI_Iterator *iter); +void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *iter); + +void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in); +void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter); +void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *iter); + +void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in); +void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter); +void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter); + +void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in); +void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter); +void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); + +#define FOREACH_SELECTED_OBJECT_BEGIN(view_layer, _instance) \ + ITER_BEGIN(BKE_view_layer_selected_objects_iterator_begin, \ + BKE_view_layer_selected_objects_iterator_next, \ + BKE_view_layer_selected_objects_iterator_end, \ + view_layer, Object *, _instance) + +#define FOREACH_SELECTED_OBJECT_END \ + ITER_END + +#define FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer, _instance) \ + ITER_BEGIN(BKE_view_layer_selected_editable_objects_iterator_begin, \ + BKE_view_layer_selected_editable_objects_iterator_next, \ + BKE_view_layer_selected_editable_objects_iterator_end, \ + view_layer, Object *, _instance) + +#define FOREACH_SELECTED_EDITABLE_OBJECT_END \ + ITER_END + +#define FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, _instance) \ + ITER_BEGIN(BKE_view_layer_visible_objects_iterator_begin, \ + BKE_view_layer_visible_objects_iterator_next, \ + BKE_view_layer_visible_objects_iterator_end, \ + view_layer, Object *, _instance) + +#define FOREACH_VISIBLE_OBJECT_END \ + ITER_END + + +#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _object_mode, _instance) \ +{ \ + struct ObjectsInModeIteratorData data_ = { \ + .object_mode = _object_mode, \ + .view_layer = _view_layer, \ + .base_active = _view_layer->basact, \ + }; \ + ITER_BEGIN(BKE_view_layer_bases_in_mode_iterator_begin, \ + BKE_view_layer_bases_in_mode_iterator_next, \ + BKE_view_layer_bases_in_mode_iterator_end, \ + &data_, Base *, _instance) + +#define FOREACH_BASE_IN_MODE_END \ + ITER_END; \ +} ((void)0) + +#define FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \ + FOREACH_BASE_IN_MODE_BEGIN(_view_layer, OB_MODE_EDIT, _instance) + +#define FOREACH_BASE_IN_EDIT_MODE_END \ + FOREACH_BASE_IN_MODE_END + +#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _object_mode, _instance) \ + FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _object_mode, _base) { \ + Object *_instance = _base->object; + +#define FOREACH_OBJECT_IN_MODE_END \ + } FOREACH_BASE_IN_MODE_END + +#define FOREACH_OBJECT_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \ + FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _base) { \ + Object *_instance = _base->object; + +#define FOREACH_OBJECT_IN_EDIT_MODE_END \ + } FOREACH_BASE_IN_EDIT_MODE_END + +#define FOREACH_SELECTED_BASE_BEGIN(view_layer, _instance) \ + ITER_BEGIN(BKE_view_layer_selected_bases_iterator_begin, \ + BKE_view_layer_selected_bases_iterator_next, \ + BKE_view_layer_selected_bases_iterator_end, \ + view_layer, Base *, _instance) + +#define FOREACH_SELECTED_BASE_END \ + ITER_END + +#define FOREACH_VISIBLE_BASE_BEGIN(view_layer, _instance) \ + ITER_BEGIN(BKE_view_layer_visible_bases_iterator_begin, \ + BKE_view_layer_visible_bases_iterator_next, \ + BKE_view_layer_visible_bases_iterator_end, \ + view_layer, Base *, _instance) + +#define FOREACH_VISIBLE_BASE_END \ + ITER_END + + +#define FOREACH_OBJECT_BEGIN(view_layer, _instance) \ +{ \ + Object *_instance; \ + Base *_base; \ + for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \ + _instance = _base->object; + +#define FOREACH_OBJECT_END \ + } \ +} ((void)0) + +#define FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, _instance) \ +{ \ + IteratorBeginCb func_begin; \ + IteratorCb func_next, func_end; \ + void *data_in; \ + \ + if (flag == SELECT) { \ + func_begin = &BKE_view_layer_selected_objects_iterator_begin; \ + func_next = &BKE_view_layer_selected_objects_iterator_next; \ + func_end = &BKE_view_layer_selected_objects_iterator_end; \ + data_in = (view_layer); \ + } \ + else { \ + func_begin = BKE_scene_objects_iterator_begin; \ + func_next = BKE_scene_objects_iterator_next; \ + func_end = BKE_scene_objects_iterator_end; \ + data_in = (scene); \ + } \ + ITER_BEGIN(func_begin, func_next, func_end, data_in, Object *, _instance) + + +#define FOREACH_OBJECT_FLAG_END \ + ITER_END; \ +} ((void)0) + +struct ObjectsRenderableIteratorData { + struct Scene *scene; + struct Base base_temp; + struct Scene scene_temp; + + struct { + struct ViewLayer *view_layer; + struct Base *base; + struct Scene *set; + } iter; +}; + +#define FOREACH_OBJECT_RENDERABLE_BEGIN(scene_, _instance) \ +{ \ + struct ObjectsRenderableIteratorData data_ = { \ + .scene = (scene_), \ + }; \ + ITER_BEGIN(BKE_view_layer_renderable_objects_iterator_begin, \ + BKE_view_layer_renderable_objects_iterator_next, \ + BKE_view_layer_renderable_objects_iterator_end, \ + &data_, Object *, _instance) + + +#define FOREACH_OBJECT_RENDERABLE_END \ + ITER_END; \ +} ((void)0) + + +/* layer_utils.c */ + +struct ObjectsInModeParams { + int object_mode; + uint no_dup_data : 1; + + bool (*filter_fn)(struct Object *ob, void *user_data); + void *filter_userdata; +}; + +Base **BKE_view_layer_array_from_bases_in_mode_params( + struct ViewLayer *view_layer, uint *r_len, + const struct ObjectsInModeParams *params); + +struct Object **BKE_view_layer_array_from_objects_in_mode_params( + struct ViewLayer *view_layer, uint *len, + const struct ObjectsInModeParams *params); + +#define BKE_view_layer_array_from_objects_in_mode(view_layer, r_len, ...) \ + BKE_view_layer_array_from_objects_in_mode_params( \ + view_layer, r_len, \ + &(const struct ObjectsInModeParams)__VA_ARGS__) + +#define BKE_view_layer_array_from_bases_in_mode(view_layer, r_len, ...) \ + BKE_view_layer_array_from_bases_in_mode_params( \ + view_layer, r_len, \ + &(const struct ObjectsInModeParams)__VA_ARGS__) + +bool BKE_view_layer_filter_edit_mesh_has_uvs(struct Object *ob, void *user_data); +bool BKE_view_layer_filter_edit_mesh_has_edges(struct Object *ob, void *user_data); + +/* Utility macros that wrap common args (add more as needed). */ + +#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, r_len) \ + BKE_view_layer_array_from_objects_in_mode( \ + view_layer, r_len, { \ + .object_mode = OB_MODE_EDIT}); + +#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, r_len) \ + BKE_view_layer_array_from_bases_in_mode( \ + view_layer, r_len, { \ + .object_mode = OB_MODE_EDIT}); + +#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, r_len) \ + BKE_view_layer_array_from_objects_in_mode( \ + view_layer, r_len, { \ + .object_mode = OB_MODE_EDIT, \ + .no_dup_data = true}); + +#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, r_len) \ + BKE_view_layer_array_from_bases_in_mode( \ + view_layer, r_len, { \ + .object_mode = OB_MODE_EDIT, \ + .no_dup_data = true}); + +#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, r_len) \ + BKE_view_layer_array_from_objects_in_mode( \ + view_layer, r_len, { \ + .object_mode = OB_MODE_EDIT, \ + .no_dup_data = true, \ + .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs}); + +#define BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, r_len, mode) \ + BKE_view_layer_array_from_objects_in_mode( \ + view_layer, r_len, { \ + .object_mode = mode, \ + .no_dup_data = true}); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_LAYER_H__ */ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index c2b971a91cd..038e9377ba4 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -52,9 +52,13 @@ struct PropertyRNA; size_t BKE_libblock_get_alloc_info(short type, const char **name); void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT; -void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT; void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1); +void *BKE_id_new(struct Main *bmain, const short type, const char *name); +void *BKE_id_new_nomain(const short type, const char *name); + + /** * New ID creation/copying options. */ @@ -75,9 +79,14 @@ enum { LIB_ID_COPY_NO_PROXY_CLEAR = 1 << 16, /* Object only, needed by make_local code. */ LIB_ID_COPY_NO_PREVIEW = 1 << 17, /* Do not copy preview data, when supported. */ LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */ - /* XXX TODO Do we want to keep that? would rather try to get rid of it... */ - LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */ - LIB_ID_COPY_KEEP_LIB = 1 << 20, /* Keep the library pointer when copying datablock outside of bmain. */ + LIB_ID_COPY_NO_ANIMDATA = 1 << 19, /* Don't copy id->adt, used by ID datablock localization routines. */ + LIB_ID_COPY_CD_REFERENCE = 1 << 20, /* Mesh: Reference CD data layers instead of doing real copy. */ + + /* XXX Hackish/not-so-nice specific behaviors needed for some corner cases. + * Ideally we should not have those, but we need them for now... */ + LIB_ID_COPY_ACTIONS = 1 << 24, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */ + LIB_ID_COPY_KEEP_LIB = 1 << 25, /* Keep the library pointer when copying datablock outside of bmain. */ + LIB_ID_COPY_SHAPEKEY = 1 << 26, /* EXCEPTION! Deep-copy shapekeys used by copied obdata ID. */ }; void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag); @@ -147,6 +156,7 @@ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const boo bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test); bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test); +void BKE_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b); void id_sort_by_name(struct ListBase *lb, struct ID *id); void BKE_id_expand_local(struct Main *bmain, struct ID *id); void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id); @@ -155,28 +165,7 @@ bool new_id(struct ListBase *lb, struct ID *id, const char *name) ATTR_NONNULL(1 void id_clear_lib_data(struct Main *bmain, struct ID *id); void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_mainlist); -struct ListBase *which_libbase(struct Main *mainlib, short type); - -#define MAX_LIBARRAY 35 -int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]); - -/* Main API */ -struct Main *BKE_main_new(void); -void BKE_main_free(struct Main *mainvar); - -void BKE_main_lock(struct Main *bmain); -void BKE_main_unlock(struct Main *bmain); - -void BKE_main_relations_create(struct Main *bmain); -void BKE_main_relations_free(struct Main *bmain); - -struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img); -struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data); -void BKE_main_thumbnail_create(struct Main *bmain); - -const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL(); -const char *BKE_main_blendfile_path_from_global(void); - +/* Affect whole Main database. */ void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value); void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value); void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value); @@ -188,8 +177,12 @@ void BKE_main_id_clear_newpoins(struct Main *bmain); void BKE_main_lib_objects_recalc_all(struct Main *bmain); -/* (MAX_ID_NAME - 2) + 3 */ -void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id); +#define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */ +#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at begining. */ +void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id); +void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const struct ID *id); + +char *BKE_id_to_unique_string_key(const struct ID *id); void BKE_library_free(struct Library *lib); @@ -200,7 +193,10 @@ void BKE_library_make_local( void BKE_id_tag_set_atomic(struct ID *id, int tag); void BKE_id_tag_clear_atomic(struct ID *id, int tag); -bool BKE_id_is_in_gobal_main(struct ID *id); +bool BKE_id_is_in_global_main(struct ID *id); + +void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb); +void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h new file mode 100644 index 00000000000..b6642bfa726 --- /dev/null +++ b/source/blender/blenkernel/BKE_library_override.h @@ -0,0 +1,91 @@ +/* + * ***** 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) 2016 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_LIBRARY_OVERRIDE_H__ +#define __BKE_LIBRARY_OVERRIDE_H__ + +/** \file BKE_library_override.h + * \ingroup bke + * \since December 2016 + * \author mont29 + */ + +struct ID; +struct IDOverrideStatic; +struct IDOverrideStaticProperty; +struct IDOverrideStaticPropertyOperation; +struct Main; + +void BKE_override_static_enable(const bool do_enable); +bool BKE_override_static_is_enabled(void); + +struct IDOverrideStatic *BKE_override_static_init(struct ID *local_id, struct ID *reference_id); +void BKE_override_static_copy(struct ID *dst_id, const struct ID *src_id); +void BKE_override_static_clear(struct IDOverrideStatic *override); +void BKE_override_static_free(struct IDOverrideStatic **override); + +struct ID *BKE_override_static_create_from_id(struct Main *bmain, struct ID *reference_id); +bool BKE_override_static_create_from_tag(struct Main *bmain); + +struct IDOverrideStaticProperty *BKE_override_static_property_find(struct IDOverrideStatic *override, const char *rna_path); +struct IDOverrideStaticProperty *BKE_override_static_property_get(struct IDOverrideStatic *override, const char *rna_path, bool *r_created); +void BKE_override_static_property_delete(struct IDOverrideStatic *override, struct IDOverrideStaticProperty *override_property); + +struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find( + struct IDOverrideStaticProperty *override_property, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict); +struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get( + struct IDOverrideStaticProperty *override_property, const short operation, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, + const bool strict, bool *r_strict, bool *r_created); +void BKE_override_static_property_operation_delete( + struct IDOverrideStaticProperty *override_property, struct IDOverrideStaticPropertyOperation *override_property_operation); + +bool BKE_override_static_status_check_local(struct Main *bmain, struct ID *local); +bool BKE_override_static_status_check_reference(struct Main *bmain, struct ID *local); + +bool BKE_override_static_operations_create(struct Main *bmain, struct ID *local, const bool force_auto); +void BKE_main_override_static_operations_create(struct Main *bmain, const bool force_auto); + +void BKE_override_static_update(struct Main *bmain, struct ID *local); +void BKE_main_override_static_update(struct Main *bmain); + + +/* Storage (.blend file writing) part. */ + +/* For now, we just use a temp main list. */ +typedef struct Main OverrideStaticStorage; + +OverrideStaticStorage *BKE_override_static_operations_store_initialize(void); +struct ID *BKE_override_static_operations_store_start( + struct Main *bmain, OverrideStaticStorage *override_storage, struct ID *local); +void BKE_override_static_operations_store_end(OverrideStaticStorage *override_storage, struct ID *local); +void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage); + + + +#endif /* __BKE_LIBRARY_OVERRIDE_H__ */ diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 65fe9abaa65..dcba5df9a72 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -56,6 +56,9 @@ enum { * How to handle that kind of cases totally depends on what caller code is doing... */ IDWALK_CB_LOOPBACK = (1 << 4), + /** That ID is used as static override's reference by its owner. */ + IDWALK_CB_STATIC_OVERRIDE_REFERENCE = (1 << 5), + /** * Adjusts #ID.us reference-count. * \note keep in sync with 'newlibadr_us' use in readfile.c diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h index fd37fd762f4..3425ca011b7 100644 --- a/source/blender/blenkernel/BKE_library_remap.h +++ b/source/blender/blenkernel/BKE_library_remap.h @@ -51,6 +51,8 @@ enum { * This is needed e.g. in reload scenario, since we have to ensure remapping of Armature data of local proxy * is also performed. Usual nightmare... */ ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4, + /* Do not remap static override pointers. */ + ID_REMAP_SKIP_STATIC_OVERRIDE = 1 << 5, }; /* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */ diff --git a/source/blender/blenkernel/BKE_bmfont_types.h b/source/blender/blenkernel/BKE_lightprobe.h index 31513e4b8f1..a769b6653d7 100644 --- a/source/blender/blenkernel/BKE_bmfont_types.h +++ b/source/blender/blenkernel/BKE_lightprobe.h @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * The Original Code is Copyright (C) Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. @@ -24,35 +24,23 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __BKE_BMFONT_TYPES_H__ -#define __BKE_BMFONT_TYPES_H__ -/** \file BKE_bmfont_types.h +#ifndef __BKE_LIGHTPROBE_H__ +#define __BKE_LIGHTPROBE_H__ + +/** \file BKE_lightprobe.h * \ingroup bke - * \since March 2001 - * \author nzc - */ -#define is_power_of_two(N) ((N ^ (N - 1)) == (2 * N - 1)) -/* - * Moved to IMB_imbuf_types.h where it will live close to the ImBuf type. - * It is used as a userflag bit mask. + * \brief General operations for probes. */ -// #define IB_BITMAPFONT 1 -typedef struct bmGlyph { - unsigned short unicode; - short locx, locy; - signed char ofsx, ofsy; - unsigned char sizex, sizey; - unsigned char advance, reserved; -} bmGlyph; +struct Main; +struct LightProbe; -typedef struct bmFont { - char magic[4]; - short version; - short glyphcount; - short xsize, ysize; - bmGlyph glyphs[1]; -} bmFont; +void BKE_lightprobe_init(struct LightProbe *probe); +void *BKE_lightprobe_add(struct Main *bmain, const char *name); +void BKE_lightprobe_copy_data(struct Main *bmain, struct LightProbe *probe_dst, const struct LightProbe *probe_src, const int flag); +struct LightProbe *BKE_lightprobe_copy(struct Main *bmain, const struct LightProbe *probe); +void BKE_lightprobe_make_local(struct Main *bmain, struct LightProbe *probe, const bool lib_local); +void BKE_lightprobe_free(struct LightProbe *probe); -#endif +#endif /* __BKE_LIGHTPROBE_H__ */ diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index 3ba4fbe0338..376a324d25c 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -48,6 +48,7 @@ struct Main; struct Object; struct ColorBand; struct bContext; +struct ViewLayer; void BKE_linestyle_init(struct FreestyleLineStyle *linestyle); FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name); @@ -59,7 +60,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineSt void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local); -FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene); +FreestyleLineStyle *BKE_linestyle_active_from_view_layer(struct ViewLayer *view_layer); LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index e224155726f..e5a816b92ce 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -42,17 +42,20 @@ */ #include "DNA_listBase.h" -#include "BKE_library.h" +#include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" #ifdef __cplusplus extern "C" { #endif -struct EvaluationContext; +struct BlendThumbnail; +struct BLI_mempool; +struct Depsgraph; +struct GHash; +struct ImBuf; struct Library; struct MainLock; -struct GHash; -struct BLI_mempool; /* Blender thumbnail, as written on file (width, height, and data as char RGBA). */ /* We pack pixel data after that struct. */ @@ -110,8 +113,9 @@ typedef struct Main { ListBase vfont; ListBase text; ListBase speaker; + ListBase lightprobe; ListBase sound; - ListBase group; + ListBase collection; ListBase armature; ListBase action; ListBase nodetree; @@ -125,11 +129,7 @@ typedef struct Main { ListBase mask; ListBase linestyle; ListBase cachefiles; - - char id_tag_update[MAX_LIBARRAY]; - - /* Evaluation context used by viewport */ - struct EvaluationContext *eval_ctx; + ListBase workspaces; /* Must be generated, used and freed by same code - never assume this is valid data unless you know * when, who and how it was created. @@ -139,6 +139,27 @@ typedef struct Main { struct MainLock *lock; } Main; +struct Main *BKE_main_new(void); +void BKE_main_free(struct Main *mainvar); + +void BKE_main_lock(struct Main *bmain); +void BKE_main_unlock(struct Main *bmain); + +void BKE_main_relations_create(struct Main *bmain); +void BKE_main_relations_free(struct Main *bmain); + +struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img); +struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data); +void BKE_main_thumbnail_create(struct Main *bmain); + +const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL(); +const char *BKE_main_blendfile_path_from_global(void); + +struct ListBase *which_libbase(struct Main *mainlib, short type); + +#define MAX_LIBARRAY 37 +int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]); + #define MAIN_VERSION_ATLEAST(main, ver, subver) \ ((main)->versionfile > (ver) || (main->versionfile == (ver) && (main)->subversionfile >= (subver))) diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 5598f0dc473..976ee5b2691 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -32,7 +32,7 @@ * \ingroup bke */ -struct EvaluationContext; +struct Depsgraph; struct ImageUser; struct Image; struct ListBase; @@ -145,7 +145,6 @@ void BKE_mask_update_display(struct Mask *mask, float ctime); void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const bool do_newframe); void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe); void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe); -void BKE_mask_update_scene(struct Main *bmain, struct Scene *scene); void BKE_mask_parent_init(struct MaskParent *parent); void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u); void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline, struct MaskSplinePoint *point, float t[2]); @@ -237,8 +236,8 @@ float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline, struct Mas void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime); void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime); -void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, struct Mask *mask); -void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, struct Mask *mask); +void BKE_mask_eval_animation(struct Depsgraph *depsgraph, struct Mask *mask); +void BKE_mask_eval_update(struct Depsgraph *depsgraph, struct Mask *mask); /* mask_rasterize.c */ struct MaskRasterHandle; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index e2f5fb23465..1ca8928c61d 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -54,11 +54,13 @@ void BKE_material_init(struct Material *ma); void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst); struct Material *BKE_material_add(struct Main *bmain, const char *name); +struct Material *BKE_material_add_gpencil(struct Main *bmain, const char *name); void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag); struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma); struct Material *BKE_material_localize(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local); +void BKE_material_init_gpencil_settings(struct Material *ma); /* UNUSED */ // void automatname(struct Material *); @@ -87,6 +89,8 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob); bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob); +struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act); + void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma); void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob); @@ -97,26 +101,19 @@ struct Material *BKE_material_pop_id(struct Main *bmain, struct ID *id, int inde void BKE_material_clear_id(struct Main *bmain, struct ID *id, bool update_data); /* rendering */ -void init_render_material(struct Main *bmain, struct Material *, int, float *); -void init_render_materials(struct Main *, int r_mode, float *amd, bool do_default_material); -void end_render_material(struct Material *); -void end_render_materials(struct Main *); - -bool material_in_material(struct Material *parmat, struct Material *mat); - void ramp_blend(int type, float r_col[3], const float fac, const float col[3]); -/* driver update hacks */ -void material_drivers_update(struct Scene *scene, struct Material *mat, float ctime); - /* copy/paste */ void clear_matcopybuf(void); void free_matcopybuf(void); void copy_matcopybuf(struct Main *bmain, struct Material *ma); void paste_matcopybuf(struct Main *bmain, struct Material *ma); -/* handle backward compatibility for tface/materials called from doversion */ -int do_version_tface(struct Main *main); +/* Evaluation. */ + +struct Depsgraph; + +void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 87bc7b2dfc5..a7706915bc5 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -32,7 +32,8 @@ * \since March 2001 * \author nzc */ -struct EvaluationContext; +struct BoundBox; +struct Depsgraph; struct Main; struct MetaBall; struct Object; @@ -47,36 +48,49 @@ struct MetaBall *BKE_mball_copy(struct Main *bmain, const struct MetaBall *mb); void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local); +bool BKE_mball_is_any_selected(const struct MetaBall *mb); +bool BKE_mball_is_any_selected_multi(struct Object **objects, int objects_len); +bool BKE_mball_is_any_unselected(const struct MetaBall *mb); bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2); bool BKE_mball_is_basis(struct Object *ob); -struct Object *BKE_mball_basis_find( - struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); +struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob); void BKE_mball_texspace_calc(struct Object *ob); +struct BoundBox *BKE_mball_boundbox_get(struct Object *ob); float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase); -void BKE_mball_properties_copy( - struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *active_object); +void BKE_mball_properties_copy(struct Scene *scene, struct Object *active_object); -bool BKE_mball_minmax(struct MetaBall *mb, float min[3], float max[3]); -bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3], - float obmat[4][4], const short flag); -bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]); -bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]); +bool BKE_mball_minmax_ex( + const struct MetaBall *mb, float min[3], float max[3], + const float obmat[4][4], const short flag); +bool BKE_mball_minmax(const struct MetaBall *mb, float min[3], float max[3]); +bool BKE_mball_center_median(const struct MetaBall *mb, float r_cent[3]); +bool BKE_mball_center_bounds(const struct MetaBall *mb, float r_cent[3]); void BKE_mball_transform(struct MetaBall *mb, float mat[4][4], const bool do_props); void BKE_mball_translate(struct MetaBall *mb, const float offset[3]); struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type); +int BKE_mball_select_count(const struct MetaBall *mb); +int BKE_mball_select_count_multi(struct Object **objects, int objects_len); void BKE_mball_select_all(struct MetaBall *mb); +void BKE_mball_select_all_multi(struct Object **objects, int objects_len); void BKE_mball_deselect_all(struct MetaBall *mb); +void BKE_mball_deselect_all_multi(struct Object **objects, int objects_len); void BKE_mball_select_swap(struct MetaBall *mb); +void BKE_mball_select_swap_multi(struct Object **objects, int objects_len); /* **** Depsgraph evaluation **** */ -struct EvaluationContext; +struct Depsgraph; -void BKE_mball_eval_geometry(struct EvaluationContext *eval_ctx, - struct MetaBall *mball); +/* Draw Cache */ + +enum { + BKE_MBALL_BATCH_DIRTY_ALL = 0, +}; +void BKE_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode); +void BKE_mball_batch_cache_free(struct MetaBall *mb); #endif diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h index 254d5e9248a..363bfe09c75 100644 --- a/source/blender/blenkernel/BKE_mball_tessellate.h +++ b/source/blender/blenkernel/BKE_mball_tessellate.h @@ -23,13 +23,13 @@ /** \file BKE_mball_tessellate.h * \ingroup bke */ -struct EvaluationContext; +struct Depsgraph; struct Main; struct Object; struct Scene; void BKE_mball_polygonize( - struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase); void BKE_mball_cubeTable_free(void); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 6d2a431f667..8f0c81ce4f9 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -31,31 +31,43 @@ * \ingroup bke */ +/* defines BLI_INLINE */ +#include "BLI_compiler_compat.h" + +/* defines CustomDataMask */ +#include "BKE_customdata.h" + struct ID; struct BMeshCreateParams; +struct BMeshFromMeshParams; +struct BMeshToMeshParams; struct BoundBox; +struct Depsgraph; struct EdgeHash; struct ListBase; struct LinkNode; struct BLI_Stack; struct MemArena; struct BMesh; +struct KeyBlock; struct MLoopTri; struct Main; struct Mesh; +struct ModifierData; struct MPoly; struct MLoop; struct MFace; struct MEdge; struct MVert; +struct MVertTri; struct MDeformVert; struct MDisps; struct Object; struct CustomData; -struct DerivedMesh; struct Scene; struct MLoopUV; struct ReportList; +struct BMEditMesh; #ifdef __cplusplus extern "C" { @@ -70,10 +82,20 @@ extern "C" { /* *** mesh.c *** */ +struct BMesh *BKE_mesh_to_bmesh_ex( + struct Mesh *me, + const struct BMeshCreateParams *create_params, + const struct BMeshFromMeshParams *convert_params); struct BMesh *BKE_mesh_to_bmesh( struct Mesh *me, struct Object *ob, const bool add_key_index, const struct BMeshCreateParams *params); +struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params); +struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, int64_t cd_mask_extra); + +struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap( + struct BMEditMesh *em, CustomDataMask data_mask, float (*vertexCos)[3]); + int poly_find_loop_from_vert( const struct MPoly *poly, const struct MLoop *loopstart, unsigned vert); @@ -83,6 +105,7 @@ int poly_get_adj_loops_from_vert( unsigned int r_adj[2]); int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); +void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh, const struct MLoopTri *looptri, int r_edges[3]); void BKE_mesh_free(struct Mesh *me); void BKE_mesh_init(struct Mesh *me); @@ -92,6 +115,24 @@ struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me); void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd); void BKE_mesh_ensure_skin_customdata(struct Mesh *me); +struct Mesh *BKE_mesh_new_nomain( + int verts_len, int edges_len, int tessface_len, + int loops_len, int polys_len); +struct Mesh *BKE_mesh_new_nomain_from_template( + const struct Mesh *me_src, + int verts_len, int edges_len, int tessface_len, + int loops_len, int polys_len); + +/* Performs copy for use during evaluation, optional referencing original arrays to reduce memory. */ +struct Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference); + +/* These functions construct a new Mesh, contrary to BKE_mesh_from_nurbs which modifies ob itself. */ +struct Mesh *BKE_mesh_new_nomain_from_curve(struct Object *ob); +struct Mesh *BKE_mesh_new_nomain_from_curve_displist(struct Object *ob, struct ListBase *dispbase); + +bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me); +bool BKE_mesh_clear_facemap_customdata(struct Mesh *me); + void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local); void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]); void BKE_mesh_texspace_calc(struct Mesh *me); @@ -100,6 +141,22 @@ void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totv int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr); struct Mesh *BKE_mesh_from_object(struct Object *ob); void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me); +void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me); +int BKE_mesh_nurbs_to_mdata( + struct Object *ob, struct MVert **r_allvert, int *r_totvert, + struct MEdge **r_alledge, int *r_totedge, struct MLoop **r_allloop, struct MPoly **r_allpoly, + int *r_totloop, int *r_totpoly); +int BKE_mesh_nurbs_displist_to_mdata( + struct Object *ob, const struct ListBase *dispbase, + struct MVert **r_allvert, int *r_totvert, + struct MEdge **r_alledge, int *r_totedge, + struct MLoop **r_allloop, struct MPoly **r_allpoly, + struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly); +void BKE_mesh_from_nurbs_displist( + struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary); +void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob); +void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, const int edge_users_test); +void BKE_mesh_to_curve(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_mesh_material_index_remove(struct Mesh *me, short index); void BKE_mesh_material_index_clear(struct Mesh *me); void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len); @@ -109,16 +166,31 @@ const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh); struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob); void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_rot[3], float r_size[3]); +void BKE_mesh_texspace_get_reference(struct Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size); void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob); -bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, const int loop_index, const int face_index, - const char *new_name, const bool do_tessface); +bool BKE_mesh_uv_cdlayer_rename_index( + struct Mesh *me, const int loop_index, const int face_index, + const char *new_name, const bool do_tessface); bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface); float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3]; void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals); +struct Mesh *BKE_mesh_new_from_object( + struct Depsgraph *depsgraph, struct Main *bmain, struct Scene *sce, struct Object *ob, + const bool apply_modifiers, const bool calc_undeformed); +struct Mesh *BKE_mesh_create_derived_for_modifier( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, + struct ModifierData *md, int build_shapekey_layers); + +/* Copies a nomain-Mesh into an existing Mesh. */ +void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, + CustomDataMask mask, bool take_ownership); +void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb); + + /* vertex level transformations & checks (no derived mesh) */ bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]); @@ -140,31 +212,13 @@ int BKE_mesh_mselect_find(struct Mesh *me, int index, int type); int BKE_mesh_mselect_active_get(struct Mesh *me, int type); void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type); -/* *** mesh_convert.c *** */ +void BKE_mesh_apply_vert_coords(struct Mesh *mesh, float (*vertCoords)[3]); +void BKE_mesh_apply_vert_normals(struct Mesh *mesh, short (*vertNormals)[3]); -void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me); -int BKE_mesh_nurbs_to_mdata( - struct Object *ob, struct MVert **r_allvert, int *r_totvert, - struct MEdge **r_alledge, int *r_totedge, struct MLoop **r_allloop, struct MPoly **r_allpoly, - int *r_totloop, int *r_totpoly); -int BKE_mesh_nurbs_displist_to_mdata( - struct Object *ob, const struct ListBase *dispbase, - struct MVert **r_allvert, int *r_totvert, - struct MEdge **r_alledge, int *r_totedge, - struct MLoop **r_allloop, struct MPoly **r_allpoly, - struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly); -void BKE_mesh_from_nurbs_displist( - struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name); -void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob); -void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblist, const int edge_users_test); -void BKE_mesh_to_curve(struct Main *bmain, struct Scene *scene, struct Object *ob); - -struct Mesh *BKE_mesh_new_from_object( - struct Main *bmain, struct Scene *sce, struct Object *ob, - int apply_modifiers, int settings, int calc_tessface, int calc_undeformed); /* *** mesh_evaluate.c *** */ +void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me); void BKE_mesh_calc_normals_mapping( struct MVert *mverts, int numVerts, const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3], @@ -181,6 +235,8 @@ void BKE_mesh_calc_normals_poly( int numLoops, int numPolys, float (*r_polyNors)[3], const bool only_face_normals); void BKE_mesh_calc_normals(struct Mesh *me); +void BKE_mesh_ensure_normals(struct Mesh *me); +void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh); void BKE_mesh_calc_normals_tessface( struct MVert *mverts, int numVerts, const struct MFace *mfaces, int numFaces, @@ -190,13 +246,6 @@ void BKE_mesh_calc_normals_looptri( const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num, float (*r_tri_nors)[3]); -void BKE_mesh_loop_tangents_ex( - const struct MVert *mverts, const int numVerts, const struct MLoop *mloops, - float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv, - const int numLoops, const struct MPoly *mpolys, const int numPolys, - struct ReportList *reports); -void BKE_mesh_loop_tangents( - struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports); void BKE_mesh_loop_manifold_fan_around_vert_next( const struct MLoop *mloops, const struct MPoly *mpolys, const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index, @@ -224,6 +273,8 @@ typedef struct MLoopNorSpace { * - BMLoop pointers. */ struct LinkNode *loops; char flags; + + void *user_data; /* To be used for extended processing related to loop normal spaces (aka smooth fans). */ } MLoopNorSpace; /** * MLoopNorSpace.flags @@ -239,6 +290,7 @@ typedef struct MLoopNorSpaceArray { MLoopNorSpace **lspacearr; /* MLoop aligned array */ struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */ char data_type; /* Whether we store loop indices, or pointers to BMLoop. */ + int num_spaces; /* Number of clnors spaces defined in this array. */ struct MemArena *mem; } MLoopNorSpaceArray; /** @@ -332,7 +384,7 @@ void BKE_mesh_loops_to_mface_corners( const int numTex, const int numCol, const bool hasPCol, const bool hasOrigSpace, const bool hasLNor); void BKE_mesh_loops_to_tessdata( - struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface, + struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface, int *polyindices, unsigned int (*loopindices)[4], const int num_faces); void BKE_mesh_tangent_loops_to_tessdata( struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface, @@ -365,6 +417,19 @@ void BKE_mesh_polygon_flip_ex( void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata); void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly); +/* merge verts */ +/* Enum for merge_mode of CDDM_merge_verts. + * Refer to mesh.c for details. */ +enum { + MESH_MERGE_VERTS_DUMP_IF_MAPPED, + MESH_MERGE_VERTS_DUMP_IF_EQUAL, +}; +struct Mesh *BKE_mesh_merge_verts( + struct Mesh *mesh, + const int *vtargetmap, const int tot_vtargetmap, + const int merge_mode); + + /* flush flags */ void BKE_mesh_flush_hidden_from_verts_ex( const struct MVert *mvert, @@ -407,7 +472,7 @@ void BKE_mesh_calc_relative_deform( /* *** mesh_validate.c *** */ bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask); -void BKE_mesh_cd_validate(struct Mesh *me); +bool BKE_mesh_is_valid(struct Mesh *me); bool BKE_mesh_validate_material_indices(struct Mesh *me); bool BKE_mesh_validate_arrays( @@ -433,15 +498,41 @@ void BKE_mesh_strip_loose_polysloops(struct Mesh *me); void BKE_mesh_strip_loose_edges(struct Mesh *me); void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old); +void BKE_mesh_calc_edges_loose(struct Mesh *mesh); void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select); +void BKE_mesh_calc_edges_tessface(struct Mesh *mesh); /* **** Depsgraph evaluation **** */ -struct EvaluationContext; - -void BKE_mesh_eval_geometry(struct EvaluationContext *eval_ctx, +void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph, struct Mesh *mesh); +/* Draw Cache */ +enum { + BKE_MESH_BATCH_DIRTY_ALL = 0, + BKE_MESH_BATCH_DIRTY_MAYBE_ALL, + BKE_MESH_BATCH_DIRTY_SELECT, + BKE_MESH_BATCH_DIRTY_SHADING, + BKE_MESH_BATCH_DIRTY_SCULPT_COORDS, + BKE_MESH_BATCH_DIRTY_UVEDIT_ALL, + BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT, +}; +void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, int mode); +void BKE_mesh_batch_cache_free(struct Mesh *me); + + +/* Inlines */ + +/* Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h, + * but I don't want to force every user of BKE_mesh.h to also include that file. + * ~~ Sybren */ +BLI_INLINE int BKE_mesh_origindex_mface_mpoly( + const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) +{ + const int j = index_mf_to_mpoly[i]; + return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1; +} + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h new file mode 100644 index 00000000000..70c10806350 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_iterators.h @@ -0,0 +1,67 @@ +/* + * ***** 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: all of this file. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_MESH_ITERATORS_H__ +#define __BKE_MESH_ITERATORS_H__ + +/** \file BKE_mesh_iterators.h + * \ingroup bke + */ + +struct Mesh; +struct MVert; +struct MEdge; +struct MPoly; +struct MLoop; +struct MLoopUV; +struct MLoopTri; + +typedef enum MeshForeachFlag { + MESH_FOREACH_NOP = 0, + MESH_FOREACH_USE_NORMAL = (1 << 0), /* foreachMappedVert, foreachMappedLoop, foreachMappedFaceCenter */ +} MeshForeachFlag; + + +void BKE_mesh_foreach_mapped_vert( + struct Mesh *mesh, + void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]), + void *userData, + MeshForeachFlag flag); +void BKE_mesh_foreach_mapped_edge( + struct Mesh *mesh, + void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), + void *userData); +void BKE_mesh_foreach_mapped_loop( + struct Mesh *mesh, + void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]), + void *userData, + MeshForeachFlag flag); +void BKE_mesh_foreach_mapped_face_center( + struct Mesh *mesh, + void (*func)(void *userData, int index, const float cent[3], const float no[3]), + void *userData, + MeshForeachFlag flag); + +void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval, float (*r_cos)[3], const int totcos); + +#endif /* __BKE_MESH_ITERATORS_H__ */ diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h index 5c77ab8a94e..7aea856ff34 100644 --- a/source/blender/blenkernel/BKE_mesh_remap.h +++ b/source/blender/blenkernel/BKE_mesh_remap.h @@ -26,7 +26,7 @@ */ struct CustomData; -struct DerivedMesh; +struct Mesh; struct MVert; struct MemArena; @@ -140,39 +140,37 @@ enum { MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY, }; -float BKE_mesh_remap_calc_difference_from_dm( +float BKE_mesh_remap_calc_difference_from_mesh( const struct SpaceTransform *space_transform, - const struct MVert *verts_dst, const int numverts_dst, struct DerivedMesh *dm_src); + const struct MVert *verts_dst, const int numverts_dst, struct Mesh *me_src); -void BKE_mesh_remap_find_best_match_from_dm( - const struct MVert *verts_dst, const int numverts_dst, struct DerivedMesh *dm_src, +void BKE_mesh_remap_find_best_match_from_mesh( + const struct MVert *verts_dst, const int numverts_dst, struct Mesh *me_src, struct SpaceTransform *r_space_transform); -/* TODO add mesh2mesh versions (we'll need mesh versions of bvhtree funcs too, though!). */ - -void BKE_mesh_remap_calc_verts_from_dm( +void BKE_mesh_remap_calc_verts_from_mesh( const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, const struct MVert *verts_dst, const int numverts_dst, const bool dirty_nors_dst, - struct DerivedMesh *dm_src, MeshPairRemap *r_map); + struct Mesh *me_src, MeshPairRemap *r_map); -void BKE_mesh_remap_calc_edges_from_dm( +void BKE_mesh_remap_calc_edges_from_mesh( const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, const struct MVert *verts_dst, const int numverts_dst, const struct MEdge *edges_dst, const int numedges_dst, - const bool dirty_nors_dst, struct DerivedMesh *dm_src, MeshPairRemap *r_map); + const bool dirty_nors_dst, struct Mesh *me_src, MeshPairRemap *r_map); -void BKE_mesh_remap_calc_loops_from_dm( +void BKE_mesh_remap_calc_loops_from_mesh( const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, struct MVert *verts_dst, const int numverts_dst, struct MEdge *edges_dst, const int numedges_dst, struct MLoop *loops_dst, const int numloops_dst, struct MPoly *polys_dst, const int numpolys_dst, struct CustomData *ldata_dst, struct CustomData *pdata_dst, const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst, - struct DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src, + struct Mesh *me_src, MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, struct MeshPairRemap *r_map); -void BKE_mesh_remap_calc_polys_from_dm( +void BKE_mesh_remap_calc_polys_from_mesh( const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius, struct MVert *verts_dst, const int numverts_dst, struct MLoop *loops_dst, const int numloops_dst, struct MPoly *polys_dst, const int numpolys_dst, struct CustomData *pdata_dst, const bool dirty_nors_dst, - struct DerivedMesh *dm_src, struct MeshPairRemap *r_map); + struct Mesh *me_src, struct MeshPairRemap *r_map); #endif /* __BKE_MESH_REMAP_H__ */ diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h new file mode 100644 index 00000000000..050d17771c9 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -0,0 +1,122 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_MESH_RUNTIME_H__ +#define __BKE_MESH_RUNTIME_H__ + +/** \file BKE_mesh_runtime.h + * \ingroup bke + * + * This file contains access functions for the Mesh.runtime struct. + */ + +#include "BKE_customdata.h" /* for CustomDataMask */ + +struct ColorBand; +struct CustomData; +struct Depsgraph; +struct KeyBlock; +struct Mesh; +struct MLoop; +struct MLoopTri; +struct MVertTri; +struct Object; +struct Scene; + +/* Undefine to hide DerivedMesh-based function declarations */ +#define USE_DERIVEDMESH + +#ifdef USE_DERIVEDMESH +struct DerivedMesh; +#endif + +void BKE_mesh_runtime_reset(struct Mesh *mesh); +int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh); +void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh); +const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh); +bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh); +bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh); +void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh); +void BKE_mesh_runtime_clear_cache(struct Mesh *mesh); + +void BKE_mesh_runtime_verttri_from_looptri( + struct MVertTri *r_verttri, + const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num); + +/* NOTE: the functions below are defined in DerivedMesh.c, and are intended to be moved + * to a more suitable location when that file is removed. + * They should also be renamed to use conventions from BKE, not old DerivedMesh.c. + * For now keep the names similar to avoid confusion. */ +#ifdef USE_DERIVEDMESH +struct DerivedMesh *mesh_get_derived_final( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); +#endif +struct Mesh *mesh_get_eval_final( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, CustomDataMask dataMask); + +#ifdef USE_DERIVEDMESH +struct DerivedMesh *mesh_get_derived_deform( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); +#endif +struct Mesh *mesh_get_eval_deform( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); + +struct Mesh *mesh_create_eval_final_render( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); + +#ifdef USE_DERIVEDMESH +struct DerivedMesh *mesh_create_derived_index_render( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask, int index); +#endif +struct Mesh *mesh_create_eval_final_index_render( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask, int index); + +#ifdef USE_DERIVEDMESH +struct DerivedMesh *mesh_create_derived_view( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); +#endif +struct Mesh *mesh_create_eval_final_view( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask); + +void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed, struct Mesh *me, struct KeyBlock *kb); + + +#ifndef NDEBUG +char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval); +void BKE_mesh_runtime_debug_print(struct Mesh *me_eval); +void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data); +bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval); +#endif /* NDEBUG */ + +#endif /* __BKE_MESH_RUNTIME_H__ */ diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h new file mode 100644 index 00000000000..62d8f3ada84 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_tangent.h @@ -0,0 +1,68 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_MESH_TANGENT_H__ +#define __BKE_MESH_TANGENT_H__ + +/** \file BKE_mesh_tangent.h + * \ingroup bke + */ + +void BKE_mesh_calc_loop_tangent_single_ex( + const struct MVert *mverts, const int numVerts, const struct MLoop *mloops, + float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv, + const int numLoops, const struct MPoly *mpolys, const int numPolys, + struct ReportList *reports); +void BKE_mesh_calc_loop_tangent_single( + struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports); + +void BKE_mesh_calc_loop_tangent_ex( + const struct MVert *mvert, + const struct MPoly *mpoly, const uint mpoly_len, + const struct MLoop *mloop, + const struct MLoopTri *looptri, const uint looptri_len, + + struct CustomData *loopdata, + bool calc_active_tangent, + const char (*tangent_names)[64], int tangent_names_len, + const float (*poly_normals)[3], + const float (*loop_normals)[3], + const float (*vert_orco)[3], + /* result */ + struct CustomData *loopdata_out, + const uint loopdata_out_len, + short *tangent_mask_curr_p); + +void BKE_mesh_calc_loop_tangents( + struct Mesh *me_eval, bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_len); + +/* Helpers */ +void BKE_mesh_add_loop_tangent_named_layer_for_uv( + struct CustomData *uv_data, struct CustomData *tan_data, int numLoopData, + const char *layer_name); + +#define DM_TANGENT_MASK_ORCO (1 << 9) +void BKE_mesh_calc_loop_tangent_step_0( + const struct CustomData *loopData, bool calc_active_tangent, + const char (*tangent_names)[64], int tangent_names_count, + bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, + char *ract_uv_name, char *rren_uv_name, short *rtangent_mask); + +#endif /* __BKE_MESH_TANGENT_H__ */ diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 2d39ac4d102..6b64b1663d8 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -33,11 +33,12 @@ #include "BKE_customdata.h" struct ID; +struct Depsgraph; struct DerivedMesh; -struct DagForest; -struct DagNode; +struct Mesh; struct Object; struct Scene; +struct ViewLayer; struct ListBase; struct bArmature; struct Main; @@ -118,27 +119,23 @@ typedef enum ModifierApplyFlag { MOD_APPLY_IGNORE_SIMPLIFY = 1 << 3, /* Ignore scene simplification flag and use subdivisions * level set in multires modifier. */ - MOD_APPLY_ALLOW_GPU = 1 << 4, /* Allow modifier to be applied and stored in the GPU. - * Used by the viewport in order to be able to have SS - * happening on GPU. - * Render pipeline (including viewport render) should - * have DM on the CPU. - */ } ModifierApplyFlag; - typedef struct ModifierUpdateDepsgraphContext { struct Scene *scene; struct Object *object; - - /* Old depsgraph node handle. */ - struct DagForest *forest; - struct DagNode *obNode; - - /* new depsgraph node handle. */ struct DepsNodeHandle *node; } ModifierUpdateDepsgraphContext; +/* Contains the information for deformXXX and applyXXX functions below that + * doesn't change between consecutive modifiers. */ +typedef struct ModifierEvalContext { + struct Depsgraph *depsgraph; + struct Object *object; + ModifierApplyFlag flag; +} ModifierEvalContext; + + typedef struct ModifierTypeInfo { /* The user visible name for this modifier */ char name[32]; @@ -159,73 +156,61 @@ typedef struct ModifierTypeInfo { /* Copy instance data for this modifier type. Should copy all user * level settings to the target modifier. + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ - void (*copyData)(const struct ModifierData *md, struct ModifierData *target); + void (*copyData)(const struct ModifierData *md, struct ModifierData *target, const int flag); + + + /********************* Deform modifier functions *********************/ /* DEPRECATED */ + + void (*deformVerts_DM_removed)(void); + void (*deformMatrices_DM_removed)(void); + void (*deformVertsEM_DM_removed)(void); + void (*deformMatricesEM_DM_removed)(void); + + /********************* Non-deform modifier functions *********************/ /* DEPRECATED */ + + void (*applyModifier_DM_removed)(void); /********************* Deform modifier functions *********************/ /* Only for deform types, should apply the deformation * to the given vertex array. If the deformer requires information from - * the object it can obtain it from the derivedData argument if non-NULL, + * the object it can obtain it from the mesh argument if non-NULL, * and otherwise the ob argument. */ - void (*deformVerts)(struct ModifierData *md, struct Object *ob, - struct DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts, - ModifierApplyFlag flag); + void (*deformVerts)(struct ModifierData *md, const struct ModifierEvalContext *ctx, + struct Mesh *mesh, float (*vertexCos)[3], int numVerts); /* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */ - void (*deformMatrices)(struct ModifierData *md, struct Object *ob, - struct DerivedMesh *derivedData, - float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); + void (*deformMatrices)(struct ModifierData *md, const struct ModifierEvalContext *ctx, + struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); /* Like deformVerts but called during editmode (for supporting modifiers) */ - void (*deformVertsEM)(struct ModifierData *md, struct Object *ob, - struct BMEditMesh *editData, struct DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts); + void (*deformVertsEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx, + struct BMEditMesh *editData, + struct Mesh *mesh, float (*vertexCos)[3], int numVerts); /* Set deform matrix per vertex for crazyspace correction */ - void (*deformMatricesEM)(struct ModifierData *md, struct Object *ob, - struct BMEditMesh *editData, struct DerivedMesh *derivedData, - float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); + void (*deformMatricesEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx, + struct BMEditMesh *editData, + struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); /********************* Non-deform modifier functions *********************/ - /* For non-deform types: apply the modifier and return a derived - * data object (type is dependent on object type). + /* For non-deform types: apply the modifier and return a mesh object. * - * The derivedData argument should always be non-NULL; the modifier - * should read the object data from the derived object instead of the + * The mesh argument should always be non-NULL; the modifier + * should read the object data from the mesh object instead of the * actual object data. * - * The useRenderParams argument indicates if the modifier is being - * applied in the service of the renderer which may alter quality - * settings. - * - * The isFinalCalc parameter indicates if the modifier is being - * calculated for a final result or for something temporary - * (like orcos). This is a hack at the moment, it is meant so subsurf - * can know if it is safe to reuse its internal cache. - * - * The modifier may reuse the derivedData argument (i.e. return it in + * The modifier may reuse the mesh argument (i.e. return it in * modified form), but must not release it. */ - struct DerivedMesh *(*applyModifier)(struct ModifierData *md, struct Object *ob, - struct DerivedMesh *derivedData, - ModifierApplyFlag flag); - - /* Like applyModifier but called during editmode (for supporting - * modifiers). - * - * The derived object that is returned must support the operations that - * are expected from editmode objects. The same qualifications regarding - * derivedData apply as for applyModifier. - */ - struct DerivedMesh *(*applyModifierEM)(struct ModifierData *md, struct Object *ob, - struct BMEditMesh *editData, - struct DerivedMesh *derivedData, - ModifierApplyFlag flag); + struct Mesh *(*applyModifier)(struct ModifierData *md, const struct ModifierEvalContext *ctx, + struct Mesh *mesh); /********************* Optional functions *********************/ @@ -270,21 +255,12 @@ typedef struct ModifierTypeInfo { * * This function is optional (assumes never disabled if not present). */ - bool (*isDisabled)(struct ModifierData *md, int userRenderParams); - - /* Add the appropriate relations to the DEP graph depending on the - * modifier data. - * - * This function is optional. - */ - void (*updateDepgraph)(struct ModifierData *md, - const ModifierUpdateDepsgraphContext *ctx); + bool (*isDisabled)(const struct Scene *scene, struct ModifierData *md, bool userRenderParams); /* Add the appropriate relations to the dependency graph. * * This function is optional. */ - /* TODO(sergey): Remove once we finally switched to the new depsgraph. */ void (*updateDepsgraph)(struct ModifierData *md, const ModifierUpdateDepsgraphContext *ctx); @@ -351,7 +327,7 @@ void modifier_free(struct ModifierData *md); bool modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md); -void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target); +void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target, const int flag); void modifier_copyData(struct ModifierData *md, struct ModifierData *target); void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag); bool modifier_dependsOnTime(struct ModifierData *md); @@ -361,7 +337,7 @@ bool modifier_couldBeCage(struct Scene *scene, struct ModifierData *md) bool modifier_isCorrectableDeformed(struct ModifierData *md); bool modifier_isSameTopology(ModifierData *md); bool modifier_isNonGeometrical(ModifierData *md); -bool modifier_isEnabled(struct Scene *scene, struct ModifierData *md, int required_mode); +bool modifier_isEnabled(const struct Scene *scene, struct ModifierData *md, int required_mode); void modifier_setError(struct ModifierData *md, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3); bool modifier_isPreview(struct ModifierData *md); @@ -387,6 +363,7 @@ bool modifiers_isClothEnabled(struct Object *ob); bool modifiers_isParticleEnabled(struct Object *ob); struct Object *modifiers_isDeformedByArmature(struct Object *ob); +struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob); struct Object *modifiers_isDeformedByLattice(struct Object *ob); struct Object *modifiers_isDeformedByCurve(struct Object *ob); bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm); @@ -433,28 +410,41 @@ void modifier_path_init(char *path, int path_maxlen, const char *name); const char *modifier_path_relbase(struct Main *bmain, struct Object *ob); const char *modifier_path_relbase_from_global(struct Object *ob); -/* wrappers for modifier callbacks */ +/* wrappers for modifier callbacks that ensure valid normals */ -struct DerivedMesh *modwrap_applyModifier( - ModifierData *md, struct Object *ob, - struct DerivedMesh *dm, - ModifierApplyFlag flag); - -struct DerivedMesh *modwrap_applyModifierEM( - ModifierData *md, struct Object *ob, - struct BMEditMesh *em, - struct DerivedMesh *dm, - ModifierApplyFlag flag); +struct Mesh *modwrap_applyModifier( + ModifierData *md, const struct ModifierEvalContext *ctx, + struct Mesh *me); void modwrap_deformVerts( - ModifierData *md, struct Object *ob, - struct DerivedMesh *dm, - float (*vertexCos)[3], int numVerts, - ModifierApplyFlag flag); + ModifierData *md, const struct ModifierEvalContext *ctx, + struct Mesh *me, + float (*vertexCos)[3], int numVerts); void modwrap_deformVertsEM( - ModifierData *md, struct Object *ob, - struct BMEditMesh *em, struct DerivedMesh *dm, + ModifierData *md, const struct ModifierEvalContext *ctx, + struct BMEditMesh *em, struct Mesh *me, float (*vertexCos)[3], int numVerts); +#define applyModifier_DM_wrapper(NEW_FUNC_NAME, OLD_FUNC_NAME) \ + static Mesh *NEW_FUNC_NAME(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) \ + { \ + DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING); \ + DerivedMesh *ndm = OLD_FUNC_NAME(md, ctx, dm); \ + if (ndm != dm) dm->release(dm); \ + DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true); \ + return mesh; \ + } + +/* wrappers for modifier callbacks that accept Mesh and select the proper implementation + * depending on if the modifier has been ported to Mesh or is still using DerivedMesh + */ + +struct DerivedMesh *modifier_applyModifier_DM_deprecated( + struct ModifierData *md, const struct ModifierEvalContext *ctx, + struct DerivedMesh *dm); + +struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object( + struct Object *ob_eval, bool *r_free_mesh); + #endif diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index b79f37fd040..5071724d772 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -32,7 +32,7 @@ * \author Sergey Sharybin */ -struct EvaluationContext; +struct Depsgraph; struct ImBuf; struct Main; struct MovieClip; @@ -84,10 +84,11 @@ struct ImBuf *BKE_movieclip_anim_ibuf_for_frame(struct MovieClip *clip, struct M bool BKE_movieclip_has_cached_frame(struct MovieClip *clip, struct MovieClipUser *user); bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip, struct MovieClipUser *user, struct ImBuf *ibuf); -/* Evaluaiton. */ -void BKE_movieclip_eval_update(struct EvaluationContext *eval_ctx, struct MovieClip *clip); +/* Evaluation. */ +void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, struct MovieClip *clip); +void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, struct MovieClip *clip); -/* cacheing flags */ +/* caching flags */ #define MOVIECLIP_CACHE_SKIP (1 << 0) /* postprocessing flags */ diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index d8199c96d6b..decfdc532a6 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -32,7 +32,11 @@ * \ingroup bke */ +#include "BLI_compiler_compat.h" + enum MultiresModifiedFlags; + +struct Depsgraph; struct DerivedMesh; struct MDisps; struct Mesh; @@ -41,6 +45,7 @@ struct Multires; struct MultiresModifierData; struct Object; struct Scene; +struct SubdivCCG; struct MLoop; struct MVert; @@ -60,7 +65,7 @@ void multires_force_render_update(struct Object *ob); void multires_force_external_reload(struct Object *ob); /* internal, only called in subsurf_ccg.c */ -void multires_modifier_update_mdisps(struct DerivedMesh *dm); +void multires_modifier_update_mdisps(struct DerivedMesh *dm, struct Scene *scene); void multires_modifier_update_hidden(struct DerivedMesh *dm); void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob); @@ -74,43 +79,35 @@ typedef enum { struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm, struct MultiresModifierData *mmd, + struct Scene *scene, struct Object *ob, MultiresFlags flags); struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene, struct ModifierData *lastmd); struct MultiresModifierData *get_multires_modifier(struct Scene *scene, struct Object *ob, bool use_first); -struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifierData *mmd, +int multires_get_level(const struct Scene *scene, const struct Object *ob, const struct MultiresModifierData *mmd, + bool render, bool ignore_simplify); +struct DerivedMesh *get_multires_dm(struct Depsgraph *depsgraph, struct Scene *scene, struct MultiresModifierData *mmd, struct Object *ob); -void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction); -void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob); -void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int updateblock, int simple); +struct Mesh *BKE_multires_create_mesh( + struct Depsgraph *depsgraph, struct Scene *scene, + struct MultiresModifierData *mmd, struct Object *ob); +void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *object, int direction); +void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *ob); +void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *ob, int updateblock, int simple); void multiresModifier_sync_levels_ex( - struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst); -int multiresModifier_reshape(struct Scene *scene, struct MultiresModifierData *mmd, - struct Object *dst, struct Object *src); -int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierData *mmd, - struct Object *ob, struct DerivedMesh *srcdm); -int multiresModifier_reshapeFromDeformMod(struct Scene *scene, struct MultiresModifierData *mmd, - struct Object *ob, struct ModifierData *md); + struct Scene *scene, struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst); void multires_stitch_grids(struct Object *); -/*switch mdisp data in dm between tangent and object space*/ -enum { - MULTIRES_SPACE_TANGENT, - MULTIRES_SPACE_OBJECT, - MULTIRES_SPACE_ABSOLUTE -}; -void multires_set_space(struct DerivedMesh *dm, struct Object *ob, int from, int to); - /* Related to the old multires */ void multires_free(struct Multires *mr); void multires_load_old(struct Object *ob, struct Mesh *me); void multires_load_old_250(struct Mesh *); -void multiresModifier_scale_disp(struct Scene *scene, struct Object *ob); -void multiresModifier_prepare_join(struct Scene *scene, struct Object *ob, struct Object *to_ob); +void multiresModifier_scale_disp(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); +void multiresModifier_prepare_join(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Object *to_ob); int multires_mdisp_corners(struct MDisps *s); @@ -121,4 +118,53 @@ void multires_topology_changed(struct Mesh *me); void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v); int mdisp_rot_face_to_crn(struct MVert *mvert, struct MPoly *mpoly, struct MLoop *mloops, const struct MLoopTri *lt, const int face_side, const float u, const float v, float *x, float *y); +/* Reshaping, define in multires_reshape.c */ + +bool multiresModifier_reshapeFromObject( + struct Depsgraph *depsgraph, + struct MultiresModifierData *mmd, + struct Object *dst, + struct Object *src); +bool multiresModifier_reshapeFromDeformModifier( + struct Depsgraph *depsgraph, + struct MultiresModifierData *mmd, + struct Object *ob, + struct ModifierData *md); +bool multiresModifier_reshapeFromCCG( + const int tot_level, + struct Mesh *coarse_mesh, + struct SubdivCCG *subdiv_ccg); + +/* Subdivision integration, defined in multires_subdiv.c */ + +struct SubdivSettings; +struct SubdivToMeshSettings; + +void BKE_multires_subdiv_settings_init( + struct SubdivSettings *settings, + const struct MultiresModifierData *mmd); + +/* TODO(sergey): Replace this set of boolean flags with bitmask. */ +void BKE_multires_subdiv_mesh_settings_init( + struct SubdivToMeshSettings *mesh_settings, + const struct Scene *scene, + const struct Object *object, + const struct MultiresModifierData *mmd, + const bool use_render_params, + const bool ignore_simplify); + +/* General helpers. */ + +/* For a given partial derivatives of a ptex face get tangent matrix for + * displacement. + * Corner needs to be known to properly "rotate" partial derivatives. + */ +BLI_INLINE void BKE_multires_construct_tangent_matrix( + float tangent_matrix[3][3], + const float dPdu[3], + const float dPdv[3], + const int corner); + #endif /* __BKE_MULTIRES_H__ */ + +#include "intern/multires_inline.h" diff --git a/source/blender/blenkernel/BKE_navmesh_conversion.h b/source/blender/blenkernel/BKE_navmesh_conversion.h deleted file mode 100644 index 3be363f4d7b..00000000000 --- a/source/blender/blenkernel/BKE_navmesh_conversion.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __BKE_NAVMESH_CONVERSION_H__ -#define __BKE_NAVMESH_CONVERSION_H__ - -/** \file BKE_navmesh_conversion.h - * \ingroup bke - */ - -struct DerivedMesh; - -/* navmesh_conversion.c */ -int buildNavMeshDataByDerivedMesh(struct DerivedMesh *dm, int *vertsPerPoly, - int *nverts, float **verts, - int *ndtris, unsigned short **dtris, - int *npolys, unsigned short **dmeshes, - unsigned short **polys, int **dtrisToPolysMap, - int **dtrisToTrisMap, int **trisToFacesMap); - -int buildRawVertIndicesData(struct DerivedMesh *dm, int *nverts, float **verts, - int *ntris, unsigned short **tris, int **trisToFacesMap, - int **recastData); - -int buildNavMeshData(const int nverts, const float *verts, - const int ntris, const unsigned short *tris, - const int *recastData, const int *trisToFacesMap, - int *ndtris, unsigned short **dtris, - int *npolys, unsigned short **dmeshes, unsigned short **polys, - int *vertsPerPoly, int **dtrisToPolysMap, int **dtrisToTrisMap); - -int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys, - unsigned short *polys, const unsigned short *dmeshes, - const float *verts, const unsigned short *dtris, - const int *dtrisToPolysMap); - -int polyNumVerts(const unsigned short *p, const int vertsPerPoly); -int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts); -int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx); -float distPointToSegmentSq(const float *point, const float *a, const float *b); - - -#endif /* NAVMESH_CONVERSION_H */ diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 37929bae042..a42819e52a2 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -47,13 +47,13 @@ struct PropertyRNA; /* ----------------------------- */ /* Data Management */ -void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip); -void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt); -void BKE_nla_tracks_free(ListBase *tracks); +void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user); +void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user); +void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user); -struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain, struct NlaStrip *strip, const bool use_same_action); -struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain, struct NlaTrack *nlt, const bool use_same_actions); -void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src); +struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain, struct NlaStrip *strip, const bool use_same_action, const int flag); +struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain, struct NlaTrack *nlt, const bool use_same_actions, const int flag); +void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src, const int flag); struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt, struct NlaTrack *prev); struct NlaStrip *BKE_nlastrip_new(struct bAction *act); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 09860972802..9b8febce756 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -74,6 +74,7 @@ struct PointerRNA; struct RenderData; struct Scene; struct Tex; +struct ViewRender; struct SpaceNode; struct ARegion; struct ColorManagedViewSettings; @@ -151,7 +152,7 @@ typedef struct bNodeType { float width, minwidth, maxwidth; float height, minheight, maxheight; - short nclass, flag, compatibility; + short nclass, flag; /* templates for static sockets */ bNodeSocketTemplate *inputs, *outputs; @@ -250,10 +251,6 @@ typedef struct bNodeType { #define NODE_CLASS_SHADER 40 #define NODE_CLASS_LAYOUT 100 -/* nodetype->compatibility */ -#define NODE_OLD_SHADING 1 -#define NODE_NEW_SHADING 2 - /* node resize directions */ #define NODE_RESIZE_TOP 1 #define NODE_RESIZE_BOTTOM 2 @@ -343,7 +340,7 @@ void ntreeUserIncrefID(struct bNodeTree *ntree); void ntreeUserDecrefID(struct bNodeTree *ntree); -struct bNodeTree *ntreeFromID(struct ID *id); +struct bNodeTree *ntreeFromID(const struct ID *id); void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist, const bool lib_local); struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); @@ -469,6 +466,10 @@ bool nodeAttachNodeCheck(struct bNode *node, struct bNode *parent); void nodeAttachNode(struct bNode *node, struct bNode *parent); void nodeDetachNode(struct bNode *node); +void nodePositionRelative(struct bNode *from_node, struct bNode *to_node, + struct bNodeSocket *from_sock, struct bNodeSocket *to_sock); +void nodePositionPropagate(struct bNode *node); + struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name); int nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **nodep, int *sockindex); struct bNode *nodeFindRootParent(bNode *node); @@ -496,7 +497,6 @@ struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree); void nodeUpdate(struct bNodeTree *ntree, struct bNode *node); bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id); void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node); -void nodeSynchronizeID(struct bNode *node, bool copy_to_id); int nodeSocketIsHidden(struct bNodeSocket *sock); void ntreeTagUsedSockets(struct bNodeTree *ntree); @@ -600,7 +600,6 @@ void node_type_update(struct bNodeType *ntype, void node_type_exec(struct bNodeType *ntype, NodeInitExecFunction initexecfunc, NodeFreeExecFunction freeexecfunc, NodeExecFunction execfunc); void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc); void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *)); -void node_type_compatibility(struct bNodeType *ntype, short compatibility); /** \} */ @@ -690,27 +689,33 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Node Tree + */ + +void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, const int layer_index); + /* -------------------------------------------------------------------- */ /** \name Shader Nodes * \{ */ -struct ShadeInput; -struct ShadeResult; /* note: types are needed to restore callbacks, don't change values */ /* range 1 - 100 is reserved for common nodes */ /* using toolbox, we add node groups by assuming the values below don't exceed NODE_GROUP_MENU for now */ -#define SH_NODE_OUTPUT 1 +//#define SH_NODE_OUTPUT 1 -#define SH_NODE_MATERIAL 100 +//#define SH_NODE_MATERIAL 100 #define SH_NODE_RGB 101 #define SH_NODE_VALUE 102 #define SH_NODE_MIX_RGB 103 #define SH_NODE_VALTORGB 104 #define SH_NODE_RGBTOBW 105 -#define SH_NODE_TEXTURE 106 +#define SH_NODE_SHADERTORGB 106 +//#define SH_NODE_TEXTURE 106 #define SH_NODE_NORMAL 107 -#define SH_NODE_GEOMETRY 108 +//#define SH_NODE_GEOMETRY 108 #define SH_NODE_MAPPING 109 #define SH_NODE_CURVE_VEC 110 #define SH_NODE_CURVE_RGB 111 @@ -718,7 +723,7 @@ struct ShadeResult; #define SH_NODE_MATH 115 #define SH_NODE_VECT_MATH 116 #define SH_NODE_SQUEEZE 117 -#define SH_NODE_MATERIAL_EXT 118 +//#define SH_NODE_MATERIAL_EXT 118 #define SH_NODE_INVERT 119 #define SH_NODE_SEPRGB 120 #define SH_NODE_COMBRGB 121 @@ -727,7 +732,7 @@ struct ShadeResult; #define SH_NODE_OUTPUT_MATERIAL 124 #define SH_NODE_OUTPUT_WORLD 125 -#define SH_NODE_OUTPUT_LAMP 126 +#define SH_NODE_OUTPUT_LIGHT 126 #define SH_NODE_FRESNEL 127 #define SH_NODE_MIX_SHADER 128 #define SH_NODE_ATTRIBUTE 129 @@ -790,6 +795,7 @@ struct ShadeResult; #define SH_NODE_TEX_POINTDENSITY 192 #define SH_NODE_BSDF_PRINCIPLED 193 #define SH_NODE_TEX_IES 194 +#define SH_NODE_EEVEE_SPECULAR 195 #define SH_NODE_BEVEL 197 #define SH_NODE_DISPLACEMENT 198 #define SH_NODE_VECTOR_DISPLACEMENT 199 @@ -806,14 +812,11 @@ struct ShadeResult; struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree); void ntreeShaderEndExecTree(struct bNodeTreeExec *exec); -bool ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr); -void ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode); - -/* switch material render loop */ -extern void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *); -void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, struct ShadeResult *)); +bool ntreeShaderExecTree(struct bNodeTree *ntree, int thread); +struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target); -void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat, short compatibility); +void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat, + bool *has_surface_output, bool *has_volume_output); /** \} */ @@ -985,7 +988,7 @@ void ntreeCompositTagRender(struct Scene *sce); int ntreeCompositTagAnimated(struct bNodeTree *ntree); void ntreeCompositTagGenerators(struct bNodeTree *ntree); void ntreeCompositUpdateRLayers(struct bNodeTree *ntree); -void ntreeCompositRegisterPass(struct bNodeTree *ntree, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int type); +void ntreeCompositRegisterPass(struct bNodeTree *ntree, struct Scene *scene, struct ViewLayer *view_layer, const char *name, int type); void ntreeCompositClearTags(struct bNodeTree *ntree); struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node, @@ -1049,10 +1052,19 @@ struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree); void ntreeTexEndExecTree(struct bNodeTreeExec *exec); int ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target, float coord[3], float dxt[3], float dyt[3], int osatex, const short thread, - struct Tex *tex, short which_output, int cfra, int preview, struct ShadeInput *shi, struct MTex *mtex); + struct Tex *tex, short which_output, int cfra, int preview, struct MTex *mtex); /** \} */ void init_nodesystem(void); void free_nodesystem(void); +/* -------------------------------------------------------------------- */ +/* evaluation support, */ + +struct Depsgraph; + +void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph, + struct bNodeTree *ntree_dst, + const struct bNodeTree *ntree_src); + #endif /* __BKE_NODE_H__ */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 677d6b3fba2..8085c541600 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -36,52 +36,73 @@ extern "C" { #include "BLI_compiler_attrs.h" struct Base; -struct EvaluationContext; +struct Depsgraph; +struct GpencilModifierData; struct Scene; +struct ShaderFxData; +struct ViewLayer; +struct ID; struct Object; struct BoundBox; struct View3D; struct SoftBody; -struct BulletSoftBody; struct MovieClip; struct Main; +struct Mesh; struct RigidBodyWorld; struct HookModifierData; struct ModifierData; +struct HookGpencilModifierData; + +#include "DNA_object_enums.h" void BKE_object_workob_clear(struct Object *workob); -void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob); +void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Object *workob); void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src); -struct SoftBody *copy_softbody(const struct SoftBody *sb, const int flag); -struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb, const int flag); +void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag); struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag); void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, const int flag); -void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_particlesystems(struct Object *ob); void BKE_object_free_softbody(struct Object *ob); -void BKE_object_free_bulletsoftbody(struct Object *ob); void BKE_object_free_curve_cache(struct Object *ob); -void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob); void BKE_object_free(struct Object *ob); void BKE_object_free_derived_caches(struct Object *ob); +void BKE_object_free_derived_mesh_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); +void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd); +bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md); + +bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md); bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type); -void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src); +void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_modifiers(struct Object *ob, const int flag); +void BKE_object_free_shaderfx(struct Object *ob, const int flag); -void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); +void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob); void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest); bool BKE_object_is_in_editmode(const struct Object *ob); bool BKE_object_is_in_editmode_vgroup(const struct Object *ob); bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob); +bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode); +bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode); + +bool BKE_object_data_is_in_editmode(const struct ID *id); + +typedef enum eObjectVisibilityCheck { + OB_VISIBILITY_CHECK_FOR_VIEWPORT, + OB_VISIBILITY_CHECK_FOR_RENDER, + OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE, +} eObjectVisibilityCheck; + +bool BKE_object_is_visible(const struct Object *ob, const eObjectVisibilityCheck mode); void BKE_object_init(struct Object *ob); struct Object *BKE_object_add_only_object( @@ -89,22 +110,21 @@ struct Object *BKE_object_add_only_object( int type, const char *name) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL; struct Object *BKE_object_add( - struct Main *bmain, struct Scene *scene, + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, int type, const char *name) - ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL; + ATTR_NONNULL(1, 2, 3) ATTR_RETURNS_NONNULL; +struct Object *BKE_object_add_from( + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, + int type, const char *name, struct Object *ob_src) + ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL; +struct Object *BKE_object_add_for_data( + struct Main *bmain, struct ViewLayer *view_layer, + int type, const char *name, struct ID *data, bool do_id_user) ATTR_RETURNS_NONNULL; void *BKE_object_obdata_add_from_type( struct Main *bmain, int type, const char *name) ATTR_NONNULL(1); -void BKE_object_lod_add(struct Object *ob); -void BKE_object_lod_sort(struct Object *ob); -bool BKE_object_lod_remove(struct Object *ob, int level); -void BKE_object_lod_update(struct Object *ob, const float camera_position[3]); -bool BKE_object_lod_is_usable(struct Object *ob, struct Scene *scene); -struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene); -struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene); - void BKE_object_copy_data(struct Main *bmain, struct Object *ob_dst, const struct Object *ob_src, const int flag); struct Object *BKE_object_copy(struct Main *bmain, const struct Object *ob); void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local); @@ -120,20 +140,36 @@ void BKE_object_mat3_to_rot(struct Object *ob, float mat[3][3], bool use_compat) void BKE_object_to_mat3(struct Object *ob, float mat[3][3]); void BKE_object_to_mat4(struct Object *ob, float mat[4][4]); void BKE_object_apply_mat4(struct Object *ob, float mat[4][4], const bool use_compat, const bool use_parent); +void BKE_object_apply_mat4_ex(struct Object *ob, float mat[4][4], struct Object *parent, float parentinv[4][4], const bool use_compat); void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]); bool BKE_object_pose_context_check(const struct Object *ob); struct Object *BKE_object_pose_armature_get(struct Object *ob); +struct Object *BKE_object_pose_armature_get_visible(struct Object *ob, struct ViewLayer *view_layer); -void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob, struct Object *par, float parentmat[4][4]); -void BKE_object_where_is_calc(struct Scene *scene, struct Object *ob); +struct Object **BKE_object_pose_array_get_ex(struct ViewLayer *view_layer, unsigned int *r_objects_len, bool unique); +struct Object **BKE_object_pose_array_get_unique(struct ViewLayer *view_layer, unsigned int *r_objects_len); +struct Object **BKE_object_pose_array_get(struct ViewLayer *view_layer, unsigned int *r_objects_len); + +struct Base **BKE_object_pose_base_array_get_ex(struct ViewLayer *view_layer, unsigned int *r_bases_len, bool unique); +struct Base **BKE_object_pose_base_array_get_unique(struct ViewLayer *view_layer, unsigned int *r_bases_len); +struct Base **BKE_object_pose_base_array_get(struct ViewLayer *view_layer, unsigned int *r_bases_len); + +void BKE_object_get_parent_matrix( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, + struct Object *par, float parentmat[4][4]); +void BKE_object_where_is_calc( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_object_where_is_calc_ex( - struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]); -void BKE_object_where_is_calc_time(struct Scene *scene, struct Object *ob, float ctime); + struct Depsgraph *depsgraph, struct Scene *scene, struct RigidBodyWorld *rbw, + struct Object *ob, float r_originmat[3][3]); +void BKE_object_where_is_calc_time( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime); void BKE_object_where_is_calc_time_ex( - struct Scene *scene, struct Object *ob, float ctime, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime, struct RigidBodyWorld *rbw, float r_originmat[3][3]); -void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float obmat[4][4]); +void BKE_object_where_is_calc_mat4( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float obmat[4][4]); /* possibly belong in own moduke? */ struct BoundBox *BKE_boundbox_alloc_unit(void); @@ -147,20 +183,18 @@ void BKE_object_dimensions_get(struct Object *ob, float vec[3]); void BKE_object_dimensions_set(struct Object *ob, const float value[3]); void BKE_object_empty_draw_type_set(struct Object *ob, const int value); void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set); +void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval); void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden); bool BKE_object_minmax_dupli( - struct Main *bmain, struct Scene *scene, - struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden); + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, + float r_min[3], float r_max[3], const bool use_hidden); /* sometimes min-max isn't enough, we need to loop over each point */ void BKE_object_foreach_display_point( struct Object *ob, float obmat[4][4], void (*func_cb)(const float[3], void *), void *user_data); void BKE_scene_foreach_display_point( - struct Main *bmain, - struct Scene *scene, - struct View3D *v3d, - const short flag, + struct Depsgraph *depsgraph, void (*func_cb)(const float[3], void *), void *user_data); bool BKE_object_parent_loop_check(const struct Object *parent, const struct Object *ob); @@ -188,54 +222,59 @@ void BKE_object_tfm_protected_restore( /* Dependency graph evaluation callbacks. */ void BKE_object_eval_local_transform( - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Object *ob); void BKE_object_eval_parent( - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_object_eval_constraints( - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); -void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob); +void BKE_object_eval_done(struct Depsgraph *depsgraph, struct Object *ob); bool BKE_object_eval_proxy_copy( - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Object *object); void BKE_object_eval_uber_transform( - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Object *ob); void BKE_object_eval_uber_data( - struct Main *bmain, - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_object_eval_cloth( - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *object); - void BKE_object_eval_transform_all( - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *object); -void BKE_object_handle_data_update( - struct Main *bmain, - struct EvaluationContext *eval_ctx, - struct Scene *scene, - struct Object *ob); -void BKE_object_handle_update( - struct Main *bmain, - struct EvaluationContext *eval_ctx, +void BKE_object_eval_update_shading( + struct Depsgraph *depsgraph, + struct Object *object); +void BKE_object_data_select_update( + struct Depsgraph *depsgraph, + struct ID *object_data); + +void BKE_object_eval_flush_base_flags( + struct Depsgraph *depsgraph, + struct Scene *scene, const int view_layer_index, + struct Object *object, int base_index, + const bool is_from_set); + +void BKE_object_handle_data_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); +void BKE_object_handle_update(struct Depsgraph *depsgraph, + struct Scene *scene, struct Object *ob); void BKE_object_handle_update_ex( - struct Main *bmain, - struct EvaluationContext *eval_ctx, + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct RigidBodyWorld *rbw, const bool do_proxy_update); @@ -243,6 +282,11 @@ void BKE_object_sculpt_modifiers_changed(struct Object *ob); int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot); +struct Mesh *BKE_object_get_evaluated_mesh(const struct Depsgraph *depsgraph, struct Object *ob); +struct Mesh *BKE_object_get_final_mesh(struct Object *object); +struct Mesh *BKE_object_get_pre_modified_mesh(struct Object *object); +struct Mesh *BKE_object_get_original_mesh(struct Object *object); + int BKE_object_insert_ptcache(struct Object *ob); void BKE_object_delete_ptcache(struct Object *ob, int index); struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain, struct Object *ob, const char *name, const bool from_mix); @@ -263,6 +307,10 @@ void BKE_object_data_relink(struct Object *ob); struct MovieClip *BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default); +void BKE_object_runtime_reset(struct Object *object); + +void BKE_object_batch_cache_dirty_tag(struct Object *ob); + /* this function returns a superset of the scenes selection based on relationships */ typedef enum eObRelationTypes { @@ -282,20 +330,17 @@ typedef enum eObjectSet { } eObjectSet; struct LinkNode *BKE_object_relational_superset( - struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter); + struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter); struct LinkNode *BKE_object_groups(struct Main *bmain, struct Object *ob); -void BKE_object_groups_clear( - struct Main *bmain, struct Scene *scene, struct Base *base, struct Object *object); +void BKE_object_groups_clear(struct Main *bmain, struct Object *object); struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot); bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md); bool BKE_object_modifier_update_subframe( - struct Main *bmain, struct EvaluationContext *eval_ctx, - struct Scene *scene, struct Object *ob, bool update_mesh, - int parent_recursion, float frame, - int type); + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, + bool update_mesh, int parent_recursion, float frame, int type); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_object_facemap.h b/source/blender/blenkernel/BKE_object_facemap.h new file mode 100644 index 00000000000..2607e5aa2dd --- /dev/null +++ b/source/blender/blenkernel/BKE_object_facemap.h @@ -0,0 +1,53 @@ +/* + * ***** 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. + * + * Contributor(s): Antony Riakiotakis + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_OBJECT_FACEMAP_H__ +#define __BKE_OBJECT_FACEMAP_H__ + +/** \file BKE_object_facemap.h + * \ingroup bke + * \brief Functions for dealing with object face-maps. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct bFaceMap; +struct ListBase; +struct Object; + +struct bFaceMap *BKE_object_facemap_add(struct Object *ob); +struct bFaceMap *BKE_object_facemap_add_name(struct Object *ob, const char *name); +void BKE_object_facemap_remove(struct Object *ob, struct bFaceMap *fmap); +void BKE_object_facemap_clear(struct Object *ob); + +int BKE_object_facemap_name_index(struct Object *ob, const char *name); +void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap); +struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name); +void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_OBJECT_FACEMAP_H__ */ diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h index 3ea104e656a..e18a063ff52 100644 --- a/source/blender/blenkernel/BKE_ocean.h +++ b/source/blender/blenkernel/BKE_ocean.h @@ -31,6 +31,8 @@ extern "C" { #endif +struct OceanModifierData; + typedef struct OceanResult { float disp[3]; float normal[3]; @@ -72,6 +74,8 @@ typedef struct OceanCache { struct Ocean *BKE_ocean_add(void); void BKE_ocean_free_data(struct Ocean *oc); void BKE_ocean_free(struct Ocean *oc); +bool BKE_ocean_ensure(struct OceanModifierData *omd); +void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData const *omd); void BKE_ocean_init( struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, @@ -99,6 +103,8 @@ void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, in void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j); void BKE_ocean_free_cache(struct OceanCache *och); +void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_outliner_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h index 454edb40c4e..8a14f8fb041 100644 --- a/source/blender/blenkernel/BKE_outliner_treehash.h +++ b/source/blender/blenkernel/BKE_outliner_treehash.h @@ -36,8 +36,12 @@ void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore) /* full rebuild for already allocated hashtable */ void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore); -/* full rebuild for already allocated hashtable */ +/* clear element usage flags */ +void BKE_outliner_treehash_clear_used(void *treehash); + +/* Add/remove hashtable elements */ void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem); +void BKE_outliner_treehash_remove_element(void *treehash, struct TreeStoreElem *elem); /* find first unused element with specific type, nr and id */ struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index eedf5f7985e..e09aed4b372 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -33,13 +33,16 @@ */ struct bContext; +struct bToolRef; struct BMesh; struct BMFace; struct Brush; struct CurveMapping; +struct EnumPropertyItem; struct MeshElemMap; struct GridPaintMask; struct Main; +struct Mesh; struct MLoop; struct MLoopTri; struct MFace; @@ -52,11 +55,15 @@ struct PaletteColor; struct PBVH; struct ReportList; struct Scene; +struct ViewLayer; struct Sculpt; struct StrokeCache; +struct SubdivCCG; struct Tex; struct ImagePool; struct UnifiedPaintSettings; +struct Depsgraph; +struct ToolSettings; enum eOverlayFlags; @@ -77,9 +84,10 @@ typedef enum ePaintMode { /** Image space (2D painting). */ PAINT_MODE_TEXTURE_2D = 4, PAINT_MODE_SCULPT_UV = 5, + PAINT_MODE_GPENCIL = 6, /** Keep last. */ - PAINT_MODE_INVALID = 6 + PAINT_MODE_INVALID = 7, } ePaintMode; /* overlay invalidation */ @@ -97,14 +105,15 @@ typedef enum eOverlayControlFlags { PAINT_OVERLAY_OVERRIDE_PRIMARY | \ PAINT_OVERLAY_OVERRIDE_CURSOR) -void BKE_paint_invalidate_overlay_tex(struct Scene *scene, const struct Tex *tex); -void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct CurveMapping *curve); +void BKE_paint_invalidate_overlay_tex(struct Scene *scene, struct ViewLayer *view_layer, const struct Tex *tex); +void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct ViewLayer *view_layer, struct CurveMapping *curve); void BKE_paint_invalidate_overlay_all(void); eOverlayControlFlags BKE_paint_get_overlay_flags(void); void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag); void BKE_paint_set_overlay_override(enum eOverlayFlags flag); /* palettes */ +void BKE_palette_init(struct Palette *palette); void BKE_palette_free(struct Palette *palette); struct Palette *BKE_palette_add(struct Main *bmain, const char *name); void BKE_palette_copy_data( @@ -124,17 +133,24 @@ void BKE_paint_curve_copy_data( struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc); void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local); +bool BKE_paint_ensure(const struct ToolSettings *ts, struct Paint **r_paint); void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]); void BKE_paint_free(struct Paint *p); void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag); +void BKE_paint_runtime_init(const struct ToolSettings *ts, struct Paint *paint); + void BKE_paint_cavity_curve_preset(struct Paint *p, int preset); -eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode); +eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode); struct Paint *BKE_paint_get_active_from_paintmode(struct Scene *sce, ePaintMode mode); -struct Paint *BKE_paint_get_active(struct Scene *sce); +const struct EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode); +const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode); +uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode); +struct Paint *BKE_paint_get_active(struct Scene *sce, struct ViewLayer *view_layer); struct Paint *BKE_paint_get_active_from_context(const struct bContext *C); ePaintMode BKE_paintmode_get_active_from_context(const struct bContext *C); +ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref); struct Brush *BKE_paint_brush(struct Paint *paint); void BKE_paint_brush_set(struct Paint *paint, struct Brush *br); struct Palette *BKE_paint_palette(struct Paint *paint); @@ -168,6 +184,15 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); + +/* Tool slot API. */ +void BKE_paint_toolslots_init_from_main(struct Main *bmain); +void BKE_paint_toolslots_len_ensure(struct Paint *paint, int len); +void BKE_paint_toolslots_brush_update_ex(struct Paint *paint, struct Brush *brush); +void BKE_paint_toolslots_brush_update(struct Paint *paint); +void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint); +struct Brush *BKE_paint_toolslots_brush_get(struct Paint *paint, int slot_index); + /* Used for both vertex color and weight paint */ struct SculptVertexPaintGeomMap { int *vert_map_mem; @@ -189,7 +214,8 @@ typedef struct SculptSession { float *vmask; /* Mesh connectivity */ - const struct MeshElemMap *pmap; + struct MeshElemMap *pmap; + int *pmap_mem; /* BMesh for dynamic topology sculpting */ struct BMesh *bm; @@ -199,6 +225,9 @@ typedef struct SculptSession { /* Undo/redo log for dynamic topology sculpting */ struct BMLog *bm_log; + /* Limit surface/grids. */ + struct SubdivCCG *subdiv_ccg; + /* PBVH acceleration structure */ struct PBVH *pbvh; bool show_diffuse_color; @@ -254,13 +283,16 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss); void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss); void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder); void BKE_sculptsession_bm_to_me_for_render(struct Object *object); -void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, - bool need_pmap, bool need_mask); +void BKE_sculpt_update_mesh_elements( + struct Depsgraph *depsgraph, struct Scene *scene, struct Sculpt *sd, struct Object *ob, + bool need_pmap, bool need_mask); struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob); int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd); void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene); +struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob); + enum { SCULPT_MASK_LAYER_CALC_VERT = (1 << 0), SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1) diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 54c927aaa99..aa00024b27b 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -49,7 +49,7 @@ struct ParticleSettings; struct Main; struct Object; struct Scene; -struct DerivedMesh; +struct Depsgraph; struct ModifierData; struct MTFace; struct MCol; @@ -62,6 +62,8 @@ struct RNG; struct BVHTreeRay; struct BVHTreeRayHit; struct EdgeHash; +struct Depsgraph; +struct ViewLayer; #define PARTICLE_COLLISION_MAX_COLLISIONS 10 @@ -77,6 +79,7 @@ struct EdgeHash; /* common stuff that many particle functions need */ typedef struct ParticleSimulationData { + struct Depsgraph *depsgraph; struct Scene *scene; struct Object *ob; struct ParticleSystem *psys; @@ -86,6 +89,8 @@ typedef struct ParticleSimulationData { * maximum value per time step is important. Only sph_integrate makes use of * this at the moment. Other solvers could, too. */ float courant_num; + /* Only valid during dynamics_step(). */ + struct RNG *rng; } ParticleSimulationData; typedef struct SPHData { @@ -133,7 +138,7 @@ typedef struct ParticleCacheKey { typedef struct ParticleThreadContext { /* shared */ struct ParticleSimulationData sim; - struct DerivedMesh *dm; + struct Mesh *mesh; struct Material *ma; /* distribution */ @@ -144,7 +149,7 @@ typedef struct ParticleThreadContext { float *jit, *jitoff, *weight; float maxweight; - int *index, *skip, jitlevel; + int *index, jitlevel; int cfrom, distr; @@ -286,8 +291,8 @@ BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float ve int count_particles(struct ParticleSystem *psys); int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur); -int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys); -int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys); +int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys, const bool use_render_params); +int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys, const bool use_render_params); struct ParticleSystem *psys_get_current(struct Object *ob); /* for rna */ @@ -298,10 +303,12 @@ void psys_set_current_num(Object *ob, int index); struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim); -bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys); +struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys); +bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys); bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); bool psys_check_edited(struct ParticleSystem *psys); +void psys_find_group_weights(struct ParticleSettings *part); void psys_check_group_weights(struct ParticleSettings *part); int psys_uses_gravity(struct ParticleSimulationData *sim); void BKE_particlesettings_fluid_default_settings(struct ParticleSettings *part); @@ -311,8 +318,9 @@ void BKE_particlesettings_free(struct ParticleSettings *part); void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit); void psys_free(struct Object *ob, struct ParticleSystem *psys); -void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset); -void psys_render_restore(struct Object *ob, struct ParticleSystem *psys); +/* Copy. */ +void psys_copy_particles(struct ParticleSystem *psys_dst, struct ParticleSystem *psys_src); + bool psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params); void psys_interpolate_uvs(const struct MTFace *tface, int quad, const float w[4], float uvco[2]); @@ -323,7 +331,7 @@ void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int tim CustomDataMask psys_emitter_customdata_mask(struct ParticleSystem *psys); void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache, float fuv[4], float foffset, float vec[3], float nor[3], - float utan[3], float vtan[3], float orco[3], float ornor[3]); + float utan[3], float vtan[3], float orco[3]); struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct ParticleSystem *psys); struct ModifierData *object_add_particle_system( @@ -341,9 +349,9 @@ void psys_reset(struct ParticleSystem *psys, int mode); void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params); void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, const bool use_render_params); -void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params); +void psys_cache_edit_paths(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params); void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, const bool editupdate, const bool use_render_params); -int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time); +int do_guides(struct Depsgraph *depsgraph, struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time); void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors); float psys_get_timestep(struct ParticleSimulationData *sim); float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime); @@ -356,7 +364,7 @@ void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part); void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part); void BKE_particlesettings_twist_curve_init(struct ParticleSettings *part); void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers, - struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4], + struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], float hairmat[4][4], struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]); void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata); @@ -376,7 +384,7 @@ void psys_tasks_create(struct ParticleThreadContext *ctx, int startpart, int end void psys_tasks_free(struct ParticleTask *tasks, int numtasks); void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]); -void psys_apply_hair_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); +void psys_apply_hair_lattice(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); /* particle_system.c */ struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt); @@ -391,7 +399,7 @@ void psys_check_boid_data(struct ParticleSystem *psys); void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra); -void particle_system_update(struct Main *bmain, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); +void particle_system_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); /* Callback format for performing operations on ID-pointers for particle systems */ typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cb_flag); @@ -409,65 +417,38 @@ void psys_free_particles(struct ParticleSystem *psys); void psys_free_children(struct ParticleSystem *psys); void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, bool velocity); -void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float vec[3]); -void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]); -void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]); -void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]); +void psys_vec_rot_to_face(struct Mesh *mesh, struct ParticleData *pa, float vec[3]); +void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]); +void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]); +void psys_mat_hair_to_orco(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]); float psys_get_dietime_from_cache(struct PointCache *cache, int index); void psys_free_pdd(struct ParticleSystem *psys); -float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup); +float *psys_cache_vgroup(struct Mesh *mesh, struct ParticleSystem *psys, int vgroup); void psys_get_texture(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleTexture *ptex, int event, float cfra); void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFace *tface, float (*orcodata)[3], float w[4], float vec[3], float nor[3], float utan[3], float vtan[3], - float orco[3], float ornor[3]); -float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct ParticleData *pa, float *values); + float orco[3]); +float psys_particle_value_from_verts(struct Mesh *mesh, short from, struct ParticleData *pa, float *values); void psys_get_from_key(struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time); /* BLI_bvhtree_ray_cast callback */ void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit); -void psys_particle_on_dm(struct DerivedMesh *dm_final, int from, int index, int index_dmcache, +void psys_particle_on_dm(struct Mesh *mesh_final, int from, int index, int index_dmcache, const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3], - float orco[3], float ornor[3]); + float orco[3]); /* particle_system.c */ void distribute_particles(struct ParticleSimulationData *sim, int from); void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa); -void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, struct ParticleSystem *psys); -int psys_particle_dm_face_lookup(struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, int findex, const float fw[4], struct LinkNode **poly_nodes); +void psys_calc_dmcache(struct Object *ob, struct Mesh *mesh_final, struct Mesh *mesh_original, struct ParticleSystem *psys); +int psys_particle_dm_face_lookup(struct Mesh *mesh_final, struct Mesh *mesh_original, int findex, const float fw[4], struct LinkNode **poly_nodes); void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra); -float psys_get_current_display_percentage(struct ParticleSystem *psys); - -typedef struct ParticleRenderElem { - int curchild, totchild, reduce; - float lambda, t, scalemin, scalemax; -} ParticleRenderElem; - -typedef struct ParticleRenderData { - ChildParticle *child; - ParticleCacheKey **pathcache; - ParticleCacheKey **childcache; - ListBase pathcachebufs, childcachebufs; - int totchild, totcached, totchildcache; - struct DerivedMesh *dm; - int totdmvert, totdmedge, totdmface; - - float mat[4][4]; - float viewmat[4][4], winmat[4][4]; - int winx, winy; - - int do_simplify; - int timeoffset; - ParticleRenderElem *elems; - - /* ORIGINDEX */ - const int *index_mf_to_mpoly; - const int *index_mp_to_orig; -} ParticleRenderData; +float psys_get_current_display_percentage(struct ParticleSystem *psys, const bool use_render_params); /* psys_reset */ #define PSYS_RESET_ALL 1 @@ -481,10 +462,17 @@ typedef struct ParticleRenderData { /* **** Depsgraph evaluation **** */ -struct EvaluationContext; +struct Depsgraph; -void BKE_particle_system_eval_init(struct EvaluationContext *eval_ctx, +void BKE_particle_system_eval_init(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); #endif + +/* Draw Cache */ +enum { + BKE_PARTICLE_BATCH_DIRTY_ALL = 0, +}; +void BKE_particle_batch_cache_dirty_tag(struct ParticleSystem *psys, int mode); +void BKE_particle_batch_cache_free(struct ParticleSystem *psys); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 1fede116193..47fedb565fc 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -30,6 +30,7 @@ #include "BLI_ghash.h" #include "BLI_utildefines.h" +struct GPUBatch; struct CCGElem; struct CCGKey; struct CCGDerivedMesh; @@ -127,10 +128,9 @@ bool BKE_pbvh_node_find_nearest_to_ray( /* Drawing */ -void BKE_pbvh_node_draw(PBVHNode *node, void *data); -void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], - int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast); -void BKE_pbvh_draw_BB(PBVH *bvh); +void BKE_pbvh_draw_cb( + PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, bool only_mask, + void (*draw_fn)(void *user_data, struct GPUBatch *batch), void *user_data); /* PBVH Access */ typedef enum { @@ -155,6 +155,8 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden, /* multires level, only valid for type == PBVH_GRIDS */ void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); +struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh, int *num_grids); + /* Only valid for type == PBVH_BMESH */ struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size); @@ -219,7 +221,7 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node); void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node); void BKE_pbvh_bmesh_after_stroke(PBVH *bvh); -/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */ +/* Update Normals/Bounding Box/Redraw and clear flags */ void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]); @@ -238,7 +240,7 @@ void BKE_pbvh_node_layer_disp_free(PBVHNode *node); /* vertex deformer */ float (*BKE_pbvh_get_vertCos(struct PBVH *pbvh))[3]; -void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); +void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3], const int totvert); bool BKE_pbvh_isDeformed(struct PBVH *pbvh); /* Vertex Iterator */ @@ -367,6 +369,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node); //void BKE_pbvh_node_BB_reset(PBVHNode *node); //void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]); +bool pbvh_has_mask(PBVH *bvh); void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color); void pbvh_show_mask_set(PBVH *bvh, bool show_mask); diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index e905a5efae4..7456a4bfb15 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -90,6 +90,7 @@ struct ParticleKey; struct ParticleSystem; struct PointCache; struct Scene; +struct ViewLayer; struct SmokeModifierData; struct SoftBody; struct RigidBodyWorld; @@ -186,6 +187,8 @@ typedef struct PTCacheID { typedef struct PTCacheBaker { struct Main *bmain; struct Scene *scene; + struct ViewLayer *view_layer; + struct Depsgraph *depsgraph; int bake; int render; int anim_init; @@ -243,13 +246,25 @@ typedef struct PTCacheUndo { size_t undo_size; } PTCacheUndo; +enum { + /* Modifier stack got evaluated during particle edit mode, need to copy + * new evaluated particles to the edit struct. + */ + PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL = (1 << 0), +}; + typedef struct PTCacheEdit { + int flags; + PTCacheEditPoint *points; struct PTCacheID pid; /* particles stuff */ struct ParticleSystem *psys; + struct ParticleSystem *psys_eval; + struct ParticleSystemModifierData *psmd; + struct ParticleSystemModifierData *psmd_eval; struct KDTree *emitter_field; float *emitter_cosnos; /* localspace face centers and normals (average of its verts), from the derived mesh */ int *mirror_cache; @@ -274,8 +289,9 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo 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); +PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache); void BKE_ptcache_ids_from_object( - struct Main *bmain, struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis); + struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis); /***************** Global funcs ****************************/ void BKE_ptcache_remove(void); @@ -318,7 +334,7 @@ struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const st /********************** Baking *********************/ /* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */ -void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene); +void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer); /* Bake cache or simulate to current frame with settings defined in the baker. */ void BKE_ptcache_bake(struct PTCacheBaker *baker); diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h deleted file mode 100644 index d917a6b55e6..00000000000 --- a/source/blender/blenkernel/BKE_property.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef __BKE_PROPERTY_H__ -#define __BKE_PROPERTY_H__ - -/** \file BKE_property.h - * \ingroup bke - */ - -struct bProperty; -struct ListBase; -struct Object; - -void BKE_bproperty_free(struct bProperty *prop); -void BKE_bproperty_free_list(struct ListBase *lb); -struct bProperty *BKE_bproperty_copy(const struct bProperty *prop); -void BKE_bproperty_copy_list(struct ListBase *lbn, const struct ListBase *lbo); -void BKE_bproperty_init(struct bProperty *prop); -struct bProperty *BKE_bproperty_new(int type); -void BKE_bproperty_unique(struct bProperty *first, struct bProperty *prop, int force); -struct bProperty *BKE_bproperty_object_get(struct Object *ob, const char *name); -void BKE_bproperty_object_set(struct Object *ob, struct bProperty *propc); -// int BKE_bproperty_cmp(struct bProperty *prop, const char *str); -void BKE_bproperty_set(struct bProperty *prop, const char *str); -void BKE_bproperty_add(struct bProperty *prop, const char *str); -/* should really be called '_get_valstr()' or '_as_string()' */ -void BKE_bproperty_set_valstr(struct bProperty *prop, char str[MAX_PROPSTRING]); - -#endif diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index 470aae40df9..1fa8106d63b 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -37,14 +37,15 @@ struct RigidBodyWorld; struct RigidBodyOb; +struct Depsgraph; struct Scene; struct Object; /* -------------- */ /* Memory Management */ -void BKE_rigidbody_free_world(struct RigidBodyWorld *rbw); -void BKE_rigidbody_free_object(struct Object *ob); +void BKE_rigidbody_free_world(struct Scene *scene); +void BKE_rigidbody_free_object(struct Object *ob, struct RigidBodyWorld *rbw); void BKE_rigidbody_free_constraint(struct Object *ob); /* ...... */ @@ -79,7 +80,7 @@ void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_center[3]); /* 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_object(struct Main *bmain, struct Scene *scene, struct Object *ob); void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob); /* -------------- */ @@ -99,21 +100,19 @@ void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[ void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime); bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime); void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw); -void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime); -void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime); +void BKE_rigidbody_rebuild_world(struct Depsgraph *depsgraph, struct Scene *scene, float ctime); +void BKE_rigidbody_do_simulation(struct Depsgraph *depsgraph, struct Scene *scene, float ctime); /* -------------------- */ /* Depsgraph evaluation */ -struct EvaluationContext; - -void BKE_rigidbody_rebuild_sim(struct EvaluationContext *eval_ctx, +void BKE_rigidbody_rebuild_sim(struct Depsgraph *depsgraph, struct Scene *scene); -void BKE_rigidbody_eval_simulation(struct EvaluationContext *eval_ctx, +void BKE_rigidbody_eval_simulation(struct Depsgraph *depsgraph, struct Scene *scene); -void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *eval_ctx, +void BKE_rigidbody_object_sync_transforms(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h deleted file mode 100644 index 653fc1afa64..00000000000 --- a/source/blender/blenkernel/BKE_sca.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef __BKE_SCA_H__ -#define __BKE_SCA_H__ - -/** \file BKE_sca.h - * \ingroup bke - */ - -struct Main; -struct Object; -struct bSensor; -struct bController; -struct bActuator; - -void link_logicbricks(void **poin, void ***ppoin, short *tot, short size); -void unlink_logicbricks(void **poin, void ***ppoin, short *tot); - -void unlink_controller(struct bController *cont); -void unlink_controllers(struct ListBase *lb); -void free_controller(struct bController *cont); -void free_controllers(struct ListBase *lb); - -void unlink_actuator(struct bActuator *act); -void unlink_actuators(struct ListBase *lb); -void free_actuator(struct bActuator *act); -void free_actuators(struct ListBase *lb); - -void free_sensor(struct bSensor *sens); -void free_sensors(struct ListBase *lb); -struct bSensor *copy_sensor(struct bSensor *sens, const int flag); -void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo, const int flag); -void init_sensor(struct bSensor *sens); -struct bSensor *new_sensor(int type); -struct bController *copy_controller(struct bController *cont, const int flag); -void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo, const int flag); -void init_controller(struct bController *cont); -struct bController *new_controller(int type); -struct bActuator *copy_actuator(struct bActuator *act, const int flag); -void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo, const int flag); -void init_actuator(struct bActuator *act); -struct bActuator *new_actuator(int type); -void clear_sca_new_poins_ob(struct Object *ob); -void clear_sca_new_poins(void); -void set_sca_new_poins_ob(struct Object *ob); -void set_sca_new_poins(void); - -void BKE_sca_logic_links_remap(struct Main *bmain, struct Object *ob_old, struct Object *ob_new); -void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob, const int flag); - -void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up); -void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up); -void sca_move_actuator(struct bActuator *act_to_move, struct Object *ob, int move_up); - -/* Callback format for performing operations on ID-pointers for sensors/controllers/actuators. */ -typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cb_flag); -typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cb_flag); -typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cb_flag); - -void BKE_sca_sensors_id_loop(struct ListBase *senslist, SCASensorIDFunc func, void *userdata); -void BKE_sca_controllers_id_loop(struct ListBase *contlist, SCAControllerIDFunc func, void *userdata); -void BKE_sca_actuators_id_loop(struct ListBase *atclist, SCAActuatorIDFunc func, void *userdata); - - -const char *sca_state_name_get(Object *ob, short bit); - -#endif diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index e85867fcbe7..e7a26afadf5 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -38,43 +38,55 @@ extern "C" { #endif struct AviCodecData; -struct Base; -struct EvaluationContext; +struct Collection; +struct Depsgraph; struct Main; struct Object; struct RenderData; -struct SceneRenderLayer; struct Scene; +struct ViewLayer; struct UnitSettings; -struct Main; - -#define SCE_COPY_NEW 0 -#define SCE_COPY_EMPTY 1 -#define SCE_COPY_LINK_OB 2 -#define SCE_COPY_LINK_DATA 3 -#define SCE_COPY_FULL 4 +struct ViewRender; +struct WorkSpace; +struct TransformOrientation; + +typedef enum eSceneCopyMethod { + SCE_COPY_NEW = 0, + SCE_COPY_EMPTY = 1, + SCE_COPY_LINK_OB = 2, + SCE_COPY_LINK_DATA = 3, + SCE_COPY_FULL = 4, +} eSceneCopyMethod; /* Use as the contents of a 'for' loop: for (SETLOOPER(...)) { ... */ #define SETLOOPER(_sce_basis, _sce_iter, _base) \ - _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, NULL); \ + _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, BKE_view_layer_context_active_PLACEHOLDER(_sce_basis), NULL); \ _base; \ - _base = _setlooper_base_step(&_sce_iter, _base) + _base = _setlooper_base_step(&_sce_iter, NULL, _base) -struct Base *_setlooper_base_step(struct Scene **sce_iter, struct Base *base); +#define SETLOOPER_VIEW_LAYER(_sce_basis, _view_layer, _sce_iter, _base) \ + _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, _view_layer, NULL); \ + _base; \ + _base = _setlooper_base_step(&_sce_iter, NULL, _base) + +#define SETLOOPER_SET_ONLY(_sce_basis, _sce_iter, _base) \ + _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, NULL, NULL); \ + _base; \ + _base = _setlooper_base_step(&_sce_iter, NULL, _base) + +struct Base *_setlooper_base_step(struct Scene **sce_iter, struct ViewLayer *view_layer, struct Base *base); void free_avicodecdata(struct AviCodecData *acd); +void BKE_scene_free_ex(struct Scene *sce, const bool do_id_user); void BKE_scene_free(struct Scene *sce); void BKE_scene_init(struct Scene *sce); struct Scene *BKE_scene_add(struct Main *bmain, const char *name); -/* base functions */ -struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name); -struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob); -struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob); -void BKE_scene_base_unlink(struct Scene *sce, struct Base *base); -void BKE_scene_base_deselect_all(struct Scene *sce); -void BKE_scene_base_select(struct Scene *sce, struct Base *selbase); +void BKE_scene_remove_rigidbody_object(struct Main *bmain, struct Scene *scene, struct Object *ob); + +bool BKE_scene_object_find(struct Scene *scene, struct Object *ob); +struct Object *BKE_scene_object_find_by_name(struct Scene *scene, const char *name); /* Scene base iteration function. * Define struct here, so no need to bother with alloc/free it. @@ -87,11 +99,14 @@ typedef struct SceneBaseIter { int phase; } SceneBaseIter; -int BKE_scene_base_iter_next(struct Main *bmain, struct EvaluationContext *eval_ctx, struct SceneBaseIter *iter, - struct Scene **scene, int val, struct Base **base, struct Object **ob); +int BKE_scene_base_iter_next( + struct Depsgraph *depsgraph, struct SceneBaseIter *iter, + struct Scene **scene, int val, struct Base **base, struct Object **ob); -void BKE_scene_base_flag_to_objects(struct Scene *scene); +void BKE_scene_base_flag_to_objects(struct ViewLayer *view_layer); void BKE_scene_base_flag_from_objects(struct Scene *scene); +void BKE_scene_object_base_flag_sync_from_base(struct Base *base); +void BKE_scene_object_base_flag_sync_from_object(struct Base *base); void BKE_scene_set_background(struct Main *bmain, struct Scene *sce); struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); @@ -105,7 +120,8 @@ void BKE_scene_groups_relink(struct Scene *sce); void BKE_scene_make_local(struct Main *bmain, struct Scene *sce, const bool lib_local); -struct Object *BKE_scene_camera_find(struct Scene *sc); +struct Scene *BKE_scene_find_from_collection(const struct Main *bmain, const struct Collection *collection); + #ifdef DURIAN_CAMERA_SWITCH struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH #endif @@ -124,12 +140,15 @@ float BKE_scene_frame_get_from_ctime(const struct Scene *scene, const float fram void BKE_scene_frame_set(struct Scene *scene, double cfra); /* ** Scene evaluation ** */ -void BKE_scene_update_tagged(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce); -void BKE_scene_update_for_newframe(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay); -void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay, bool do_invisible_flush); -struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name); -bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl); +void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, + struct Main *bmain); + +void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph, + struct Main *bmain); + +void BKE_scene_view_layer_graph_evaluated_ensure( + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer); struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name); bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv); @@ -137,16 +156,13 @@ bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *s /* render profile */ int get_render_subsurf_level(const struct RenderData *r, int level, bool for_render); int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render); -int get_render_shadow_samples(const struct RenderData *r, int samples); -float get_render_aosss_error(const struct RenderData *r, float error); -bool BKE_scene_use_new_shading_nodes(const struct Scene *scene); bool BKE_scene_use_shading_nodes_custom(struct Scene *scene); -bool BKE_scene_use_world_space_shading(struct Scene *scene); bool BKE_scene_use_spherical_stereo(struct Scene *scene); -bool BKE_scene_uses_blender_internal(const struct Scene *scene); -bool BKE_scene_uses_blender_game(const struct Scene *scene); +bool BKE_scene_uses_blender_eevee(const struct Scene *scene); +bool BKE_scene_uses_blender_opengl(const struct Scene *scene); +bool BKE_scene_uses_cycles(const struct Scene *scene); void BKE_scene_disable_color_management(struct Scene *scene); bool BKE_scene_check_color_management_enabled(const struct Scene *scene); @@ -157,6 +173,8 @@ int BKE_render_num_threads(const struct RenderData *r); int BKE_render_preview_pixel_size(const struct RenderData *r); +/**********************************/ + double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value); /* multiview */ @@ -176,6 +194,20 @@ void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height); int BKE_scene_multiview_num_videos_get(const struct RenderData *rd); +/* depsgraph */ +void BKE_scene_allocate_depsgraph_hash(struct Scene *scene); +void BKE_scene_ensure_depsgraph_hash(struct Scene *scene); +void BKE_scene_free_depsgraph_hash(struct Scene *scene); + +struct Depsgraph *BKE_scene_get_depsgraph(struct Scene *scene, struct ViewLayer *view_layer, bool allocate); + +void BKE_scene_transform_orientation_remove( + struct Scene *scene, struct TransformOrientation *orientation); +struct TransformOrientation *BKE_scene_transform_orientation_find( + const struct Scene *scene, const int index); +int BKE_scene_transform_orientation_get_index( + const struct Scene *scene, const struct TransformOrientation *orientation); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index b33b9e455f1..0d766e83299 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -41,18 +41,25 @@ struct Menu; struct Panel; struct Scene; struct ScrArea; +struct ScrVert; struct SpaceType; +struct TransformOrientation; struct View3D; +struct View3DShading; struct bContext; struct bContextDataResult; struct bScreen; struct uiLayout; struct uiList; struct wmKeyConfig; +struct wmGizmoMap; struct wmNotifier; struct wmWindow; struct wmWindowManager; +struct WorkSpace; struct GPUFXSettings; +struct wmMsgBus; +struct ScrAreaMap; #include "BLI_compiler_attrs.h" @@ -71,8 +78,9 @@ typedef struct SpaceType { int spaceid; /* unique space identifier */ int iconid; /* icon lookup for menus */ - /* initial allocation, after this WM will call init() too */ - struct SpaceLink *(*new)(const struct bContext *C); + /* Initial allocation, after this WM will call init() too. Some editors need + * area and scene data (e.g. frame range) to set their initial scrolling. */ + struct SpaceLink *(*new)(const struct ScrArea *sa, const struct Scene *scene); /* not free spacelink itself */ void (*free)(struct SpaceLink *sl); @@ -81,7 +89,8 @@ typedef struct SpaceType { /* exit is called when the area is hidden or removed */ void (*exit)(struct wmWindowManager *wm, struct ScrArea *sa); /* Listeners can react to bContext changes */ - void (*listener)(struct bScreen *sc, struct ScrArea *sa, struct wmNotifier *wmn); + void (*listener)(struct wmWindow *win, struct ScrArea *sa, + struct wmNotifier *wmn, struct Scene *scene); /* refresh context, called after filereads, ED_area_tag_refresh() */ void (*refresh)(const struct bContext *C, struct ScrArea *sa); @@ -96,18 +105,22 @@ typedef struct SpaceType { /* on startup, define dropboxes for spacetype+regions */ void (*dropboxes)(void); + /* initialize gizmo-map-types and gizmo-group-types with the region */ + void (*gizmos)(void); + /* return context data */ int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result); /* Used when we want to replace an ID by another (or NULL). */ void (*id_remap)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id); + int (*space_subtype_get)(struct ScrArea *sa); + void (*space_subtype_set)(struct ScrArea *sa, int value); + void (*space_subtype_item_extend)(struct bContext *C, EnumPropertyItem **item, int *totitem); + /* region type definitions */ ListBase regiontypes; - /* tool shelf definitions */ - ListBase toolshelf; - /* read and write... */ /* default keymaps to add */ @@ -120,8 +133,7 @@ typedef struct SpaceType { typedef struct ARegionType { struct ARegionType *next, *prev; - /* unique identifier within this space, defines RGN_TYPE_xxxx */ - int regionid; + int regionid; /* unique identifier within this space, defines RGN_TYPE_xxxx */ /* add handlers, stuff you only do once or on area/region type/size changes */ void (*init)(struct wmWindowManager *wm, struct ARegion *ar); @@ -129,10 +141,21 @@ typedef struct ARegionType { void (*exit)(struct wmWindowManager *wm, struct ARegion *ar); /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct ARegion *ar); + /* optional, compute button layout before drawing for dynamic size */ + void (*layout)(const struct bContext *C, struct ARegion *ar); + /* snap the size of the region (can be NULL for no snapping). */ + int (*snap_size)(const struct ARegion *ar, int size, int axis); /* contextual changes should be handled here */ - void (*listener)(struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, struct wmNotifier *wmn); + void (*listener)(struct wmWindow *win, struct ScrArea *sa, struct ARegion *ar, + struct wmNotifier *wmn, const struct Scene *scene); + /* Optional callback to generate subscriptions. */ + void (*message_subscribe)( + const struct bContext *C, + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus); - void (*free)(struct ARegion *ar); + void (*free)(struct ARegion *); /* split region, copy data optionally */ void *(*duplicate)(void *poin); @@ -179,8 +202,12 @@ typedef struct PanelType { char translation_context[BKE_ST_MAXNAME]; char context[BKE_ST_MAXNAME]; /* for buttons window */ char category[BKE_ST_MAXNAME]; /* for category tabs */ - int space_type; - int region_type; + char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */ + char parent_id[BKE_ST_MAXNAME]; /* parent idname for subpanels */ + short space_type; + short region_type; + /* For popovers, 0 for default. */ + int ui_units_x; int flag; @@ -188,9 +215,15 @@ typedef struct PanelType { bool (*poll)(const struct bContext *C, struct PanelType *pt); /* draw header (optional) */ void (*draw_header)(const struct bContext *C, struct Panel *pa); + /* draw header preset (optional) */ + void (*draw_header_preset)(const struct bContext *C, struct Panel *pa); /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct Panel *pa); + /* sub panels */ + struct PanelType *parent; + ListBase children; + /* RNA integration */ ExtensionRNA ext; } PanelType; @@ -205,7 +238,7 @@ typedef void (*uiListDrawItemFunc)( /* Draw the filtering part of an uiList */ typedef void (*uiListDrawFilterFunc)( - struct uiList *ui_list, struct bContext *C, struct uiLayout *layout); + struct uiList *ui_list, struct bContext *C, struct uiLayout *layout, bool reverse); /* Filter items of an uiList */ typedef void (*uiListFilterItemsFunc)( @@ -231,7 +264,9 @@ typedef struct HeaderType { char idname[BKE_ST_MAXNAME]; /* unique name */ int space_type; + int region_type; + bool (*poll)(const struct bContext *C, struct HeaderType *ht); /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct Header *header); @@ -253,6 +288,7 @@ typedef struct MenuType { char idname[BKE_ST_MAXNAME]; /* unique name */ char label[BKE_ST_MAXNAME]; /* for button text */ char translation_context[BKE_ST_MAXNAME]; + char owner_id[BKE_ST_MAXNAME]; /* optional, see: #wmOwnerID */ const char *description; /* verify if the menu should draw or not */ @@ -290,35 +326,42 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID /* area/regions */ struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar); +void BKE_area_region_panels_free(struct ListBase *panels); void BKE_screen_area_free(struct ScrArea *sa); +/* Gizmo-maps of a region need to be freed with the region. Uses callback to avoid low-level call. */ +void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *)); +void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *)); struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa); struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y); struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min); +struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap, const int spacetype, int x, int y); struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y); -unsigned int BKE_screen_view3d_layer_active_ex( - const struct View3D *v3d, const struct Scene *scene, bool use_localvd) ATTR_NONNULL(2); -unsigned int BKE_screen_view3d_layer_active( - const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2); - -unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void BKE_screen_gizmo_tag_refresh(struct bScreen *sc); void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene); -void BKE_screen_view3d_scene_sync(struct bScreen *sc); -void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene); -void BKE_screen_view3d_twmode_remove(struct View3D *v3d, const int i); -void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, struct Scene *scene, const int i); -void BKE_screen_gpu_fx_validate(struct GPUFXSettings *fx_settings); +void BKE_screen_view3d_scene_sync(struct bScreen *sc, struct Scene *scene); +bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* zoom factor conversion */ float BKE_screen_view3d_zoom_to_fac(float camzoom); float BKE_screen_view3d_zoom_from_fac(float zoomfac); +void BKE_screen_view3d_shading_init(struct View3DShading *shading); + /* screen */ void BKE_screen_free(struct bScreen *sc); -unsigned int BKE_screen_visible_layers(struct bScreen *screen, struct Scene *scene); +void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL(); + +struct ScrEdge *BKE_screen_find_edge(struct bScreen *sc, struct ScrVert *v1, struct ScrVert *v2); +void BKE_screen_sort_scrvert(struct ScrVert **v1, struct ScrVert **v2); +void BKE_screen_remove_double_scrverts(struct bScreen *sc); +void BKE_screen_remove_double_scredges(struct bScreen *sc); +void BKE_screen_remove_unused_scredges(struct bScreen *sc); +void BKE_screen_remove_unused_scrverts(struct bScreen *sc); -#endif /* __BKE_SCREEN_H__ */ +#endif diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index c408597de32..00fd4ded8c6 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -31,7 +31,7 @@ */ struct bContext; -struct EvaluationContext; +struct Depsgraph; struct StripColorBalance; struct Editing; struct GSet; @@ -40,6 +40,7 @@ struct GPUFX; struct ImBuf; struct Main; struct Mask; +struct RenderEngineType; struct Scene; struct Sequence; struct SequenceModifierData; @@ -92,12 +93,13 @@ void BKE_sequence_iterator_end(SeqIterator *iter); } typedef struct SeqRenderData { - struct EvaluationContext *eval_ctx; struct Main *bmain; + struct Depsgraph *depsgraph; struct Scene *scene; int rectx; int recty; int preview_render_size; + int for_render; int motion_blur_samples; float motion_blur_shutter; bool skip_cache; @@ -112,8 +114,9 @@ typedef struct SeqRenderData { } SeqRenderData; void BKE_sequencer_new_render_data( - struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *scene, + struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, int rectx, int recty, int preview_render_size, + int for_render, SeqRenderData *r_context); int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b); @@ -249,7 +252,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra); void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change); bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra); -void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue); +void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue); void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress); void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop); @@ -434,11 +437,12 @@ enum { }; typedef struct ImBuf *(*SequencerDrawView)( - struct Main *bmain, struct Scene *scene, + struct Depsgraph *depsgraph, struct Scene *scene, + int drawtype, struct Object *camera, int width, int height, - unsigned int flag, unsigned int draw_flags, int drawtype, int alpha_mode, + unsigned int flag, unsigned int draw_flags, int alpha_mode, int samples, const char *viewname, - struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]); + struct GPUOffScreen *ofs, char err_out[256]); extern SequencerDrawView sequencer_view3d_cb; /* copy/paste */ diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h new file mode 100644 index 00000000000..3306d8256e8 --- /dev/null +++ b/source/blender/blenkernel/BKE_shader_fx.h @@ -0,0 +1,180 @@ +/* + * ***** 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: all of this file. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_SHADER_FX_H__ +#define __BKE_SHADER_FX_H__ + +/** \file BKE_shader_fx.h + * \ingroup bke + */ + +#include "DNA_shader_fx_types.h" /* needed for all enum typdefs */ +#include "BLI_compiler_attrs.h" +#include "BKE_customdata.h" + +struct ID; +struct Depsgraph; +struct DerivedMesh; +struct Mesh; +struct Object; +struct Scene; +struct ViewLayer; +struct ListBase; +struct bArmature; +struct Main; +struct ShaderFxData; +struct DepsNodeHandle; +struct bGPDlayer; +struct bGPDframe; +struct bGPDstroke; +struct ModifierUpdateDepsgraphContext; + +#define SHADER_FX_ACTIVE(_fx, _is_render) (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \ + ((_fx->mode & eShaderFxMode_Render) && (_is_render == true))) +#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit)) + +typedef enum { + /* Should not be used, only for None type */ + eShaderFxType_NoneType, + + /* grease pencil effects */ + eShaderFxType_GpencilType, +} ShaderFxTypeType; + +typedef enum { + eShaderFxTypeFlag_SupportsEditmode = (1 << 0), + + /* For effects that support editmode this determines if the + * effect should be enabled by default in editmode. + */ + eShaderFxTypeFlag_EnableInEditmode = (1 << 2), + + /* max one per type */ + eShaderFxTypeFlag_Single = (1 << 4), + + /* can't be added manually by user */ + eShaderFxTypeFlag_NoUserAdd = (1 << 5), +} ShaderFxTypeFlag; + +/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */ +typedef void(*ShaderFxObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag); +typedef void(*ShaderFxIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag); +typedef void(*ShaderFxTexWalkFunc)(void *userData, struct Object *ob, struct ShaderFxData *fx, const char *propname); + +typedef struct ShaderFxTypeInfo { + /* The user visible name for this effect */ + char name[32]; + + /* The DNA struct name for the effect data type, used to + * write the DNA data out. + */ + char struct_name[32]; + + /* The size of the effect data type, used by allocation. */ + int struct_size; + + ShaderFxTypeType type; + ShaderFxTypeFlag flags; + + /* Copy instance data for this effect type. Should copy all user + * level settings to the target effect. + */ + void(*copyData)(const struct ShaderFxData *fx, struct ShaderFxData *target); + + /* Initialize new instance data for this effect type, this function + * should set effect variables to their default values. + * + * This function is optional. + */ + void (*initData)(struct ShaderFxData *fx); + + /* Free internal effect data variables, this function should + * not free the fx variable itself. + * + * This function is optional. + */ + void (*freeData)(struct ShaderFxData *fx); + + /* Return a boolean value indicating if this effect is able to be + * calculated based on the effect data. This is *not* regarding the + * fx->flag, that is tested by the system, this is just if the data + * validates (for example, a lattice will return false if the lattice + * object is not defined). + * + * This function is optional (assumes never disabled if not present). + */ + bool (*isDisabled)(struct ShaderFxData *fx, int userRenderParams); + + /* Add the appropriate relations to the dependency graph. + * + * This function is optional. + */ + void (*updateDepsgraph)(struct ShaderFxData *fx, + const struct ModifierUpdateDepsgraphContext *ctx); + + /* Should return true if the effect needs to be recalculated on time + * changes. + * + * This function is optional (assumes false if not present). + */ + bool (*dependsOnTime)(struct ShaderFxData *fx); + + + /* Should call the given walk function on with a pointer to each Object + * pointer that the effect data stores. This is used for linking on file + * load and for unlinking objects or forwarding object references. + * + * This function is optional. + */ + void (*foreachObjectLink)(struct ShaderFxData *fx, struct Object *ob, + ShaderFxObjectWalkFunc walk, void *userData); + + /* Should call the given walk function with a pointer to each ID + * pointer (i.e. each datablock pointer) that the effect data + * stores. This is used for linking on file load and for + * unlinking datablocks or forwarding datablock references. + * + * This function is optional. If it is not present, foreachObjectLink + * will be used. + */ + void (*foreachIDLink)(struct ShaderFxData *fx, struct Object *ob, + ShaderFxIDWalkFunc walk, void *userData); +} ShaderFxTypeInfo; + +/* Initialize global data (type info and some common global storages). */ +void BKE_shaderfx_init(void); + +const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type); +struct ShaderFxData *BKE_shaderfx_new(int type); +void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag); +void BKE_shaderfx_free(struct ShaderFxData *fx); +bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx); +bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx); +struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type); +struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name); +void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst); +void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target); +void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag); +void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData); + +bool BKE_shaderfx_has_gpencil(struct Object *ob); + +#endif /* __BKE_SHADER_FX_H__ */ diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 2dd42a9da1f..caba7a6f284 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -33,6 +33,7 @@ /* Shrinkwrap stuff */ #include "BKE_bvhutils.h" +#include "BLI_bitmap.h" /* * Shrinkwrap is composed by a set of functions and options that define the type of shrink. @@ -47,37 +48,64 @@ */ struct Object; -struct DerivedMesh; +struct Mesh; struct MVert; struct MDeformVert; +struct ModifierEvalContext; struct ShrinkwrapModifierData; -struct MDeformVert; struct BVHTree; struct SpaceTransform; +/* Information about boundary edges in the mesh. */ +typedef struct ShrinkwrapBoundaryVertData { + /* Average direction of edges that meet here. */ + float direction[3]; + + /* Closest vector to direction that is orthogonal to vertex normal. */ + float normal_plane[3]; +} ShrinkwrapBoundaryVertData; + +typedef struct ShrinkwrapBoundaryData { + /* True if the edge belongs to exactly one face. */ + const BLI_bitmap *edge_is_boundary; + /* True if the looptri has any boundary edges. */ + const BLI_bitmap *looptri_has_boundary; + + /* Mapping from vertex index to boundary vertex index, or -1. + * Used for compact storage of data about boundary vertices. */ + const int *vert_boundary_id; + unsigned int num_boundary_verts; + + /* Direction data about boundary vertices. */ + const ShrinkwrapBoundaryVertData *boundary_verts; +} ShrinkwrapBoundaryData; -typedef struct ShrinkwrapCalcData { - ShrinkwrapModifierData *smd; //shrinkwrap modifier data +void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh); +void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh); - struct Object *ob; //object we are applying shrinkwrap to +/* Information about a mesh and BVH tree. */ +typedef struct ShrinkwrapTreeData { + Mesh *mesh; - struct MVert *vert; //Array of verts being projected (to fetch normals or other data) - float (*vertexCos)[3]; //vertexs being shrinkwraped - int numVerts; + BVHTree *bvh; + BVHTreeFromMesh treeData; - struct MDeformVert *dvert; //Pointer to mdeform array - int vgroup; //Vertex group num - bool invert_vgroup; /* invert vertex group influence */ + float (*clnors)[3]; + ShrinkwrapBoundaryData *boundary; +} ShrinkwrapTreeData; - struct DerivedMesh *target; //mesh we are shrinking to - struct SpaceTransform local2target; //transform to move between local and target space +/* Checks if the modifier needs target normals with these settings. */ +bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode); - float keepDist; //Distance to keep above target surface (units are in local space) +/* Initializes the mesh data structure from the given mesh and settings. */ +bool BKE_shrinkwrap_init_tree(struct ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals); -} ShrinkwrapCalcData; +/* Frees the tree data if necessary. */ +void BKE_shrinkwrap_free_tree(struct ShrinkwrapTreeData *data); -void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, - float (*vertexCos)[3], int numVerts, bool for_render); +/* Implementation of the Shrinkwrap modifier */ +void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Scene *scene, struct Object *ob, struct Mesh *mesh, + float (*vertexCos)[3], int numVerts); /* * This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is: @@ -91,8 +119,22 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object */ bool BKE_shrinkwrap_project_normal( char options, const float vert[3], const float dir[3], const float ray_radius, - const struct SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, - BVHTree_RayCastCallback callback, void *userdata); + const struct SpaceTransform *transf, struct ShrinkwrapTreeData *tree, BVHTreeRayHit *hit); + +/* Maps the point to the nearest surface, either by simple nearest, or by target normal projection. */ +void BKE_shrinkwrap_find_nearest_surface( + struct ShrinkwrapTreeData *tree, struct BVHTreeNearest *nearest, float co[3], int type); + +/* Computes a smooth normal of the target (if applicable) at the hit location. */ +void BKE_shrinkwrap_compute_smooth_normal( + const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform, + int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3]); + +/* Apply the shrink to surface modes to the given original coordinates and nearest point. */ +void BKE_shrinkwrap_snap_point_to_surface( + const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform, + int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist, + const float point_co[3], float r_point_co[3]); /* * NULL initializers to local data diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h deleted file mode 100644 index 9b9c125fbe6..00000000000 --- a/source/blender/blenkernel/BKE_sketch.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * ***** 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. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef __BKE_SKETCH_H__ -#define __BKE_SKETCH_H__ - -/** \file BKE_sketch.h - * \ingroup bke - */ - -typedef enum SK_PType { - PT_CONTINUOUS, - PT_EXACT, -} SK_PType; - -typedef enum SK_PMode { - PT_SNAP, - PT_PROJECT, -} SK_PMode; - -typedef struct SK_Point { - float p[3]; - short p2d[2]; - float no[3]; - float size; - SK_PType type; - SK_PMode mode; -} SK_Point; - -typedef struct SK_Stroke { - struct SK_Stroke *next, *prev; - - SK_Point *points; - int nb_points; - int buf_size; - int selected; -} SK_Stroke; - -#define SK_OVERDRAW_LIMIT 5 - -typedef struct SK_Overdraw { - SK_Stroke *target; - int start, end; - int count; -} SK_Overdraw; - -#define SK_Stroke_BUFFER_INIT_SIZE 20 - -typedef struct SK_DrawData { - int mval[2]; - int previous_mval[2]; - SK_PType type; -} SK_DrawData; - -typedef struct SK_Intersection { - struct SK_Intersection *next, *prev; - SK_Stroke *stroke; - int before; - int after; - int gesture_index; - float p[3]; - float lambda; /* used for sorting intersection points */ -} SK_Intersection; - -typedef struct SK_Sketch { - ListBase strokes; - SK_Stroke *active_stroke; - SK_Stroke *gesture; - SK_Point next_point; - SK_Overdraw over; -} SK_Sketch; - - -typedef struct SK_Gesture { - SK_Stroke *stk; - SK_Stroke *segments; - - ListBase intersections; - ListBase self_intersections; - - int nb_self_intersections; - int nb_intersections; - int nb_segments; -} SK_Gesture; - - -/************************************************/ - -void freeSketch(SK_Sketch *sketch); -SK_Sketch *createSketch(void); - -void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk); - -void sk_freeStroke(SK_Stroke *stk); -SK_Stroke *sk_createStroke(void); - -SK_Point *sk_lastStrokePoint(SK_Stroke *stk); - -void sk_allocStrokeBuffer(SK_Stroke *stk); -void sk_shrinkStrokeBuffer(SK_Stroke *stk); -void sk_growStrokeBuffer(SK_Stroke *stk); -void sk_growStrokeBufferN(SK_Stroke *stk, int n); - -void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n); -void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n); -void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt); -void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end); - -void sk_trimStroke(SK_Stroke *stk, int start, int end); -void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]); -void sk_polygonizeStroke(SK_Stroke *stk, int start, int end); -void sk_flattenStroke(SK_Stroke *stk, int start, int end); -void sk_reverseStroke(SK_Stroke *stk); - -void sk_filterLastContinuousStroke(SK_Stroke *stk); -void sk_filterStroke(SK_Stroke *stk, int start, int end); - -void sk_initPoint(SK_Point *pt, SK_DrawData *dd, const float no[3]); -void sk_copyPoint(SK_Point *dst, SK_Point *src); - -int sk_stroke_filtermval(SK_DrawData *dd); -void sk_endContinuousStroke(SK_Stroke *stk); - -void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk); - -void sk_initDrawData(SK_DrawData *dd, const int mval[2]); - -void sk_deleteSelectedStrokes(SK_Sketch *sketch); -void sk_selectAllSketch(SK_Sketch *sketch, int mode); - -#endif diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h index a54d50cb154..deee85c02d4 100644 --- a/source/blender/blenkernel/BKE_smoke.h +++ b/source/blender/blenkernel/BKE_smoke.h @@ -35,7 +35,10 @@ typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); -struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm); +struct Mesh *smokeModifier_do( + struct SmokeModifierData *smd, struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, struct Mesh *me); void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old); void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old); @@ -43,7 +46,7 @@ void smokeModifier_free(struct SmokeModifierData *smd); void smokeModifier_reset(struct SmokeModifierData *smd); void smokeModifier_reset_turbulence(struct SmokeModifierData *smd); void smokeModifier_createType(struct SmokeModifierData *smd); -void smokeModifier_copy(const SmokeModifierData *smd, struct SmokeModifierData *tsmd); +void smokeModifier_copy(const SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag); float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]); int smoke_get_data_flags(struct SmokeDomainSettings *sds); diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h index 5e8ea89c0f4..b173c995727 100644 --- a/source/blender/blenkernel/BKE_softbody.h +++ b/source/blender/blenkernel/BKE_softbody.h @@ -31,6 +31,7 @@ * \ingroup bke */ +struct Depsgraph; struct Object; struct Scene; struct SoftBody; @@ -53,13 +54,14 @@ typedef struct BodyPoint { extern struct SoftBody *sbNew(struct Scene *scene); /* frees internal data and softbody itself */ -extern void sbFree(struct SoftBody *sb); +extern void sbFree(struct Object *ob); /* frees simulation data to reset simulation */ extern void sbFreeSimulation(struct SoftBody *sb); /* do one simul step, reading and writing vertex locs from given array */ -extern void sbObjectStep(struct Scene *scene, struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts); +extern void sbObjectStep(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, + float framnr, float (*vertexCos)[3], int numVerts); /* makes totally fresh start situation, resets time */ extern void sbObjectToSoftbody(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 6f8274fabc8..98fb4f47339 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -35,8 +35,8 @@ #define SOUND_WAVE_SAMPLES_PER_SECOND 250 -#ifdef WITH_SYSTEM_AUDASPACE -# include AUD_DEVICE_H +#if defined(WITH_AUDASPACE) +# include <AUD_Device.h> #endif struct bSound; @@ -84,7 +84,7 @@ void BKE_sound_copy_data(struct Main *bmain, struct bSound *sound_dst, const str void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local); -#if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE) +#if defined(WITH_AUDASPACE) AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume); #endif @@ -149,6 +149,4 @@ float BKE_sound_get_length(struct bSound *sound); char **BKE_sound_get_device_names(void); -bool BKE_sound_is_jack_supported(void); - #endif /* __BKE_SOUND_H__ */ diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h new file mode 100644 index 00000000000..4a7f29d7190 --- /dev/null +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -0,0 +1,156 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006-2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_STUDIOLIGHT_H__ +#define __BKE_STUDIOLIGHT_H__ + +/** \file BKE_studiolight.h + * \ingroup bke + * + * Studio lighting for the 3dview + */ + +#include "BKE_context.h" + +#include "BLI_sys_types.h" + +#include "DNA_space_types.h" + +#include "IMB_imbuf_types.h" + +/* + * These defines are the indexes in the StudioLight.diffuse_light + * X_POS means the light that is traveling towards the positive X + * So Light direction. + */ +#define STUDIOLIGHT_X_POS 0 +#define STUDIOLIGHT_X_NEG 1 +#define STUDIOLIGHT_Y_POS 2 +#define STUDIOLIGHT_Y_NEG 3 +#define STUDIOLIGHT_Z_POS 4 +#define STUDIOLIGHT_Z_NEG 5 + +#define STUDIOLIGHT_ICON_ID_TYPE_RADIANCE (1 << 0) +#define STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE (1 << 1) +#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP (1 << 2) +#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED (1 << 3) + +#define STUDIOLIGHT_ICON_SIZE 96 + +#define STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL 2 +#define STUDIOLIGHT_SPHERICAL_HARMONICS_MAX_COMPONENTS 18 + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 0 +# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 1 +#endif + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 1 +# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 4 +#endif + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 2 +# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 9 +# define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN 10.0f +#endif + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 4 +# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 18 +#endif +struct GPUTexture; +struct StudioLight; + +/* StudioLight.flag */ +enum StudioLightFlag { + STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED = (1 << 0), + STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED = (1 << 1), + STUDIOLIGHT_INTERNAL = (1 << 2), + STUDIOLIGHT_EXTERNAL_FILE = (1 << 3), + STUDIOLIGHT_USER_DEFINED = (1 << 12), + STUDIOLIGHT_ORIENTATION_CAMERA = (1 << 4), + STUDIOLIGHT_ORIENTATION_WORLD = (1 << 5), + STUDIOLIGHT_ORIENTATION_VIEWNORMAL = (1 << 6), + STUDIOLIGHT_EXTERNAL_IMAGE_LOADED = (1 << 7), + STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED = (1 << 8), + STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE = (1 << 9), + STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 10), + STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11), + STUDIOLIGHT_UI_EXPANDED = (1 << 13), +}; + +#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE) +#define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_VIEWNORMAL) +#define STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE (STUDIOLIGHT_ORIENTATION_WORLD) +#define STUDIOLIGHT_ORIENTATIONS_SOLID (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD) + +typedef void StudioLightFreeFunction(struct StudioLight *, void *data); + +typedef struct StudioLight { + struct StudioLight *next, *prev; + + int index; + int flag; + char name[FILE_MAXFILE]; + char path[FILE_MAX]; + char *path_irr_cache; + char *path_sh_cache; + int icon_id_irradiance; + int icon_id_radiance; + int icon_id_matcap; + int icon_id_matcap_flipped; + float spherical_harmonics_coefs[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS][3]; + float light_direction[3]; + ImBuf *equirectangular_radiance_buffer; + ImBuf *equirectangular_irradiance_buffer; + ImBuf *radiance_cubemap_buffers[6]; + struct GPUTexture *equirectangular_radiance_gputexture; + struct GPUTexture *equirectangular_irradiance_gputexture; + float *gpu_matcap_3components; /* 3 channel buffer for GPU_R11F_G11F_B10F */ + + /* + * Free function to clean up the running icons previews (wmJob) the usage is in + * interface_icons. Please be aware that this was build to handle only one free function + * that cleans up all icons. just to keep the code simple. + */ + StudioLightFreeFunction *free_function; + void *free_function_data; +} StudioLight; + +void BKE_studiolight_init(void); +void BKE_studiolight_free(void); +struct StudioLight *BKE_studiolight_find(const char *name, int flag); +struct StudioLight *BKE_studiolight_findindex(int index, int flag); +struct StudioLight *BKE_studiolight_find_first(int flag); +void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type); +struct ListBase *BKE_studiolight_listbase(void); +void BKE_studiolight_ensure_flag(StudioLight *sl, int flag); +void BKE_studiolight_refresh(void); +StudioLight *BKE_studiolight_new(const char *path, int orientation); +void BKE_studiolight_remove(StudioLight *sl); +void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data); +void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id); + +#endif /* __BKE_STUDIOLIGHT_H__ */ diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h new file mode 100644 index 00000000000..0a09d3528b4 --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -0,0 +1,237 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_subdiv.h + * \ingroup bke + * \since July 2018 + * \author Sergey Sharybin + */ + +#ifndef __BKE_SUBDIV_H__ +#define __BKE_SUBDIV_H__ + +#include "BLI_compiler_compat.h" +#include "BLI_sys_types.h" + +struct Mesh; +struct MultiresModifierData; +struct Object; +struct OpenSubdiv_Converter; +struct OpenSubdiv_Evaluator; +struct OpenSubdiv_TopologyRefiner; +struct Subdiv; +struct SubdivToMeshSettings; + +typedef enum eSubdivVtxBoundaryInterpolation { + /* Do not interpolate boundaries. */ + SUBDIV_VTX_BOUNDARY_NONE, + /* Sharpen edges. */ + SUBDIV_VTX_BOUNDARY_EDGE_ONLY, + /* sharpen edges and corners, */ + SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER, +} eSubdivVtxBoundaryInterpolation; + +typedef enum eSubdivFVarLinearInterpolation { + SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE, + SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY, + SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS, + SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE, + SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES, + SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL, +} eSubdivFVarLinearInterpolation; + +typedef struct SubdivSettings { + bool is_simple; + bool is_adaptive; + int level; + eSubdivVtxBoundaryInterpolation vtx_boundary_interpolation; + eSubdivFVarLinearInterpolation fvar_linear_interpolation; +} SubdivSettings; + +/* NOTE: Order of enumerators MUST match order of values in SubdivStats. */ +typedef enum eSubdivStatsValue { + SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME = 0, + SUBDIV_STATS_SUBDIV_TO_MESH, + SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY, + SUBDIV_STATS_EVALUATOR_CREATE, + SUBDIV_STATS_EVALUATOR_REFINE, + SUBDIV_STATS_SUBDIV_TO_CCG, + SUBDIV_STATS_SUBDIV_TO_CCG_ELEMENTS, + + NUM_SUBDIV_STATS_VALUES, +} eSubdivStatsValue; + +typedef struct SubdivStats { + union { + struct { + /* Time spend on creating topology refiner, which includes time + * spend on conversion from Blender data to OpenSubdiv data, and + * time spend on topology orientation on OpenSubdiv C-API side. + */ + double topology_refiner_creation_time; + /* Total time spent in BKE_subdiv_to_mesh(). */ + double subdiv_to_mesh_time; + /* Geometry (MVert and co) creation time during SUBDIV_TYO_MESH. */ + double subdiv_to_mesh_geometry_time; + /* Time spent on evaluator creation from topology refiner. */ + double evaluator_creation_time; + /* Time spent on evaluator->refine(). */ + double evaluator_refine_time; + /* Total time spent on whole CCG creation. */ + double subdiv_to_ccg_time; + /* Time spent on CCG elements evaluation/initialization. */ + double subdiv_to_ccg_elements_time; + }; + double values_[NUM_SUBDIV_STATS_VALUES]; + }; + + /* Per-value timestamp on when corresponding BKE_subdiv_stats_begin() was + * called. + */ + double begin_timestamp_[NUM_SUBDIV_STATS_VALUES]; +} SubdivStats; + +/* Functor which evaluates dispalcement at a given (u, v) of given ptex face. */ +typedef struct SubdivDisplacement { + /* Return displacement which is to be added to the original coordinate. + * + * NOTE: This function is supposed to return "continuous" displacement for + * each pf PTex faces created for special (non-quad) polygon. This means, + * if displacement is stored on per-corner manner (like MDisps for multires) + * this is up the displacement implementation to average boundaries of the + * displacement grids if needed. + * + * Averaging of displacement for vertices created for over coarse vertices + * and edges is done by subdiv code. + */ + void (*eval_displacement)(struct SubdivDisplacement *displacement, + const int ptex_face_index, + const float u, const float v, + const float dPdu[3], const float dPdv[3], + float r_D[3]); + + /* Free the data, not the evaluator itself. */ + void (*free)(struct SubdivDisplacement *displacement); + + void *user_data; +} SubdivDisplacement; + +/* This structure contains everything needed to construct subdivided surface. + * It does not specify storage, memory layout or anything else. + * It is possible to create different storages (like, grid based CPU side + * buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same + * Subdiv structure. + */ +typedef struct Subdiv { + /* Settings this subdivision surface is created for. + * + * It is read-only after assignment in BKE_subdiv_new_from_FOO(). + */ + SubdivSettings settings; + /* Topology refiner includes all the glue logic to feed Blender side + * topology to OpenSubdiv. It can be shared by both evaluator and GL mesh + * drawer. + */ + struct OpenSubdiv_TopologyRefiner *topology_refiner; + /* CPU side evaluator. */ + struct OpenSubdiv_Evaluator *evaluator; + /* Optional displacement evaluator. */ + struct SubdivDisplacement *displacement_evaluator; + /* Statistics for debugging. */ + SubdivStats stats; + + /* Cached values, are not supposed to be accessed directly. */ + struct { + /* Indexed by base face index, element indicates total number of ptex + *faces created for preceding base faces. + */ + int *face_ptex_offset; + } cache_; +} Subdiv; + +/* ================================ HELPERS ================================= */ + +/* NOTE: uv_smooth is eSubsurfUVSmooth. */ +eSubdivFVarLinearInterpolation +BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth); + +/* =============================== STATISTICS =============================== */ + +void BKE_subdiv_stats_init(SubdivStats *stats); + +void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value); +void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value); + +void BKE_subdiv_stats_print(const SubdivStats *stats); + +/* ============================== CONSTRUCTION ============================== */ + +Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings, + struct OpenSubdiv_Converter *converter); + +Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings, + struct Mesh *mesh); + +void BKE_subdiv_free(Subdiv *subdiv); + +/* ============================ DISPLACEMENT API ============================ */ + +void BKE_subdiv_displacement_attach_from_multires( + Subdiv *subdiv, + const struct Mesh *mesh, + const struct MultiresModifierData *mmd); + +void BKE_subdiv_displacement_detach(Subdiv *subdiv); + +/* ============================ TOPOLOGY HELPERS ============================ */ + +int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv); + +/* ============================= VARIOUS HELPERS ============================ */ + +/* For a given (ptex_u, ptex_v) within a ptex face get corresponding + * (grid_u, grid_v) within a grid. + */ +BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv( + const float ptex_u, const float ptex_v, + float *r_grid_u, float *r_grid_v); + +/* For a given subdivision level (which is NOT refinement level) get size of + * CCG grid (number of grid points on a side). + */ +BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level); + +/* Simplified version of mdisp_rot_face_to_crn, only handles quad and + * works in normalized coordinates. + * + * NOTE: Output coordinates are in ptex coordinates. + */ +BLI_INLINE int BKE_subdiv_rotate_quad_to_corner( + const float u, const float v, + float *r_u, float *r_v); + +#endif /* __BKE_SUBDIV_H__ */ + +#include "intern/subdiv_inline.h" diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h new file mode 100644 index 00000000000..b2aaf6fc4cc --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -0,0 +1,249 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_subdiv_ccg.h + * \ingroup bke + * \since July 2018 + * \author Sergey Sharybin + */ + +#ifndef __BKE_SUBDIV_CCG_H__ +#define __BKE_SUBDIV_CCG_H__ + +#include "BKE_customdata.h" +#include "BLI_bitmap.h" +#include "BLI_sys_types.h" + +struct CCGElem; +struct CCGFace; +struct CCGKey; +struct DMFlagMat; +struct Mesh; +struct Subdiv; + +/* ============================================================================= + * Masks. + */ + +/* Functor which evaluates mask value at a given (u, v) of given ptex face. */ +typedef struct SubdivCCGMask { + float (*eval_mask)(struct SubdivCCGMask *mask, + const int ptex_face_index, + const float u, const float v); + + /* Free the data, not the evaluator itself. */ + void (*free)(struct SubdivCCGMask *mask); + + void *user_data; +} SubdivCCGMask; + +/* Return true if mesh has mask and evaluator can be used. */ +bool BKE_subdiv_ccg_mask_init_from_paint( + SubdivCCGMask *mask_evaluator, + const struct Mesh *mesh); + +/* ============================================================================= + * SubdivCCG. + */ + +typedef struct SubdivToCCGSettings { + /* Resolution at which regular ptex (created for quad polygon) are being + * evaluated. This defines how many vertices final mesh will have: every + * regular ptex has resolution^2 vertices. Special (irregular, or ptex + * created for a corner of non-quad polygon) will have resolution of + * `resolution - 1`. + */ + int resolution; + /* Denotes which extra layers to be added to CCG elements. */ + bool need_normal; + bool need_mask; +} SubdivToCCGSettings; + +/* This is actually a coarse face, which consists of multiple CCG grids. */ +typedef struct SubdivCCGFace { + /* Total number of grids in this face. + * + * This 1:1 corresponds to a number of corners (or loops) from a coarse + * face. + */ + int num_grids; + /* Index of first grid from this face in SubdivCCG->grids array. */ + int start_grid_index; +} SubdivCCGFace; + +/* Definition of an edge which is adjacent to at least one of the faces. */ +typedef struct SubdivCCGAdjacentEdge { + int num_adjacent_faces; + /* Indexed by adjacent face index. */ + SubdivCCGFace **faces; + /* Indexed by adjacent face index, then by point index on the edge. + * points to a grid element. + */ + struct CCGElem ***boundary_elements; +} SubdivCCGAdjacentEdge; + +/* Definition of a vertex which is adjacent to at least one of the faces. */ +typedef struct SubdivCCGAdjacentVertex { + int num_adjacent_faces; + /* Indexed by adjacent face index. */ + SubdivCCGFace **faces; + /* Indexed by adjacent face index, points to a grid element. + */ + struct CCGElem **corner_elements; +} SubdivCCGAdjacentVertex; + +/* Representation of subdivision surface which uses CCG grids. */ +typedef struct SubdivCCG { + /* This is a subdivision surface this CCG was created for. + * + * TODO(sergey): Make sure the whole descriptor is valid, including all the + * displacement attached to the surface. + */ + struct Subdiv *subdiv; + /* A level at which geometry was subdivided. This is what defines grid + * resolution. It is NOT the topology refinement level. + */ + int level; + /* Resolution of grid. All grids have matching resolution, and resolution + * is same as ptex created for non-quad polygons. + */ + int grid_size; + /* Grids represent limit surface, with displacement applied. Grids are + * corresponding to face-corners of coarse mesh, each grid has + * grid_size^2 elements. + */ + /* Indexed by a grid index, points to a grid data which is stored in + * grids_storage. + */ + struct CCGElem **grids; + /* Flat array of all grids' data. */ + unsigned char *grids_storage; + int num_grids; + /* Loose edges, each array element contains grid_size elements + * corresponding to vertices created by subdividing coarse edges. + */ + struct CCGElem **edges; + int num_edges; + /* Loose vertices. Every element corresponds to a loose vertex from a coarse + * mesh, every coarse loose vertex corresponds to a single sundivided + * element. + */ + struct CCGElem *vertices; + int num_vertices; + /* Denotes which layers present in the elements. + * + * Grids always has coordinates, followed by extra layers which are set to + * truth here. + */ + bool has_normal; + bool has_mask; + /* Offsets of corresponding data layers in the elements. */ + int normal_offset; + int mask_offset; + + /* Faces from which grids are emitted. */ + int num_faces; + SubdivCCGFace *faces; + /* Indexed by grid index, points to corresponding face from `faces`. */ + SubdivCCGFace **grid_faces; + + /* Edges which are adjacent to faces. + * Used for faster grid stitching, in the cost of extra memory. + */ + int num_adjacent_edges; + SubdivCCGAdjacentEdge *adjacent_edges; + + /* Vertices which are adjacent to faces + * Used for faster grid stitching, in the cost of extra memory. + */ + int num_adjacent_vertices; + SubdivCCGAdjacentVertex *adjacent_vertices; + + struct DMFlagMat *grid_flag_mats; + BLI_bitmap **grid_hidden; + + /* TODO(sergey): Consider adding some accessors to a "decoded" geometry, + * to make integration with draw manager and such easy. + */ + + /* TODO(sergey): Consider adding CD layers here, so we can draw final mesh + * from grids, and have UVs and such work. + */ + + /* Integration with sculpting. */ + /* TODO(sergey): Is this really best way to go? Kind of annoying to have + * such use-related flags in a more or less generic structure. + */ + struct { + /* Corresponds to MULTIRES_COORDS_MODIFIED. */ + bool coords; + /* Corresponds to MULTIRES_HIDDEN_MODIFIED. */ + bool hidden; + } dirty; +} SubdivCCG; + +/* Create real hi-res CCG from subdivision. + * + * NOTE: Subdiv is expected to be refined and ready for evaluation. + * NOTE: CCG becomes an owner of subdiv. + * + * TODO(sergey): Allow some user-counter or more explicit control over who owns + * the Subdiv. The goal should be to allow viewport GL Mesh and CCG to share + * same Subsurf without conflicts. + */ +struct SubdivCCG *BKE_subdiv_to_ccg( + struct Subdiv *subdiv, + const SubdivToCCGSettings *settings, + SubdivCCGMask *mask_evaluator); + +/* Destroy CCG representation of subdivision surface. */ +void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg); + +/* Helper function, creates Mesh structure which is properly setup to use + * grids. + */ +struct Mesh *BKE_subdiv_to_ccg_mesh( + struct Subdiv *subdiv, + const SubdivToCCGSettings *settings, + const struct Mesh *coarse_mesh); + +/* Create a key for accessing grid elements at a given level. */ +void BKE_subdiv_ccg_key( + struct CCGKey *key, const SubdivCCG *subdiv_ccg, int level); +void BKE_subdiv_ccg_key_top_level( + struct CCGKey *key, const SubdivCCG *subdiv_ccg); + +/* Recalculate all normals based on grid element coordinates. */ +void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg); + +/* Average grid coordinates and normals along the grid boundatries. */ +void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg); + +/* Similar to above, but only updates given faces. */ +void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG *subdiv_ccg, + struct CCGFace **effected_faces, + int num_effected_faces); + +#endif /* __BKE_SUBDIV_CCG_H__ */ diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h new file mode 100644 index 00000000000..0ea5c978e62 --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -0,0 +1,127 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_subdiv_eval.h + * \ingroup bke + * \since September 2018 + * \author Sergey Sharybin + */ + +#ifndef __BKE_SUBDIV_EVAL_H__ +#define __BKE_SUBDIV_EVAL_H__ + +#include "BLI_sys_types.h" + +struct Mesh; +struct Subdiv; + +/* Returns true if evaluator is ready for use. */ +bool BKE_subdiv_eval_begin(struct Subdiv *subdiv); +bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv, + const struct Mesh *mesh); + +/* Single point queries. */ + +void BKE_subdiv_eval_limit_point( + struct Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3]); +void BKE_subdiv_eval_limit_point_and_derivatives( + struct Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3], float r_dPdu[3], float r_dPdv[3]); +void BKE_subdiv_eval_limit_point_and_normal( + struct Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3], float r_N[3]); +void BKE_subdiv_eval_limit_point_and_short_normal( + struct Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3], short r_N[3]); + +void BKE_subdiv_eval_face_varying( + struct Subdiv *subdiv, + const int face_varying_channel, + const int ptex_face_index, + const float u, const float v, + float r_varying[2]); + +/* NOTE: Expects derivatives to be correct. + * + * TODO(sergey): This is currently used together with + * BKE_subdiv_eval_final_point() which cas easily evaluate derivatives. + * Would be nice to have dispalcement evaluation function which does not require + * knowing derivatives ahead of a time. + */ +void BKE_subdiv_eval_displacement( + struct Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + const float dPdu[3], const float dPdv[3], + float r_D[3]); + +void BKE_subdiv_eval_final_point( + struct Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3]); + +/* Patch queries at given resolution. + * + * Will evaluate patch at uniformly distributed (u, v) coordinates on a grid + * of given resolution, producing resolution^2 evaluation points. The order + * goes as u in rows, v in columns. + */ + +void BKE_subdiv_eval_limit_patch_resolution_point( + struct Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *buffer, const int offset, const int stride); +void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives( + struct Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *point_buffer, const int point_offset, const int point_stride, + void *du_buffer, const int du_offset, const int du_stride, + void *dv_buffer, const int dv_offset, const int dv_stride); +void BKE_subdiv_eval_limit_patch_resolution_point_and_normal( + struct Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *point_buffer, const int point_offset, const int point_stride, + void *normal_buffer, const int normal_offset, const int normal_stride); +void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal( + struct Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *point_buffer, const int point_offset, const int point_stride, + void *normal_buffer, const int normal_offset, const int normal_stride); + +#endif /* __BKE_SUBDIV_EVAL_H__ */ diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h new file mode 100644 index 00000000000..d4ef0ee3601 --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv_foreach.h @@ -0,0 +1,181 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_subdiv_foreach.h + * \ingroup bke + * \since September 2018 + * \author Sergey Sharybin + */ + +#ifndef __BKE_SUBDIV_FOREACH_H__ +#define __BKE_SUBDIV_FOREACH_H__ + +#include "BLI_sys_types.h" + +struct Mesh; +struct Subdiv; +struct SubdivForeachContext; +struct SubdivToMeshSettings; + +typedef bool (*SubdivForeachTopologyInformationCb)( + const struct SubdivForeachContext *context, + const int num_vertices, + const int num_edges, + const int num_loops, + const int num_polygons); + +typedef void (*SubdivForeachVertexFromCornerCb)( + const struct SubdivForeachContext *context, + void *tls, + const int ptex_face_index, + const float u, const float v, + const int coarse_vertex_index, + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index); + +typedef void (*SubdivForeachVertexFromEdgeCb)( + const struct SubdivForeachContext *context, + void *tls, + const int ptex_face_index, + const float u, const float v, + const int coarse_edge_index, + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index); + +typedef void (*SubdivForeachVertexInnerCb)( + const struct SubdivForeachContext *context, + void *tls, + const int ptex_face_index, + const float u, const float v, + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index); + +typedef void (*SubdivForeachEdgeCb)( + const struct SubdivForeachContext *context, + void *tls, + const int coarse_edge_index, + const int subdiv_edge_index, + const int subdiv_v1, const int subdiv_v2); + +typedef void (*SubdivForeachLoopCb)( + const struct SubdivForeachContext *context, + void *tls, + const int ptex_face_index, + const float u, const float v, + const int coarse_loop_index, + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_loop_index, + const int subdiv_vertex_index, const int subdiv_edge_index); + +typedef void (*SubdivForeachPolygonCb)( + const struct SubdivForeachContext *context, + void *tls, + const int coarse_poly_index, + const int subdiv_poly_index, + const int start_loop_index, const int num_loops); + +typedef void (*SubdivForeachLooseCb)( + const struct SubdivForeachContext *context, + void *tls, + const int coarse_vertex_index, + const int subdiv_vertex_index); + +typedef void (*SubdivForeachVertexOfLooseEdgeCb)( + const struct SubdivForeachContext *context, + void *tls, + const int coarse_edge_index, + const float u, + const int subdiv_vertex_index); + +typedef struct SubdivForeachContext { + /* Is called when topology information becomes available. + * Is only called once. + * + * NOTE: If this callback returns false, the foreach loop is aborted. + */ + SubdivForeachTopologyInformationCb topology_info; + /* These callbacks are called from every ptex which shares "emitting" + * vertex or edge. + */ + SubdivForeachVertexFromCornerCb vertex_every_corner; + SubdivForeachVertexFromEdgeCb vertex_every_edge; + /* Those callbacks are run once per subdivision vertex, ptex is undefined + * as in it will be whatever first ptex face happened to be tarversed in + * the multi-threaded environment ahd which shares "emitting" vertex or + * edge. + */ + SubdivForeachVertexFromCornerCb vertex_corner; + SubdivForeachVertexFromEdgeCb vertex_edge; + /* Called exactly once, always corresponds to a single ptex face. */ + SubdivForeachVertexInnerCb vertex_inner; + /* Called once for each loose vertex. One loose coarse vertexcorresponds + * to a single subdivision vertex. + */ + SubdivForeachLooseCb vertex_loose; + /* Called once per vertex created for loose edge. */ + SubdivForeachVertexOfLooseEdgeCb vertex_of_loose_edge; + /* NOTE: If subdivided edge does not come from coarse edge, ORIGINDEX_NONE + * will be passed as coarse_edge_index. + */ + SubdivForeachEdgeCb edge; + /* NOTE: If subdivided loop does not come from coarse loop, ORIGINDEX_NONE + * will be passed as coarse_loop_index. + */ + SubdivForeachLoopCb loop; + SubdivForeachPolygonCb poly; + + /* User-defined pointer, to allow callbacks know something about context the + * traversal is happening for, + */ + void *user_data; + + /* Initial value of TLS data. */ + void *user_data_tls; + /* Size of TLS data. */ + size_t user_data_tls_size; + /* Function to free TLS storage. */ + void (*user_data_tls_free)(void *tls); +} SubdivForeachContext; + +/* Invokes callbacks in the order and with values which corresponds to creation + * of final subdivided mesh. + * + * Returns truth if the whole topology was traversed, without any early exits. + * + * TODO(sergey): Need to either get rid of subdiv or of coarse_mesh. + * The main point here is th be abel to get base level topology, which can be + * done with either of those. Having both of them is kind of redundant. + */ +bool BKE_subdiv_foreach_subdiv_geometry( + struct Subdiv *subdiv, + const struct SubdivForeachContext *context, + const struct SubdivToMeshSettings *mesh_settings, + const struct Mesh *coarse_mesh); + +#endif /* __BKE_SUBDIV_FOREACH_H__ */ diff --git a/source/blender/blenkernel/BKE_subdiv_mesh.h b/source/blender/blenkernel/BKE_subdiv_mesh.h new file mode 100644 index 00000000000..f719527eed8 --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv_mesh.h @@ -0,0 +1,56 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_subdiv_mesh.h + * \ingroup bke + * \since September 2018 + * \author Sergey Sharybin + */ + +#ifndef __BKE_SUBDIV_MESH_H__ +#define __BKE_SUBDIV_MESH_H__ + +#include "BLI_sys_types.h" + +struct Mesh; +struct Subdiv; + +typedef struct SubdivToMeshSettings { + /* Resolution at which regular ptex (created for quad polygon) are being + * evaluated. This defines how many vertices final mesh will have: every + * regular ptex has resolution^2 vertices. Special (irregular, or ptex + * created for a corner of non-quad polygon) will have resolution of + * `resolution - 1`. + */ + int resolution; +} SubdivToMeshSettings; + +/* Create real hi-res mesh from subdivision, all geometry is "real". */ +struct Mesh *BKE_subdiv_to_mesh( + struct Subdiv *subdiv, + const SubdivToMeshSettings *settings, + const struct Mesh *coarse_mesh); + +#endif /* __BKE_SUBDIV)MESH_H__ */ diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index 96320415b16..6cb09ff8822 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -67,6 +67,7 @@ typedef enum { struct DerivedMesh *subsurf_make_derived_from_derived( struct DerivedMesh *dm, struct SubsurfModifierData *smd, + struct Scene *scene, float (*vertCos)[3], SubsurfFlags flags); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index b53af3cec53..e7a8fb1c4a9 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -112,10 +112,6 @@ bool txt_cursor_is_line_end(struct Text *text); int txt_calc_tab_left(struct TextLine *line, int ch); int txt_calc_tab_right(struct TextLine *line, int ch); -#if 0 -void txt_print_undo (struct Text *text); -#endif - /* utility functions, could be moved somewhere more generic but are python/text related */ int text_check_bracket(const char ch); bool text_check_delim(const char ch); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 7ffa22ac49b..228e17cd2ef 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -40,7 +40,6 @@ extern "C" { struct bNode; struct Brush; struct ColorBand; -struct EnvMap; struct FreestyleLineStyle; struct ImagePool; struct Lamp; @@ -53,7 +52,6 @@ struct PointDensity; struct Tex; struct TexMapping; struct TexResult; -struct VoxelData; struct World; /* in ColorBand struct */ @@ -76,27 +74,17 @@ struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot); // void autotexname(struct Tex *tex); struct Tex *give_current_object_texture(struct Object *ob); -struct Tex *give_current_material_texture(struct Material *ma); -struct Tex *give_current_lamp_texture(struct Lamp *la); struct Tex *give_current_linestyle_texture(struct FreestyleLineStyle *linestyle); -struct Tex *give_current_world_texture(struct World *world); struct Tex *give_current_brush_texture(struct Brush *br); struct Tex *give_current_particle_texture(struct ParticleSettings *part); -struct bNode *give_current_material_texture_node(struct Material *ma); - bool give_active_mtex(struct ID *id, struct MTex ***mtex_ar, short *act); void set_active_mtex(struct ID *id, short act); void set_current_brush_texture(struct Brush *br, struct Tex *tex); -void set_current_world_texture(struct World *wo, struct Tex *tex); -void set_current_material_texture(struct Material *ma, struct Tex *tex); -void set_current_lamp_texture(struct Lamp *la, struct Tex *tex); void set_current_linestyle_texture(struct FreestyleLineStyle *linestyle, struct Tex *tex); void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex); -bool has_current_material_texture(struct Material *ma); - struct TexMapping *BKE_texture_mapping_add(int type); void BKE_texture_mapping_default(struct TexMapping *texmap, int type); void BKE_texture_mapping_init(struct TexMapping *texmap); @@ -104,26 +92,12 @@ void BKE_texture_mapping_init(struct TexMapping *texmap); struct ColorMapping *BKE_texture_colormapping_add(void); void BKE_texture_colormapping_default(struct ColorMapping *colormap); -void BKE_texture_envmap_free_data(struct EnvMap *env); -void BKE_texture_envmap_free(struct EnvMap *env); -struct EnvMap *BKE_texture_envmap_add(void); -struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env, const int flag); - void BKE_texture_pointdensity_init_data(struct PointDensity *pd); void BKE_texture_pointdensity_free_data(struct PointDensity *pd); void BKE_texture_pointdensity_free(struct PointDensity *pd); struct PointDensity *BKE_texture_pointdensity_add(void); struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag); -void BKE_texture_voxeldata_free_data(struct VoxelData *vd); -void BKE_texture_voxeldata_free(struct VoxelData *vd); -struct VoxelData *BKE_texture_voxeldata_add(void); -struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd); - -void BKE_texture_ocean_free(struct OceanTex *ot); -struct OceanTex *BKE_texture_ocean_add(void); -struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot, const int flag); - bool BKE_texture_dependsOnTime(const struct Tex *texture); bool BKE_texture_is_image_user(const struct Tex *tex); diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index 13302caa09d..0c3b118d947 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -32,6 +32,7 @@ * \author Sergey Sharybin */ +struct Depsgraph; struct bGPDlayer; struct ImBuf; struct ListBase; @@ -61,7 +62,8 @@ struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *trac struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(struct MovieTracking *tracking); /* matrices for constraints and drawing */ -void BKE_tracking_get_camera_object_matrix(struct Scene *scene, struct Object *ob, float mat[4][4]); +void BKE_tracking_get_camera_object_matrix( + struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float mat[4][4]); void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking, struct MovieTrackingObject *object, int framenr, int winx, int winy, float mat[4][4]); diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h index 82a4659eec7..bb7fb006038 100644 --- a/source/blender/blenkernel/BKE_unit.h +++ b/source/blender/blenkernel/BKE_unit.h @@ -31,14 +31,23 @@ extern "C" { #endif +struct UnitSettings; + /* in all cases the value is assumed to be scaled by the user preference */ /* humanly readable representation of a value in units (used for button drawing) */ -size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad); +size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad); +size_t bUnit_AsString2(char *str, int len_max, double value, int prec, int type, const struct UnitSettings *settings, bool pad); /* replace units with values, used before python button evaluation */ bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type); +/* return true if the string contains any valid unit for the given type */ +bool bUnit_ContainsUnit(const char *str, int system, int type); + +/* if user does not specify a unit, multiply with this value */ +double bUnit_PreferredUnitScalar(const struct UnitSettings *settings, int type); + /* make string keyboard-friendly: 10µm --> 10um */ void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type); @@ -56,9 +65,11 @@ bool bUnit_IsValid(int system, int type); void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len); int bUnit_GetBaseUnit(const void *usys_pt); +int bUnit_GetBaseUnitOfType(int system, int type); const char *bUnit_GetName(const void *usys_pt, int index); const char *bUnit_GetNameDisplay(const void *usys_pt, int index); double bUnit_GetScaler(const void *usys_pt, int index); +bool bUnit_IsSuppressed(const void *usys_pt, int index); /* aligned with PropertyUnit */ enum { diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h new file mode 100644 index 00000000000..6902fb631e4 --- /dev/null +++ b/source/blender/blenkernel/BKE_workspace.h @@ -0,0 +1,110 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BKE_workspace.h + * \ingroup bke + */ + +#ifndef __BKE_WORKSPACE_H__ +#define __BKE_WORKSPACE_H__ + +#include "BLI_compiler_attrs.h" + +struct bScreen; +struct bToolRef; +struct Main; +struct Scene; +struct TransformOrientation; +struct ViewLayer; + +/* -------------------------------------------------------------------- */ +/* Create, delete, init */ + +struct WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name); +void BKE_workspace_free(struct WorkSpace *workspace); +void BKE_workspace_remove(struct Main *bmain, struct WorkSpace *workspace); + +struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain); +void BKE_workspace_instance_hook_free(const struct Main *bmain, struct WorkSpaceInstanceHook *hook); + +struct WorkSpaceLayout *BKE_workspace_layout_add( + struct Main *bmain, + struct WorkSpace *workspace, + struct bScreen *screen, + const char *name) ATTR_NONNULL(); +void BKE_workspace_layout_remove( + struct Main *bmain, + struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL(); + +void BKE_workspace_relations_free( + ListBase *relation_list); + + +/* -------------------------------------------------------------------- */ +/* General Utils */ + +struct WorkSpaceLayout *BKE_workspace_layout_find( + const struct WorkSpace *workspace, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +struct WorkSpaceLayout *BKE_workspace_layout_find_global( + const struct Main *bmain, const struct bScreen *screen, + struct WorkSpace **r_workspace) ATTR_NONNULL(1, 2); + +struct WorkSpaceLayout *BKE_workspace_layout_iter_circular( + const struct WorkSpace *workspace, struct WorkSpaceLayout *start, + bool (*callback)(const struct WorkSpaceLayout *layout, void *arg), + void *arg, const bool iter_backward); + +void BKE_workspace_tool_remove( + struct WorkSpace *workspace, struct bToolRef *tref) ATTR_NONNULL(1, 2); + +/* -------------------------------------------------------------------- */ +/* Getters/Setters */ + +#define GETTER_ATTRS ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT +#define SETTER_ATTRS ATTR_NONNULL(1) + +struct WorkSpace *BKE_workspace_active_get(struct WorkSpaceInstanceHook *hook) GETTER_ATTRS; +void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace) SETTER_ATTRS; +struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS; +void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook, struct WorkSpaceLayout *layout) SETTER_ATTRS; +struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS; +void BKE_workspace_active_screen_set( + struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct bScreen *screen) SETTER_ATTRS; + +struct ListBase *BKE_workspace_layouts_get(struct WorkSpace *workspace) GETTER_ATTRS; + +const char *BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS; +void BKE_workspace_layout_name_set( + struct WorkSpace *workspace, struct WorkSpaceLayout *layout, const char *new_name) ATTR_NONNULL(); +struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS; +void BKE_workspace_layout_screen_set(struct WorkSpaceLayout *layout, struct bScreen *screen) SETTER_ATTRS; + +struct WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get( + const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS; +void BKE_workspace_hook_layout_for_workspace_set( + struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL(); + +bool BKE_workspace_owner_id_check( + const struct WorkSpace *workspace, const char *owner_id) ATTR_NONNULL(); + +#undef GETTER_ATTRS +#undef SETTER_ATTRS + +#endif /* __BKE_WORKSPACE_H__ */ diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index b28bac08727..eb0548c682e 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -33,6 +33,7 @@ * \author nzc */ +struct Depsgraph; struct Main; struct World; @@ -43,5 +44,6 @@ void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struc struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld); struct World *BKE_world_localize(struct World *wrld); void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local); +void BKE_world_eval(struct Depsgraph *depsgraph, struct World *world); -#endif /* __BKE_WORLD_H__ */ +#endif diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h deleted file mode 100644 index c38b1b196c3..00000000000 --- a/source/blender/blenkernel/BKE_writeframeserver.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __BKE_WRITEFRAMESERVER_H__ -#define __BKE_WRITEFRAMESERVER_H__ - -/** \file BKE_writeframeserver.h - * \ingroup bke - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct RenderData; -struct ReportList; -struct Scene; - -int BKE_frameserver_start( - void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, - struct ReportList *reports, bool preview, const char *suffix); -void BKE_frameserver_end(void *context_v); -int BKE_frameserver_append( - void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels, - int rectx, int recty, const char *suffix, struct ReportList *reports); -int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports); -void *BKE_frameserver_context_create(void); -void BKE_frameserver_context_free(void *context_v); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 45f2ac083dd..4161a5ecd79 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -30,6 +30,7 @@ set(INC ../blenloader ../blentranslation ../depsgraph + ../draw ../gpu ../ikplugin ../imbuf @@ -37,6 +38,8 @@ set(INC ../makesrna ../bmesh ../modifiers + ../gpencil_modifiers + ../shader_fx ../nodes ../physics ../render/extern/include @@ -50,6 +53,7 @@ set(INC ../../../intern/atomic ../../../intern/clog ../../../intern/libmv + ../../../intern/opensubdiv ../../../extern/curve_fit_nd ) @@ -76,17 +80,17 @@ set(SRC intern/blender.c intern/blender_copybuffer.c intern/blender_undo.c + intern/blender_user_menu.c intern/blendfile.c - intern/bmfont.c intern/boids.c intern/bpath.c intern/brush.c - intern/bullet.c intern/bvhutils.c intern/cachefile.c intern/camera.c intern/cdderivedmesh.c intern/cloth.c + intern/collection.c intern/collision.c intern/colorband.c intern/colortools.c @@ -99,13 +103,14 @@ set(SRC intern/customdata_file.c intern/data_transfer.c intern/deform.c - intern/depsgraph.c intern/displist.c intern/dynamicpaint.c intern/editderivedmesh.c intern/editlattice.c intern/editmesh.c intern/editmesh_bvh.c + intern/editmesh_cache.c + intern/editmesh_tangent.c intern/effect.c intern/fcurve.c intern/fluidsim.c @@ -113,8 +118,9 @@ set(SRC intern/font.c intern/freestyle.c intern/gpencil.c - intern/group.c + intern/gpencil_modifier.c intern/icons.c + intern/icons_rasterize.c intern/idcode.c intern/idprop.c intern/idprop_utils.c @@ -126,9 +132,11 @@ set(SRC intern/lattice.c intern/library.c intern/library_idmap.c + intern/library_override.c intern/library_query.c intern/library_remap.c intern/linestyle.c + intern/main.c intern/mask.c intern/mask_evaluate.c intern/mask_rasterize.c @@ -138,16 +146,22 @@ set(SRC intern/mesh.c intern/mesh_convert.c intern/mesh_evaluate.c + intern/mesh_iterators.c intern/mesh_mapping.c + intern/mesh_merge.c intern/mesh_remap.c + intern/mesh_runtime.c + intern/mesh_tangent.c intern/mesh_validate.c intern/modifier.c - intern/modifiers_bmesh.c intern/movieclip.c intern/multires.c + intern/multires_reshape.c + intern/multires_subdiv.c intern/nla.c intern/node.c intern/object.c + intern/object_facemap.c intern/object_deform.c intern/object_dupli.c intern/object_update.c @@ -155,6 +169,7 @@ set(SRC intern/outliner_treehash.c intern/packedFile.c intern/paint.c + intern/paint_toolslots.c intern/particle.c intern/particle_child.c intern/particle_distribute.c @@ -162,22 +177,35 @@ set(SRC intern/pbvh.c intern/pbvh_bmesh.c intern/pointcache.c - intern/property.c + intern/layer.c + intern/layer_utils.c + intern/lightprobe.c intern/report.c intern/rigidbody.c - intern/sca.c intern/scene.c intern/screen.c intern/seqcache.c intern/seqeffects.c intern/seqmodifier.c intern/sequencer.c + intern/shader_fx.c intern/shrinkwrap.c - intern/sketch.c intern/smoke.c intern/softbody.c intern/sound.c intern/speaker.c + intern/studiolight.c + intern/subdiv.c + intern/subdiv_ccg.c + intern/subdiv_ccg_mask.c + intern/subdiv_converter.c + intern/subdiv_converter_mesh.c + intern/subdiv_displacement.c + intern/subdiv_displacement_multires.c + intern/subdiv_eval.c + intern/subdiv_foreach.c + intern/subdiv_mesh.c + intern/subdiv_stats.c intern/subsurf_ccg.c intern/suggestions.c intern/text.c @@ -192,9 +220,9 @@ set(SRC intern/tracking_util.c intern/undo_system.c intern/unit.c + intern/workspace.c intern/world.c intern/writeavi.c - intern/writeframeserver.c BKE_DerivedMesh.h BKE_action.h @@ -207,20 +235,19 @@ set(SRC BKE_blender.h BKE_blender_copybuffer.h BKE_blender_undo.h + BKE_blender_user_menu.h BKE_blender_version.h BKE_blendfile.h - BKE_bmfont.h - BKE_bmfont_types.h BKE_boids.h BKE_bpath.h BKE_brush.h - BKE_bullet.h BKE_bvhutils.h BKE_cachefile.h BKE_camera.h BKE_ccg.h BKE_cdderivedmesh.h BKE_cloth.h + BKE_collection.h BKE_collision.h BKE_colorband.h BKE_colortools.h @@ -232,12 +259,13 @@ set(SRC BKE_customdata_file.h BKE_data_transfer.h BKE_deform.h - BKE_depsgraph.h BKE_displist.h BKE_dynamicpaint.h BKE_editlattice.h BKE_editmesh.h BKE_editmesh_bvh.h + BKE_editmesh_cache.h + BKE_editmesh_tangent.h BKE_effect.h BKE_fcurve.h BKE_fluidsim.h @@ -245,7 +273,7 @@ set(SRC BKE_freestyle.h BKE_global.h BKE_gpencil.h - BKE_group.h + BKE_gpencil_modifier.h BKE_icons.h BKE_idcode.h BKE_idprop.h @@ -256,6 +284,7 @@ set(SRC BKE_lattice.h BKE_library.h BKE_library_idmap.h + BKE_library_override.h BKE_library_query.h BKE_library_remap.h BKE_linestyle.h @@ -265,14 +294,18 @@ set(SRC BKE_mball.h BKE_mball_tessellate.h BKE_mesh.h + BKE_mesh_iterators.h BKE_mesh_mapping.h BKE_mesh_remap.h + BKE_mesh_runtime.h + BKE_mesh_tangent.h BKE_modifier.h BKE_movieclip.h BKE_multires.h BKE_nla.h BKE_node.h BKE_object.h + BKE_object_facemap.h BKE_object_deform.h BKE_ocean.h BKE_outliner_treehash.h @@ -281,19 +314,25 @@ set(SRC BKE_particle.h BKE_pbvh.h BKE_pointcache.h - BKE_property.h + BKE_layer.h + BKE_lightprobe.h BKE_report.h BKE_rigidbody.h - BKE_sca.h BKE_scene.h BKE_screen.h BKE_sequencer.h + BKE_shader_fx.h BKE_shrinkwrap.h - BKE_sketch.h BKE_smoke.h BKE_softbody.h BKE_sound.h BKE_speaker.h + BKE_studiolight.h + BKE_subdiv.h + BKE_subdiv_ccg.h + BKE_subdiv_eval.h + BKE_subdiv_foreach.h + BKE_subdiv_mesh.h BKE_subsurf.h BKE_suggestions.h BKE_text.h @@ -301,19 +340,19 @@ set(SRC BKE_tracking.h BKE_undo_system.h BKE_unit.h + BKE_workspace.h BKE_world.h BKE_writeavi.h - BKE_writeframeserver.h - depsgraph_private.h nla_private.h tracking_private.h particle_private.h intern/CCGSubSurf.h intern/CCGSubSurf_inline.h intern/CCGSubSurf_intern.h - intern/pbvh_intern.h intern/data_transfer_intern.h + intern/pbvh_intern.h + intern/subdiv_converter.h ) if(WITH_BINRELOC) @@ -332,7 +371,7 @@ if(WIN32) endif() if(WITH_AUDASPACE) - add_definitions(${AUDASPACE_DEFINITIONS}) + add_definitions(-DWITH_AUDASPACE) list(APPEND INC_SYS ${AUDASPACE_C_INCLUDE_DIRS} @@ -420,6 +459,10 @@ if(WITH_PYTHON) ) add_definitions(-DWITH_PYTHON) + if(WITH_PYTHON_SAFETY) + add_definitions(-DWITH_PYTHON_SAFETY) + endif() + if(WITH_PYTHON_SECURITY) add_definitions(-DWITH_PYTHON_SECURITY) endif() @@ -472,18 +515,6 @@ if(WITH_LZMA) add_definitions(-DWITH_LZMA) endif() -if(WITH_GAMEENGINE) - list(APPEND INC_SYS - ../../../extern/recastnavigation - ) - list(APPEND SRC - intern/navmesh_conversion.c - BKE_navmesh_conversion.h - ) - - add_definitions(-DWITH_GAMEENGINE) -endif() - if(WITH_LIBMV) add_definitions(-DWITH_LIBMV) endif() @@ -513,9 +544,11 @@ endif() if(WITH_OPENSUBDIV) add_definitions(-DWITH_OPENSUBDIV) list(APPEND INC_SYS - ../../../intern/opensubdiv ${OPENSUBDIV_INCLUDE_DIRS} ) + if(WITH_OPENSUBDIV_MODIFIER) + add_definitions(-DWITH_OPENSUBDIV_MODIFIER) + endif() endif() if(WITH_OPENVDB) @@ -536,8 +569,4 @@ endif() # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") #endif() -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h deleted file mode 100644 index 69ca75836d9..00000000000 --- a/source/blender/blenkernel/depsgraph_private.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * ***** 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) 2004 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/depsgraph_private.h - * \ingroup bke - */ - -#ifndef __DEPSGRAPH_PRIVATE_H__ -#define __DEPSGRAPH_PRIVATE_H__ - -#include "BKE_depsgraph.h" -#include "DNA_constraint_types.h" -#include "BKE_constraint.h" - -struct Scene; -struct Group; -struct EffectorWeights; -struct ModifierData; - -/* **** DAG relation types *** */ - -/* scene link to object */ -#define DAG_RL_SCENE (1 << 0) -/* object link to data */ -#define DAG_RL_DATA (1 << 1) - -/* object changes object (parent, track, constraints) */ -#define DAG_RL_OB_OB (1 << 2) -/* object changes obdata (hooks, constraints) */ -#define DAG_RL_OB_DATA (1 << 3) -/* data changes object (vertex parent) */ -#define DAG_RL_DATA_OB (1 << 4) -/* data changes data (deformers) */ -#define DAG_RL_DATA_DATA (1 << 5) - -#define DAG_NO_RELATION (1 << 6) - -#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE | DAG_RL_OB_OB | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_DATA_DATA) -#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA | DAG_RL_DATA) - - -#define DAGQUEUEALLOC 50 - -enum { - DAG_WHITE = 0, - DAG_GRAY = 1, - DAG_BLACK = 2 -}; - -typedef struct DagAdjList { - struct DagNode *node; - short type; - int count; /* number of identical arcs */ - unsigned int lay; // for flushing redraw/rebuild events - const char *name; - struct DagAdjList *next; -} DagAdjList; - - -typedef struct DagNode { - int color; - short type; - float x, y, k; - void *ob; - void *first_ancestor; - int ancestor_count; - unsigned int lay; /* accumulated layers of its relations + itself */ - unsigned int scelay; /* layers due to being in scene */ - uint64_t customdata_mask; /* customdata mask */ - int lasttime; /* if lasttime != DagForest->time, this node was not evaluated yet for flushing */ - int BFS_dist; /* BFS distance */ - int DFS_dist; /* DFS distance */ - int DFS_dvtm; /* DFS discovery time */ - int DFS_fntm; /* DFS Finishing time */ - struct DagAdjList *child; - struct DagAdjList *parent; - struct DagNode *next; - - /* Threaded evaluation routines */ - uint32_t num_pending_parents; /* number of parents which are not updated yet - * this node has got. - * Used by threaded update for faster detect whether node could be - * updated aready. - */ - bool scheduled; - - /* Runtime flags mainly used to determine which extra data is to be evaluated - * during object_handle_update(). Such an extra data is what depends on the - * DAG topology, meaning this flags indicates the data evaluation of which - * depends on the node dependencies. - */ - short eval_flags; -} DagNode; - -typedef struct DagNodeQueueElem { - struct DagNode *node; - struct DagNodeQueueElem *next; -} DagNodeQueueElem; - -typedef struct DagNodeQueue { - DagNodeQueueElem *first; - DagNodeQueueElem *last; - int count; - int maxlevel; - struct DagNodeQueue *freenodes; -} DagNodeQueue; - -/* forest as we may have more than one DAG unconnected */ -typedef struct DagForest { - ListBase DagNode; - struct GHash *nodeHash; - int numNodes; - bool is_acyclic; - int time; /* for flushing/tagging, compare with node->lasttime */ - bool ugly_hack_sorry; /* prevent type check */ - bool need_update; -} DagForest; - -// queue operations -DagNodeQueue *queue_create(int slots); -void queue_raz(DagNodeQueue *queue); -void push_queue(DagNodeQueue *queue, DagNode *node); -void push_stack(DagNodeQueue *queue, DagNode *node); -DagNode *pop_queue(DagNodeQueue *queue); -DagNode *get_top_node_queue(DagNodeQueue *queue); -void queue_delete(DagNodeQueue *queue); - -// Dag management -DagForest *dag_init(void); -DagForest *build_dag(struct Main *bmain, struct Scene *sce, short mask); -void free_forest(struct DagForest *Dag); -DagNode *dag_find_node(DagForest *forest, void *fob); -DagNode *dag_add_node(DagForest *forest, void *fob); -DagNode *dag_get_node(DagForest *forest, void *fob); -DagNode *dag_get_sub_node(DagForest *forest, void *fob); -void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name); - -typedef bool (*DagCollobjFilterFunction)(struct Object *obj, struct ModifierData *md); - -void dag_add_collision_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name); -void dag_add_forcefield_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name); - -void graph_print_queue(DagNodeQueue *nqueue); -void graph_print_queue_dist(DagNodeQueue *nqueue); -void graph_print_adj_list(DagForest *dag); - -#endif /* __DEPSGRAPH_PRIVATE_H__ */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 40dea6ca663..6ec1b1b36b9 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -40,9 +40,11 @@ #ifdef WITH_OPENSUBDIV # include "opensubdiv_capi.h" # include "opensubdiv_converter_capi.h" +# include "opensubdiv_evaluator_capi.h" +# include "opensubdiv_topology_refiner_capi.h" #endif -#include "GL/glew.h" +#include "GPU_glew.h" /***/ @@ -329,7 +331,7 @@ void ccgSubSurf_free(CCGSubSurf *ss) CCGAllocatorHDL allocator = ss->allocator; #ifdef WITH_OPENSUBDIV if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator); + openSubdiv_deleteEvaluator(ss->osd_evaluator); } if (ss->osd_mesh != NULL) { ccgSubSurf__delete_osdGLMesh(ss->osd_mesh); @@ -341,7 +343,7 @@ void ccgSubSurf_free(CCGSubSurf *ss) MEM_freeN(ss->osd_coarse_coords); } if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner); + openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); } #endif diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h index 50959d21425..e1cb82d7868 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -236,7 +236,7 @@ struct CCGSubSurf { * Refiner is created from the modifier stack and used later from the main * thread to construct GL mesh to avoid threaded access to GL. */ - struct OpenSubdiv_TopologyRefinerDescr *osd_topology_refiner; /* Only used at synchronization stage. */ + struct OpenSubdiv_TopologyRefiner *osd_topology_refiner; /* Only used at synchronization stage. */ /* Denotes whether osd_mesh is invalid now due to topology changes and needs * to be reconstructed. * @@ -249,7 +249,7 @@ struct CCGSubSurf { /* ** CPU backend. ** */ /* Limit evaluator, used to evaluate CCG. */ - struct OpenSubdiv_EvaluatorDescr *osd_evaluator; + struct OpenSubdiv_Evaluator *osd_evaluator; /* Next PTex face index, used while CCG synchronization * to fill in PTex index of CCGFace. */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index 65c6518cee4..004a50205ba 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -42,8 +42,11 @@ #include "opensubdiv_capi.h" #include "opensubdiv_converter_capi.h" +#include "opensubdiv_evaluator_capi.h" +#include "opensubdiv_gl_mesh_capi.h" +#include "opensubdiv_topology_refiner_capi.h" -#include "GL/glew.h" +#include "GPU_glew.h" #include "GPU_extensions.h" #define OSD_LOG if (false) printf @@ -131,7 +134,6 @@ static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner; OpenSubdiv_Converter converter; bool result; if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) { @@ -140,15 +142,10 @@ static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm) /* TODO(sergey): De-duplicate with topology counter at the bottom of * the file. */ - if (ss->osd_topology_refiner != NULL) { - topology_refiner = ss->osd_topology_refiner; - } - else { - topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - } ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); - result = openSubdiv_topologyRefnerCompareConverter(topology_refiner, - &converter); + result = openSubdiv_topologyRefinerCompareWithConverter( + ss->osd_topology_refiner, + &converter); ccgSubSurf_converter_free(&converter); return result; } @@ -159,22 +156,13 @@ static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm) return true; } if (ss->osd_topology_refiner != NULL) { - int levels = openSubdiv_topologyRefinerGetSubdivLevel( + const int levels = ss->osd_topology_refiner->getSubdivisionLevel( ss->osd_topology_refiner); BLI_assert(ss->osd_mesh_invalid == true); if (levels != ss->subdivLevels) { return true; } } - if (ss->osd_mesh != NULL && ss->osd_mesh_invalid == false) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner = - openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - int levels = openSubdiv_topologyRefinerGetSubdivLevel(topology_refiner); - BLI_assert(ss->osd_topology_refiner == NULL); - if (levels != ss->subdivLevels) { - return true; - } - } if (ss->skip_grids == false) { return compare_ccg_derivedmesh_topology(ss, dm) == false; } @@ -194,13 +182,13 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm) /* Reset GPU part. */ ss->osd_mesh_invalid = true; if (ss->osd_topology_refiner != NULL) { - openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner); + openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner); ss->osd_topology_refiner = NULL; } - /* Reste CPU side. */ + /* Reset CPU side. */ if (ss->osd_evaluator != NULL) { - openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator); + openSubdiv_deleteEvaluator(ss->osd_evaluator); ss->osd_evaluator = NULL; } } @@ -209,10 +197,10 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm) static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss) { BLI_assert(ss->meshIFC.numLayers == 3); - openSubdiv_osdGLMeshUpdateVertexBuffer(ss->osd_mesh, - (float *) ss->osd_coarse_coords, - 0, - ss->osd_num_coarse_coords); + ss->osd_mesh->setCoarsePositions(ss->osd_mesh, + (float *) ss->osd_coarse_coords, + 0, + ss->osd_num_coarse_coords); } bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, @@ -232,6 +220,9 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, CHECK_COMPUTE_TYPE(CUDA) CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK) CHECK_COMPUTE_TYPE(GLSL_COMPUTE) + default: + compute_type = OPENSUBDIV_EVALUATOR_CPU; + break; #undef CHECK_COMPUTE_TYPE } @@ -256,9 +247,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner( ss->osd_topology_refiner, - compute_type, - ss->subdivLevels); - ss->osd_topology_refiner = NULL; + compute_type); if (UNLIKELY(ss->osd_mesh == NULL)) { /* Most likely compute device is not available. */ @@ -266,13 +255,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, } ccgSubSurf__updateGLMeshCoords(ss); - openSubdiv_osdGLMeshRefine(ss->osd_mesh); - openSubdiv_osdGLMeshSynchronize(ss->osd_mesh); + ss->osd_mesh->refine(ss->osd_mesh); + ss->osd_mesh->synchronize(ss->osd_mesh); ss->osd_coarse_coords_invalid = false; glBindVertexArray(ss->osd_vao); - glBindBuffer(GL_ARRAY_BUFFER, - openSubdiv_getOsdGLMeshVertexBuffer(ss->osd_mesh)); + ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); @@ -286,12 +274,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, } else if (ss->osd_coarse_coords_invalid) { ccgSubSurf__updateGLMeshCoords(ss); - openSubdiv_osdGLMeshRefine(ss->osd_mesh); - openSubdiv_osdGLMeshSynchronize(ss->osd_mesh); + ss->osd_mesh->refine(ss->osd_mesh); + ss->osd_mesh->synchronize(ss->osd_mesh); ss->osd_coarse_coords_invalid = false; } - openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index); + ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index); return true; } @@ -302,12 +290,12 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads, if (LIKELY(ss->osd_mesh != NULL)) { glBindVertexArray(ss->osd_vao); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, - openSubdiv_getOsdGLMeshPatchIndexBuffer(ss->osd_mesh)); + ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh)); - openSubdiv_osdGLMeshBindVertexBuffer(ss->osd_mesh); + ss->osd_mesh->bindVertexBuffer(ss->osd_mesh); glBindVertexArray(ss->osd_vao); - openSubdiv_osdGLMeshDisplay(ss->osd_mesh, fill_quads, - start_partition, num_partitions); + ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, + start_partition, num_partitions); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -316,33 +304,21 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads, int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner; if (ss->osd_topology_refiner != NULL) { - topology_refiner = ss->osd_topology_refiner; - } - else if (ss->osd_mesh != NULL) { - topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - } - else { - return 0; + return ss->osd_topology_refiner->getNumFaces( + ss->osd_topology_refiner); } - return openSubdiv_topologyRefinerGetNumFaces(topology_refiner); + return 0; } /* Get number of vertices in base faces in a particular GL mesh. */ int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face) { - const OpenSubdiv_TopologyRefinerDescr *topology_refiner; if (ss->osd_topology_refiner != NULL) { - topology_refiner = ss->osd_topology_refiner; - } - else if (ss->osd_mesh != NULL) { - topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh); - } - else { - return 0; + return ss->osd_topology_refiner->getNumFaceVertices( + ss->osd_topology_refiner, face); } - return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face); + return 0; } void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids) @@ -450,17 +426,21 @@ void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss, static bool opensubdiv_createEvaluator(CCGSubSurf *ss) { OpenSubdiv_Converter converter; - OpenSubdiv_TopologyRefinerDescr *topology_refiner; + OpenSubdiv_TopologyRefiner *topology_refiner; if (ss->fMap->numEntries == 0) { /* OpenSubdiv doesn't support meshes without faces. */ return false; } ccgSubSurf_converter_setup_from_ccg(ss, &converter); - topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter); + OpenSubdiv_TopologyRefinerSettings settings; + settings.level = ss->subdivLevels; + settings.is_adaptive = false; + topology_refiner = + openSubdiv_createTopologyRefinerFromConverter( + &converter, &settings); ccgSubSurf_converter_free(&converter); ss->osd_evaluator = - openSubdiv_createEvaluatorDescr(topology_refiner, - ss->subdivLevels); + openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner); if (ss->osd_evaluator == NULL) { BLI_assert(!"OpenSubdiv initialization failed, should not happen."); return false; @@ -516,10 +496,11 @@ static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss) } } - openSubdiv_setEvaluatorCoarsePositions(ss->osd_evaluator, - (float *)positions, - 0, - num_basis_verts); + ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, + (float *)positions, + 0, + num_basis_verts); + ss->osd_evaluator->refine(ss->osd_evaluator); MEM_freeN(positions); } @@ -540,7 +521,7 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss, for (S = 0; S < face->numVerts; S++) { int x, y, k; CCGEdge *edge = NULL; - bool inverse_edge; + bool inverse_edge = false; for (x = 0; x < gridSize; x++) { for (y = 0; y < gridSize; y++) { @@ -554,11 +535,12 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss, ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v); /* TODO(sergey): Need proper port. */ - openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index, - face_u, face_v, - P, - do_normals ? dPdu : NULL, - do_normals ? dPdv : NULL); + ss->osd_evaluator->evaluateLimit( + ss->osd_evaluator, osd_face_index, + face_u, face_v, + P, + do_normals ? dPdu : NULL, + do_normals ? dPdv : NULL); OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n", osd_face_index, S, grid_u, grid_v, face_u, face_v, P[0], P[1], P[2]); @@ -632,7 +614,11 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss, * let's just re-evaluate for simplicity. */ /* TODO(sergey): Need proper port. */ - openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv); + ss->osd_evaluator->evaluateLimit( + ss->osd_evaluator, + osd_face_index, + u, v, + P, dPdu, dPdv); VertDataCopy(co, P, ss); if (do_normals) { cross_v3_v3v3(no, dPdu, dPdv); @@ -696,7 +682,11 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss, float P[3], dPdu[3], dPdv[3]; /* TODO(sergey): Need proper port. */ - openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv); + ss->osd_evaluator->evaluateLimit( + ss->osd_evaluator, + osd_face_index + S, + u, v, + P, dPdu, dPdv); OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n", osd_face_index + S, S, u, v, P[0], P[1], P[2]); @@ -739,7 +729,7 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss, /* Evaluate edges. */ for (S = 0; S < face->numVerts; S++) { CCGEdge *edge = FACE_getEdges(face)[S]; - int x, S0, S1; + int x, S0 = 0, S1 = 0; bool flip; for (x = 0; x < face->numVerts; ++x) { @@ -834,7 +824,12 @@ void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm) OpenSubdiv_Converter converter; ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter); /* TODO(sergey): Remove possibly previously allocated refiner. */ - ss->osd_topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter); + OpenSubdiv_TopologyRefinerSettings settings; + settings.level = ss->subdivLevels; + settings.is_adaptive = false; + ss->osd_topology_refiner = + openSubdiv_createTopologyRefinerFromConverter( + &converter, &settings); ccgSubSurf_converter_free(&converter); } } @@ -995,7 +990,7 @@ void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs) void BKE_subsurf_osd_init(void) { - openSubdiv_init(GPU_legacy_support()); + openSubdiv_init(); BLI_spin_init(&delete_spin); } diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c index d6b15148ed1..0301582b303 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c @@ -84,6 +84,13 @@ static OpenSubdiv_SchemeType conv_dm_get_type( return OSD_SCHEME_CATMARK; } +static OpenSubdiv_VtxBoundaryInterpolation +conv_dm_get_vtx_boundary_interpolation( + const OpenSubdiv_Converter *UNUSED(converter)) +{ + return OSD_VTX_BOUNDARY_EDGE_ONLY; +} + static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation( const OpenSubdiv_Converter *converter) { @@ -94,6 +101,12 @@ static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation( return OSD_FVAR_LINEAR_INTERPOLATION_ALL; } +static bool conv_dm_specifies_full_topology( + const OpenSubdiv_Converter *UNUSED(converter)) +{ + return true; +} + static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter) { ConvDMStorage *storage = converter->user_data; @@ -306,6 +319,20 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter, #endif } +static bool conv_dm_is_infinite_sharp_vertex( + const OpenSubdiv_Converter *UNUSED(converter), + int UNUSED(manifold_vertex_index)) +{ + return false; +} + +static float conv_dm_get_vertex_sharpness( + const OpenSubdiv_Converter *UNUSED(converter), + int UNUSED(manifold_vertex_index)) +{ + return 0.0f; +} + static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter) { ConvDMStorage *storage = converter->user_data; @@ -389,12 +416,6 @@ static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter) return storage->num_uvs; } -static void conv_dm_get_uvs(const OpenSubdiv_Converter *converter, float *uvs) -{ - ConvDMStorage *storage = converter->user_data; - memcpy(uvs, storage->uvs, sizeof(float) * 2 * storage->num_uvs); -} - static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter, int face, int corner) @@ -432,35 +453,39 @@ void ccgSubSurf_converter_setup_from_derivedmesh( { ConvDMStorage *user_data; - converter->get_scheme_type = conv_dm_get_type; + converter->getSchemeType = conv_dm_get_type; - converter->get_fvar_linear_interpolation = + converter->getVtxBoundaryInterpolation = + conv_dm_get_vtx_boundary_interpolation; + converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation; - - converter->get_num_faces = conv_dm_get_num_faces; - converter->get_num_edges = conv_dm_get_num_edges; - converter->get_num_verts = conv_dm_get_num_verts; - - converter->get_num_face_verts = conv_dm_get_num_face_verts; - converter->get_face_verts = conv_dm_get_face_verts; - converter->get_face_edges = conv_dm_get_face_edges; - - converter->get_edge_verts = conv_dm_get_edge_verts; - converter->get_num_edge_faces = conv_dm_get_num_edge_faces; - converter->get_edge_faces = conv_dm_get_edge_faces; - converter->get_edge_sharpness = conv_dm_get_edge_sharpness; - - converter->get_num_vert_edges = conv_dm_get_num_vert_edges; - converter->get_vert_edges = conv_dm_get_vert_edges; - converter->get_num_vert_faces = conv_dm_get_num_vert_faces; - converter->get_vert_faces = conv_dm_get_vert_faces; - - converter->get_num_uv_layers = conv_dm_get_num_uv_layers; - converter->precalc_uv_layer = conv_dm_precalc_uv_layer; - converter->finish_uv_layer = conv_dm_finish_uv_layer; - converter->get_num_uvs = conv_dm_get_num_uvs; - converter->get_uvs = conv_dm_get_uvs; - converter->get_face_corner_uv_index = conv_dm_get_face_corner_uv_index; + converter->specifiesFullTopology = conv_dm_specifies_full_topology; + + converter->getNumFaces = conv_dm_get_num_faces; + converter->getNumEdges = conv_dm_get_num_edges; + converter->getNumVertices = conv_dm_get_num_verts; + + converter->getNumFaceVertices = conv_dm_get_num_face_verts; + converter->getFaceVertices = conv_dm_get_face_verts; + converter->getFaceEdges = conv_dm_get_face_edges; + + converter->getEdgeVertices = conv_dm_get_edge_verts; + converter->getNumEdgeFaces = conv_dm_get_num_edge_faces; + converter->getEdgeFaces = conv_dm_get_edge_faces; + converter->getEdgeSharpness = conv_dm_get_edge_sharpness; + + converter->getNumVertexEdges = conv_dm_get_num_vert_edges; + converter->getVertexEdges = conv_dm_get_vert_edges; + converter->getNumVertexFaces = conv_dm_get_num_vert_faces; + converter->getVertexFaces = conv_dm_get_vert_faces; + converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex; + converter->getVertexSharpness = conv_dm_get_vertex_sharpness; + + converter->getNumUVLayers = conv_dm_get_num_uv_layers; + converter->precalcUVLayer = conv_dm_precalc_uv_layer; + converter->finishUVLayer = conv_dm_finish_uv_layer; + converter->getNumUVCoordinates = conv_dm_get_num_uvs; + converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index; user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__); user_data->ss = ss; @@ -476,7 +501,7 @@ void ccgSubSurf_converter_setup_from_derivedmesh( user_data->uvs = NULL; user_data->face_uvs = NULL; - converter->free_user_data = conv_dm_free_user_data; + converter->freeUserData = conv_dm_free_user_data; converter->user_data = user_data; #ifdef USE_MESH_ELEMENT_MAPPING @@ -530,6 +555,13 @@ static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type( } } +static OpenSubdiv_VtxBoundaryInterpolation +conv_ccg_get_vtx_boundary_interpolation( + const OpenSubdiv_Converter *UNUSED(converter)) +{ + return OSD_VTX_BOUNDARY_EDGE_ONLY; +} + static OpenSubdiv_FVarLinearInterpolation conv_ccg_get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter) { @@ -540,6 +572,12 @@ conv_ccg_get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter) return OSD_FVAR_LINEAR_INTERPOLATION_ALL; } +static bool conv_ccg_specifies_full_topology( + const OpenSubdiv_Converter *UNUSED(converter)) +{ + return true; +} + static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter) { CCGSubSurf *ss = converter->user_data; @@ -683,6 +721,20 @@ static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter, } } +static bool conv_ccg_is_infinite_sharp_vertex( + const OpenSubdiv_Converter *UNUSED(converter), + int UNUSED(manifold_vertex_index)) +{ + return false; +} + +static float conv_ccg_get_vertex_sharpness( + const OpenSubdiv_Converter *UNUSED(converter), + int UNUSED(manifold_vertex_index)) +{ + return 0.0f; +} + static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter)) { return 0; @@ -702,11 +754,6 @@ static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter)) return 0; } -static void conv_ccg_get_uvs(const OpenSubdiv_Converter * UNUSED(converter), - float *UNUSED(uvs)) -{ -} - static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter), int UNUSED(face), int UNUSED(corner_)) @@ -717,45 +764,49 @@ static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED( void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter) { - converter->get_scheme_type = conv_ccg_get_bilinear_type; + converter->getSchemeType = conv_ccg_get_bilinear_type; - converter->get_fvar_linear_interpolation = + converter->getVtxBoundaryInterpolation = + conv_ccg_get_vtx_boundary_interpolation; + converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation; - - converter->get_num_faces = conv_ccg_get_num_faces; - converter->get_num_edges = conv_ccg_get_num_edges; - converter->get_num_verts = conv_ccg_get_num_verts; - - converter->get_num_face_verts = conv_ccg_get_num_face_verts; - converter->get_face_verts = conv_ccg_get_face_verts; - converter->get_face_edges = conv_ccg_get_face_edges; - - converter->get_edge_verts = conv_ccg_get_edge_verts; - converter->get_num_edge_faces = conv_ccg_get_num_edge_faces; - converter->get_edge_faces = conv_ccg_get_edge_faces; - converter->get_edge_sharpness = conv_ccg_get_edge_sharpness; - - converter->get_num_vert_edges = conv_ccg_get_num_vert_edges; - converter->get_vert_edges = conv_ccg_get_vert_edges; - converter->get_num_vert_faces = conv_ccg_get_num_vert_faces; - converter->get_vert_faces = conv_ccg_get_vert_faces; - - converter->get_num_uv_layers = conv_ccg_get_num_uv_layers; - converter->precalc_uv_layer = conv_ccg_precalc_uv_layer; - converter->finish_uv_layer = conv_ccg_finish_uv_layer; - converter->get_num_uvs = conv_ccg_get_num_uvs; - converter->get_uvs = conv_ccg_get_uvs; - converter->get_face_corner_uv_index = conv_ccg_get_face_corner_uv_index; - - converter->free_user_data = NULL; + converter->specifiesFullTopology = conv_ccg_specifies_full_topology; + + converter->getNumFaces = conv_ccg_get_num_faces; + converter->getNumEdges = conv_ccg_get_num_edges; + converter->getNumVertices = conv_ccg_get_num_verts; + + converter->getNumFaceVertices = conv_ccg_get_num_face_verts; + converter->getFaceVertices = conv_ccg_get_face_verts; + converter->getFaceEdges = conv_ccg_get_face_edges; + + converter->getEdgeVertices = conv_ccg_get_edge_verts; + converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces; + converter->getEdgeFaces = conv_ccg_get_edge_faces; + converter->getEdgeSharpness = conv_ccg_get_edge_sharpness; + + converter->getNumVertexEdges = conv_ccg_get_num_vert_edges; + converter->getVertexEdges = conv_ccg_get_vert_edges; + converter->getNumVertexFaces = conv_ccg_get_num_vert_faces; + converter->getVertexFaces = conv_ccg_get_vert_faces; + converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex; + converter->getVertexSharpness = conv_ccg_get_vertex_sharpness; + + converter->getNumUVLayers = conv_ccg_get_num_uv_layers; + converter->precalcUVLayer = conv_ccg_precalc_uv_layer; + converter->finishUVLayer = conv_ccg_finish_uv_layer; + converter->getNumUVCoordinates = conv_ccg_get_num_uvs; + converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index; + + converter->freeUserData = NULL; converter->user_data = ss; } void ccgSubSurf_converter_free( struct OpenSubdiv_Converter *converter) { - if (converter->free_user_data) { - converter->free_user_data(converter); + if (converter->freeUserData) { + converter->freeUserData(converter); } } diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index e099ceaea53..1d787388774 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -55,32 +55,29 @@ #include "BKE_colorband.h" #include "BKE_editmesh.h" #include "BKE_key.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_mesh.h" +#include "BKE_mesh_iterators.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" +#include "BKE_mesh_tangent.h" #include "BKE_object.h" #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_multires.h" #include "BKE_bvhutils.h" #include "BKE_deform.h" -#include "BKE_global.h" /* For debug flag, DM_update_tessface_data() func. */ - -#ifdef WITH_GAMEENGINE -#include "BKE_navmesh_conversion.h" -static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); -#endif #include "BLI_sys_types.h" /* for intptr_t support */ -#include "GPU_buffers.h" -#include "GPU_glew.h" -#include "GPU_shader.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" +#include "BKE_shrinkwrap.h" #ifdef WITH_OPENSUBDIV -# include "BKE_depsgraph.h" # include "DNA_userdef_types.h" #endif @@ -89,17 +86,20 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); #ifdef USE_MODIFIER_VALIDATE # define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true))) +# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true))) #else # define ASSERT_IS_VALID_DM(dm) +# define ASSERT_IS_VALID_MESH(mesh) #endif static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; -static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob); static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid); +static void mesh_init_origspace(Mesh *mesh); + /* -------------------------------------------------------------------- */ @@ -327,7 +327,7 @@ void DM_init_funcs(DerivedMesh *dm) dm->getPolyDataArray = DM_get_poly_data_layer; dm->getLoopDataArray = DM_get_loop_data_layer; - bvhcache_init(&dm->bvhCache); + dm->bvhCache = NULL; } /** @@ -349,7 +349,6 @@ void DM_init( DM_init_funcs(dm); dm->needsFree = 1; - dm->auto_bump_scale = -1.0f; dm->dirty = 0; /* don't use CustomData_reset(...); because we dont want to touch customdata */ @@ -406,7 +405,6 @@ int DM_release(DerivedMesh *dm) { if (dm->needsFree) { bvhcache_free(&dm->bvhCache); - GPU_drawobject_free(dm); CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numTessFaceData); @@ -466,39 +464,6 @@ void DM_ensure_normals(DerivedMesh *dm) BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0); } -static void DM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, float split_angle) -{ - dm->calcLoopNormals(dm, use_split_normals, split_angle); - dm->dirty |= DM_DIRTY_TESS_CDLAYERS; -} - -/* note: until all modifiers can take MPoly's as input, - * use this at the start of modifiers */ -void DM_ensure_tessface(DerivedMesh *dm) -{ - const int numTessFaces = dm->getNumTessFaces(dm); - const int numPolys = dm->getNumPolys(dm); - - if ((numTessFaces == 0) && (numPolys != 0)) { - dm->recalcTessellation(dm); - - if (dm->getNumTessFaces(dm) != 0) { - /* printf("info %s: polys -> ngons calculated\n", __func__); */ - } - else { - printf("warning %s: could not create tessfaces from %d polygons, dm->type=%u\n", - __func__, numPolys, dm->type); - } - } - - else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) { - BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX) || numTessFaces == 0); - DM_update_tessface_data(dm); - } - - dm->dirty &= ~DM_DIRTY_TESS_CDLAYERS; -} - /** * Ensure the array is large enough * @@ -533,195 +498,13 @@ void DM_ensure_looptri_data(DerivedMesh *dm) } } -void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num) -{ - int i; - for (i = 0; i < looptri_num; i++) { - verttri[i].tri[0] = mloop[looptri[i].tri[0]].v; - verttri[i].tri[1] = mloop[looptri[i].tri[1]].v; - verttri[i].tri[2] = mloop[looptri[i].tri[2]].v; - } -} - -/* Update tessface CD data from loop/poly ones. Needed when not retessellating after modstack evaluation. */ -/* NOTE: Assumes dm has valid tessellated data! */ -void DM_update_tessface_data(DerivedMesh *dm) -{ - MFace *mf, *mface = dm->getTessFaceArray(dm); - MPoly *mp = dm->getPolyArray(dm); - MLoop *ml = dm->getLoopArray(dm); - - CustomData *fdata = dm->getTessFaceDataLayout(dm); - CustomData *pdata = dm->getPolyDataLayout(dm); - CustomData *ldata = dm->getLoopDataLayout(dm); - - const int totface = dm->getNumTessFaces(dm); - int mf_idx; - - int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX); - unsigned int (*loopindex)[4]; - - /* Should never occur, but better abort than segfault! */ - if (!polyindex) - return; - - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); - - if (CustomData_has_layer(fdata, CD_MTFACE) || - CustomData_has_layer(fdata, CD_MCOL) || - CustomData_has_layer(fdata, CD_PREVIEW_MCOL) || - CustomData_has_layer(fdata, CD_ORIGSPACE) || - CustomData_has_layer(fdata, CD_TESSLOOPNORMAL) || - CustomData_has_layer(fdata, CD_TANGENT)) - { - loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__); - - for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) { - const int mf_len = mf->v4 ? 4 : 3; - unsigned int *ml_idx = loopindex[mf_idx]; - int i, not_done; - - /* Find out loop indices. */ - /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */ - for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) { - const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v); - if (tf_v != -1) { - ml_idx[tf_v] = i; - not_done--; - } - } - } - - /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: - * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be - * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code). - * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test. - */ - BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface, polyindex, loopindex, totface); - - MEM_freeN(loopindex); - } - - if (G.debug & G_DEBUG) - printf("%s: Updated tessellated customdata of dm %p\n", __func__, dm); - - dm->dirty &= ~DM_DIRTY_TESS_CDLAYERS; -} - -void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate) -{ - MFace *mf, *mface = dm->getTessFaceArray(dm); - MPoly *mp = dm->getPolyArray(dm); - MLoop *ml = dm->getLoopArray(dm); - - CustomData *fdata = dm->getTessFaceDataLayout(dm); - CustomData *pdata = dm->getPolyDataLayout(dm); - CustomData *ldata = dm->getLoopDataLayout(dm); - - const int totface = dm->getNumTessFaces(dm); - int mf_idx; - - int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX); - unsigned int (*loopindex)[4] = NULL; - - /* Should never occur, but better abort than segfault! */ - if (!polyindex) - return; - - if (generate) { - for (int j = 0; j < ldata->totlayer; j++) { - if (ldata->layers[j].type == CD_TANGENT) { - CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name); - CustomData_bmesh_update_active_layers(fdata, pdata, ldata); - - if (!loopindex) { - loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__); - for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) { - const int mf_len = mf->v4 ? 4 : 3; - unsigned int *ml_idx = loopindex[mf_idx]; - - /* Find out loop indices. */ - /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */ - for (int i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) { - const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v); - if (tf_v != -1) { - ml_idx[tf_v] = i; - not_done--; - } - } - } - } - - /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: - * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be - * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code). - * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test. - */ - BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface, ldata->layers[j].name); - } - } - if (loopindex) - MEM_freeN(loopindex); - BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true)); - } - - if (G.debug & G_DEBUG) - printf("%s: Updated tessellated tangents of dm %p\n", __func__, dm); -} - - -void DM_update_materials(DerivedMesh *dm, Object *ob) -{ - int i, totmat = ob->totcol + 1; /* materials start from 1, default material is 0 */ - - if (dm->totmat != totmat) { - dm->totmat = totmat; - /* invalidate old materials */ - if (dm->mat) - MEM_freeN(dm->mat); - - dm->mat = MEM_malloc_arrayN(totmat, sizeof(*dm->mat), "DerivedMesh.mat"); - } - - /* we leave last material as empty - rationale here is being able to index - * the materials by using the mf->mat_nr directly and leaving the last - * material as NULL in case no materials exist on mesh, so indexing will not fail */ - for (i = 0; i < totmat - 1; i++) { - dm->mat[i] = give_current_material(ob, i + 1); - } - dm->mat[i] = NULL; -} - -MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr) -{ - MLoopUV *uv_base; - - BLI_assert(mat_nr < dm->totmat); - - if (dm->mat[mat_nr] && dm->mat[mat_nr]->texpaintslot && - dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname) - { - uv_base = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, - dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname); - /* This can fail if we have changed the name in the UV layer list and have assigned the old name in the material - * texture slot.*/ - if (!uv_base) - uv_base = CustomData_get_layer(&dm->loopData, CD_MLOOPUV); - } - else { - uv_base = CustomData_get_layer(&dm->loopData, CD_MLOOPUV); - } - - return uv_base; -} - void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool take_ownership) { /* dm might depend on me, so we need to do everything with a local copy */ Mesh tmp = *me; int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly; int did_shapekeys = 0; - int alloctype = CD_DUPLICATE; + eCDAllocType alloctype = CD_DUPLICATE; if (take_ownership && dm->type == DM_TYPE_CDDM && dm->needsFree) { bool has_any_referenced_layers = @@ -754,6 +537,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool CustomData_copy(&dm->loopData, &tmp.ldata, mask, alloctype, totloop); CustomData_copy(&dm->polyData, &tmp.pdata, mask, alloctype, totpoly); tmp.cd_flag = dm->cd_flag; + tmp.runtime.deformed_only = dm->deformedOnly; if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) { KeyBlock *kb; @@ -831,8 +615,9 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool * stack */ if (tmp.totvert != me->totvert && !did_shapekeys && me->key) { printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name); - if (tmp.key) + if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) { id_us_min(&tmp.key->id); + } tmp.key = NULL; } @@ -859,26 +644,18 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool } } -void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb) +/** Utility function to convert an (evaluated) Mesh to a shape key block. */ +/* Just a shallow wrapper around BKE_keyblock_convert_from_mesh, + * that ensures both evaluated mesh and original one has same number of vertices. */ +void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb) { - int a, totvert = dm->getNumVerts(dm); - float *fp; - MVert *mvert; + const int totvert = me_deformed->totvert; if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) { return; } - if (kb->data) MEM_freeN(kb->data); - kb->data = MEM_malloc_arrayN(me->key->elemsize, me->totvert, "kb->data"); - kb->totelem = totvert; - - fp = kb->data; - mvert = dm->getVertDataArray(dm, CD_MVERT); - - for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) { - copy_v3_v3(fp, mvert->co); - } + BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb); } /** @@ -900,27 +677,41 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask) #endif } -void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +static void mesh_set_only_copy(Mesh *mesh, CustomDataMask mask) +{ + CustomData_set_only_copy(&mesh->vdata, mask); + CustomData_set_only_copy(&mesh->edata, mask); + CustomData_set_only_copy(&mesh->fdata, mask); + /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with + * weight paint mode when there are modifiers applied, needs further investigation, + * see replies to r50969, Campbell */ +#if 0 + CustomData_set_only_copy(&mesh->ldata, mask); + CustomData_set_only_copy(&mesh->pdata, mask); +#endif +} + +void DM_add_vert_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) { CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData); } -void DM_add_edge_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) { CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData); } -void DM_add_tessface_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +void DM_add_tessface_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) { CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData); } -void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) { CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData); } -void DM_add_poly_layer(DerivedMesh *dm, int type, int alloctype, void *layer) +void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer) { CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData); } @@ -1109,11 +900,6 @@ void DM_interp_tessface_data( weights, (float *)vert_weights, count, dest_index); } -void DM_swap_tessface_data(DerivedMesh *dm, int index, const int *corner_indices) -{ - CustomData_swap_corners(&dm->faceData, index, corner_indices); -} - void DM_interp_loop_data( DerivedMesh *source, DerivedMesh *dest, int *src_indices, @@ -1146,56 +932,6 @@ DerivedMesh *mesh_create_derived(Mesh *me, float (*vertCos)[3]) return dm; } -DerivedMesh *mesh_create_derived_for_modifier( - Scene *scene, Object *ob, - ModifierData *md, int build_shapekey_layers) -{ - Mesh *me = ob->data; - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - DerivedMesh *dm; - KeyBlock *kb; - - md->scene = scene; - - if (!(md->mode & eModifierMode_Realtime)) { - return NULL; - } - - if (mti->isDisabled && mti->isDisabled(md, 0)) { - return NULL; - } - - if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) { - BKE_keyblock_convert_to_mesh(kb, me); - } - - if (mti->type == eModifierTypeType_OnlyDeform) { - int numVerts; - float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts); - - modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, 0); - dm = mesh_create_derived(me, deformedVerts); - - if (build_shapekey_layers) - add_shapekey_layers(dm, me, ob); - - MEM_freeN(deformedVerts); - } - else { - DerivedMesh *tdm = mesh_create_derived(me, NULL); - - if (build_shapekey_layers) - add_shapekey_layers(tdm, me, ob); - - dm = modwrap_applyModifier(md, ob, tdm, 0); - ASSERT_IS_VALID_DM(dm); - - if (tdm != dm) tdm->release(tdm); - } - - return dm; -} - static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3] { BMIter iter; @@ -1216,7 +952,7 @@ static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3] } /* orco custom data layer */ -static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free))[3] +static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free))[3] { *free = 0; @@ -1247,386 +983,77 @@ static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *fr return NULL; } -static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em, int layer) +static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer) { - DerivedMesh *dm; + Mesh *mesh; float (*orco)[3]; int free; if (em) { - dm = CDDM_from_editbmesh(em, false, false); + mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0); } else { - dm = CDDM_from_mesh(me); + mesh = BKE_mesh_copy_for_eval(me, true); } - orco = get_orco_coords_dm(ob, em, layer, &free); + orco = get_orco_coords(ob, em, layer, &free); if (orco) { - CDDM_apply_vert_coords(dm, orco); + BKE_mesh_apply_vert_coords(mesh, orco); if (free) MEM_freeN(orco); } - return dm; + return mesh; } -static void add_orco_dm( - Object *ob, BMEditMesh *em, DerivedMesh *dm, - DerivedMesh *orcodm, int layer) +static void add_orco_mesh( + Object *ob, BMEditMesh *em, Mesh *mesh, + Mesh *me_orco, int layer) { float (*orco)[3], (*layerorco)[3]; int totvert, free; - totvert = dm->getNumVerts(dm); + totvert = mesh->totvert; - if (orcodm) { - orco = MEM_calloc_arrayN(totvert, sizeof(float[3]), "dm orco"); + if (me_orco) { free = 1; - if (orcodm->getNumVerts(orcodm) == totvert) - orcodm->getVertCos(orcodm, orco); - else - dm->getVertCos(dm, orco); - } - else - orco = get_orco_coords_dm(ob, em, layer, &free); - - if (orco) { - if (layer == CD_ORCO) - BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0); - - if (!(layerorco = DM_get_vert_data_layer(dm, layer))) { - DM_add_vert_layer(dm, layer, CD_CALLOC, NULL); - layerorco = DM_get_vert_data_layer(dm, layer); - } - - memcpy(layerorco, orco, sizeof(float) * 3 * totvert); - if (free) MEM_freeN(orco); - } -} - -/* weight paint colors */ - -/* Something of a hack, at the moment deal with weightpaint - * by tucking into colors during modifier eval, only in - * wpaint mode. Works ok but need to make sure recalc - * happens on enter/exit wpaint. - */ - -void weight_to_rgb(float r_rgb[3], const float weight) -{ - const float blend = ((weight / 2.0f) + 0.5f); - - if (weight <= 0.25f) { /* blue->cyan */ - r_rgb[0] = 0.0f; - r_rgb[1] = blend * weight * 4.0f; - r_rgb[2] = blend; - } - else if (weight <= 0.50f) { /* cyan->green */ - r_rgb[0] = 0.0f; - r_rgb[1] = blend; - r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f)); - } - else if (weight <= 0.75f) { /* green->yellow */ - r_rgb[0] = blend * ((weight - 0.50f) * 4.0f); - r_rgb[1] = blend; - r_rgb[2] = 0.0f; - } - else if (weight <= 1.0f) { /* yellow->red */ - r_rgb[0] = blend; - r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f)); - r_rgb[2] = 0.0f; - } - else { - /* exceptional value, unclamped or nan, - * avoid uninitialized memory use */ - r_rgb[0] = 1.0f; - r_rgb[1] = 0.0f; - r_rgb[2] = 1.0f; - } -} - -/* draw_flag's for calc_weightpaint_vert_color */ -enum { - /* only one of these should be set, keep first (for easy bit-shifting) */ - CALC_WP_GROUP_USER_ACTIVE = (1 << 1), - CALC_WP_GROUP_USER_ALL = (1 << 2), - - CALC_WP_MULTIPAINT = (1 << 3), - CALC_WP_AUTO_NORMALIZE = (1 << 4), - CALC_WP_MIRROR_X = (1 << 5), -}; - -typedef struct DMWeightColorInfo { - const ColorBand *coba; - const char *alert_color; -} DMWeightColorInfo; - - -static int dm_drawflag_calc(const ToolSettings *ts, const Mesh *me) -{ - return ((ts->multipaint ? CALC_WP_MULTIPAINT : 0) | - /* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL */ - (1 << ts->weightuser) | - (ts->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0) | - ((me->editflag & ME_EDIT_MIRROR_X) ? CALC_WP_MIRROR_X : 0)); -} - -static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcinfo, const float input) -{ - float colf[4]; - - if (dm_wcinfo && dm_wcinfo->coba) { - BKE_colorband_evaluate(dm_wcinfo->coba, input, colf); - } - else { - weight_to_rgb(colf, input); - } - - /* don't use rgb_float_to_uchar() here because - * the resulting float doesn't need 0-1 clamp check */ - r_col[0] = (unsigned char)(colf[0] * 255.0f); - r_col[1] = (unsigned char)(colf[1] * 255.0f); - r_col[2] = (unsigned char)(colf[2] * 255.0f); - r_col[3] = 255; -} - - -static void calc_weightpaint_vert_color( - unsigned char r_col[4], - const MDeformVert *dv, - DMWeightColorInfo *dm_wcinfo, - const int defbase_tot, const int defbase_act, - const bool *defbase_sel, const int defbase_sel_tot, - const int draw_flag) -{ - float input = 0.0f; - - bool show_alert_color = false; - - if ((defbase_sel_tot > 1) && (draw_flag & CALC_WP_MULTIPAINT)) { - /* Multi-Paint feature */ - input = BKE_defvert_multipaint_collective_weight( - dv, defbase_tot, defbase_sel, defbase_sel_tot, (draw_flag & CALC_WP_AUTO_NORMALIZE) != 0); - - /* make it black if the selected groups have no weight on a vertex */ - if (input == 0.0f) { - show_alert_color = true; - } - } - else { - /* default, non tricky behavior */ - input = defvert_find_weight(dv, defbase_act); - - if (draw_flag & CALC_WP_GROUP_USER_ACTIVE) { - if (input == 0.0f) { - show_alert_color = true; - } - } - else if (draw_flag & CALC_WP_GROUP_USER_ALL) { - if (input == 0.0f) { - show_alert_color = defvert_is_weight_zero(dv, defbase_tot); - } - } - } - - if (show_alert_color == false) { - CLAMP(input, 0.0f, 1.0f); - weightpaint_color(r_col, dm_wcinfo, input); - } - else { - copy_v3_v3_char((char *)r_col, dm_wcinfo->alert_color); - r_col[3] = 255; - } -} - -static DMWeightColorInfo G_dm_wcinfo; - -void vDM_ColorBand_store(const ColorBand *coba, const char alert_color[4]) -{ - G_dm_wcinfo.coba = coba; - G_dm_wcinfo.alert_color = alert_color; -} - -/** - * return an array of vertex weight colors, caller must free. - * - * \note that we could save some memory and allocate RGB only but then we'd need to - * re-arrange the colors when copying to the face since MCol has odd ordering, - * so leave this as is - campbell - */ -static void calc_weightpaint_vert_array( - Object *ob, DerivedMesh *dm, int const draw_flag, DMWeightColorInfo *dm_wcinfo, - unsigned char (*r_wtcol_v)[4]) -{ - BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL; - const int numVerts = dm->getNumVerts(dm); - - if ((ob->actdef != 0) && - (CustomData_has_layer(em ? &em->bm->vdata : &dm->vertData, CD_MDEFORMVERT))) - { - unsigned char (*wc)[4] = r_wtcol_v; - unsigned int i; - - /* variables for multipaint */ - const int defbase_tot = BLI_listbase_count(&ob->defbase); - const int defbase_act = ob->actdef - 1; - - int defbase_sel_tot = 0; - bool *defbase_sel = NULL; - - if (draw_flag & CALC_WP_MULTIPAINT) { - defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_sel_tot); - - if (defbase_sel_tot > 1 && (draw_flag & CALC_WP_MIRROR_X)) { - BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_sel_tot); - } - } - - /* editmesh won't have deform verts unless modifiers require it, - * avoid having to create an array of deform-verts only for drawing - * by reading from the bmesh directly. */ - if (em) { - BMIter iter; - BMVert *eve; - const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - BLI_assert(cd_dvert_offset != -1); - - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - calc_weightpaint_vert_color( - (unsigned char *)wc, dv, dm_wcinfo, - defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); - wc++; - } + if (me_orco->totvert == totvert) { + orco = BKE_mesh_vertexCos_get(me_orco, NULL); } else { - const MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT); - for (i = numVerts; i != 0; i--, wc++, dv++) { - calc_weightpaint_vert_color( - (unsigned char *)wc, dv, dm_wcinfo, - defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); - } - } - - if (defbase_sel) { - MEM_freeN(defbase_sel); + orco = BKE_mesh_vertexCos_get(mesh, NULL); } } else { - unsigned char col[4]; - if ((ob->actdef == 0) && !BLI_listbase_is_empty(&ob->defbase)) { - /* color-code for missing data (full brightness isn't easy on the eye). */ - ARRAY_SET_ITEMS(col, 0xa0, 0, 0xa0, 0xff); - } - else if (draw_flag & (CALC_WP_GROUP_USER_ACTIVE | CALC_WP_GROUP_USER_ALL)) { - copy_v3_v3_char((char *)col, dm_wcinfo->alert_color); - col[3] = 255; - } - else { - weightpaint_color(col, dm_wcinfo, 0.0f); - } - copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col)); + /* TODO(sybren): totvert should potentially change here, as ob->data + * or em may have a different number of vertices than dm. */ + orco = get_orco_coords(ob, em, layer, &free); } -} -/** return an array of vertex weight colors from given weights, caller must free. - * - * \note that we could save some memory and allocate RGB only but then we'd need to - * re-arrange the colors when copying to the face since MCol has odd ordering, - * so leave this as is - campbell - */ -static void calc_colors_from_weights_array( - const int num, const float *weights, - unsigned char (*r_wtcol_v)[4]) -{ - unsigned char (*wc)[4] = r_wtcol_v; - int i; - - for (i = 0; i < num; i++, wc++, weights++) { - weightpaint_color((unsigned char *)wc, NULL, *weights); - } -} - -void DM_update_weight_mcol( - Object *ob, DerivedMesh *dm, int const draw_flag, - float *weights, int num, const int *indices) -{ - BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL; - unsigned char (*wtcol_v)[4]; - int numVerts = dm->getNumVerts(dm); - int i; - - if (em) { - BKE_editmesh_color_ensure(em, BM_VERT); - wtcol_v = em->derivedVertColor; - } - else { - wtcol_v = MEM_malloc_arrayN(numVerts, sizeof(*wtcol_v), __func__); - } - - /* Weights are given by caller. */ - if (weights) { - float *w = weights; - /* If indices is not NULL, it means we do not have weights for all vertices, - * so we must create them (and set them to zero)... */ - if (indices) { - w = MEM_calloc_arrayN(numVerts, sizeof(float), "Temp weight array DM_update_weight_mcol"); - i = num; - while (i--) - w[indices[i]] = weights[i]; - } - - /* Convert float weights to colors. */ - calc_colors_from_weights_array(numVerts, w, wtcol_v); - - if (indices) - MEM_freeN(w); - } - else { - /* No weights given, take them from active vgroup(s). */ - calc_weightpaint_vert_array(ob, dm, draw_flag, &G_dm_wcinfo, wtcol_v); - } - - if (dm->type == DM_TYPE_EDITBMESH) { - /* editmesh draw function checks specifically for this */ - } - else { - const int dm_totpoly = dm->getNumPolys(dm); - const int dm_totloop = dm->getNumLoops(dm); - unsigned char(*wtcol_l)[4] = CustomData_get_layer(dm->getLoopDataLayout(dm), CD_PREVIEW_MLOOPCOL); - MLoop *mloop = dm->getLoopArray(dm), *ml; - MPoly *mp = dm->getPolyArray(dm); - int l_index; - int j; - - /* now add to loops, so the data can be passed through the modifier stack - * If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */ - if (!wtcol_l) { - wtcol_l = MEM_malloc_arrayN(dm_totloop, sizeof(*wtcol_l), __func__); - CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, dm_totloop); + if (orco) { + if (layer == CD_ORCO) { + BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0); } - l_index = 0; - for (i = 0; i < dm_totpoly; i++, mp++) { - ml = mloop + mp->loopstart; + if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) { + CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert); + BKE_mesh_update_customdata_pointers(mesh, false); - for (j = 0; j < mp->totloop; j++, ml++, l_index++) { - copy_v4_v4_uchar(&wtcol_l[l_index][0], - &wtcol_v[ml->v][0]); - } + layerorco = CustomData_get_layer(&mesh->vdata, layer); } - MEM_freeN(wtcol_v); - dm->dirty |= DM_DIRTY_TESS_CDLAYERS; + memcpy(layerorco, orco, sizeof(float) * 3 * totvert); + if (free) MEM_freeN(orco); } } -static void DM_update_statvis_color(const Scene *scene, Object *ob, DerivedMesh *dm) +static void editmesh_update_statvis_color(const Scene *scene, Object *ob) { BMEditMesh *em = BKE_editmesh_from_object(ob); - - BKE_editmesh_statvis_calc(em, dm, &scene->toolsettings->statvis); + Mesh *me = ob->data; + BKE_mesh_runtime_ensure_edit_data(me); + BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis); } static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid) @@ -1685,20 +1112,20 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape } } -static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob)) +static void add_shapekey_layers(Mesh *me_dst, Mesh *me_src, Object *UNUSED(ob)) { KeyBlock *kb; - Key *key = me->key; + Key *key = me_src->key; int i; - if (!me->key) + if (!me_src->key) return; /* ensure we can use mesh vertex count for derived mesh custom data */ - if (me->totvert != dm->getNumVerts(dm)) { + if (me_src->totvert != me_dst->totvert) { fprintf(stderr, - "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n", - __func__, me->id.name + 2, me->totvert, dm->getNumVerts(dm)); + "%s: vertex size mismatch (mesh/eval) '%s' (%d != %d)\n", + __func__, me_src->id.name + 2, me_src->totvert, me_dst->totvert); return; } @@ -1706,131 +1133,79 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob)) int ci; float *array; - if (me->totvert != kb->totelem) { + if (me_src->totvert != kb->totelem) { fprintf(stderr, "%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n", - __func__, me->id.name + 2, me->totvert, kb->name, kb->totelem); - array = MEM_calloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__); + __func__, me_src->id.name + 2, me_src->totvert, kb->name, kb->totelem); + array = MEM_calloc_arrayN((size_t)me_src->totvert, sizeof(float[3]), __func__); } else { - array = MEM_malloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__); - memcpy(array, kb->data, (size_t)me->totvert * 3 * sizeof(float)); + array = MEM_malloc_arrayN((size_t)me_src->totvert, sizeof(float[3]), __func__); + memcpy(array, kb->data, (size_t)me_src->totvert * sizeof(float[3])); } - CustomData_add_layer_named(&dm->vertData, CD_SHAPEKEY, CD_ASSIGN, array, dm->numVertData, kb->name); - ci = CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i); + CustomData_add_layer_named(&me_dst->vdata, CD_SHAPEKEY, CD_ASSIGN, array, me_dst->totvert, kb->name); + ci = CustomData_get_layer_index_n(&me_dst->vdata, CD_SHAPEKEY, i); - dm->vertData.layers[ci].uid = kb->uid; + me_dst->vdata.layers[ci].uid = kb->uid; } } -/** - * Called after calculating all modifiers. - * - * \note tessfaces should already be calculated. - */ -static void dm_ensure_display_normals(DerivedMesh *dm) -{ - /* Note: dm *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.). - * We do not use it here, though. And it should be tagged as temp! - */ - /* BLI_assert((CustomData_has_layer(&dm->polyData, CD_NORMAL) == false)); */ - - if ((dm->type == DM_TYPE_CDDM) && - ((dm->dirty & DM_DIRTY_NORMALS) || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false)) - { - /* if normals are dirty we want to calculate vertex normals too */ - CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true); - } -} - -/** - * new value for useDeform -1 (hack for the gameengine): - * - * - apply only the modifier stack of the object, skipping the virtual modifiers, - * - don't apply the key - * - apply deform modifiers and input vertexco - */ static void mesh_calc_modifiers( - Scene *scene, Object *ob, float (*inputVertexCos)[3], - const bool useRenderParams, int useDeform, + struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3], + int useDeform, const bool need_mapping, CustomDataMask dataMask, const int index, const bool useCache, const bool build_shapekey_layers, - const bool allow_gpu, /* return args */ - DerivedMesh **r_deform, DerivedMesh **r_final) + Mesh **r_deform, Mesh **r_final) { - Mesh *me = ob->data; ModifierData *firstmd, *md, *previewmd = NULL; CDMaskLink *datamasks, *curr; /* XXX Always copying POLYINDEX, else tessellated data are no more valid! */ CustomDataMask mask, nextmask, previewmask = 0, append_mask = CD_MASK_ORIGINDEX; float (*deformedVerts)[3] = NULL; - DerivedMesh *dm = NULL, *orcodm, *clothorcodm, *finaldm; - int numVerts = me->totvert; + int numVerts = ((Mesh *)ob->data)->totvert; + const bool useRenderParams = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); const int required_mode = useRenderParams ? eModifierMode_Render : eModifierMode_Realtime; bool isPrevDeform = false; - const bool skipVirtualArmature = (useDeform < 0); MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); const bool has_multires = (mmd && mmd->sculptlvl != 0); bool multires_applied = false; const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !useRenderParams; const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !useRenderParams; - const int draw_flag = dm_drawflag_calc(scene->toolsettings, me); /* Generic preview only in object mode! */ const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT); -#if 0 /* XXX Will re-enable this when we have global mod stack options. */ - const bool do_final_wmcol = (scene->toolsettings->weights_preview == WP_WPREVIEW_FINAL) && do_wmcol; -#endif - const bool do_final_wmcol = false; - const bool do_init_wmcol = ((dataMask & CD_MASK_PREVIEW_MLOOPCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT) && !do_final_wmcol); - /* XXX Same as above... For now, only weights preview in WPaint mode. */ - const bool do_mod_wmcol = do_init_wmcol; - - const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH) != 0; - const float loop_normals_split_angle = me->smoothresh; + const bool do_loop_normals = (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) != 0; VirtualModifierData virtualModifierData; ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0; ModifierApplyFlag deform_app_flags = app_flags; + BLI_assert((((Mesh *)ob->data)->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); if (useCache) app_flags |= MOD_APPLY_USECACHE; - if (allow_gpu) - app_flags |= MOD_APPLY_ALLOW_GPU; if (useDeform) deform_app_flags |= MOD_APPLY_USECACHE; - if (!skipVirtualArmature) { - firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); - } - else { - /* game engine exception */ - firstmd = ob->modifiers.first; - if (firstmd && firstmd->type == eModifierType_Armature) - firstmd = firstmd->next; - } + /* TODO(sybren): do we really need three context objects? Or do we modify + * them on the fly to change the flags where needed? */ + const ModifierEvalContext mectx_deform = {depsgraph, ob, deform_app_flags}; + const ModifierEvalContext mectx_apply = {depsgraph, ob, app_flags}; + const ModifierEvalContext mectx_orco = {depsgraph, ob, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO}; - md = firstmd; + md = firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); modifiers_clearErrors(ob); - if (do_mod_wmcol || do_mod_mcol) { + if (do_mod_mcol) { /* Find the last active modifier generating a preview, or NULL if none. */ /* XXX Currently, DPaint modifier just ignores this. * Needs a stupid hack... * The whole "modifier preview" thing has to be (re?)designed, anyway! */ previewmd = modifiers_getLastPreview(scene, md, required_mode); - - /* even if the modifier doesn't need the data, to make a preview it may */ - if (previewmd) { - if (do_mod_wmcol) { - previewmask = CD_MASK_MDEFORMVERT; - } - } } datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, previewmask); @@ -1849,8 +1224,6 @@ static void mesh_calc_modifiers( for (; md; md = md->next, curr = curr->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - if (!modifier_isEnabled(scene, md, required_mode)) { continue; } @@ -1861,9 +1234,9 @@ static void mesh_calc_modifiers( if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) { if (!deformedVerts) - deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); + deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts); - modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, deform_app_flags); + modwrap_deformVerts(md, &mectx_deform, NULL, deformedVerts, numVerts); } else { break; @@ -1879,13 +1252,16 @@ static void mesh_calc_modifiers( * coordinates (vpaint, etc.) */ if (r_deform) { - *r_deform = CDDM_from_mesh(me); + *r_deform = BKE_mesh_copy_for_eval(ob->data, true); - if (build_shapekey_layers) - add_shapekey_layers(dm, me, ob); + /* XXX: Is build_shapekey_layers ever even true? This should have crashed long ago... */ + BLI_assert(!build_shapekey_layers); + if (build_shapekey_layers) { + add_shapekey_layers(*r_deform, ob->data, ob); + } if (deformedVerts) { - CDDM_apply_vert_coords(*r_deform, deformedVerts); + BKE_mesh_apply_vert_coords(*r_deform, deformedVerts); } } } @@ -1894,22 +1270,20 @@ static void mesh_calc_modifiers( if (inputVertexCos) deformedVerts = inputVertexCos; else - deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); + deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts); } /* Now apply all remaining modifiers. If useDeform is off then skip * OnlyDeform ones. */ - dm = NULL; - orcodm = NULL; - clothorcodm = NULL; + Mesh *me = NULL; + Mesh *me_orco = NULL; + Mesh *me_orco_cloth = NULL; for (; md; md = md->next, curr = curr->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - if (!modifier_isEnabled(scene, md, required_mode)) { continue; } @@ -1918,7 +1292,7 @@ static void mesh_calc_modifiers( continue; } - if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { + if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && me) { modifier_setError(md, "Modifier requires original data, bad stack position"); continue; } @@ -1969,29 +1343,27 @@ static void mesh_calc_modifiers( else mask = 0; - if (dm && (mask & CD_MASK_ORCO)) - add_orco_dm(ob, NULL, dm, orcodm, CD_ORCO); + if (me && (mask & CD_MASK_ORCO)) { + add_orco_mesh(ob, NULL, me, me_orco, CD_ORCO); + } /* How to apply modifier depends on (a) what we already have as - * a result of previous modifiers (could be a DerivedMesh or just + * a result of previous modifiers (could be a Mesh or just * deformed vertices) and (b) what type the modifier is. */ if (mti->type == eModifierTypeType_OnlyDeform) { /* No existing verts to deform, need to build them. */ if (!deformedVerts) { - if (dm) { - /* Deforming a derived mesh, read the vertex locations + if (me) { + /* Deforming a mesh, read the vertex locations * out of the mesh and deform them. Once done with this * run of deformers verts will be written back. */ - numVerts = dm->getNumVerts(dm); - deformedVerts = - MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv"); - dm->getVertCos(dm, deformedVerts); + deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); } else { - deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); + deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts); } } @@ -1999,46 +1371,38 @@ static void mesh_calc_modifiers( * to avoid giving bogus normals to the next modifier see: [#23673] */ if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { /* XXX, this covers bug #23673, but we may need normal calc for other types */ - if (dm && dm->type == DM_TYPE_CDDM) { - CDDM_apply_vert_coords(dm, deformedVerts); + if (me) { + BKE_mesh_apply_vert_coords(me, deformedVerts); } } - modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, deform_app_flags); + modwrap_deformVerts(md, &mectx_deform, me, deformedVerts, numVerts); } else { - DerivedMesh *ndm; - /* determine which data layers are needed by following modifiers */ if (curr->next) nextmask = curr->next->mask; else nextmask = dataMask; - /* apply vertex coordinates or build a DerivedMesh as necessary */ - if (dm) { + /* apply vertex coordinates or build a Mesh as necessary */ + if (me) { if (deformedVerts) { - DerivedMesh *tdm = CDDM_copy(dm); - dm->release(dm); - dm = tdm; - - CDDM_apply_vert_coords(dm, deformedVerts); + BKE_mesh_apply_vert_coords(me, deformedVerts); } } else { - dm = CDDM_from_mesh(me); - ASSERT_IS_VALID_DM(dm); + me = BKE_mesh_copy_for_eval(ob->data, true); + ASSERT_IS_VALID_MESH(me); - if (build_shapekey_layers) - add_shapekey_layers(dm, me, ob); + if (build_shapekey_layers) { + add_shapekey_layers(me, ob->data, ob); + } if (deformedVerts) { - CDDM_apply_vert_coords(dm, deformedVerts); + BKE_mesh_apply_vert_coords(me, deformedVerts); } - if (do_init_wmcol) - DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL); - /* Constructive modifiers need to have an origindex * otherwise they wont have anywhere to copy the data from. * @@ -2048,91 +1412,101 @@ static void mesh_calc_modifiers( */ if (need_mapping || (nextmask & CD_MASK_ORIGINDEX)) { /* calc */ - DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); - DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); - DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); + CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totvert); + CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totedge); + CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totpoly); /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */ - 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); + range_vn_i(CustomData_get_layer(&me->vdata, CD_ORIGINDEX), me->totvert, 0); + range_vn_i(CustomData_get_layer(&me->edata, CD_ORIGINDEX), me->totedge, 0); + range_vn_i(CustomData_get_layer(&me->pdata, CD_ORIGINDEX), me->totpoly, 0); } } - /* set the DerivedMesh to only copy needed data */ + /* set the Mesh to only copy needed data */ mask = curr->mask; /* needMapping check here fixes bug [#28112], otherwise it's * possible that it won't be copied */ mask |= append_mask; - DM_set_only_copy(dm, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0)); + mesh_set_only_copy(me, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0)); /* add cloth rest shape key if needed */ if (mask & CD_MASK_CLOTH_ORCO) - add_orco_dm(ob, NULL, dm, clothorcodm, CD_CLOTH_ORCO); + add_orco_mesh(ob, NULL, me, me_orco, CD_CLOTH_ORCO); /* add an origspace layer if needed */ if ((curr->mask) & CD_MASK_ORIGSPACE_MLOOP) { - if (!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) { - DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL); - DM_init_origspace(dm); + if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) { + CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop); + mesh_init_origspace(me); } } - ndm = modwrap_applyModifier(md, ob, dm, app_flags); - ASSERT_IS_VALID_DM(ndm); - - if (ndm) { - /* if the modifier returned a new dm, release the old one */ - if (dm && dm != ndm) dm->release(dm); + Mesh *me_next = modwrap_applyModifier(md, &mectx_apply, me); + ASSERT_IS_VALID_MESH(me_next); - dm = ndm; + if (me_next) { + /* if the modifier returned a new mesh, release the old one */ + if (me && me != me_next) { + BLI_assert(me != ob->data); + BKE_id_free(NULL, me); + } + me = me_next; if (deformedVerts) { - if (deformedVerts != inputVertexCos) + if (deformedVerts != inputVertexCos) { MEM_freeN(deformedVerts); - + } deformedVerts = NULL; } } - /* create an orco derivedmesh in parallel */ + /* create an orco mesh in parallel */ if (nextmask & CD_MASK_ORCO) { - if (!orcodm) - orcodm = create_orco_dm(ob, me, NULL, CD_ORCO); + if (!me_orco) { + me_orco = create_orco_mesh(ob, ob->data, NULL, CD_ORCO); + } nextmask &= ~CD_MASK_ORCO; - DM_set_only_copy(orcodm, nextmask | CD_MASK_ORIGINDEX | + mesh_set_only_copy(me_orco, nextmask | CD_MASK_ORIGINDEX | (mti->requiredDataMask ? mti->requiredDataMask(ob, md) : 0)); - ndm = modwrap_applyModifier(md, ob, orcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO); - ASSERT_IS_VALID_DM(ndm); + me_next = modwrap_applyModifier(md, &mectx_orco, me_orco); + ASSERT_IS_VALID_MESH(me_next); - if (ndm) { - /* if the modifier returned a new dm, release the old one */ - if (orcodm && orcodm != ndm) orcodm->release(orcodm); - orcodm = ndm; + if (me_next) { + /* if the modifier returned a new mesh, release the old one */ + if (me_orco && me_orco != me_next) { + BLI_assert(me_orco != ob->data); + BKE_id_free(NULL, me_orco); + } + + me_orco = me_next; } } - /* create cloth orco derivedmesh in parallel */ + /* create cloth orco mesh in parallel */ if (nextmask & CD_MASK_CLOTH_ORCO) { - if (!clothorcodm) - clothorcodm = create_orco_dm(ob, me, NULL, CD_CLOTH_ORCO); + if (!me_orco_cloth) { + me_orco_cloth = create_orco_mesh(ob, ob->data, NULL, CD_CLOTH_ORCO); + } nextmask &= ~CD_MASK_CLOTH_ORCO; - DM_set_only_copy(clothorcodm, nextmask | CD_MASK_ORIGINDEX); + mesh_set_only_copy(me_orco_cloth, nextmask | CD_MASK_ORIGINDEX); - ndm = modwrap_applyModifier(md, ob, clothorcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO); - ASSERT_IS_VALID_DM(ndm); + me_next = modwrap_applyModifier(md, &mectx_orco, me_orco_cloth); + ASSERT_IS_VALID_DM(me_next); - if (ndm) { - /* if the modifier returned a new dm, release the old one */ - if (clothorcodm && clothorcodm != ndm) { - clothorcodm->release(clothorcodm); + if (me_next) { + /* if the modifier returned a new mesh, release the old one */ + if (me_orco_cloth && me_orco_cloth != me_next) { + BLI_assert(me_orco != ob->data); + BKE_id_free(NULL, me_orco_cloth); } - clothorcodm = ndm; + + me_orco_cloth = me_next; } } @@ -2140,13 +1514,8 @@ static void mesh_calc_modifiers( /* XXX Temp and hackish solution! */ if (md->type == eModifierType_DynamicPaint) append_mask |= CD_MASK_PREVIEW_MLOOPCOL; - /* In case of active preview modifier, make sure preview mask remains for following modifiers. */ - else if ((md == previewmd) && (do_mod_wmcol)) { - DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL); - append_mask |= CD_MASK_PREVIEW_MLOOPCOL; - } - dm->deformedOnly = false; + me->runtime.deformed_only = false; } isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform); @@ -2163,65 +1532,47 @@ static void mesh_calc_modifiers( for (md = firstmd; md; md = md->next) modifier_freeTemporaryData(md); - /* Yay, we are done. If we have a DerivedMesh and deformed vertices - * need to apply these back onto the DerivedMesh. If we have no - * DerivedMesh then we need to build one. + /* Yay, we are done. If we have a Mesh and deformed vertices + * need to apply these back onto the Mesh. If we have no + * Mesh then we need to build one. */ - if (dm && deformedVerts) { - finaldm = CDDM_copy(dm); - - dm->release(dm); - - CDDM_apply_vert_coords(finaldm, deformedVerts); - -#if 0 /* For later nice mod preview! */ - /* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */ - if (do_final_wmcol) - DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL); -#endif - } - else if (dm) { - finaldm = dm; + if (me) { + *r_final = me; -#if 0 /* For later nice mod preview! */ - /* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */ - if (do_final_wmcol) - DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL); -#endif + if (deformedVerts) { + BKE_mesh_apply_vert_coords(*r_final, deformedVerts); + } } else { - finaldm = CDDM_from_mesh(me); + *r_final = BKE_mesh_copy_for_eval(ob->data, true); if (build_shapekey_layers) { - add_shapekey_layers(finaldm, me, ob); + add_shapekey_layers(*r_final, ob->data, ob); } if (deformedVerts) { - CDDM_apply_vert_coords(finaldm, deformedVerts); + BKE_mesh_apply_vert_coords(*r_final, deformedVerts); } - - /* In this case, we should never have weight-modifying modifiers in stack... */ - if (do_init_wmcol) - DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL); } /* add an orco layer if needed */ if (dataMask & CD_MASK_ORCO) { - add_orco_dm(ob, NULL, finaldm, orcodm, CD_ORCO); + add_orco_mesh(ob, NULL, *r_final, me_orco, CD_ORCO); if (r_deform && *r_deform) - add_orco_dm(ob, NULL, *r_deform, NULL, CD_ORCO); + add_orco_mesh(ob, NULL, *r_deform, NULL, CD_ORCO); } if (do_loop_normals) { /* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */ - DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle); + BKE_mesh_calc_normals_split(*r_final); + BKE_mesh_tessface_clear(*r_final); } if (sculpt_dyntopo == false) { /* watch this! after 2.75a we move to from tessface to looptri (by default) */ if (dataMask & CD_MASK_MFACE) { - DM_ensure_tessface(finaldm); + BKE_mesh_tessface_ensure(*r_final); } /* without this, drawing ngon tri's faces will show ugly tessellated face @@ -2234,36 +1585,22 @@ static void mesh_calc_modifiers( * If using loop normals, poly nors have already been computed. */ if (!do_loop_normals) { - dm_ensure_display_normals(finaldm); + BKE_mesh_ensure_normals_for_display(*r_final); } } /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them, * as they are used by display code when available (i.e. even if autosmooth is disabled). */ - if (!do_loop_normals && CustomData_has_layer(&finaldm->loopData, CD_NORMAL)) { - CustomData_free_layers(&finaldm->loopData, CD_NORMAL, finaldm->numLoopData); + if (!do_loop_normals && CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) { + CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop); } -#ifdef WITH_GAMEENGINE - /* NavMesh - this is a hack but saves having a NavMesh modifier */ - if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) { - DerivedMesh *tdm; - tdm = navmesh_dm_createNavMeshForVisualization(finaldm); - if (finaldm != tdm) { - finaldm->release(finaldm); - finaldm = tdm; - } - - DM_ensure_tessface(finaldm); + if (me_orco) { + BKE_id_free(NULL, me_orco); + } + if (me_orco_cloth) { + BKE_id_free(NULL, me_orco_cloth); } -#endif /* WITH_GAMEENGINE */ - - *r_final = finaldm; - - if (orcodm) - orcodm->release(orcodm); - if (clothorcodm) - clothorcodm->release(clothorcodm); if (deformedVerts && deformedVerts != inputVertexCos) MEM_freeN(deformedVerts); @@ -2271,6 +1608,30 @@ static void mesh_calc_modifiers( BLI_linklist_free((LinkNode *)datamasks, NULL); } +static void mesh_calc_modifiers_dm( + struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3], + int useDeform, + const bool need_mapping, CustomDataMask dataMask, + const int index, const bool useCache, const bool build_shapekey_layers, + /* return args */ + DerivedMesh **r_deformdm, DerivedMesh **r_finaldm) +{ + Mesh *deform_mesh = NULL, *final_mesh = NULL; + + mesh_calc_modifiers( + depsgraph, scene, ob, inputVertexCos, useDeform, + need_mapping, dataMask, index, useCache, build_shapekey_layers, + (r_deformdm ? &deform_mesh : NULL), &final_mesh); + + if (deform_mesh) { + *r_deformdm = CDDM_from_mesh_ex(deform_mesh, CD_DUPLICATE, CD_MASK_MESH); + BKE_id_free(NULL, deform_mesh); + } + + *r_finaldm = CDDM_from_mesh_ex(final_mesh, CD_DUPLICATE, CD_MASK_MESH); + BKE_id_free(NULL, final_mesh); +} + float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3] { BMIter iter; @@ -2289,7 +1650,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3] return cos; } -bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm) +bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; @@ -2298,7 +1659,7 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh * return false; } - if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { + if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) { modifier_setError(md, "Modifier requires original data, bad stack position"); return false; } @@ -2307,68 +1668,56 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh * } static void editbmesh_calc_modifiers( - Scene *scene, Object *ob, BMEditMesh *em, - CustomDataMask dataMask, + struct Depsgraph *depsgraph, Scene *scene, Object *ob, + BMEditMesh *em, CustomDataMask dataMask, /* return args */ - DerivedMesh **r_cage, DerivedMesh **r_final) + Mesh **r_cage, Mesh **r_final) { - ModifierData *md, *previewmd = NULL; + ModifierData *md; float (*deformedVerts)[3] = NULL; - CustomDataMask mask = 0, previewmask = 0, append_mask = 0; - DerivedMesh *dm = NULL, *orcodm = NULL; + CustomDataMask mask = 0, append_mask = 0; int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); CDMaskLink *datamasks, *curr; const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; - int draw_flag = dm_drawflag_calc(scene->toolsettings, ob->data); - - // const bool do_mod_mcol = true; // (ob->mode == OB_MODE_OBJECT); -#if 0 /* XXX Will re-enable this when we have global mod stack options. */ - const bool do_final_wmcol = (scene->toolsettings->weights_preview == WP_WPREVIEW_FINAL) && do_wmcol; -#endif - const bool do_final_wmcol = false; - const bool do_init_wmcol = ((((Mesh *)ob->data)->drawflag & ME_DRAWEIGHT) && !do_final_wmcol); - - const bool do_init_statvis = ((((Mesh *)ob->data)->drawflag & ME_DRAW_STATVIS) && !do_init_wmcol); - const bool do_mod_wmcol = do_init_wmcol; + const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */ VirtualModifierData virtualModifierData; + /* TODO(sybren): do we really need multiple objects, or shall we change the flags where needed? */ + const ModifierEvalContext mectx = {depsgraph, ob, 0}; + const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO}; + const ModifierEvalContext mectx_cache = {depsgraph, ob, MOD_APPLY_USECACHE}; + const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH) != 0; - const float loop_normals_split_angle = ((Mesh *)(ob->data))->smoothresh; modifiers_clearErrors(ob); if (r_cage && cageIndex == -1) { - *r_cage = getEditDerivedBMesh(em, ob, dataMask, NULL); + *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, NULL); } md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* copied from mesh_calc_modifiers */ - if (do_mod_wmcol) { - previewmd = modifiers_getLastPreview(scene, md, required_mode); - /* even if the modifier doesn't need the data, to make a preview it may */ - if (previewmd) { - previewmask = CD_MASK_MDEFORMVERT; - } - } - - datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, previewmask); + datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, NULL, 0); curr = datamasks; + + Mesh *me = NULL; + Mesh *me_orco = NULL; + for (i = 0; md; i++, md = md->next, curr = curr->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - - if (!editbmesh_modifier_is_enabled(scene, md, dm)) { + if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) { continue; } /* add an orco layer if needed by this modifier */ - if (dm && mti->requiredDataMask) { + if (me && mti->requiredDataMask) { mask = mti->requiredDataMask(ob, md); - if (mask & CD_MASK_ORCO) - add_orco_dm(ob, em, dm, orcodm, CD_ORCO); + if (mask & CD_MASK_ORCO) { + add_orco_mesh(ob, em, me, me_orco, CD_ORCO); + } } /* How to apply modifier depends on (a) what we already have as @@ -2379,15 +1728,12 @@ static void editbmesh_calc_modifiers( if (mti->type == eModifierTypeType_OnlyDeform) { /* No existing verts to deform, need to build them. */ if (!deformedVerts) { - if (dm) { + if (me) { /* Deforming a derived mesh, read the vertex locations * out of the mesh and deform them. Once done with this * run of deformers verts will be written back. */ - numVerts = dm->getNumVerts(dm); - deformedVerts = - MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv"); - dm->getVertCos(dm, deformedVerts); + deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); } else { deformedVerts = editbmesh_get_vertex_cos(em, &numVerts); @@ -2395,64 +1741,58 @@ static void editbmesh_calc_modifiers( } if (mti->deformVertsEM) - modwrap_deformVertsEM(md, ob, em, dm, deformedVerts, numVerts); + modwrap_deformVertsEM(md, &mectx, em, me, deformedVerts, numVerts); else - modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, 0); + modwrap_deformVerts(md, &mectx, me, deformedVerts, numVerts); } else { - DerivedMesh *ndm; + Mesh *me_next; /* apply vertex coordinates or build a DerivedMesh as necessary */ - if (dm) { + if (me) { if (deformedVerts) { - DerivedMesh *tdm = CDDM_copy(dm); - if (!(r_cage && dm == *r_cage)) { - dm->release(dm); - } - dm = tdm; + Mesh *me_temp = BKE_mesh_copy_for_eval(me, false); - CDDM_apply_vert_coords(dm, deformedVerts); + if (!(r_cage && me == *r_cage)) { + BKE_id_free(NULL, me); + } + me = me_temp; + BKE_mesh_apply_vert_coords(me, deformedVerts); } - else if (r_cage && dm == *r_cage) { - /* dm may be changed by this modifier, so we need to copy it */ - dm = CDDM_copy(dm); + else if (r_cage && me == *r_cage) { + /* 'me' may be changed by this modifier, so we need to copy it. */ + me = BKE_mesh_copy_for_eval(me, false); } } else { - dm = CDDM_from_editbmesh(em, false, false); - ASSERT_IS_VALID_DM(dm); + me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0); + ASSERT_IS_VALID_MESH(me); if (deformedVerts) { - CDDM_apply_vert_coords(dm, deformedVerts); - } - - if (do_init_wmcol) { - DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL); + BKE_mesh_apply_vert_coords(me, deformedVerts); } } /* create an orco derivedmesh in parallel */ mask = curr->mask; if (mask & CD_MASK_ORCO) { - if (!orcodm) - orcodm = create_orco_dm(ob, ob->data, em, CD_ORCO); + if (!me_orco) { + me_orco = create_orco_mesh(ob, ob->data, em, CD_ORCO); + } mask &= ~CD_MASK_ORCO; - DM_set_only_copy(orcodm, mask | CD_MASK_ORIGINDEX); + mesh_set_only_copy(me_orco, mask | CD_MASK_ORIGINDEX); - if (mti->applyModifierEM) { - ndm = modwrap_applyModifierEM(md, ob, em, orcodm, MOD_APPLY_ORCO); - } - else { - ndm = modwrap_applyModifier(md, ob, orcodm, MOD_APPLY_ORCO); - } - ASSERT_IS_VALID_DM(ndm); + me_next = modwrap_applyModifier(md, &mectx_orco, me_orco); + ASSERT_IS_VALID_MESH(me_next); - if (ndm) { + if (me_next) { /* if the modifier returned a new dm, release the old one */ - if (orcodm && orcodm != ndm) orcodm->release(orcodm); - orcodm = ndm; + if (me_orco && me_orco != me_next) { + BKE_id_free(NULL, me_orco); + } + me_orco = me_next; } } @@ -2460,53 +1800,48 @@ static void editbmesh_calc_modifiers( mask |= append_mask; mask = curr->mask; /* CD_MASK_ORCO may have been cleared above */ - DM_set_only_copy(dm, mask | CD_MASK_ORIGINDEX); + mesh_set_only_copy(me, mask | CD_MASK_ORIGINDEX); if (mask & CD_MASK_ORIGSPACE_MLOOP) { - if (!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) { - DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL); - DM_init_origspace(dm); + if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) { + CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop); + mesh_init_origspace(me); } } - if (mti->applyModifierEM) - ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU); - else - ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU); - ASSERT_IS_VALID_DM(ndm); - - if (ndm) { - if (dm && dm != ndm) - dm->release(dm); + me_next = modwrap_applyModifier(md, &mectx_cache, me); + ASSERT_IS_VALID_MESH(me_next); - dm = ndm; + if (me_next) { + if (me && me != me_next) { + BKE_id_free(NULL, me); + } + me = me_next; if (deformedVerts) { MEM_freeN(deformedVerts); deformedVerts = NULL; } } - - dm->deformedOnly = false; - } - - /* In case of active preview modifier, make sure preview mask remains for following modifiers. */ - if ((md == previewmd) && (do_mod_wmcol)) { - DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL); - append_mask |= CD_MASK_PREVIEW_MLOOPCOL; + me->runtime.deformed_only = false; } if (r_cage && i == cageIndex) { - if (dm && deformedVerts) { - *r_cage = CDDM_copy(dm); - CDDM_apply_vert_coords(*r_cage, deformedVerts); + if (me && deformedVerts) { + *r_cage = BKE_mesh_copy_for_eval(me, false); + BKE_mesh_apply_vert_coords(*r_cage, deformedVerts); } - else if (dm) { - *r_cage = dm; + else if (me) { + *r_cage = me; } else { - *r_cage = getEditDerivedBMesh( - em, ob, mask, + Mesh *me_orig = ob->data; + if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) { + BKE_mesh_runtime_ensure_edit_data(me_orig); + me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformedVerts); + } + *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap( + em, mask, deformedVerts ? MEM_dupallocN(deformedVerts) : NULL); } } @@ -2518,45 +1853,44 @@ static void editbmesh_calc_modifiers( * to apply these back onto the DerivedMesh. If we have no DerivedMesh * then we need to build one. */ - if (dm && deformedVerts) { - *r_final = CDDM_copy(dm); + if (me && deformedVerts) { + *r_final = BKE_mesh_copy_for_eval(me, false); - if (!(r_cage && dm == *r_cage)) { - dm->release(dm); + if (!(r_cage && me == *r_cage)) { + BKE_id_free(NULL, me); } - - CDDM_apply_vert_coords(*r_final, deformedVerts); + BKE_mesh_apply_vert_coords(*r_final, deformedVerts); } - else if (dm) { - *r_final = dm; + else if (me) { + *r_final = me; } else if (!deformedVerts && r_cage && *r_cage) { /* cage should already have up to date normals */ *r_final = *r_cage; /* In this case, we should never have weight-modifying modifiers in stack... */ - if (do_init_wmcol) - DM_update_weight_mcol(ob, *r_final, draw_flag, NULL, 0, NULL); - if (do_init_statvis) - DM_update_statvis_color(scene, ob, *r_final); + if (do_init_statvis) { + editmesh_update_statvis_color(scene, ob); + } } else { /* this is just a copy of the editmesh, no need to calc normals */ - *r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts); + *r_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, deformedVerts); deformedVerts = NULL; /* In this case, we should never have weight-modifying modifiers in stack... */ - if (do_init_wmcol) - DM_update_weight_mcol(ob, *r_final, draw_flag, NULL, 0, NULL); - if (do_init_statvis) - DM_update_statvis_color(scene, ob, *r_final); + if (do_init_statvis) { + editmesh_update_statvis_color(scene, ob); + } } if (do_loop_normals) { /* Compute loop normals */ - DM_calc_loop_normals(*r_final, do_loop_normals, loop_normals_split_angle); + BKE_mesh_calc_normals_split(*r_final); + BKE_mesh_tessface_clear(*r_final); if (r_cage && *r_cage && (*r_cage != *r_final)) { - DM_calc_loop_normals(*r_cage, do_loop_normals, loop_normals_split_angle); + BKE_mesh_calc_normals_split(*r_cage); + BKE_mesh_tessface_clear(*r_cage); } } @@ -2565,13 +1899,13 @@ static void editbmesh_calc_modifiers( * check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential * but quiets annoying error messages since tessfaces wont be created. */ if (dataMask & CD_MASK_MFACE) { - if ((*r_final)->type != DM_TYPE_EDITBMESH) { - DM_ensure_tessface(*r_final); + if ((*r_final)->edit_btmesh == NULL) { + BKE_mesh_tessface_ensure(*r_final); } if (r_cage && *r_cage) { - if ((*r_cage)->type != DM_TYPE_EDITBMESH) { + if ((*r_cage)->edit_btmesh == NULL) { if (*r_cage != *r_final) { - DM_ensure_tessface(*r_cage); + BKE_mesh_tessface_ensure(*r_cage); } } } @@ -2580,63 +1914,84 @@ static void editbmesh_calc_modifiers( /* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */ if (!do_loop_normals) { - dm_ensure_display_normals(*r_final); + BKE_mesh_ensure_normals_for_display(*r_final); /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them, * as they are used by display code when available (i.e. even if autosmooth is disabled). */ - if (CustomData_has_layer(&(*r_final)->loopData, CD_NORMAL)) { - CustomData_free_layers(&(*r_final)->loopData, CD_NORMAL, (*r_final)->numLoopData); + if (CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) { + CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop); } - if (r_cage && CustomData_has_layer(&(*r_cage)->loopData, CD_NORMAL)) { - CustomData_free_layers(&(*r_cage)->loopData, CD_NORMAL, (*r_cage)->numLoopData); + if (r_cage && CustomData_has_layer(&(*r_cage)->ldata, CD_NORMAL)) { + CustomData_free_layers(&(*r_cage)->ldata, CD_NORMAL, (*r_cage)->totloop); } } /* add an orco layer if needed */ if (dataMask & CD_MASK_ORCO) - add_orco_dm(ob, em, *r_final, orcodm, CD_ORCO); + add_orco_mesh(ob, em, *r_final, me_orco, CD_ORCO); - if (orcodm) - orcodm->release(orcodm); + if (me_orco) { + BKE_id_free(NULL, me_orco); + } - if (deformedVerts) + if (deformedVerts) { MEM_freeN(deformedVerts); + } } -#ifdef WITH_OPENSUBDIV -/* The idea is to skip CPU-side ORCO calculation when - * we'll be using GPU backend of OpenSubdiv. This is so - * playback performance is kept as high as possible. - */ -static bool calc_modifiers_skip_orco(Scene *scene, - Object *ob, - bool use_render_params) +static void mesh_finalize_eval(Object *object) { - ModifierData *last_md = ob->modifiers.last; - const int required_mode = use_render_params ? eModifierMode_Render : eModifierMode_Realtime; - if (last_md != NULL && - last_md->type == eModifierType_Subsurf && - modifier_isEnabled(scene, last_md, required_mode)) - { - if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) { - return false; - } - else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) { - return false; - } - else if ((DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CPU) != 0) { - return false; - } - SubsurfModifierData *smd = (SubsurfModifierData *)last_md; - /* TODO(sergey): Deduplicate this with checks from subsurf_ccg.c. */ - return smd->use_opensubdiv != 0; + Mesh *mesh = (Mesh *)object->data; + Mesh *mesh_eval = object->runtime.mesh_eval; + /* Special Tweaks for cases when evaluated mesh came from + * BKE_mesh_new_nomain_from_template(). + */ + BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name)); + if (mesh_eval->mat != NULL) { + MEM_freeN(mesh_eval->mat); + } + /* Set flag which makes it easier to see what's going on in a debugger. */ + mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT; + mesh_eval->mat = MEM_dupallocN(mesh->mat); + mesh_eval->totcol = mesh->totcol; + /* Make evaluated mesh to share same edit mesh pointer as original + * and copied meshes. + */ + mesh_eval->edit_btmesh = mesh->edit_btmesh; + /* Copy autosmooth settings from original mesh. + * This is not done by BKE_mesh_new_nomain_from_template(), so need to take + * extra care here. + */ + mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH); + mesh_eval->smoothresh = mesh->smoothresh; + /* Replace evaluated object's data with fully evaluated mesh. */ + /* TODO(sergey): There was statement done by Sybren and Mai that this + * caused modifiers to be applied twice. which is weirtd and shouldn't + * really happen. But since there is no reference to the report, can not + * do much about this. + */ + + /* Object is sometimes not evaluated! + * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */ + if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) { + object->data = mesh_eval; + } + else { + /* evaluated will be available via: 'object->runtime.mesh_eval' */ + } +} + +static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob) +{ + uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id); + + if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) { + BKE_shrinkwrap_compute_boundary_data(ob->runtime.mesh_eval); } - return false; } -#endif static void mesh_build_data( - Scene *scene, Object *ob, CustomDataMask dataMask, + struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask, const bool build_shapekey_layers, const bool need_mapping) { BLI_assert(ob->type == OB_MESH); @@ -2644,18 +1999,18 @@ static void mesh_build_data( BKE_object_free_derived_caches(ob); BKE_object_sculpt_modifiers_changed(ob); -#ifdef WITH_OPENSUBDIV - if (calc_modifiers_skip_orco(scene, ob, false)) { - dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL); - } -#endif - mesh_calc_modifiers( - scene, ob, NULL, false, 1, need_mapping, dataMask, -1, true, build_shapekey_layers, - true, - &ob->derivedDeform, &ob->derivedFinal); + depsgraph, scene, ob, NULL, 1, need_mapping, dataMask, -1, true, build_shapekey_layers, + &ob->runtime.mesh_deform_eval, &ob->runtime.mesh_eval); + + mesh_finalize_eval(ob); - DM_set_object_boundbox(ob, ob->derivedFinal); + /* TODO(campbell): remove these copies, they are expected in various places over the code. */ + ob->derivedDeform = CDDM_from_mesh_ex(ob->runtime.mesh_deform_eval, CD_REFERENCE, CD_MASK_MESH); + ob->derivedFinal = CDDM_from_mesh_ex(ob->runtime.mesh_eval, CD_REFERENCE, CD_MASK_MESH); + + BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval); + BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob); ob->derivedFinal->needsFree = 0; ob->derivedDeform->needsFree = 0; @@ -2665,49 +2020,53 @@ static void mesh_build_data( if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { /* create PBVH immediately (would be created on the fly too, * but this avoids waiting on first stroke) */ - - BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false); + /* XXX Disabled for now. + * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */ +// BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false); } BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); + + mesh_build_extra_data(depsgraph, ob); } -static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask) +static void editbmesh_build_data( + struct Depsgraph *depsgraph, Scene *scene, + Object *obedit, BMEditMesh *em, CustomDataMask dataMask) { BKE_object_free_derived_caches(obedit); BKE_object_sculpt_modifiers_changed(obedit); BKE_editmesh_free_derivedmesh(em); -#ifdef WITH_OPENSUBDIV - if (calc_modifiers_skip_orco(scene, obedit, false)) { - dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL); - } -#endif + Mesh *me_cage; + Mesh *me_final; editbmesh_calc_modifiers( - scene, obedit, em, dataMask, - &em->derivedCage, &em->derivedFinal); + depsgraph, scene, obedit, em, dataMask, + &me_cage, &me_final); + + em->mesh_eval_final = me_final; + em->mesh_eval_cage = me_cage; - DM_set_object_boundbox(obedit, em->derivedFinal); + BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final); em->lastDataMask = dataMask; - em->derivedFinal->needsFree = 0; - em->derivedCage->needsFree = 0; - BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS)); + BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS)); } -static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *r_need_mapping) +static CustomDataMask object_get_datamask(const Depsgraph *depsgraph, Object *ob, bool *r_need_mapping) { - Object *actob = scene->basact ? scene->basact->object : NULL; + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL; CustomDataMask mask = ob->customdata_mask; if (r_need_mapping) { *r_need_mapping = false; } - if (ob == actob) { + if (DEG_get_original_object(ob) == actob) { bool editing = BKE_paint_select_face_test(ob); /* weight paint and face select need original indices because of selection buffer drawing */ @@ -2726,7 +2085,7 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool * } if (ob->mode & OB_MODE_WEIGHT_PAINT) { - mask |= CD_MASK_PREVIEW_MLOOPCOL; + mask |= CD_MASK_MDEFORMVERT; } if (ob->mode & OB_MODE_EDIT) @@ -2737,151 +2096,208 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool * } void makeDerivedMesh( - Scene *scene, Object *ob, BMEditMesh *em, + struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em, CustomDataMask dataMask, const bool build_shapekey_layers) { bool need_mapping; - dataMask |= object_get_datamask(scene, ob, &need_mapping); + dataMask |= object_get_datamask(depsgraph, ob, &need_mapping); if (em) { - editbmesh_build_data(scene, ob, em, dataMask); + editbmesh_build_data(depsgraph, scene, ob, em, dataMask); } else { - mesh_build_data(scene, ob, dataMask, build_shapekey_layers, need_mapping); + mesh_build_data(depsgraph, scene, ob, dataMask, build_shapekey_layers, need_mapping); } } /***/ -DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dataMask) +#ifdef USE_DERIVEDMESH +/* Deprecated DM, use: 'mesh_get_eval_final'. */ +DerivedMesh *mesh_get_derived_final( + struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ bool need_mapping; - dataMask |= object_get_datamask(scene, ob, &need_mapping); + dataMask |= object_get_datamask(depsgraph, ob, &need_mapping); if (!ob->derivedFinal || ((dataMask & ob->lastDataMask) != dataMask) || (need_mapping != ob->lastNeedMapping)) { - mesh_build_data(scene, ob, dataMask, false, need_mapping); + mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping); } if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); } return ob->derivedFinal; } +#endif +Mesh *mesh_get_eval_final( + struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) +{ + /* if there's no evaluated mesh or the last data mask used doesn't include + * the data we need, rebuild the derived mesh + */ + bool need_mapping; + dataMask |= object_get_datamask(depsgraph, ob, &need_mapping); + + if (!ob->runtime.mesh_eval || + ((dataMask & ob->lastDataMask) != dataMask) || + (need_mapping != ob->lastNeedMapping)) + { + mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping); + } + + if (ob->runtime.mesh_eval) { BLI_assert(!(ob->runtime.mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL)); } + return ob->runtime.mesh_eval; +} -DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask dataMask) +#ifdef USE_DERIVEDMESH +/* Deprecated DM, use: 'mesh_get_eval_deform' instead. */ +DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ bool need_mapping; - dataMask |= object_get_datamask(scene, ob, &need_mapping); + dataMask |= object_get_datamask(depsgraph, ob, &need_mapping); if (!ob->derivedDeform || ((dataMask & ob->lastDataMask) != dataMask) || (need_mapping != ob->lastNeedMapping)) { - mesh_build_data(scene, ob, dataMask, false, need_mapping); + mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping); } return ob->derivedDeform; } +#endif +Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) +{ + /* if there's no derived mesh or the last data mask used doesn't include + * the data we need, rebuild the derived mesh + */ + bool need_mapping; -DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask dataMask) + dataMask |= object_get_datamask(depsgraph, ob, &need_mapping); + + if (!ob->runtime.mesh_deform_eval || + ((dataMask & ob->lastDataMask) != dataMask) || + (need_mapping != ob->lastNeedMapping)) + { + mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping); + } + + return ob->runtime.mesh_deform_eval; +} + + +#ifdef USE_DERIVEDMESH +/* Deprecated, use `mesh_create_eval_final_render` instead. */ +DerivedMesh *mesh_create_derived_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) { DerivedMesh *final; - mesh_calc_modifiers( - scene, ob, NULL, true, 1, false, dataMask, -1, false, false, false, + mesh_calc_modifiers_dm( + depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false, NULL, &final); return final; } - -DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDataMask dataMask, int index) +#endif +Mesh *mesh_create_eval_final_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask) { - DerivedMesh *final; + Mesh *final; mesh_calc_modifiers( - scene, ob, NULL, true, 1, false, dataMask, index, false, false, false, + depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false, NULL, &final); return final; } -DerivedMesh *mesh_create_derived_view( - Scene *scene, Object *ob, - CustomDataMask dataMask) +#ifdef USE_DERIVEDMESH +/* Deprecated, use `mesh_create_eval_final_index_render` instead. */ +DerivedMesh *mesh_create_derived_index_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask, int index) { DerivedMesh *final; - /* XXX hack - * psys modifier updates particle state when called during dupli-list generation, - * which can lead to wrong transforms. This disables particle system modifier execution. - */ - ob->transflag |= OB_NO_PSYS_UPDATE; - - mesh_calc_modifiers( - scene, ob, NULL, false, 1, false, dataMask, -1, false, false, false, + mesh_calc_modifiers_dm( + depsgraph, scene, ob, NULL, 1, false, dataMask, index, false, false, NULL, &final); - ob->transflag &= ~OB_NO_PSYS_UPDATE; - return final; } - -DerivedMesh *mesh_create_derived_no_deform( - Scene *scene, Object *ob, float (*vertCos)[3], - CustomDataMask dataMask) +#endif +Mesh *mesh_create_eval_final_index_render( + struct Depsgraph *depsgraph, struct Scene *scene, + struct Object *ob, CustomDataMask dataMask, int index) { - DerivedMesh *final; + Mesh *final; mesh_calc_modifiers( - scene, ob, vertCos, false, 0, false, dataMask, -1, false, false, false, + depsgraph, scene, ob, NULL, 1, false, dataMask, index, false, false, NULL, &final); return final; } -DerivedMesh *mesh_create_derived_no_virtual( - Scene *scene, Object *ob, float (*vertCos)[3], - CustomDataMask dataMask) +#ifdef USE_DERIVEDMESH +/* Deprecated, use `mesh_create_eval_final_view` instead. */ +DerivedMesh *mesh_create_derived_view( + struct Depsgraph *depsgraph, Scene *scene, + Object *ob, CustomDataMask dataMask) { DerivedMesh *final; - mesh_calc_modifiers( - scene, ob, vertCos, false, -1, false, dataMask, -1, false, false, false, + /* XXX hack + * psys modifier updates particle state when called during dupli-list generation, + * which can lead to wrong transforms. This disables particle system modifier execution. + */ + ob->transflag |= OB_NO_PSYS_UPDATE; + + mesh_calc_modifiers_dm( + depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false, NULL, &final); + ob->transflag &= ~OB_NO_PSYS_UPDATE; + return final; } +#endif -DerivedMesh *mesh_create_derived_physics( - Scene *scene, Object *ob, float (*vertCos)[3], - CustomDataMask dataMask) +Mesh *mesh_create_eval_final_view( + struct Depsgraph *depsgraph, Scene *scene, + Object *ob, CustomDataMask dataMask) { - DerivedMesh *final; + Mesh *final; + + /* XXX hack + * psys modifier updates particle state when called during dupli-list generation, + * which can lead to wrong transforms. This disables particle system modifier execution. + */ + ob->transflag |= OB_NO_PSYS_UPDATE; mesh_calc_modifiers( - scene, ob, vertCos, false, -1, true, dataMask, -1, false, false, false, + depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false, NULL, &final); + ob->transflag &= ~OB_NO_PSYS_UPDATE; + return final; } -DerivedMesh *mesh_create_derived_no_deform_render( - Scene *scene, Object *ob, - float (*vertCos)[3], - CustomDataMask dataMask) +DerivedMesh *mesh_create_derived_no_deform( + struct Depsgraph *depsgraph, Scene *scene, Object *ob, + float (*vertCos)[3], CustomDataMask dataMask) { DerivedMesh *final; - mesh_calc_modifiers( - scene, ob, vertCos, true, 0, false, dataMask, -1, false, false, false, + mesh_calc_modifiers_dm( + depsgraph, scene, ob, vertCos, 0, false, dataMask, -1, false, false, NULL, &final); return final; @@ -2889,74 +2305,48 @@ DerivedMesh *mesh_create_derived_no_deform_render( /***/ -DerivedMesh *editbmesh_get_derived_cage_and_final( - Scene *scene, Object *obedit, BMEditMesh *em, +Mesh *editbmesh_get_eval_cage_and_final( + struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask, /* return args */ - DerivedMesh **r_final) + Mesh **r_final) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, obedit, NULL); + dataMask |= object_get_datamask(depsgraph, obedit, NULL); - if (!em->derivedCage || + if (!em->mesh_eval_cage || (em->lastDataMask & dataMask) != dataMask) { - editbmesh_build_data(scene, obedit, em, dataMask); + editbmesh_build_data(depsgraph, scene, obedit, em, dataMask); } - *r_final = em->derivedFinal; - if (em->derivedFinal) { BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS)); } - return em->derivedCage; + *r_final = em->mesh_eval_final; + if (em->mesh_eval_final) { BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS)); } + return em->mesh_eval_cage; } -DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask) +Mesh *editbmesh_get_eval_cage( + struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em, + CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - dataMask |= object_get_datamask(scene, obedit, NULL); + dataMask |= object_get_datamask(depsgraph, obedit, NULL); - if (!em->derivedCage || + if (!em->mesh_eval_cage || (em->lastDataMask & dataMask) != dataMask) { - editbmesh_build_data(scene, obedit, em, dataMask); + editbmesh_build_data(depsgraph, scene, obedit, em, dataMask); } - return em->derivedCage; -} - -DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDataMask data_mask) -{ - return getEditDerivedBMesh(em, obedit, data_mask, NULL); + return em->mesh_eval_cage; } /***/ -/* get derived mesh from an object, using editbmesh if available. */ -DerivedMesh *object_get_derived_final(Object *ob, const bool for_render) -{ - if (for_render) { - /* TODO(sergey): use proper derived render here in the future. */ - return ob->derivedFinal; - } - - /* only return the editmesh if its from this object because - * we don't a mesh from another object's modifier stack: T43122 */ - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_btmesh; - if (em && (em->ob == ob)) { - DerivedMesh *dm = em->derivedFinal; - return dm; - } - } - - return ob->derivedFinal; -} - - /* UNUSED */ #if 0 @@ -3038,289 +2428,24 @@ static void make_vertexcos__mapFunc( } } -void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos) +void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int totcos) { - if (dm->foreachMappedVert) { + if (me_eval->runtime.deformed_only == false) { MappedUserData userData; memset(r_cos, 0, sizeof(*r_cos) * totcos); userData.vertexcos = r_cos; userData.vertex_visit = BLI_BITMAP_NEW(totcos, "vertexcos flags"); - dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP); + BKE_mesh_foreach_mapped_vert(me_eval, make_vertexcos__mapFunc, &userData, MESH_FOREACH_NOP); MEM_freeN(userData.vertex_visit); } else { - int i; - for (i = 0; i < totcos; i++) { - dm->getVertCo(dm, i, r_cos[i]); + MVert *mv = me_eval->mvert; + for (int i = 0; i < totcos; i++, mv++) { + copy_v3_v3(r_cos[i], mv->co); } } } -/* ******************* GLSL ******************** */ - -/** \name Tangent Space Calculation - * \{ */ - -/* Necessary complexity to handle looptri's as quads for correct tangents */ -#define USE_LOOPTRI_DETECT_QUADS - -typedef struct { - float (*precomputedFaceNormals)[3]; - float (*precomputedLoopNormals)[3]; - const MLoopTri *looptri; - MLoopUV *mloopuv; /* texture coordinates */ - MPoly *mpoly; /* indices */ - MLoop *mloop; /* indices */ - MVert *mvert; /* vertices & normals */ - float (*orco)[3]; - float (*tangent)[4]; /* destination */ - int numTessFaces; - -#ifdef USE_LOOPTRI_DETECT_QUADS - /* map from 'fake' face index to looptri, - * quads will point to the first looptri of the quad */ - const int *face_as_quad_map; - int num_face_as_quad_map; -#endif - -} SGLSLMeshToTangent; - -/* interface */ -#include "mikktspace.h" - -static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) -{ - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - -#ifdef USE_LOOPTRI_DETECT_QUADS - return pMesh->num_face_as_quad_map; -#else - return pMesh->numTessFaces; -#endif -} - -static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) -{ -#ifdef USE_LOOPTRI_DETECT_QUADS - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - if (pMesh->face_as_quad_map) { - const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - return 4; - } - } - return 3; -#else - UNUSED_VARS(pContext, face_num); - return 3; -#endif -} - -static void dm_ts_GetPosition( - const SMikkTSpaceContext *pContext, float r_co[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - const float *co; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - -finally: - co = pMesh->mvert[pMesh->mloop[loop_index].v].co; - copy_v3_v3(r_co, co); -} - -static void dm_ts_GetTextureCoordinate( - const SMikkTSpaceContext *pContext, float r_uv[2], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - -finally: - if (pMesh->mloopuv != NULL) { - const float *uv = pMesh->mloopuv[loop_index].uv; - copy_v2_v2(r_uv, uv); - } - else { - const float *orco = pMesh->orco[pMesh->mloop[loop_index].v]; - map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); - } -} - -static void dm_ts_GetNormal( - const SMikkTSpaceContext *pContext, float r_no[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - -finally: - if (pMesh->precomputedLoopNormals) { - copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]); - } - else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */ - if (pMesh->precomputedFaceNormals) { - copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]); - } - else { -#ifdef USE_LOOPTRI_DETECT_QUADS - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - normal_quad_v3( - r_no, - pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co, - pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co, - pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co, - pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co); - } - else -#endif - { - normal_tri_v3( - r_no, - pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co, - pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co, - pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co); - } - } - } - else { - const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no; - normal_short_to_float_v3(r_no, no); - } -} - -static void dm_ts_SetTSpace( - const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; - const MLoopTri *lt; - int loop_index; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; - const MPoly *mp = &pMesh->mpoly[lt->poly]; - if (mp->totloop == 4) { - loop_index = mp->loopstart + vert_index; - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = &pMesh->looptri[face_num]; - } -#else - lt = &pMesh->looptri[face_num]; -#endif - loop_index = lt->tri[vert_index]; - - float *pRes; - -finally: - pRes = pMesh->tangent[loop_index]; - copy_v3_v3(pRes, fvTangent); - pRes[3] = fSign; -} - -void DM_calc_tangents_names_from_gpu( - const GPUVertexAttribs *gattribs, - char (*tangent_names)[MAX_NAME], int *r_tangent_names_count) -{ - int count = 0; - for (int b = 0; b < gattribs->totlayer; b++) { - if (gattribs->layer[b].type == CD_TANGENT) { - strcpy(tangent_names[count++], gattribs->layer[b].name); - } - } - *r_tangent_names_count = count; -} - -static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) -{ - struct SGLSLMeshToTangent *mesh2tangent = taskdata; - /* new computation method */ - { - SMikkTSpaceContext sContext = {NULL}; - SMikkTSpaceInterface sInterface = {NULL}; - - sContext.m_pUserData = mesh2tangent; - sContext.m_pInterface = &sInterface; - sInterface.m_getNumFaces = dm_ts_GetNumFaces; - sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace; - sInterface.m_getPosition = dm_ts_GetPosition; - sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate; - sInterface.m_getNormal = dm_ts_GetNormal; - sInterface.m_setTSpaceBasic = dm_ts_SetTSpace; - - /* 0 if failed */ - genTangSpaceDefault(&sContext); - } -} - void DM_add_named_tangent_layer_for_uv( CustomData *uv_data, CustomData *tan_data, int numLoopData, const char *layer_name) @@ -3334,805 +2459,107 @@ void DM_add_named_tangent_layer_for_uv( } } -/** - * Here we get some useful information such as active uv layer name and search if it is already in tangent_names. - * Also, we calculate tangent_mask that works as a descriptor of tangents state. - * If tangent_mask has changed, then recalculate tangents. - */ -void DM_calc_loop_tangents_step_0( - const CustomData *loopData, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count, - bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, - char *ract_uv_name, char *rren_uv_name, short *rtangent_mask) -{ - /* Active uv in viewport */ - int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV); - *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV); - ract_uv_name[0] = 0; - if (*ract_uv_n != -1) { - strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name); - } - - /* Active tangent in render */ - *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV); - rren_uv_name[0] = 0; - if (*rren_uv_n != -1) { - strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name); - } - - /* If active tangent not in tangent_names we take it into account */ - *rcalc_act = false; - *rcalc_ren = false; - for (int i = 0; i < tangent_names_count; i++) { - if (tangent_names[i][0] == 0) { - calc_active_tangent = true; - } - } - if (calc_active_tangent) { - *rcalc_act = true; - *rcalc_ren = true; - for (int i = 0; i < tangent_names_count; i++) { - if (STREQ(ract_uv_name, tangent_names[i])) - *rcalc_act = false; - if (STREQ(rren_uv_name, tangent_names[i])) - *rcalc_ren = false; - } - } - *rtangent_mask = 0; - - const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV); - for (int n = 0; n < uv_layer_num; n++) { - const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n); - bool add = false; - for (int i = 0; i < tangent_names_count; i++) { - if (tangent_names[i][0] && STREQ(tangent_names[i], name)) { - add = true; - break; - } - } - if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) || - (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))) - { - add = true; - } - if (add) - *rtangent_mask |= 1 << n; - } - - if (uv_layer_num == 0) - *rtangent_mask |= DM_TANGENT_MASK_ORCO; -} - void DM_calc_loop_tangents( DerivedMesh *dm, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count) -{ - int act_uv_n = -1; - int ren_uv_n = -1; - bool calc_act = false; - bool calc_ren = false; - char act_uv_name[MAX_NAME]; - char ren_uv_name[MAX_NAME]; - short tangent_mask = 0; - DM_calc_loop_tangents_step_0( - &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count, - &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); - if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) { - /* Check we have all the needed layers */ - MPoly *mpoly = dm->getPolyArray(dm); - const MLoopTri *looptri = dm->getLoopTriArray(dm); - int totface = dm->getNumLoopTri(dm); - /* Allocate needed tangent layers */ - for (int i = 0; i < tangent_names_count; i++) - if (tangent_names[i][0]) - DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]); - if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1) - CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, ""); - if (calc_act && act_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name); - if (calc_ren && ren_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name); - -#ifdef USE_LOOPTRI_DETECT_QUADS - int num_face_as_quad_map; - int *face_as_quad_map = NULL; - - /* map faces to quads */ - if (totface != dm->getNumPolys(dm)) { - /* over alloc, since we dont know how many ngon or quads we have */ - - /* map fake face index to looptri */ - face_as_quad_map = MEM_malloc_arrayN(totface, sizeof(int), __func__); - int k, j; - for (k = 0, j = 0; j < totface; k++, j++) { - face_as_quad_map[k] = j; - /* step over all quads */ - if (mpoly[looptri[j].poly].totloop == 4) { - j++; /* skips the nest looptri */ - } - } - num_face_as_quad_map = k; - } - else { - num_face_as_quad_map = totface; - } -#endif - - /* Calculation */ - { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL); - - dm->tangent_mask = 0; - /* Calculate tangent layers */ - SGLSLMeshToTangent data_array[MAX_MTFACE]; - const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT); - for (int n = 0; n < tangent_layer_num; n++) { - int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n); - BLI_assert(n < MAX_MTFACE); - SGLSLMeshToTangent *mesh2tangent = &data_array[n]; - mesh2tangent->numTessFaces = totface; -#ifdef USE_LOOPTRI_DETECT_QUADS - mesh2tangent->face_as_quad_map = face_as_quad_map; - mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; -#endif - mesh2tangent->mvert = dm->getVertArray(dm); - mesh2tangent->mpoly = dm->getPolyArray(dm); - mesh2tangent->mloop = dm->getLoopArray(dm); - mesh2tangent->looptri = dm->getLoopTriArray(dm); - /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), - * have to check this is valid... - */ - mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL); - mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL); - - mesh2tangent->orco = NULL; - mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name); - - /* Fill the resulting tangent_mask */ - if (!mesh2tangent->mloopuv) { - mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO); - if (!mesh2tangent->orco) - continue; - - dm->tangent_mask |= DM_TANGENT_MASK_ORCO; - } - else { - int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name); - int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV); - BLI_assert(uv_ind != -1 && uv_start != -1); - BLI_assert(uv_ind - uv_start < MAX_MTFACE); - dm->tangent_mask |= 1 << (uv_ind - uv_start); - } - - mesh2tangent->tangent = dm->loopData.layers[index].data; - BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); - } - - BLI_assert(dm->tangent_mask == tangent_mask); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - } -#ifdef USE_LOOPTRI_DETECT_QUADS - if (face_as_quad_map) { - MEM_freeN(face_as_quad_map); - } -#undef USE_LOOPTRI_DETECT_QUADS - -#endif - - /* Update active layer index */ - int act_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n); - if (act_uv_index != -1) { - int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[act_uv_index].name); - CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index); - } /* else tangent has been built from orco */ - - /* Update render layer index */ - int ren_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n); - if (ren_uv_index != -1) { - int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[ren_uv_index].name); - CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index); - } /* else tangent has been built from orco */ - } -} - -/** \} */ - - -void DM_calc_auto_bump_scale(DerivedMesh *dm) + const char (*tangent_names)[MAX_NAME], int tangent_names_len) { - /* int totvert = dm->getNumVerts(dm); */ /* UNUSED */ - int totface = dm->getNumTessFaces(dm); - - MVert *mvert = dm->getVertArray(dm); - MFace *mface = dm->getTessFaceArray(dm); - MTFace *mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); - - if (mtface) { - double dsum = 0.0; - int nr_accumulated = 0; - int f; - - for (f = 0; f < totface; f++) { - { - float *verts[4], *tex_coords[4]; - const int nr_verts = mface[f].v4 != 0 ? 4 : 3; - bool is_degenerate; - int i; - - verts[0] = mvert[mface[f].v1].co; verts[1] = mvert[mface[f].v2].co; verts[2] = mvert[mface[f].v3].co; - tex_coords[0] = mtface[f].uv[0]; tex_coords[1] = mtface[f].uv[1]; tex_coords[2] = mtface[f].uv[2]; - if (nr_verts == 4) { - verts[3] = mvert[mface[f].v4].co; - tex_coords[3] = mtface[f].uv[3]; - } - - /* discard degenerate faces */ - is_degenerate = 0; - if (equals_v3v3(verts[0], verts[1]) || - equals_v3v3(verts[0], verts[2]) || - equals_v3v3(verts[1], verts[2]) || - equals_v2v2(tex_coords[0], tex_coords[1]) || - equals_v2v2(tex_coords[0], tex_coords[2]) || - equals_v2v2(tex_coords[1], tex_coords[2])) - { - is_degenerate = 1; - } - - /* verify last vertex as well if this is a quad */ - if (is_degenerate == 0 && nr_verts == 4) { - if (equals_v3v3(verts[3], verts[0]) || - equals_v3v3(verts[3], verts[1]) || - equals_v3v3(verts[3], verts[2]) || - equals_v2v2(tex_coords[3], tex_coords[0]) || - equals_v2v2(tex_coords[3], tex_coords[1]) || - equals_v2v2(tex_coords[3], tex_coords[2])) - { - is_degenerate = 1; - } - - /* verify the winding is consistent */ - if (is_degenerate == 0) { - float prev_edge[2]; - bool is_signed = 0; - sub_v2_v2v2(prev_edge, tex_coords[0], tex_coords[3]); - - i = 0; - while (is_degenerate == 0 && i < 4) { - float cur_edge[2], signed_area; - sub_v2_v2v2(cur_edge, tex_coords[(i + 1) & 0x3], tex_coords[i]); - signed_area = cross_v2v2(prev_edge, cur_edge); - - if (i == 0) { - is_signed = (signed_area < 0.0f) ? 1 : 0; - } - else if ((is_signed != 0) != (signed_area < 0.0f)) { - is_degenerate = 1; - } - - if (is_degenerate == 0) { - copy_v2_v2(prev_edge, cur_edge); - i++; - } - } - } - } - - /* proceed if not a degenerate face */ - if (is_degenerate == 0) { - int nr_tris_to_pile = 0; - /* quads split at shortest diagonal */ - int offs = 0; /* initial triangulation is 0,1,2 and 0, 2, 3 */ - if (nr_verts == 4) { - float pos_len_diag0, pos_len_diag1; - - pos_len_diag0 = len_squared_v3v3(verts[2], verts[0]); - pos_len_diag1 = len_squared_v3v3(verts[3], verts[1]); - - if (pos_len_diag1 < pos_len_diag0) { - offs = 1; // alter split - } - else if (pos_len_diag0 == pos_len_diag1) { /* do UV check instead */ - float tex_len_diag0, tex_len_diag1; - - tex_len_diag0 = len_squared_v2v2(tex_coords[2], tex_coords[0]); - tex_len_diag1 = len_squared_v2v2(tex_coords[3], tex_coords[1]); - - if (tex_len_diag1 < tex_len_diag0) { - offs = 1; /* alter split */ - } - } - } - nr_tris_to_pile = nr_verts - 2; - if (nr_tris_to_pile == 1 || nr_tris_to_pile == 2) { - const int indices[6] = {offs + 0, offs + 1, offs + 2, offs + 0, offs + 2, (offs + 3) & 0x3 }; - int t; - for (t = 0; t < nr_tris_to_pile; t++) { - float f2x_area_uv; - const float *p0 = verts[indices[t * 3 + 0]]; - const float *p1 = verts[indices[t * 3 + 1]]; - const float *p2 = verts[indices[t * 3 + 2]]; - - float edge_t0[2], edge_t1[2]; - sub_v2_v2v2(edge_t0, tex_coords[indices[t * 3 + 1]], tex_coords[indices[t * 3 + 0]]); - sub_v2_v2v2(edge_t1, tex_coords[indices[t * 3 + 2]], tex_coords[indices[t * 3 + 0]]); - - f2x_area_uv = fabsf(cross_v2v2(edge_t0, edge_t1)); - if (f2x_area_uv > FLT_EPSILON) { - float norm[3], v0[3], v1[3], f2x_surf_area, fsurf_ratio; - sub_v3_v3v3(v0, p1, p0); - sub_v3_v3v3(v1, p2, p0); - cross_v3_v3v3(norm, v0, v1); - - f2x_surf_area = len_v3(norm); - fsurf_ratio = f2x_surf_area / f2x_area_uv; /* tri area divided by texture area */ - - nr_accumulated++; - dsum += (double)(fsurf_ratio); - } - } - } - } - } - } - - /* finalize */ - { - const float avg_area_ratio = (nr_accumulated > 0) ? ((float)(dsum / nr_accumulated)) : 1.0f; - const float use_as_render_bump_scale = sqrtf(avg_area_ratio); // use width of average surface ratio as your bump scale - dm->auto_bump_scale = use_as_render_bump_scale; - } - } - else { - dm->auto_bump_scale = 1.0f; - } + BKE_mesh_calc_loop_tangent_ex( + dm->getVertArray(dm), + dm->getPolyArray(dm), dm->getNumPolys(dm), + dm->getLoopArray(dm), + dm->getLoopTriArray(dm), dm->getNumLoopTri(dm), + &dm->loopData, + calc_active_tangent, + tangent_names, tangent_names_len, + CustomData_get_layer(&dm->polyData, CD_NORMAL), + dm->getLoopDataArray(dm, CD_NORMAL), + dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */ + /* result */ + &dm->loopData, dm->getNumLoops(dm), + &dm->tangent_mask); } -void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, DMVertexAttribs *attribs) +void DM_init_origspace(DerivedMesh *dm) { - CustomData *vdata, *ldata; - int a, b, layer; - const bool is_editmesh = (dm->type == DM_TYPE_EDITBMESH); - - /* From the layers requested by the GLSL shader, figure out which ones are - * actually available for this derivedmesh, and retrieve the pointers */ - - memset(attribs, 0, sizeof(DMVertexAttribs)); - - vdata = &dm->vertData; - ldata = dm->getLoopDataLayout(dm); - - /* calc auto bump scale if necessary */ - if (dm->auto_bump_scale <= 0.0f) - DM_calc_auto_bump_scale(dm); - - char tangent_names[MAX_MTFACE][MAX_NAME]; - int tangent_names_count; - /* Add a tangent layer/layers. */ - DM_calc_tangents_names_from_gpu(gattribs, tangent_names, &tangent_names_count); - - if (tangent_names_count) - dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count); - - for (b = 0; b < gattribs->totlayer; b++) { - int type = gattribs->layer[b].type; - layer = -1; - if (type == CD_AUTO_FROM_NAME) { - /* We need to deduct what exact layer is used. - * - * We do it based on the specified name. - */ - if (gattribs->layer[b].name[0]) { - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name); - type = CD_MTFACE; - if (layer == -1) { - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name); - type = CD_MCOL; - } - if (layer == -1) { - layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name); - type = CD_TANGENT; - } - if (layer == -1) { - continue; - } - } - else { - /* Fall back to the UV layer, which matches old behavior. */ - type = CD_MTFACE; - } - } - if (type == CD_MTFACE) { - /* uv coordinates */ - if (layer == -1) { - if (gattribs->layer[b].name[0]) - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name); - else - layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV); - } - - a = attribs->tottface++; - - if (layer != -1) { - attribs->tface[a].array = is_editmesh ? NULL : ldata->layers[layer].data; - attribs->tface[a].em_offset = ldata->layers[layer].offset; - } - else { - attribs->tface[a].array = NULL; - attribs->tface[a].em_offset = -1; - } - - attribs->tface[a].gl_index = gattribs->layer[b].glindex; - attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex; - attribs->tface[a].gl_texco = gattribs->layer[b].gltexco; - } - else if (type == CD_MCOL) { - if (layer == -1) { - if (gattribs->layer[b].name[0]) - layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name); - else - layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL); - } - - a = attribs->totmcol++; - - if (layer != -1) { - attribs->mcol[a].array = is_editmesh ? NULL : ldata->layers[layer].data; - /* odd, store the offset for a different layer type here, but editmode draw code expects it */ - attribs->mcol[a].em_offset = ldata->layers[layer].offset; - } - else { - attribs->mcol[a].array = NULL; - attribs->mcol[a].em_offset = -1; - } - - attribs->mcol[a].gl_index = gattribs->layer[b].glindex; - attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex; - } - else if (type == CD_TANGENT) { - /* note, even with 'is_editmesh' this uses the derived-meshes loop data */ - if (layer == -1) { - if (gattribs->layer[b].name[0]) - layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name); - else - layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT); - } + const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; - a = attribs->tottang++; + OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP); + const int numpoly = dm->getNumPolys(dm); + // const int numloop = dm->getNumLoops(dm); + MVert *mv = dm->getVertArray(dm); + MLoop *ml = dm->getLoopArray(dm); + MPoly *mp = dm->getPolyArray(dm); + int i, j, k; - if (layer != -1) { - attribs->tang[a].array = dm->loopData.layers[layer].data; - attribs->tang[a].em_offset = dm->loopData.layers[layer].offset; - } - else { - attribs->tang[a].array = NULL; - attribs->tang[a].em_offset = -1; - } + float (*vcos_2d)[2] = NULL; + BLI_array_staticdeclare(vcos_2d, 64); - attribs->tang[a].gl_index = gattribs->layer[b].glindex; - attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex; - } - else if (type == CD_ORCO) { - /* original coordinates */ - if (layer == -1) { - layer = CustomData_get_layer_index(vdata, CD_ORCO); - } - attribs->totorco = 1; + for (i = 0; i < numpoly; i++, mp++) { + OrigSpaceLoop *lof = lof_array + mp->loopstart; - if (layer != -1) { - attribs->orco.array = vdata->layers[layer].data; - attribs->orco.em_offset = vdata->layers[layer].offset; - } - else { - attribs->orco.array = NULL; - attribs->orco.em_offset = -1; + if (mp->totloop == 3 || mp->totloop == 4) { + for (j = 0; j < mp->totloop; j++, lof++) { + copy_v2_v2(lof->uv, default_osf[j]); } - - attribs->orco.gl_index = gattribs->layer[b].glindex; - attribs->orco.gl_texco = gattribs->layer[b].gltexco; - attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex; - } - } -} - -/** - * Set vertex shader attribute inputs for a particular tessface vert - * - * \param a: tessface index - * \param index: vertex index - * \param vert: corner index (0, 1, 2, 3) - * \param loop: absolute loop corner index - */ -void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop) -{ - const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - int b; - - UNUSED_VARS(a, vert); - - /* orco texture coordinates */ - if (attribs->totorco) { - /*const*/ float (*array)[3] = attribs->orco.array; - const float *orco = (array) ? array[index] : zero; - - if (attribs->orco.gl_texco) - glTexCoord3fv(orco); - else - glVertexAttrib3fv(attribs->orco.gl_index, orco); - } - - /* uv texture coordinates */ - for (b = 0; b < attribs->tottface; b++) { - const float *uv; - - if (attribs->tface[b].array) { - const MLoopUV *mloopuv = &attribs->tface[b].array[loop]; - uv = mloopuv->uv; - } - else { - uv = zero; - } - - if (attribs->tface[b].gl_texco) - glTexCoord2fv(uv); - else - glVertexAttrib2fv(attribs->tface[b].gl_index, uv); - } - - /* vertex colors */ - for (b = 0; b < attribs->totmcol; b++) { - GLfloat col[4]; - - if (attribs->mcol[b].array) { - const MLoopCol *cp = &attribs->mcol[b].array[loop]; - rgba_uchar_to_float(col, &cp->r); } else { - zero_v4(col); - } - - glVertexAttrib4fv(attribs->mcol[b].gl_index, col); - } - - /* tangent for normal mapping */ - for (b = 0; b < attribs->tottang; b++) { - if (attribs->tang[b].array) { - /*const*/ float (*array)[4] = attribs->tang[b].array; - const float *tang = (array) ? array[loop] : zero; - glVertexAttrib4fv(attribs->tang[b].gl_index, tang); - } - } -} - -void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs) -{ - int i; - if (attribs->totorco) { - if (attribs->orco.gl_info_index != -1) { - glUniform1i(attribs->orco.gl_info_index, 0); - } - } - for (i = 0; i < attribs->tottface; i++) { - if (attribs->tface[i].gl_info_index != -1) { - glUniform1i(attribs->tface[i].gl_info_index, 0); - } - } - for (i = 0; i < attribs->totmcol; i++) { - if (attribs->mcol[i].gl_info_index != -1) { - glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB); - } - } - - for (i = 0; i < attribs->tottang; i++) { - if (attribs->tang[i].gl_info_index != -1) { - glUniform1i(attribs->tang[i].gl_info_index, 0); - } - } -} - -/* Set object's bounding box based on DerivedMesh min/max data */ -void DM_set_object_boundbox(Object *ob, DerivedMesh *dm) -{ - float min[3], max[3]; - - INIT_MINMAX(min, max); - dm->getMinMax(dm, min, max); - - if (!ob->bb) - ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox"); - - BKE_boundbox_init_from_minmax(ob->bb, min, max); - - ob->bb->flag &= ~BOUNDBOX_DIRTY; -} - -/* --- NAVMESH (begin) --- */ -#ifdef WITH_GAMEENGINE - -/* BMESH_TODO, navmesh is not working right currently - * All tools set this as MPoly data, but derived mesh currently draws from MFace (tessface) - * - * Proposed solution, rather then copy CD_RECAST into the MFace array, - * use ORIGINDEX to get the original poly index and then get the CD_RECAST - * data from the original me->mpoly layer. - campbell - */ - - -BLI_INLINE int navmesh_bit(int a, int b) -{ - return (a & (1 << b)) >> b; -} - -BLI_INLINE void navmesh_intToCol(int i, float col[3]) -{ - int r = navmesh_bit(i, 0) + navmesh_bit(i, 3) * 2 + 1; - int g = navmesh_bit(i, 1) + navmesh_bit(i, 4) * 2 + 1; - int b = navmesh_bit(i, 2) + navmesh_bit(i, 5) * 2 + 1; - col[0] = 1 - r * 63.0f / 255.0f; - col[1] = 1 - g * 63.0f / 255.0f; - col[2] = 1 - b * 63.0f / 255.0f; -} - -static void navmesh_drawColored(DerivedMesh *dm) -{ - int a, glmode; - MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT); - MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE); - int *polygonIdx = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST); - float col[3]; + MLoop *l = &ml[mp->loopstart]; + float p_nor[3], co[3]; + float mat[3][3]; - if (!polygonIdx) - return; + float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX}; + float translate[2], scale[2]; -#if 0 - //UI_ThemeColor(TH_WIRE); - glLineWidth(2.0); - dm->drawEdges(dm, 0, 1); -#endif + BKE_mesh_calc_poly_normal(mp, l, mv, p_nor); + axis_dominant_v3_to_m3(mat, p_nor); - /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */ - { - DEBUG_VBO("Using legacy code. drawNavMeshColored\n"); - glBegin(glmode = GL_QUADS); - for (a = 0; a < dm->numTessFaceData; a++, mface++) { - int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES; - int pi = polygonIdx[a]; - if (pi <= 0) { - zero_v3(col); - } - else { - navmesh_intToCol(pi, col); - } + BLI_array_clear(vcos_2d); + BLI_array_reserve(vcos_2d, mp->totloop); + for (j = 0; j < mp->totloop; j++, l++) { + mul_v3_m3v3(co, mat, mv[l->v].co); + copy_v2_v2(vcos_2d[j], co); - if (new_glmode != glmode) { - glEnd(); - glBegin(glmode = new_glmode); - } - glColor3fv(col); - glVertex3fv(mvert[mface->v1].co); - glVertex3fv(mvert[mface->v2].co); - glVertex3fv(mvert[mface->v3].co); - if (mface->v4) { - glVertex3fv(mvert[mface->v4].co); + for (k = 0; k < 2; k++) { + if (co[k] > max[k]) + max[k] = co[k]; + else if (co[k] < min[k]) + min[k] = co[k]; + } } - } - glEnd(); - } -} - -static void navmesh_DM_drawFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsTex UNUSED(setDrawOptions), - DMCompareDrawOptions UNUSED(compareDrawOptions), - void *UNUSED(userData), DMDrawFlag UNUSED(flag)) -{ - navmesh_drawColored(dm); -} -static void navmesh_DM_drawFacesSolid( - DerivedMesh *dm, - float (*partial_redraw_planes)[4], - bool UNUSED(fast), DMSetMaterial UNUSED(setMaterial)) -{ - UNUSED_VARS(partial_redraw_planes); + /* Brings min to (0, 0). */ + negate_v2_v2(translate, min); - //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial); - navmesh_drawColored(dm); -} + /* Scale will bring max to (1, 1). */ + sub_v2_v2v2(scale, max, min); + if (scale[0] == 0.0f) + scale[0] = 1e-9f; + if (scale[1] == 0.0f) + scale[1] = 1e-9f; + invert_v2(scale); -static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm) -{ - DerivedMesh *result; - int maxFaces = dm->getNumPolys(dm); - int *recastData; - int vertsPerPoly = 0, nverts = 0, ndtris = 0, npolys = 0; - float *verts = NULL; - unsigned short *dtris = NULL, *dmeshes = NULL, *polys = NULL; - int *dtrisToPolysMap = NULL, *dtrisToTrisMap = NULL, *trisToFacesMap = NULL; - int res; - - result = CDDM_copy(dm); - if (!CustomData_has_layer(&result->polyData, CD_RECAST)) { - int *sourceRecastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST); - if (sourceRecastData) { - CustomData_add_layer_named(&result->polyData, CD_RECAST, CD_DUPLICATE, - sourceRecastData, maxFaces, "recastData"); - } - } - recastData = (int *)CustomData_get_layer(&result->polyData, CD_RECAST); - - /* note: This is not good design! - really should not be doing this */ - result->drawFacesTex = navmesh_DM_drawFacesTex; - result->drawFacesSolid = navmesh_DM_drawFacesSolid; - - - /* process mesh */ - res = buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nverts, &verts, &ndtris, &dtris, - &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap, - &trisToFacesMap); - if (res) { - size_t polyIdx; - - /* invalidate concave polygon */ - for (polyIdx = 0; polyIdx < (size_t)npolys; polyIdx++) { - unsigned short *poly = &polys[polyIdx * 2 * vertsPerPoly]; - if (!polyIsConvex(poly, vertsPerPoly, verts)) { - /* set negative polygon idx to all faces */ - unsigned short *dmesh = &dmeshes[4 * polyIdx]; - unsigned short tbase = dmesh[2]; - unsigned short tnum = dmesh[3]; - unsigned short ti; - - for (ti = 0; ti < tnum; ti++) { - unsigned short triidx = dtrisToTrisMap[tbase + ti]; - unsigned short faceidx = trisToFacesMap[triidx]; - if (recastData[faceidx] > 0) { - recastData[faceidx] = -recastData[faceidx]; - } - } + /* Finally, transform all vcos_2d into ((0, 0), (1, 1)) square and assign them as origspace. */ + for (j = 0; j < mp->totloop; j++, lof++) { + add_v2_v2v2(lof->uv, vcos_2d[j], translate); + mul_v2_v2(lof->uv, scale); } } } - else { - printf("Navmesh: Unable to generate valid Navmesh"); - } - /* clean up */ - if (verts != NULL) - MEM_freeN(verts); - if (dtris != NULL) - MEM_freeN(dtris); - if (dmeshes != NULL) - MEM_freeN(dmeshes); - if (polys != NULL) - MEM_freeN(polys); - if (dtrisToPolysMap != NULL) - MEM_freeN(dtrisToPolysMap); - if (dtrisToTrisMap != NULL) - MEM_freeN(dtrisToTrisMap); - if (trisToFacesMap != NULL) - MEM_freeN(trisToFacesMap); - - return result; + dm->dirty |= DM_DIRTY_TESS_CDLAYERS; + BLI_array_free(vcos_2d); } -#endif /* WITH_GAMEENGINE */ - -/* --- NAVMESH (end) --- */ - - -void DM_init_origspace(DerivedMesh *dm) +static void mesh_init_origspace(Mesh *mesh) { const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; - OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP); - const int numpoly = dm->getNumPolys(dm); - // const int numloop = dm->getNumLoops(dm); - MVert *mv = dm->getVertArray(dm); - MLoop *ml = dm->getLoopArray(dm); - MPoly *mp = dm->getPolyArray(dm); + OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP); + const int numpoly = mesh->totpoly; + // const int numloop = mesh->totloop; + MVert *mv = mesh->mvert; + MLoop *ml = mesh->mloop; + MPoly *mp = mesh->mpoly; int i, j, k; float (*vcos_2d)[2] = NULL; @@ -4190,12 +2617,11 @@ void DM_init_origspace(DerivedMesh *dm) } } - dm->dirty |= DM_DIRTY_TESS_CDLAYERS; + BKE_mesh_tessface_clear(mesh); BLI_array_free(vcos_2d); } - /* derivedmesh info printing function, * to help track down differences DM output */ @@ -4235,7 +2661,6 @@ char *DM_debug_info(DerivedMesh *dm) BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm); switch (dm->type) { case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break; - case DM_TYPE_EDITBMESH: tstr = "DM_TYPE_EDITMESH"; break; case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break; default: tstr = "UNKNOWN"; break; } @@ -4334,84 +2759,3 @@ bool DM_is_valid(DerivedMesh *dm) } #endif /* NDEBUG */ - -/* -------------------------------------------------------------------- */ - -MVert *DM_get_vert_array(DerivedMesh *dm, bool *allocated) -{ - CustomData *vert_data = dm->getVertDataLayout(dm); - MVert *mvert = CustomData_get_layer(vert_data, CD_MVERT); - *allocated = false; - - if (mvert == NULL) { - mvert = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(MVert), "dmvh vert data array"); - dm->copyVertArray(dm, mvert); - *allocated = true; - } - - return mvert; -} - -MEdge *DM_get_edge_array(DerivedMesh *dm, bool *allocated) -{ - CustomData *edge_data = dm->getEdgeDataLayout(dm); - MEdge *medge = CustomData_get_layer(edge_data, CD_MEDGE); - *allocated = false; - - if (medge == NULL) { - medge = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(MEdge), "dm medge data array"); - dm->copyEdgeArray(dm, medge); - *allocated = true; - } - - return medge; -} - -MLoop *DM_get_loop_array(DerivedMesh *dm, bool *r_allocated) -{ - CustomData *loop_data = dm->getLoopDataLayout(dm); - MLoop *mloop = CustomData_get_layer(loop_data, CD_MLOOP); - *r_allocated = false; - - if (mloop == NULL) { - mloop = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(MLoop), "dm loop data array"); - dm->copyLoopArray(dm, mloop); - *r_allocated = true; - } - - return mloop; -} - -MPoly *DM_get_poly_array(DerivedMesh *dm, bool *r_allocated) -{ - CustomData *poly_data = dm->getPolyDataLayout(dm); - MPoly *mpoly = CustomData_get_layer(poly_data, CD_MPOLY); - *r_allocated = false; - - if (mpoly == NULL) { - mpoly = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(MPoly), "dm poly data array"); - dm->copyPolyArray(dm, mpoly); - *r_allocated = true; - } - - return mpoly; -} - -MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated) -{ - CustomData *tessface_data = dm->getTessFaceDataLayout(dm); - MFace *mface = CustomData_get_layer(tessface_data, CD_MFACE); - *r_allocated = false; - - if (mface == NULL) { - int numTessFaces = dm->getNumTessFaces(dm); - - if (numTessFaces > 0) { - mface = MEM_malloc_arrayN(numTessFaces, sizeof(MFace), "bvh mface data array"); - dm->copyTessFaceArray(dm, mface); - *r_allocated = true; - } - } - - return mface; -} diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 7612e9a3fdb..87f821130c7 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -55,7 +55,6 @@ #include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idprop.h" @@ -65,6 +64,8 @@ #include "BKE_main.h" #include "BKE_object.h" +#include "DEG_depsgraph_build.h" + #include "BIK_api.h" #include "RNA_access.h" @@ -425,7 +426,7 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name) return NULL; /* See if this channel exists */ - chan = BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name)); + chan = BKE_pose_channel_find_name(pose, name); if (chan) { return chan; } @@ -453,7 +454,9 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name) chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */ BLI_addtail(&pose->chanbase, chan); - BKE_pose_channels_hash_free(pose); + if (pose->chanhash) { + BLI_ghash_insert(pose->chanhash, chan->name, chan); + } return chan; } @@ -581,12 +584,16 @@ void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const if (copy_constraints) { BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb pchan->constraints = listb; - pchan->mpath = NULL; /* motion paths should not get copied yet... */ + + /* XXX: This is needed for motionpath drawing to work. Dunno why it was setting to null before... */ + pchan->mpath = animviz_copy_motionpath(pchan->mpath); } if (pchan->prop) { pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag); } + + pchan->draw_data = NULL; /* Drawing cache, no need to copy. */ } /* for now, duplicate Bone Groups too when doing this */ @@ -780,6 +787,9 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) IDP_FreeProperty(pchan->prop); MEM_freeN(pchan->prop); } + + /* Cached data, for new draw manager rendering code. */ + MEM_SAFE_FREE(pchan->draw_data); } void BKE_pose_channel_free(bPoseChannel *pchan) @@ -849,39 +859,6 @@ void BKE_pose_free(bPose *pose) BKE_pose_free_ex(pose, true); } -static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan) -{ - bConstraint *pcon, *con; - - copy_v3_v3(pchan->loc, chan->loc); - copy_v3_v3(pchan->size, chan->size); - copy_v3_v3(pchan->eul, chan->eul); - copy_v3_v3(pchan->rotAxis, chan->rotAxis); - pchan->rotAngle = chan->rotAngle; - copy_qt_qt(pchan->quat, chan->quat); - pchan->rotmode = chan->rotmode; - copy_m4_m4(pchan->chan_mat, (float(*)[4])chan->chan_mat); - copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat); - pchan->flag = chan->flag; - - pchan->roll1 = chan->roll1; - pchan->roll2 = chan->roll2; - pchan->curveInX = chan->curveInX; - pchan->curveInY = chan->curveInY; - pchan->curveOutX = chan->curveOutX; - pchan->curveOutY = chan->curveOutY; - pchan->ease1 = chan->ease1; - pchan->ease2 = chan->ease2; - pchan->scaleIn = chan->scaleIn; - pchan->scaleOut = chan->scaleOut; - - con = chan->constraints.first; - for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) { - pcon->enforce = con->enforce; - pcon->headtail = con->headtail; - } -} - /** * Copy the internal members of each pose channel including constraints * and ID-Props, used when duplicating bones in editmode. @@ -910,7 +887,6 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f pchan->iklinweight = pchan_from->iklinweight; /* bbone settings (typically not animated) */ - pchan->bboneflag = pchan_from->bboneflag; pchan->bbone_next = pchan_from->bbone_next; pchan->bbone_prev = pchan_from->bbone_prev; @@ -1323,25 +1299,6 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan, /* ************** Pose Management Tools ****************** */ -/* Copy the data from the action-pose (src) into the pose */ -/* both args are assumed to be valid */ -/* exported to game engine */ -/* Note! this assumes both poses are aligned, this isn't always true when dealing with user poses */ -void extract_pose_from_pose(bPose *pose, const bPose *src) -{ - const bPoseChannel *schan; - bPoseChannel *pchan = pose->chanbase.first; - - if (pose == src) { - printf("extract_pose_from_pose source and target are the same\n"); - return; - } - - for (schan = src->chanbase.first; (schan && pchan); schan = schan->next, pchan = pchan->next) { - copy_pose_channel_data(pchan, schan); - } -} - /* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */ void BKE_pose_rest(bPose *pose) { @@ -1370,6 +1327,36 @@ void BKE_pose_rest(bPose *pose) } } +void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom) +{ + copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat); + copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat); + + /* used for local constraints */ + copy_v3_v3(pchanto->loc, pchanfrom->loc); + copy_qt_qt(pchanto->quat, pchanfrom->quat); + copy_v3_v3(pchanto->eul, pchanfrom->eul); + copy_v3_v3(pchanto->size, pchanfrom->size); + + copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head); + copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail); + + pchanto->roll1 = pchanfrom->roll1; + pchanto->roll2 = pchanfrom->roll2; + pchanto->curveInX = pchanfrom->curveInX; + pchanto->curveInY = pchanfrom->curveInY; + pchanto->curveOutX = pchanfrom->curveOutX; + pchanto->curveOutY = pchanfrom->curveOutY; + pchanto->ease1 = pchanfrom->ease1; + pchanto->ease2 = pchanfrom->ease2; + pchanto->scaleIn = pchanfrom->scaleIn; + pchanto->scaleOut = pchanfrom->scaleOut; + + pchanto->rotmode = pchanfrom->rotmode; + pchanto->flag = pchanfrom->flag; + pchanto->protectflag = pchanfrom->protectflag; +} + /* both poses should be in sync */ bool BKE_pose_copy_result(bPose *to, bPose *from) { @@ -1388,34 +1375,8 @@ bool BKE_pose_copy_result(bPose *to, bPose *from) for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) { pchanto = BKE_pose_channel_find_name(to, pchanfrom->name); - if (pchanto) { - copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat); - copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat); - - /* used for local constraints */ - copy_v3_v3(pchanto->loc, pchanfrom->loc); - copy_qt_qt(pchanto->quat, pchanfrom->quat); - copy_v3_v3(pchanto->eul, pchanfrom->eul); - copy_v3_v3(pchanto->size, pchanfrom->size); - - copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head); - copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail); - - pchanto->roll1 = pchanfrom->roll1; - pchanto->roll2 = pchanfrom->roll2; - pchanto->curveInX = pchanfrom->curveInX; - pchanto->curveInY = pchanfrom->curveInY; - pchanto->curveOutX = pchanfrom->curveOutX; - pchanto->curveOutY = pchanfrom->curveOutY; - pchanto->ease1 = pchanfrom->ease1; - pchanto->ease2 = pchanfrom->ease2; - pchanto->scaleIn = pchanfrom->scaleIn; - pchanto->scaleOut = pchanfrom->scaleOut; - - pchanto->rotmode = pchanfrom->rotmode; - pchanto->flag = pchanfrom->flag; - pchanto->protectflag = pchanfrom->protectflag; - pchanto->bboneflag = pchanfrom->bboneflag; + if (pchanto != NULL) { + BKE_pose_copyesult_pchan_result(pchanto, pchanfrom); } } return true; @@ -1428,7 +1389,7 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose) /* Depsgraph components depends on actual pose state, * if pose was changed depsgraph is to be updated as well. */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); } /* For the calculation of the effects of an Action at the given frame on an object @@ -1486,7 +1447,7 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c RNA_id_pointer_create(&workob->id, &id_ptr); /* execute action for this group only */ - animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe); + animsys_evaluate_action_group(&id_ptr, act, agrp, cframe); } else { AnimData adt = {NULL}; @@ -1498,6 +1459,6 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c adt.action = act; /* execute effects of Action on to workob (or it's PoseChannels) */ - BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(NULL, NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM); } } diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index d5f269b82a8..c3b6041243d 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -35,6 +35,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_dlrbTree.h" #include "BLT_translation.h" @@ -43,18 +44,29 @@ #include "DNA_key_types.h" #include "DNA_scene_types.h" +#include "BKE_anim.h" +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_key.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" -#include "BKE_anim.h" #include "BKE_report.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" +#include "DEG_depsgraph_build.h" + +#include "GPU_batch.h" + // XXX bad level call... +extern short compare_ak_cfraPtr(void *node, void *data); +extern void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys, int saction_flag); +extern void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, int saction_flag); /* --------------------- */ /* forward declarations */ @@ -87,6 +99,8 @@ void animviz_settings_init(bAnimVizSettings *avs) avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS); avs->path_step = 1; + + avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS; } /* ------------------- */ @@ -102,6 +116,10 @@ void animviz_free_motionpath_cache(bMotionPath *mpath) if (mpath->points) MEM_freeN(mpath->points); + GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo); + GPU_BATCH_DISCARD_SAFE(mpath->batch_line); + GPU_BATCH_DISCARD_SAFE(mpath->batch_points); + /* reset the relevant parameters */ mpath->points = NULL; mpath->length = 0; @@ -125,6 +143,27 @@ void animviz_free_motionpath(bMotionPath *mpath) /* ------------------- */ +/* Make a copy of motionpath data, so that viewing with copy on write works */ +bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src) +{ + bMotionPath *mpath_dst; + + if (mpath_src == NULL) + return NULL; + + mpath_dst = MEM_dupallocN(mpath_src); + mpath_dst->points = MEM_dupallocN(mpath_src->points); + + /* should get recreated on draw... */ + mpath_dst->points_vbo = NULL; + mpath_dst->batch_line = NULL; + mpath_dst->batch_points = NULL; + + return mpath_dst; +} + +/* ------------------- */ + /** * Setup motion paths for the given data. * \note Only used when explicitly calculating paths on bones which may/may not be consider already @@ -207,7 +246,7 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec mpath->color[1] = 0.0; mpath->color[2] = 0.0; - mpath->line_thickness = 1; + mpath->line_thickness = 2; mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */ /* allocate a cache */ @@ -228,8 +267,16 @@ typedef struct MPathTarget { bMotionPath *mpath; /* motion path in question */ + DLRBT_Tree keys; /* temp, to know where the keyframes are */ + + /* Original (Source Objects) */ Object *ob; /* source object */ bPoseChannel *pchan; /* source posechannel (if applicable) */ + + /* "Evaluated" Copies (these come from the background COW copie + * that provide all the coordinates we want to save off) + */ + Object *ob_eval; /* evaluated object */ } MPathTarget; /* ........ */ @@ -273,127 +320,95 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets) /* ........ */ -/* Note on evaluation optimizations: - * Optimization's currently used here play tricks with the depsgraph in order to try and - * evaluate as few objects as strictly necessary to get nicer performance under standard - * production conditions. For those people who really need the accurate version, - * disable the ifdef (i.e. 1 -> 0) and comment out the call to motionpaths_calc_optimise_depsgraph() - */ - -/* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */ -static void motionpaths_calc_optimise_depsgraph(Main *bmain, Scene *scene, ListBase *targets) -{ - Base *base, *baseNext; - MPathTarget *mpt; - - /* make sure our temp-tag isn't already in use */ - for (base = scene->base.first; base; base = base->next) - base->object->flag &= ~BA_TEMP_TAG; - - /* for each target, dump its object to the start of the list if it wasn't moved already */ - for (mpt = targets->first; mpt; mpt = mpt->next) { - for (base = scene->base.first; base; base = baseNext) { - baseNext = base->next; - - if ((base->object == mpt->ob) && !(mpt->ob->flag & BA_TEMP_TAG)) { - BLI_remlink(&scene->base, base); - BLI_addhead(&scene->base, base); - - mpt->ob->flag |= BA_TEMP_TAG; - - /* we really don't need to continue anymore once this happens, but this line might really 'break' */ - break; - } - } - } - - /* "brew me a list that's sorted a bit faster now depsy" */ - DAG_scene_relations_rebuild(bmain, scene); -} - /* update scene for current frame */ -static void motionpaths_calc_update_scene(Main *bmain, Scene *scene) +static void motionpaths_calc_update_scene(Main *bmain, + struct Depsgraph *depsgraph) { -#if 1 // 'production' optimizations always on - /* rigid body simulation needs complete update to work correctly for now */ - /* RB_TODO investigate if we could avoid updating everything */ - if (BKE_scene_check_rigidbody_active(scene)) { - BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); - } - else { /* otherwise we can optimize by restricting updates */ - Base *base, *last = NULL; - - /* only stuff that moves or needs display still */ - DAG_scene_update_flags(bmain, scene, scene->lay, true, false); - - /* find the last object with the tag - * - all those afterwards are assumed to not be relevant for our calculations - */ - /* optimize further by moving out... */ - for (base = scene->base.first; base; base = base->next) { - if (base->object->flag & BA_TEMP_TAG) - last = base; - } - - /* 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 */ - for (base = scene->base.first; base; base = base->next) { - /* update this object */ - BKE_object_handle_update(bmain, bmain->eval_ctx, scene, base->object); - - /* if this is the last one we need to update, let's stop to save some time */ - if (base == last) - break; - } - } -#else // original, 'always correct' version - /* do all updates - * - if this is too slow, resort to using a more efficient way - * that doesn't force complete update, but for now, this is the - * most accurate way! + /* Do all updates + * - if this is too slow, resort to using a more efficient way + * that doesn't force complete update, but for now, this is the + * most accurate way! + * + * TODO(segey): Bring back partial updates, which became impossible + * with the new depsgraph due to unsorted nature of bases. + * + * TODO(sergey): Use evaluation context dedicated to motion paths. */ - BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); /* XXX this is the best way we can get anything moving */ -#endif + BKE_scene_graph_update_for_newframe(depsgraph, bmain); } /* ........ */ /* perform baking for the targets on the current frame */ -static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets) +static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) { MPathTarget *mpt; /* for each target, check if it can be baked on the current frame */ for (mpt = targets->first; mpt; mpt = mpt->next) { bMotionPath *mpath = mpt->mpath; - bMotionPathVert *mpv; /* current frame must be within the range the cache works for * - is inclusive of the first frame, but not the last otherwise we get buffer overruns */ - if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame)) + if ((cframe < mpath->start_frame) || (cframe >= mpath->end_frame)) { continue; + } /* get the relevant cache vert to write to */ - mpv = mpath->points + (CFRA - mpath->start_frame); + bMotionPathVert *mpv = mpath->points + (cframe - mpath->start_frame); - /* pose-channel or object path baking? */ + Object *ob_eval = mpt->ob_eval; + + /* Lookup evaluated pose channel, here because the depsgraph + * evaluation can change them so they are not cached in mpt. */ + bPoseChannel *pchan_eval = NULL; if (mpt->pchan) { + pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name); + } + + /* pose-channel or object path baking? */ + if (pchan_eval) { /* heads or tails */ if (mpath->flag & MOTIONPATH_FLAG_BHEAD) { - copy_v3_v3(mpv->co, mpt->pchan->pose_head); + copy_v3_v3(mpv->co, pchan_eval->pose_head); } else { - copy_v3_v3(mpv->co, mpt->pchan->pose_tail); + copy_v3_v3(mpv->co, pchan_eval->pose_tail); } /* result must be in worldspace */ - mul_m4_v3(mpt->ob->obmat, mpv->co); + mul_m4_v3(ob_eval->obmat, mpv->co); } else { /* worldspace object location */ - copy_v3_v3(mpv->co, mpt->ob->obmat[3]); + copy_v3_v3(mpv->co, ob_eval->obmat[3]); + } + + float mframe = (float)(cframe); + + /* Tag if it's a keyframe */ + if (BLI_dlrbTree_search_exact(&mpt->keys, compare_ak_cfraPtr, &mframe)) { + mpv->flag |= MOTIONPATH_VERT_KEY; + } + + /* Incremental update on evaluated object if possible, for fast updating + * while dragging in transform. */ + bMotionPath *mpath_eval = NULL; + if (mpt->pchan) { + mpath_eval = (pchan_eval) ? pchan_eval->mpath : NULL; + } + else { + mpath_eval = ob_eval->mpath; + } + + if (mpath_eval && mpath_eval->length == mpath->length) { + bMotionPathVert *mpv_eval = mpath_eval->points + (cframe - mpath_eval->start_frame); + *mpv_eval = *mpv; + + GPU_VERTBUF_DISCARD_SAFE(mpath_eval->points_vbo); + GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_line); + GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_points); } } } @@ -404,50 +419,110 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets) * - recalc: whether we need to */ /* TODO: include reports pointer? */ -void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets) +void animviz_calc_motionpaths(Depsgraph *depsgraph, + Main *bmain, + Scene *scene, + ListBase *targets, + bool restore, + bool current_frame_only) { - MPathTarget *mpt; - int sfra, efra; - int cfra; - /* sanity check */ if (ELEM(NULL, targets, targets->first)) return; - /* set frame values */ - cfra = CFRA; - sfra = efra = cfra; - - /* TODO: this method could be improved... + /* Compute frame range to bake within. + * TODO: this method could be improved... * 1) max range for standard baking * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */ - for (mpt = targets->first; mpt; mpt = mpt->next) { + int sfra = INT_MAX; + int efra = INT_MIN; + + for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { /* try to increase area to do (only as much as needed) */ sfra = MIN2(sfra, mpt->mpath->start_frame); efra = MAX2(efra, mpt->mpath->end_frame); } - if (efra <= sfra) return; - /* optimize the depsgraph for faster updates */ - /* TODO: whether this is used should depend on some setting for the level of optimizations used */ - motionpaths_calc_optimise_depsgraph(bmain, scene, targets); + if (efra <= sfra) { + return; + } + + /* Limit frame range if we are updating just the current frame. */ + /* set frame values */ + int cfra = CFRA; + if (current_frame_only) { + if (cfra < sfra || cfra > efra) { + return; + } + sfra = efra = cfra; + } + + /* get copies of objects/bones to get the calculated results from + * (for copy-on-write evaluation), so that we actually get some results + */ + // TODO: Create a copy of background depsgraph that only contain these entities, and only evaluates them.. + for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { + mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob); + + AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id); + + /* build list of all keyframes in active action for object or pchan */ + BLI_dlrbTree_init(&mpt->keys); + + if (adt) { + bAnimVizSettings *avs; + + /* get pointer to animviz settings for each target */ + if (mpt->pchan) + avs = &mpt->ob->pose->avs; + else + avs = &mpt->ob->avs; + + /* it is assumed that keyframes for bones are all grouped in a single group + * unless an option is set to always use the whole action + */ + if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) { + bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name); + + if (agrp) { + agroup_to_keylist(adt, agrp, &mpt->keys, 0); + } + } + else { + action_to_keylist(adt, adt->action, &mpt->keys, 0); + } + } + } /* calculate path over requested range */ + printf("Calculating MotionPaths between frames %d - %d (%d frames)\n", sfra, efra, efra - sfra + 1); for (CFRA = sfra; CFRA <= efra; CFRA++) { - /* update relevant data for new frame */ - motionpaths_calc_update_scene(bmain, scene); + if (current_frame_only) { + /* For current frame, only update tagged. */ + BKE_scene_graph_update_tagged(depsgraph, bmain); + } + else { + /* Update relevant data for new frame. */ + motionpaths_calc_update_scene(bmain, depsgraph); + } /* perform baking for targets */ - motionpaths_calc_bake_targets(scene, targets); + motionpaths_calc_bake_targets(targets, CFRA); } /* reset original environment */ + /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph + * may be a temporary one that works on a subset of the data. We always have + * to resoture the current frame though. */ CFRA = cfra; - motionpaths_calc_update_scene(bmain, scene); + if (!current_frame_only && restore) { + motionpaths_calc_update_scene(bmain, depsgraph); + } /* clear recalc flags from targets */ - for (mpt = targets->first; mpt; mpt = mpt->next) { + for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { bAnimVizSettings *avs; + bMotionPath *mpath = mpt->mpath; /* get pointer to animviz settings for each target */ if (mpt->pchan) @@ -457,6 +532,14 @@ void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets) /* clear the flag requesting recalculation of targets */ avs->recalc &= ~ANIMVIZ_RECALC_PATHS; + + /* Clean temp data */ + BLI_dlrbTree_free(&mpt->keys); + + /* Free previous batches to force update. */ + GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo); + GPU_BATCH_DISCARD_SAFE(mpath->batch_line); + GPU_BATCH_DISCARD_SAFE(mpath->batch_points); } } @@ -494,18 +577,18 @@ void calc_curvepath(Object *ob, ListBase *nurbs) return; } - if (ob->curve_cache->path) free_path(ob->curve_cache->path); - ob->curve_cache->path = NULL; + if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path); + ob->runtime.curve_cache->path = NULL; /* weak! can only use first curve */ - bl = ob->curve_cache->bev.first; + bl = ob->runtime.curve_cache->bev.first; if (bl == NULL || !bl->nr) { return; } nu = nurbs->first; - ob->curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath"); + ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath"); /* if POLY: last vertice != first vertice */ cycl = (bl->poly != -1); @@ -622,15 +705,15 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua if (ob == NULL || ob->type != OB_CURVE) return 0; cu = ob->data; - if (ob->curve_cache == NULL || ob->curve_cache->path == NULL || ob->curve_cache->path->data == NULL) { + if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL || ob->runtime.curve_cache->path->data == NULL) { printf("no path!\n"); return 0; } - path = ob->curve_cache->path; + path = ob->runtime.curve_cache->path; pp = path->data; /* test for cyclic */ - bl = ob->curve_cache->bev.first; + bl = ob->runtime.curve_cache->bev.first; if (!bl) return 0; if (!bl->nr) return 0; if (bl->poly > -1) cycl = 1; diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index b17bc70c51a..351e765a8ea 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -57,27 +57,27 @@ #include "DNA_texture_types.h" #include "DNA_world_types.h" -#include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" -#include "BKE_nla.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_library.h" +#include "BKE_nla.h" #include "BKE_report.h" #include "BKE_texture.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "RNA_access.h" #include "nla_private.h" #include "atomic_ops.h" -#include "DEG_depsgraph.h" - /* ***************************************** */ /* AnimData API */ @@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type) case ID_MA: case ID_TE: case ID_NT: case ID_LA: case ID_CA: case ID_WO: case ID_LS: + case ID_LP: case ID_SPK: case ID_SCE: case ID_MC: @@ -245,11 +246,14 @@ void BKE_animdata_free(ID *id, const bool do_id_user) } /* free nla data */ - BKE_nla_tracks_free(&adt->nla_tracks); + BKE_nla_tracks_free(&adt->nla_tracks, do_id_user); /* free drivers - stored as a list of F-Curves */ free_fcurves(&adt->drivers); + /* free driver array cache */ + MEM_SAFE_FREE(adt->driver_array); + /* free overrides */ /* TODO... */ @@ -262,11 +266,18 @@ void BKE_animdata_free(ID *id, const bool do_id_user) /* Copying -------------------------------------------- */ -/* Make a copy of the given AnimData - to be used when copying datablocks */ -AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action) +/** + * Make a copy of the given AnimData - to be used when copying datablocks. + * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h + * \return The copied animdata. + */ +AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag) { AnimData *dadt; + const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0; + const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0; + /* sanity check before duplicating struct */ if (adt == NULL) return NULL; @@ -278,16 +289,17 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action) BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, 0, false); BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, 0, false); } - else { + else if (do_id_user) { id_us_plus((ID *)dadt->action); id_us_plus((ID *)dadt->tmpact); } /* duplicate NLA data */ - BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks); + BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag); /* duplicate drivers (F-Curves) */ copy_fcurves(&dadt->drivers, &adt->drivers); + dadt->driver_array = NULL; /* don't copy overrides */ BLI_listbase_clear(&dadt->overrides); @@ -296,19 +308,23 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action) return dadt; } -bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action) +/** + * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h + * \return true is succesfully copied. + */ +bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag) { AnimData *adt; if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) return false; - BKE_animdata_free(id_to, true); + BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0); adt = BKE_animdata_from_id(id_from); if (adt) { IdAdtTemplate *iat = (IdAdtTemplate *)id_to; - iat->adt = BKE_animdata_copy(bmain, adt, do_action); + iat->adt = BKE_animdata_copy(bmain, adt, flag); } return true; @@ -368,7 +384,7 @@ void BKE_animdata_merge_copy( if (src->nla_tracks.first) { ListBase tracks = {NULL, NULL}; - BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks); + BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0); BLI_movelisttolist(&dst->nla_tracks, &tracks); } @@ -604,36 +620,8 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p Object *ob = CTX_data_active_object(C); if (ob && id) { - /* only id-types which can be remapped to go through objects should be considered */ - switch (GS(id->name)) { - case ID_TE: /* textures */ - { - Material *ma = give_current_material(ob, ob->actcol); - Tex *tex = give_current_material_texture(ma); - - /* assumes: texture will only be shown if it is active material's active texture it's ok */ - if ((ID *)tex == id) { - char name_esc_ma[(sizeof(ma->id.name) - 2) * 2]; - char name_esc_tex[(sizeof(tex->id.name) - 2) * 2]; - - BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma)); - BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex)); - - /* create new path */ - // TODO: use RNA path functions to construct step by step instead? - // FIXME: maybe this isn't even needed anymore... - path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s", - name_esc_ma, name_esc_tex, basepath); - - /* free old one */ - if (basepath != base_path) - MEM_freeN(basepath); - } - break; - } - default: - break; - } + /* TODO: after material textures were removed, this function serves + * no purpose anymore, but could be used again so was not removed. */ /* fix RNA pointer, as we've now changed the ID root by changing the paths */ if (basepath != path) { @@ -1173,6 +1161,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use /* grease pencil */ ANIMDATA_IDS_CB(bmain->gpencil.first); + /* palettes */ + ANIMDATA_IDS_CB(bmain->palettes.first); + /* cache files */ ANIMDATA_IDS_CB(bmain->cachefiles.first); } @@ -1477,42 +1468,14 @@ void BKE_keyingsets_free(ListBase *list) /* ***************************************** */ /* Evaluation Data-Setting Backend */ -/* Retrieve string to act as RNA-path, adjusted using mapping-table if provided - * It returns whether the string needs to be freed (i.e. if it was a temp remapped one) - * // FIXME: maybe it would be faster if we didn't have to alloc/free strings like this all the time, but for now it's safer - * - * - remap: remapping table to use - * - path: original path string (as stored in F-Curve data) - * - dst: destination string to write data to - */ -static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst) -{ - /* is there a valid remapping table to use? */ -#if 0 - if (remap) { - /* find a matching entry... to use to remap */ - /* ...TODO... */ - } -#endif - - /* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */ - *dst = path; - return false; -} - static bool animsys_store_rna_setting( - PointerRNA *ptr, AnimMapper *remap, + PointerRNA *ptr, /* typically 'fcu->rna_path', 'fcu->array_index' */ const char *rna_path, const int array_index, PathResolvedRNA *r_result) { bool success = false; - - char *path = NULL; - bool free_path; - - /* get path, remapped as appropriate to work in its new environment */ - free_path = animsys_remap_path(remap, (char *)rna_path, &path); + const char *path = rna_path; /* write value to setting */ if (path) { @@ -1546,11 +1509,6 @@ static bool animsys_store_rna_setting( } } - /* free temp path-info */ - if (free_path) { - MEM_freeN((void *)path); - } - return success; } @@ -1558,6 +1516,72 @@ static bool animsys_store_rna_setting( /* less than 1.0 evaluates to false, use epsilon to avoid float error */ #define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON))) +static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value) +{ + PropertyRNA *prop = anim_rna->prop; + PointerRNA *ptr = &anim_rna->ptr; + int array_index = anim_rna->prop_index; + float orig_value; + + /* caller must ensure this is animatable */ + BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + { + if (array_index != -1) { + const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index); + orig_value = (float)orig_value_coerce; + } + else { + const int orig_value_coerce = RNA_property_boolean_get(ptr, prop); + orig_value = (float)orig_value_coerce; + } + break; + } + case PROP_INT: + { + if (array_index != -1) { + const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index); + orig_value = (float)orig_value_coerce; + } + else { + const int orig_value_coerce = RNA_property_int_get(ptr, prop); + orig_value = (float)orig_value_coerce; + } + break; + } + case PROP_FLOAT: + { + if (array_index != -1) { + const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index); + orig_value = (float)orig_value_coerce; + } + else { + const float orig_value_coerce = RNA_property_float_get(ptr, prop); + orig_value = (float)orig_value_coerce; + } + break; + } + case PROP_ENUM: + { + const int orig_value_coerce = RNA_property_enum_get(ptr, prop); + orig_value = (float)orig_value_coerce; + break; + } + default: + /* nothing can be done here... so it is unsuccessful? */ + return false; + } + + if (r_value != NULL) { + *r_value = orig_value; + } + + /* successful */ + return true; +} + /* Write the given value to a setting using RNA, and return success */ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value) { @@ -1568,27 +1592,24 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val /* caller must ensure this is animatable */ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL); - /* set value for animatable numerical values only - * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated - * without an ID provided, which causes the animateable test to fail! - */ - bool written = false; + /* Check whether value is new. Otherwise we skip all the updates. */ + float old_value; + if (!animsys_read_rna_setting(anim_rna, &old_value)) { + return false; + } + if (old_value == value) { + return true; + } switch (RNA_property_type(prop)) { case PROP_BOOLEAN: { const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value); if (array_index != -1) { - if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) { - RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce); - written = true; - } + RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce); } else { - if (RNA_property_boolean_get(ptr, prop) != value_coerce) { - RNA_property_boolean_set(ptr, prop, value_coerce); - written = true; - } + RNA_property_boolean_set(ptr, prop, value_coerce); } break; } @@ -1597,16 +1618,10 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val int value_coerce = (int)value; RNA_property_int_clamp(ptr, prop, &value_coerce); if (array_index != -1) { - if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) { - RNA_property_int_set_index(ptr, prop, array_index, value_coerce); - written = true; - } + RNA_property_int_set_index(ptr, prop, array_index, value_coerce); } else { - if (RNA_property_int_get(ptr, prop) != value_coerce) { - RNA_property_int_set(ptr, prop, value_coerce); - written = true; - } + RNA_property_int_set(ptr, prop, value_coerce); } break; } @@ -1615,26 +1630,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val float value_coerce = value; RNA_property_float_clamp(ptr, prop, &value_coerce); if (array_index != -1) { - if (RNA_property_float_get_index(ptr, prop, array_index) != value_coerce) { - RNA_property_float_set_index(ptr, prop, array_index, value_coerce); - written = true; - } + RNA_property_float_set_index(ptr, prop, array_index, value_coerce); } else { - if (RNA_property_float_get(ptr, prop) != value_coerce) { - RNA_property_float_set(ptr, prop, value_coerce); - written = true; - } + RNA_property_float_set(ptr, prop, value_coerce); } break; } case PROP_ENUM: { const int value_coerce = (int)value; - if (RNA_property_enum_get(ptr, prop) != value_coerce) { - RNA_property_enum_set(ptr, prop, value_coerce); - written = true; - } + RNA_property_enum_set(ptr, prop, value_coerce); break; } default: @@ -1642,54 +1648,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val return false; } - /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */ -#if 0 - /* buffer property update for later flushing */ - if (written && RNA_property_update_check(prop)) { - short skip_updates_hack = 0; - - /* optimization hacks: skip property updates for those properties - * for we know that which the updates in RNA were really just for - * flushing property editing via UI/Py - */ - if (new_ptr.type == &RNA_PoseBone) { - /* bone transforms - update pose (i.e. tag depsgraph) */ - skip_updates_hack = 1; - } - - if (skip_updates_hack == 0) - RNA_property_update_cache_add(ptr, prop); - } -#endif - - /* as long as we don't do property update, we still tag datablock - * as having been updated. this flag does not cause any updates to - * be run, it's for e.g. render engines to synchronize data */ - if (written && ptr->id.data) { - ID *id = ptr->id.data; - - /* for cases like duplifarmes it's only a temporary so don't - * notify anyone of updates */ - if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) { - /* NOTE: This is a bit annoying to use atomic API here, but this - * code is at it's EOL and removed already in 2.8 branch. - */ - atomic_fetch_and_or_int32(&id->recalc, ID_RECALC); - DAG_id_type_tag(G.main, GS(id->name)); - } - } - /* successful */ return true; } /* Simple replacement based data-setting of the FCurve using RNA */ -bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval) +bool BKE_animsys_execute_fcurve(PointerRNA *ptr, FCurve *fcu, float curval) { PathResolvedRNA anim_rna; bool ok = false; - if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { ok = animsys_write_rna_setting(&anim_rna, curval); } @@ -1697,24 +1666,53 @@ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, return ok; } +static void animsys_write_orig_anim_rna( + PointerRNA *ptr, + const char *rna_path, + int array_index, + float value) +{ + /* Pointer is expected to be an ID pointer, if it's not -- we are doomed. + * + * NOTE: It is possible to have animation data on NLA strip, see T57360. + * TODO(sergey): Find solution for those cases. + */ + if (ptr->id.data == NULL) { + return; + } + PointerRNA orig_ptr = *ptr; + orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id; + orig_ptr.data = orig_ptr.id.data; + PathResolvedRNA orig_anim_rna; + /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */ + if (animsys_store_rna_setting(&orig_ptr, rna_path, array_index, &orig_anim_rna)) { + animsys_write_rna_setting(&orig_anim_rna, value); + } +} + /* Evaluate all the F-Curves in the given list * This performs a set of standard checks. If extra checks are required, separate code should be used */ -static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper *remap, float ctime) -{ - FCurve *fcu; - - /* calculate then execute each curve */ - for (fcu = list->first; fcu; fcu = fcu->next) { - /* check if this F-Curve doesn't belong to a muted group */ - if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) { - /* check if this curve should be skipped */ - if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { - PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { - const float curval = calculate_fcurve(&anim_rna, fcu, ctime); - animsys_write_rna_setting(&anim_rna, curval); - } +static void animsys_evaluate_fcurves( + Depsgraph *depsgraph, PointerRNA *ptr, ListBase *list, float ctime) +{ + const bool is_active_depsgraph = DEG_is_active(depsgraph); + /* Calculate then execute each curve. */ + for (FCurve *fcu = list->first; fcu; fcu = fcu->next) { + /* Check if this F-Curve doesn't belong to a muted group. */ + if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) { + continue; + } + /* Check if this curve should be skipped. */ + if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) { + continue; + } + PathResolvedRNA anim_rna; + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float curval = calculate_fcurve(&anim_rna, fcu, ctime); + animsys_write_rna_setting(&anim_rna, curval); + if (is_active_depsgraph) { + animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval); } } } @@ -1745,7 +1743,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime * new to only be done when drivers only changed */ PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); ok = animsys_write_rna_setting(&anim_rna, curval); } @@ -1798,13 +1796,12 @@ static void action_idcode_patch_check(ID *id, bAction *act) /* ----------------------------------------- */ /* Evaluate Action Group */ -void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, AnimMapper *remap, float ctime) +void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, float ctime) { FCurve *fcu; /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ if (ELEM(NULL, act, agrp)) return; - if ((remap) && (remap->target != act)) remap = NULL; action_idcode_patch_check(ptr->id.data, act); @@ -1817,7 +1814,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, ctime); animsys_write_rna_setting(&anim_rna, curval); } @@ -1826,16 +1823,21 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup * } /* Evaluate Action (F-Curve Bag) */ -void animsys_evaluate_action(PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime) +static void animsys_evaluate_action_ex( + Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime) { /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ if (act == NULL) return; - if ((remap) && (remap->target != act)) remap = NULL; action_idcode_patch_check(ptr->id.data, act); /* calculate then execute each curve */ - animsys_evaluate_fcurves(ptr, &act->curves, remap, ctime); + animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, ctime); +} + +void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime) +{ + animsys_evaluate_action_ex(depsgraph, ptr, act, ctime); } /* ***************************************** */ @@ -1864,7 +1866,7 @@ static float nlastrip_get_influence(NlaStrip *strip, float cframe) } /* evaluate the evaluation time and influence for the strip, storing the results in the strip */ -static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime) +static void nlastrip_evaluate_controls(Depsgraph *depsgraph, NlaStrip *strip, float ctime) { /* now strip's evaluate F-Curves for these settings (if applicable) */ if (strip->fcurves.first) { @@ -1874,7 +1876,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime) RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); /* execute these settings as per normal */ - animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime); + animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, ctime); } /* analytically generate values for influence and time (if applicable) @@ -1896,7 +1898,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime) } /* gets the strip active at the current time for a list of strips for evaluation purposes */ -NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime) +NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime) { NlaStrip *strip, *estrip = NULL; NlaEvalStrip *nes; @@ -1973,7 +1975,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short * - negative influence is not supported yet... how would that be defined? */ /* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */ - nlastrip_evaluate_controls(estrip, ctime); + nlastrip_evaluate_controls(depsgraph, estrip, ctime); if (estrip->influence <= 0.0f) return NULL; @@ -1992,8 +1994,8 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short return NULL; /* evaluate controls for the relevant extents of the bordering strips... */ - nlastrip_evaluate_controls(estrip->prev, estrip->start); - nlastrip_evaluate_controls(estrip->next, estrip->end); + nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start); + nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end); break; } @@ -2016,7 +2018,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short /* find an NlaEvalChannel that matches the given criteria * - ptr and prop are the RNA data to find a match for */ -static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index) +static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, const PathResolvedRNA *prna) { NlaEvalChannel *nec; @@ -2031,7 +2033,7 @@ static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *pt * other data stored in PointerRNA cannot allow us to definitively * identify the data */ - if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index)) + if ((nec->rna.ptr.data == prna->ptr.data) && (nec->rna.prop == prna->prop) && ELEM(nec->rna.prop_index, -1, prna->prop_index)) return nec; } @@ -2040,11 +2042,11 @@ static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *pt } /* initialise default value for NlaEvalChannel, so that it doesn't blend things wrong */ -static void nlaevalchan_value_init(NlaEvalChannel *nec) +static float nlaevalchan_init_value(PathResolvedRNA *rna) { - PointerRNA *ptr = &nec->ptr; - PropertyRNA *prop = nec->prop; - int index = nec->index; + PointerRNA *ptr = &rna->ptr; + PropertyRNA *prop = rna->prop; + int index = rna->prop_index; /* NOTE: while this doesn't work for all RNA properties as default values aren't in fact * set properly for most of them, at least the common ones (which also happen to get used @@ -2053,61 +2055,43 @@ static void nlaevalchan_value_init(NlaEvalChannel *nec) switch (RNA_property_type(prop)) { case PROP_BOOLEAN: if (RNA_property_array_check(prop)) - nec->value = (float)RNA_property_boolean_get_default_index(ptr, prop, index); + return (float)RNA_property_boolean_get_default_index(ptr, prop, index); else - nec->value = (float)RNA_property_boolean_get_default(ptr, prop); - break; + return (float)RNA_property_boolean_get_default(ptr, prop); case PROP_INT: if (RNA_property_array_check(prop)) - nec->value = (float)RNA_property_int_get_default_index(ptr, prop, index); + return (float)RNA_property_int_get_default_index(ptr, prop, index); else - nec->value = (float)RNA_property_int_get_default(ptr, prop); - break; + return (float)RNA_property_int_get_default(ptr, prop); case PROP_FLOAT: if (RNA_property_array_check(prop)) - nec->value = RNA_property_float_get_default_index(ptr, prop, index); + return RNA_property_float_get_default_index(ptr, prop, index); else - nec->value = RNA_property_float_get_default(ptr, prop); - break; + return RNA_property_float_get_default(ptr, prop); case PROP_ENUM: - nec->value = (float)RNA_property_enum_get_default(ptr, prop); - break; + return (float)RNA_property_enum_get_default(ptr, prop); default: - break; + return 0.0f; } } /* verify that an appropriate NlaEvalChannel for this F-Curve exists */ -static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, bool *newChan) +static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, FCurve *fcu, bool *newChan) { NlaEvalChannel *nec; - NlaStrip *strip = nes->strip; - PropertyRNA *prop; - PointerRNA new_ptr; - char *path = NULL; - /* short free_path = 0; */ + PathResolvedRNA rna; /* sanity checks */ if (channels == NULL) return NULL; /* get RNA pointer+property info from F-Curve for more convenient handling */ - /* get path, remapped as appropriate to work in its new environment */ - /* free_path = */ /* UNUSED */ animsys_remap_path(strip->remap, fcu->rna_path, &path); - - /* a valid property must be available, and it must be animatable */ - if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop) == false) { - if (G.debug & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path\n"); - return NULL; - } - /* only ok if animatable */ - else if (RNA_property_animateable(&new_ptr, prop) == 0) { - if (G.debug & G_DEBUG) printf("NLA Strip Eval: Property not animatable\n"); + if (!animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &rna)) { return NULL; } /* try to find a match */ - nec = nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index); + nec = nlaevalchan_find_match(channels, &rna); /* allocate a new struct for this if none found */ if (nec == NULL) { @@ -2115,12 +2099,13 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, N BLI_addtail(channels, nec); /* store property links for writing to the property later */ - nec->ptr = new_ptr; - nec->prop = prop; - nec->index = fcu->array_index; + nec->rna = rna; + + /* store parameters for use with write_orig_anim_rna */ + nec->rna_path = fcu->rna_path; /* initialise value using default value of property [#35856] */ - nlaevalchan_value_init(nec); + nec->value = nlaevalchan_init_value(&rna); *newChan = true; } else @@ -2199,7 +2184,7 @@ static void nlaevalchan_buffers_accumulate(ListBase *channels, ListBase *tmp_buf necn = nec->next; /* try to find an existing matching channel for this setting in the accumulation buffer */ - necd = nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index); + necd = nlaevalchan_find_match(channels, &nec->rna); /* if there was a matching channel already in the buffer, accumulate to it, * otherwise, add the current channel to the buffer for efficiency @@ -2326,7 +2311,7 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, ListBase *channels, Li /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s) * stored in this channel if it has been used already */ - nec = nlaevalchan_verify(ptr, channels, nes, fcu, &newChan); + nec = nlaevalchan_verify(ptr, channels, fcu, &newChan); if (nec) nlaevalchan_accumulate(nec, nes, value, newChan); } @@ -2339,7 +2324,8 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, ListBase *channels, Li } /* evaluate transition strip */ -static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) +static void nlastrip_evaluate_transition( + Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) { ListBase tmp_channels = {NULL, NULL}; ListBase tmp_modifiers = {NULL, NULL}; @@ -2379,12 +2365,12 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li /* first strip */ tmp_nes.strip_mode = NES_TIME_TRANSITION_START; tmp_nes.strip = s1; - nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); + nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); /* second strip */ tmp_nes.strip_mode = NES_TIME_TRANSITION_END; tmp_nes.strip = s2; - nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); + nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); /* accumulate temp-buffer and full-buffer, using the 'real' strip */ @@ -2395,7 +2381,8 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li } /* evaluate meta-strip */ -static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) +static void nlastrip_evaluate_meta( + Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) { ListBase tmp_modifiers = {NULL, NULL}; NlaStrip *strip = nes->strip; @@ -2415,13 +2402,13 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase /* find the child-strip to evaluate */ evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start; - tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime); + tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime); /* directly evaluate child strip into accumulation buffer... * - there's no need to use a temporary buffer (as it causes issues [T40082]) */ if (tmp_nes) { - nlastrip_evaluate(ptr, channels, &tmp_modifiers, tmp_nes); + nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes); /* free temp eval-strip */ MEM_freeN(tmp_nes); @@ -2432,7 +2419,7 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase } /* evaluates the given evaluation strip */ -void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) +void nlastrip_evaluate(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) { NlaStrip *strip = nes->strip; @@ -2450,10 +2437,10 @@ void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes); break; case NLASTRIP_TYPE_TRANSITION: /* transition */ - nlastrip_evaluate_transition(ptr, channels, modifiers, nes); + nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes); break; case NLASTRIP_TYPE_META: /* meta */ - nlastrip_evaluate_meta(ptr, channels, modifiers, nes); + nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes); break; default: /* do nothing */ @@ -2465,7 +2452,7 @@ void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, } /* write the accumulated settings to */ -void nladata_flush_channels(ListBase *channels) +void nladata_flush_channels(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels) { NlaEvalChannel *nec; @@ -2473,39 +2460,13 @@ void nladata_flush_channels(ListBase *channels) if (channels == NULL) return; + const bool is_active_depsgraph = DEG_is_active(depsgraph); + /* for each channel with accumulated values, write its value on the property it affects */ for (nec = channels->first; nec; nec = nec->next) { - PointerRNA *ptr = &nec->ptr; - PropertyRNA *prop = nec->prop; - int array_index = nec->index; - float value = nec->value; - - /* write values - see animsys_write_rna_setting() to sync the code */ - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - if (RNA_property_array_check(prop)) - RNA_property_boolean_set_index(ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value)); - else - RNA_property_boolean_set(ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value)); - break; - case PROP_INT: - if (RNA_property_array_check(prop)) - RNA_property_int_set_index(ptr, prop, array_index, (int)value); - else - RNA_property_int_set(ptr, prop, (int)value); - break; - case PROP_FLOAT: - if (RNA_property_array_check(prop)) - RNA_property_float_set_index(ptr, prop, array_index, value); - else - RNA_property_float_set(ptr, prop, value); - break; - case PROP_ENUM: - RNA_property_enum_set(ptr, prop, (int)value); - break; - default: - /* can't do anything with other types of property.... */ - break; + animsys_write_rna_setting(&nec->rna, nec->value); + if (is_active_depsgraph) { + animsys_write_orig_anim_rna(ptr, nec->rna_path, nec->rna.prop_index, nec->value); } } } @@ -2519,7 +2480,7 @@ void nladata_flush_channels(ListBase *channels) * * \param[out] echannels Evaluation channels with calculated values */ -static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime) +static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime) { NlaTrack *nlt; short track_index = 0; @@ -2557,7 +2518,7 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData has_strips = true; /* otherwise, get strip to evaluate for this channel */ - nes = nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime); + nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime); if (nes) nes->track = nlt; } @@ -2582,7 +2543,6 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData else { /* set settings of dummy NLA strip from AnimData settings */ dummy_strip.act = adt->action; - dummy_strip.remap = adt->remap; /* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */ calc_action_range(dummy_strip.act, &dummy_strip.actstart, &dummy_strip.actend, 1); @@ -2598,14 +2558,14 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData } /* add this to our list of evaluation strips */ - nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime); + nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime); } else { /* special case - evaluate as if there isn't any NLA data */ /* TODO: this is really just a stop-gap measure... */ if (G.debug & G_DEBUG) printf("NLA Eval: Stopgap for active action on NLA Stack - no strips case\n"); - animsys_evaluate_action(ptr, adt->action, adt->remap, ctime); + animsys_evaluate_action(depsgraph, ptr, adt->action, ctime); BLI_freelistN(&estrips); return; } @@ -2618,28 +2578,17 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */ for (nes = estrips.first; nes; nes = nes->next) - nlastrip_evaluate(ptr, echannels, NULL, nes); + nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes); /* 3. free temporary evaluation data that's not used elsewhere */ BLI_freelistN(&estrips); - - /* Tag ID as updated so render engines will recognize changes in data - * which is animated but doesn't have actions. - */ - if (ptr->id.data != NULL) { - ID *id = ptr->id.data; - if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) { - id->recalc |= ID_RECALC; - DAG_id_type_tag(G.main, GS(id->name)); - } - } } /* NLA Evaluation function (mostly for use through do_animdata) * - All channels that will be affected are not cleared anymore. Instead, we just evaluate into * some temp channels, where values can be accumulated in one go. */ -static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime) +static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimData *adt, float ctime) { ListBase echannels = {NULL, NULL}; @@ -2647,10 +2596,10 @@ static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime) * and also when the user jumps between different times instead of moving sequentially... */ /* evaluate the NLA stack, obtaining a set of values to flush */ - animsys_evaluate_nla(&echannels, ptr, adt, ctime); + animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime); /* flush effects of accumulating channels in NLA to the actual data they affect */ - nladata_flush_channels(&echannels); + nladata_flush_channels(depsgraph, ptr, &echannels); /* free temp data */ BLI_freelistN(&echannels); @@ -2659,19 +2608,6 @@ static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime) /* ***************************************** */ /* Overrides System - Public API */ -/* Clear all overrides */ - -/* Add or get existing Override for given setting */ -#if 0 -AnimOverride *BKE_animsys_validate_override(PointerRNA *UNUSED(ptr), char *UNUSED(path), int UNUSED(array_index)) -{ - /* FIXME: need to define how to get overrides */ - return NULL; -} -#endif - -/* -------------------- */ - /* Evaluate Overrides */ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) { @@ -2680,7 +2616,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) /* for each override, simply execute... */ for (aor = adt->overrides.first; aor; aor = aor->next) { PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(ptr, NULL, aor->rna_path, aor->array_index, &anim_rna)) { + if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { animsys_write_rna_setting(&anim_rna, aor->value); } } @@ -2726,7 +2662,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) * and that the flags for which parts of the anim-data settings need to be recalculated * have been set already by the depsgraph. Now, we use the recalc */ -void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ctime, short recalc) +void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc) { PointerRNA id_ptr; @@ -2748,11 +2684,11 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct /* evaluate NLA-stack * - active action is evaluated as part of the NLA stack as the last item */ - animsys_calculate_nla(&id_ptr, adt, ctime); + animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime); } /* evaluate Active Action only */ else if (adt->action) - animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime); + animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, ctime); /* reset tag */ adt->recalc &= ~ADT_RECALC_ANIM; @@ -2796,7 +2732,7 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a * standard 'root') block are overridden by a larger 'user' */ -void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) +void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene *scene, float ctime) { ID *id; @@ -2812,7 +2748,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) for (id = first; id; id = id->next) { \ if (ID_REAL_USERS(id) > 0) { \ AnimData *adt = BKE_animdata_from_id(id); \ - BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \ + BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \ } \ } (void)0 @@ -2829,9 +2765,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) NtId_Type *ntp = (NtId_Type *)id; \ if (ntp->nodetree) { \ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \ - BKE_animsys_evaluate_animdata(scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \ + BKE_animsys_evaluate_animdata(depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \ } \ - BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \ + BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \ } \ } (void)0 @@ -2898,6 +2834,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) /* grease pencil */ EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM); + /* palettes */ + EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM); + /* cache files */ EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM); @@ -2923,27 +2862,60 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) /* ************** */ /* Evaluation API */ -void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id) +void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id) { + float ctime = DEG_get_ctime(depsgraph); AnimData *adt = BKE_animdata_from_id(id); Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates, * which should get handled as part of the dependency graph instead... */ - DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime); - BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM); + DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime); + short recalc = ADT_RECALC_ANIM; + BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, recalc); } -void BKE_animsys_eval_driver(EvaluationContext *eval_ctx, +void BKE_animsys_update_driver_array(ID *id) +{ + AnimData *adt = BKE_animdata_from_id(id); + + /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver. + * Ideally the depsgraph could pass a pointer to the COW driver directly, + * but this is difficult in the current design. */ + if (adt && adt->drivers.first) { + BLI_assert(!adt->driver_array); + + int num_drivers = BLI_listbase_count(&adt->drivers); + adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array"); + + int driver_index = 0; + for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) { + adt->driver_array[driver_index++] = fcu; + } + } +} + +void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, - FCurve *fcu) + int driver_index, + ChannelDriver *driver_orig) { /* TODO(sergey): De-duplicate with BKE animsys. */ - ChannelDriver *driver = fcu->driver; PointerRNA id_ptr; bool ok = false; + /* Lookup driver, accelerated with driver array map. */ + const AnimData *adt = BKE_animdata_from_id(id); + FCurve *fcu; + + if (adt->driver_array) { + fcu = adt->driver_array[driver_index]; + } + else { + fcu = BLI_findlink(&adt->drivers, driver_index); + } + DEG_debug_print_eval_subdata_index( - __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index); + depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index); RNA_id_pointer_create(id, &id_ptr); @@ -2951,27 +2923,31 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx, if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) { /* check if driver itself is tagged for recalculation */ /* XXX driver recalc flag is not set yet by depsgraph! */ - if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) { + if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID) /*&& (driver_orig->flag & DRIVER_FLAG_RECALC)*/) { /* evaluate this using values set already in other places * NOTE: for 'layering' option later on, we should check if we should remove old value before adding * new to only be done when drivers only changed */ //printf("\told val = %f\n", fcu->curval); PathResolvedRNA anim_rna; - if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) { - const float curval = calculate_fcurve(&anim_rna, fcu, eval_ctx->ctime); + if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + const float ctime = DEG_get_ctime(depsgraph); + const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime); ok = animsys_write_rna_setting(&anim_rna, curval); + if (ok && DEG_is_active(depsgraph)) { + animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval); + } } //printf("\tnew val = %f\n", fcu->curval); /* clear recalc flag */ - driver->flag &= ~DRIVER_FLAG_RECALC; + driver_orig->flag &= ~DRIVER_FLAG_RECALC; /* set error-flag if evaluation failed */ if (ok == 0) { printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index); - driver->flag |= DRIVER_FLAG_INVALID; + driver_orig->flag |= DRIVER_FLAG_INVALID; } } } diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 8d6c34222d7..2848c245553 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -28,9 +28,11 @@ #include <stdio.h> #include "BLI_utildefines.h" -#include "BLI_string.h" #include "BLI_fileops.h" +#include "BLI_fileops_types.h" +#include "BLI_listbase.h" #include "BLI_path_util.h" +#include "BLI_string.h" #include "BKE_blender_version.h" #include "BKE_appdir.h" /* own include */ @@ -738,6 +740,32 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz return false; } +void BKE_appdir_app_templates(ListBase *templates) +{ + BLI_listbase_clear(templates); + + for (int i = 0; i < 2; i++) { + char subdir[FILE_MAX]; + if (!BKE_appdir_folder_id_ex( + app_template_directory_id[i], app_template_directory_search[i], + subdir, sizeof(subdir))) + { + continue; + } + + struct direntry *dir; + uint totfile = BLI_filelist_dir_contents(subdir, &dir); + for (int f = 0; f < totfile; f++) { + if (!FILENAME_IS_CURRPAR(dir[f].relname) && S_ISDIR(dir[f].type)) { + char *template = BLI_strdup(dir[f].relname); + BLI_addtail(templates, BLI_genericNodeN(template)); + } + } + + BLI_filelist_free(dir, totfile); + } +} + /** * Gets the temp directory when blender first runs. * If the default path is not found, use try $TEMP @@ -813,7 +841,9 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c BLI_dir_create_recursive(tmp_name); } #else - mkdtemp(tmp_name); + if (mkdtemp(tmp_name) == NULL) { + BLI_dir_create_recursive(tmp_name); + } #endif } if (BLI_is_dir(tmp_name)) { diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 4ad9e9c8205..66106a97566 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -27,7 +27,6 @@ * \ingroup bke */ - #include <ctype.h> #include <stdlib.h> #include <math.h> @@ -47,6 +46,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_lattice_types.h" #include "DNA_listBase.h" @@ -60,8 +60,6 @@ #include "BKE_anim.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_idprop.h" @@ -73,8 +71,9 @@ #include "BKE_object.h" #include "BKE_scene.h" +#include "DEG_depsgraph_build.h" + #include "BIK_api.h" -#include "BKE_sketch.h" /* **************** Generic Functions, data level *************** */ @@ -136,12 +135,6 @@ void BKE_armature_free(bArmature *arm) MEM_freeN(arm->edbo); arm->edbo = NULL; } - - /* free sketch */ - if (arm->sketch) { - freeSketch(arm->sketch); - arm->sketch = NULL; - } } void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local) @@ -205,7 +198,6 @@ void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArma arm_dst->edbo = NULL; arm_dst->act_edbone = NULL; - arm_dst->sketch = NULL; } bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm) @@ -401,7 +393,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a /* ************* B-Bone support ******************* */ /* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */ -void equalize_bbone_bezier(float *data, int desired) +static void equalize_bbone_bezier(float *data, int desired) { float *fp, totdist, ddist, dist, fac1, fac2; float pdist[MAX_BBONE_SUBDIV + 1]; @@ -441,169 +433,276 @@ void equalize_bbone_bezier(float *data, int desired) copy_qt_qt(fp, temp[MAX_BBONE_SUBDIV]); } -/* returns pointer to static array, filled with desired amount of bone->segments elements */ -/* this calculation is done within unit bone space */ -void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]) +/* Get "next" and "prev" bones - these are used for handle calculations. */ +void BKE_pchan_get_bbone_handles(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next) +{ + if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) { + /* Use connected parent. */ + if (pchan->bone->flag & BONE_CONNECTED) { + *r_prev = pchan->parent; + } + else { + *r_prev = NULL; + } + } + else { + /* Use the provided bone as prev - leave blank to eliminate this effect altogether. */ + *r_prev = pchan->bbone_prev; + } + + if (pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO) { + /* Use connected child. */ + *r_next = pchan->child; + } + else { + /* Use the provided bone as next - leave blank to eliminate this effect altogether. */ + *r_next = pchan->bbone_next; + } +} + +/* Fills the array with the desired amount of bone->segments elements. + * This calculation is done within unit bone space. */ +void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV]) { bPoseChannel *next, *prev; Bone *bone = pchan->bone; - float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2; - float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4]; - float data[MAX_BBONE_SUBDIV + 1][4], *fp; - int a; - bool do_scale = false; + BBoneSplineParameters param; + float imat[4][4], posemat[4][4]; + float delta[3]; + + memset(¶m, 0, sizeof(param)); - length = bone->length; + param.segments = bone->segments; + param.length = bone->length; if (!rest) { - /* check if we need to take non-uniform bone scaling into account */ + float scale[3]; + + /* Check if we need to take non-uniform bone scaling into account. */ mat4_to_size(scale, pchan->pose_mat); if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) { - size_to_mat4(scalemat, scale); - invert_m4_m4(iscalemat, scalemat); - - length *= scale[1]; - do_scale = 1; + param.do_scale = true; + copy_v3_v3(param.scale, scale); } } - /* get "next" and "prev" bones - these are used for handle calculations */ - if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) { - /* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */ - prev = pchan->bbone_prev; - next = pchan->bbone_next; - } - else { - /* evaluate next and prev bones */ - if (bone->flag & BONE_CONNECTED) - prev = pchan->parent; - else - prev = NULL; - - next = pchan->child; - } + BKE_pchan_get_bbone_handles(pchan, &prev, &next); - /* find the handle points, since this is inside bone space, the + /* Find the handle points, since this is inside bone space, the * first point = (0, 0, 0) * last point = (0, length, 0) */ if (rest) { invert_m4_m4(imat, pchan->bone->arm_mat); } - else if (do_scale) { + else if (param.do_scale) { copy_m4_m4(posemat, pchan->pose_mat); normalize_m4(posemat); invert_m4_m4(imat, posemat); } - else + else { invert_m4_m4(imat, pchan->pose_mat); + } if (prev) { - float difmat[4][4], result[3][3], imat3[3][3]; + float h1[3]; + bool done = false; - /* transform previous point inside this bone space */ - if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) && - (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL)) - { - /* Use delta movement (from restpose), and apply this relative to the current bone's head */ + param.use_prev = true; + + /* Transform previous point inside this bone space. */ + if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE) { + /* Use delta movement (from restpose), and apply this relative to the current bone's head. */ if (rest) { - /* in restpose, arm_head == pose_head */ - h1[0] = h1[1] = h1[2] = 0.0f; + /* In restpose, arm_head == pose_head */ + zero_v3(param.prev_h); + done = true; } else { - float delta[3]; sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head); sub_v3_v3v3(h1, pchan->pose_head, delta); } } - else { - /* Use bone head as absolute position */ - if (rest) - copy_v3_v3(h1, prev->bone->arm_head); - else - copy_v3_v3(h1, prev->pose_head); + else if (bone->bbone_prev_type == BBONE_HANDLE_TANGENT) { + /* Use bone direction by offsetting so that its tail meets current bone's head */ + if (rest) { + sub_v3_v3v3(delta, prev->bone->arm_tail, prev->bone->arm_head); + sub_v3_v3v3(h1, bone->arm_head, delta); + } + else { + sub_v3_v3v3(delta, prev->pose_tail, prev->pose_head); + sub_v3_v3v3(h1, pchan->pose_head, delta); + } } - mul_m4_v3(imat, h1); + else { + /* Apply special handling for smoothly joining B-Bone chains */ + param.prev_bbone = (prev->bone->segments > 1); - if (prev->bone->segments > 1) { - /* if previous bone is B-bone too, use average handle direction */ - h1[1] -= length; - roll1 = 0.0f; + /* Use bone head as absolute position. */ + copy_v3_v3(h1, rest ? prev->bone->arm_head : prev->pose_head); } - normalize_v3(h1); - negate_v3(h1); - - if (prev->bone->segments == 1) { - /* find the previous roll to interpolate */ - if (rest) - mul_m4_m4m4(difmat, imat, prev->bone->arm_mat); - else - mul_m4_m4m4(difmat, imat, prev->pose_mat); - copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */ - - vec_roll_to_mat3(h1, 0.0f, mat3); /* the result of vec_roll without roll */ - - invert_m3_m3(imat3, mat3); - mul_m3_m3m3(mat3, result, imat3); /* the matrix transforming vec_roll to desired roll */ + if (!done) { + mul_v3_m4v3(param.prev_h, imat, h1); + } - roll1 = atan2f(mat3[2][0], mat3[2][2]); + if (!param.prev_bbone) { + /* Find the previous roll to interpolate. */ + mul_m4_m4m4(param.prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat); } } - else { - h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f; - roll1 = 0.0f; - } + if (next) { - float difmat[4][4], result[3][3], imat3[3][3]; + float h2[3]; + bool done = false; - /* transform next point inside this bone space */ - if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) && - (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL)) - { - /* Use delta movement (from restpose), and apply this relative to the current bone's tail */ + param.use_next = true; + + /* Transform next point inside this bone space. */ + if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE) { + /* Use delta movement (from restpose), and apply this relative to the current bone's tail. */ + if (rest) { + /* In restpose, arm_head == pose_head */ + copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0); + done = true; + } + else { + sub_v3_v3v3(delta, next->pose_head, next->bone->arm_head); + add_v3_v3v3(h2, pchan->pose_tail, delta); + } + } + else if (bone->bbone_next_type == BBONE_HANDLE_TANGENT) { + /* Use bone direction by offsetting so that its head meets current bone's tail */ if (rest) { - /* in restpose, arm_tail == pose_tail */ - h2[0] = h2[1] = h2[2] = 0.0f; + sub_v3_v3v3(delta, next->bone->arm_tail, next->bone->arm_head); + add_v3_v3v3(h2, bone->arm_tail, delta); } else { - float delta[3]; - sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail); + sub_v3_v3v3(delta, next->pose_tail, next->pose_head); add_v3_v3v3(h2, pchan->pose_tail, delta); } } else { - /* Use bone tail as absolute position */ - if (rest) - copy_v3_v3(h2, next->bone->arm_tail); - else - copy_v3_v3(h2, next->pose_tail); + /* Apply special handling for smoothly joining B-Bone chains */ + param.next_bbone = (next->bone->segments > 1); + + /* Use bone tail as absolute position. */ + copy_v3_v3(h2, rest ? next->bone->arm_tail : next->pose_tail); } - mul_m4_v3(imat, h2); - /* if next bone is B-bone too, use average handle direction */ - if (next->bone->segments > 1) { - /* pass */ + if (!done) { + mul_v3_m4v3(param.next_h, imat, h2); } - else { - h2[1] -= length; + + /* Find the next roll to interpolate as well. */ + mul_m4_m4m4(param.next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat); + } + + /* Add effects from bbone properties over the top + * - These properties allow users to hand-animate the + * bone curve/shape, without having to resort to using + * extra bones + * - The "bone" level offsets are for defining the restpose + * shape of the bone (e.g. for curved eyebrows for example). + * -> In the viewport, it's needed to define what the rest pose + * looks like + * -> For "rest == 0", we also still need to have it present + * so that we can "cancel out" this restpose when it comes + * time to deform some geometry, it won't cause double transforms. + * - The "pchan" level offsets are the ones that animators actually + * end up animating + */ + { + param.ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f); + param.ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f); + + param.roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f); + param.roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f); + + if (bone->flag & BONE_ADD_PARENT_END_ROLL) { + if (prev) { + if (prev->bone) { + param.roll1 += prev->bone->roll2; + } + + if (!rest) { + param.roll1 += prev->roll2; + } + } } - normalize_v3(h2); - /* find the next roll to interpolate as well */ - if (rest) - mul_m4_m4m4(difmat, imat, next->bone->arm_mat); - else - mul_m4_m4m4(difmat, imat, next->pose_mat); - copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */ + param.scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f); + param.scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f); - vec_roll_to_mat3(h2, 0.0f, mat3); /* the result of vec_roll without roll */ + /* Extra curve x / y */ + param.curveInX = bone->curveInX + (!rest ? pchan->curveInX : 0.0f); + param.curveInY = bone->curveInY + (!rest ? pchan->curveInY : 0.0f); - invert_m3_m3(imat3, mat3); - mul_m3_m3m3(mat3, imat3, result); /* the matrix transforming vec_roll to desired roll */ + param.curveOutX = bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f); + param.curveOutY = bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f); + } - roll2 = atan2f(mat3[2][0], mat3[2][2]); + bone->segments = BKE_compute_b_bone_spline(¶m, result_array); +} +/* Fills the array with the desired amount of bone->segments elements. + * This calculation is done within unit bone space. */ +int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]) +{ + float scalemat[4][4], iscalemat[4][4]; + float mat3[3][3]; + float h1[3], roll1, h2[3], roll2; + float data[MAX_BBONE_SUBDIV + 1][4], *fp; + int a; + + float length = param->length; + + if (param->do_scale) { + size_to_mat4(scalemat, param->scale); + invert_m4_m4(iscalemat, scalemat); + + length *= param->scale[1]; + } + + if (param->use_prev) { + copy_v3_v3(h1, param->prev_h); + + if (param->prev_bbone) { + /* If previous bone is B-bone too, use average handle direction. */ + h1[1] -= length; + roll1 = 0.0f; + } + + normalize_v3(h1); + negate_v3(h1); + + if (!param->prev_bbone) { + /* Find the previous roll to interpolate. */ + copy_m3_m4(mat3, param->prev_mat); + mat3_vec_to_roll(mat3, h1, &roll1); + } + } + else { + h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f; + roll1 = 0.0f; + } + + if (param->use_next) { + copy_v3_v3(h2, param->next_h); + + /* If next bone is B-bone too, use average handle direction. */ + if (param->next_bbone) { + /* pass */ + } + else { + h2[1] -= length; + } + + normalize_v3(h2); + + /* Find the next roll to interpolate as well. */ + copy_m3_m4(mat3, param->next_mat); + mat3_vec_to_roll(mat3, h2, &roll2); } else { h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f; @@ -613,10 +712,8 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB { const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f); - const float combined_ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f); - const float combined_ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f); - const float hlength1 = combined_ease1 * circle_factor; - const float hlength2 = combined_ease2 * circle_factor; + const float hlength1 = param->ease1 * circle_factor; + const float hlength2 = param->ease2 * circle_factor; /* and only now negate h2 */ mul_v3_fl(h1, hlength1); @@ -638,67 +735,56 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB * end up animating */ { - /* add extra rolls */ - roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f); - roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f); - - if (bone->flag & BONE_ADD_PARENT_END_ROLL) { - if (prev) { - if (prev->bone) - roll1 += prev->bone->roll2; + /* Add extra rolls. */ + roll1 += param->roll1; + roll2 += param->roll2; - if (!rest) - roll1 += prev->roll2; - } - } - - /* extra curve x / y */ + /* Extra curve x / y */ /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches * when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results * in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out. */ - const float xscale_correction = (do_scale) ? scale[0] : 1.0f; - const float yscale_correction = (do_scale) ? scale[2] : 1.0f; + const float xscale_correction = (param->do_scale) ? param->scale[0] : 1.0f; + const float yscale_correction = (param->do_scale) ? param->scale[2] : 1.0f; - h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction; - h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction; + h1[0] += param->curveInX * xscale_correction; + h1[2] += param->curveInY * yscale_correction; - h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction; - h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction; + h2[0] += param->curveOutX * xscale_correction; + h2[2] += param->curveOutY * yscale_correction; } - /* make curve */ - if (bone->segments > MAX_BBONE_SUBDIV) - bone->segments = MAX_BBONE_SUBDIV; + /* Make curve. */ + CLAMP_MAX(param->segments, MAX_BBONE_SUBDIV); BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float)); BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float)); BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float)); BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float)); - equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */ + equalize_bbone_bezier(data[0], param->segments); /* note: does stride 4! */ - /* make transformation matrices for the segments for drawing */ - for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) { + /* Make transformation matrices for the segments for drawing. */ + for (a = 0, fp = data[0]; a < param->segments; a++, fp += 4) { sub_v3_v3v3(h1, fp + 4, fp); vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */ copy_m4_m3(result_array[a].mat, mat3); copy_v3_v3(result_array[a].mat[3], fp); - if (do_scale) { - /* correct for scaling when this matrix is used in scaled space */ + if (param->do_scale) { + /* Correct for scaling when this matrix is used in scaled space. */ mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat); } /* BBone scale... */ { - const int num_segments = bone->segments; + const int num_segments = param->segments; - const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f); + const float scaleIn = param->scaleIn; const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments); - const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f); + const float scaleOut = param->scaleOut; const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments); const float scalefac = scaleFactorIn * scaleFactorOut; @@ -714,8 +800,9 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB /*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat); } - } + + return param->segments; } /* ************ Armature Deform ******************* */ @@ -734,8 +821,8 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info DualQuat *b_bone_dual_quats = NULL; int a; - b_bone_spline_setup(pchan, 0, b_bone); - b_bone_spline_setup(pchan, 1, b_bone_rest); + b_bone_spline_setup(pchan, false, b_bone); + b_bone_spline_setup(pchan, true, b_bone_rest); /* allocate b_bone matrices and dual quats */ b_bone_mats = MEM_mallocN((1 + bone->segments) * sizeof(Mat4), "BBone defmats"); @@ -972,9 +1059,10 @@ static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index) } } -void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], - float (*defMats)[3][3], int numVerts, int deformflag, - float (*prevCos)[3], const char *defgrp_name) +void armature_deform_verts( + Object *armOb, Object *target, const Mesh *mesh, float (*vertexCos)[3], + float (*defMats)[3][3], int numVerts, int deformflag, + float (*prevCos)[3], const char *defgrp_name, bGPDstroke *gps) { bPoseChanDeform *pdef_info_array; bPoseChanDeform *pdef_info = NULL; @@ -1028,7 +1116,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float /* get the def_nr for the overall armature vertex group if present */ armature_def_nr = defgroup_name_index(target, defgrp_name); - if (ELEM(target->type, OB_MESH, OB_LATTICE)) { + if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { defbase_tot = BLI_listbase_count(&target->defbase); if (target->type == OB_MESH) { @@ -1037,20 +1125,25 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float if (dverts) target_totvert = me->totvert; } - else { + else if (target->type == OB_LATTICE) { Lattice *lt = target->data; dverts = lt->dvert; if (dverts) target_totvert = lt->pntsu * lt->pntsv * lt->pntsw; } + else if (target->type == OB_GPENCIL) { + dverts = gps->dvert; + if (dverts) + target_totvert = gps->totpoints; + } } /* get a vertex-deform-index to posechannel array */ if (deformflag & ARM_DEF_VGROUP) { - if (ELEM(target->type, OB_MESH, OB_LATTICE)) { - /* if we have a DerivedMesh, only use dverts if it has them */ - if (dm) { - use_dverts = (dm->getVertDataArray(dm, CD_MDEFORMVERT) != NULL); + if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + /* if we have a Mesh, only use dverts if it has them */ + if (mesh) { + use_dverts = (mesh->dvert != NULL); } else if (dverts) { use_dverts = true; @@ -1112,8 +1205,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float } if (use_dverts || armature_def_nr != -1) { - if (dm) - dvert = dm->getVertData(dm, i, CD_MDEFORMVERT); + if (mesh) { + BLI_assert(i < mesh->totvert); + dvert = mesh->dvert + i; + } else if (dverts && i < target_totvert) dvert = dverts + i; else @@ -1149,7 +1244,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float MDeformWeight *dw = dvert->dw; int deformed = 0; unsigned int j; - + float acum_weight = 0; for (j = dvert->totweight; j != 0; j--, dw++) { const int index = dw->def_nr; if (index >= 0 && index < defbase_tot && (pchan = defnrToPC[index])) { @@ -1163,7 +1258,21 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); } + + /* check limit of weight */ + if (target->type == OB_GPENCIL) { + if (acum_weight + weight >= 1.0f) { + weight = 1.0f - acum_weight; + } + acum_weight += weight; + } + pchan_bone_deform(pchan, pdef_info, weight, vec, dq, smat, co, &contrib); + + /* if acumulated weight limit exceed, exit loop */ + if ((target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) { + break; + } } } /* if there are vertexgroups but not groups with bones @@ -1202,7 +1311,9 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float smat = summat; } else { - mul_v3_fl(vec, armature_weight / contrib); + if (target->type != OB_GPENCIL) { + mul_v3_fl(vec, armature_weight / contrib); + } add_v3_v3v3(co, vec, co); } @@ -1463,16 +1574,16 @@ void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], fl copy_v3_v3(outloc, nLocMat[3]); } -void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]) +void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]) { bPoseChannel work_pchan = *pchan; /* recalculate pose matrix with only parent transformations, * bone loc/sca/rot is ignored, scene and frame are not used. */ - BKE_pose_where_is_bone(NULL, ob, &work_pchan, 0.0f, false); + BKE_pose_where_is_bone(depsgraph, NULL, ob, &work_pchan, 0.0f, false); /* find the matrix, need to remove the bone transforms first so this is - * calculated as a matrix to set rather then a difference ontop of whats + * calculated as a matrix to set rather then a difference ontop of what's * already there. */ unit_m4(outmat); BKE_pchan_apply_mat4(&work_pchan, outmat, false); @@ -1594,21 +1705,28 @@ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float /* Computes vector and roll based on a rotation. * "mat" must contain only a rotation, and no scaling. */ -void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll) +void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll) { if (r_vec) { copy_v3_v3(r_vec, mat[1]); } if (r_roll) { - float vecmat[3][3], vecmatinv[3][3], rollmat[3][3]; + mat3_vec_to_roll(mat, mat[1], r_roll); + } +} - vec_roll_to_mat3(mat[1], 0.0f, vecmat); - invert_m3_m3(vecmatinv, vecmat); - mul_m3_m3m3(rollmat, vecmatinv, mat); +/* Computes roll around the vector that best approximates the matrix. + * If vec is the Y vector from purely rotational mat, result should be exact. */ +void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll) +{ + float vecmat[3][3], vecmatinv[3][3], rollmat[3][3]; - *r_roll = atan2f(rollmat[2][0], rollmat[2][2]); - } + vec_roll_to_mat3(vec, 0.0f, vecmat); + invert_m3_m3(vecmatinv, vecmat); + mul_m3_m3m3(rollmat, vecmatinv, mat); + + *r_roll = atan2f(rollmat[2][0], rollmat[2][2]); } /* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */ @@ -1835,6 +1953,8 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected pchanw.parent = pchan->parent; pchanw.child = pchan->child; pchanw.custom_tx = pchan->custom_tx; + pchanw.bbone_prev = pchan->bbone_prev; + pchanw.bbone_next = pchan->bbone_next; pchanw.mpath = pchan->mpath; pchan->mpath = NULL; @@ -1950,9 +2070,36 @@ void BKE_pose_clear_pointers(bPose *pose) } } -/* only after leave editmode, duplicating, validating older files, library syncing */ -/* NOTE: pose->flag is set for it */ -void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) +void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose) +{ + GHash *bone_hash = BKE_armature_bone_from_name_map(armature); + for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name); + } + BLI_ghash_free(bone_hash, NULL, NULL); +} + +/** Find the matching pose channel using the bone name, if not NULL. */ +static bPoseChannel *pose_channel_find_bone(bPose *pose, Bone *bone) +{ + return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL; +} + +/** Update the links for the B-Bone handles from Bone data. */ +void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan) +{ + pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev); + pchan->bbone_next = pose_channel_find_bone(pose, pchan->bone->bbone_next); +} + +/** + * Only after leave editmode, duplicating, validating older files, library syncing. + * + * \note pose->flag is set for it. + * + * \param bmain May be NULL, only used to tag depsgraph as being dirty... + */ +void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user) { Bone *bone; bPose *pose; @@ -1981,40 +2128,39 @@ void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) for (pchan = pose->chanbase.first; pchan; pchan = next) { next = pchan->next; if (pchan->bone == NULL) { - BKE_pose_channel_free(pchan); + BKE_pose_channel_free_ex(pchan, do_id_user); BKE_pose_channels_hash_free(pose); BLI_freelinkN(&pose->chanbase, pchan); } } + + BKE_pose_channels_hash_make(pose); + + for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + /* Find the custom B-Bone handles. */ + BKE_pchan_rebuild_bbone_handles(pose, pchan); + } + /* printf("rebuild pose %s, %d bones\n", ob->id.name, counter); */ /* synchronize protected layers with proxy */ - if (ob->proxy) { + /* HACK! To preserve 2.7x behavior that you always can pose even locked bones, + * do not do any restoration if this is a COW temp copy! */ + /* Switched back to just NO_MAIN tag, for some reasons (c) using COW tag was working this morning, but not anymore... */ + if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) { BKE_object_copy_proxy_drivers(ob, ob->proxy); pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected); } - BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */ - -#ifdef WITH_LEGACY_DEPSGRAPH - /* the sorting */ - /* Sorting for new dependnecy graph is done on the scene graph level. */ - if (counter > 1 && sort_bones) { - DAG_pose_sort(ob); - } -#else - UNUSED_VARS(sort_bones); -#endif + BKE_pose_update_constraint_flags(pose); /* for IK detection for example */ - ob->pose->flag &= ~POSE_RECALC; - ob->pose->flag |= POSE_WAS_REBUILT; + pose->flag &= ~POSE_RECALC; + pose->flag |= POSE_WAS_REBUILT; - BKE_pose_channels_hash_make(ob->pose); -} - -void BKE_pose_rebuild(Object *ob, bArmature *arm) -{ - BKE_pose_rebuild_ex(ob, arm, true); + /* Rebuilding poses forces us to also rebuild the dependency graph, since there is one node per pose/bone... */ + if (bmain != NULL) { + DEG_relations_tag_update(bmain); + } } /* ********************** THE POSE SOLVER ******************* */ @@ -2071,132 +2217,6 @@ void BKE_pchan_calc_mat(bPoseChannel *pchan) BKE_pchan_to_mat4(pchan, pchan->chan_mat); } -#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */ - -/* NLA strip modifiers */ -static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseChannel *pchan) -{ - bActionModifier *amod; - bActionStrip *strip, *strip2; - float scene_cfra = BKE_scene_frame_get(scene); - int do_modif; - - for (strip = armob->nlastrips.first; strip; strip = strip->next) { - do_modif = false; - - if (scene_cfra >= strip->start && scene_cfra <= strip->end) - do_modif = true; - - if ((scene_cfra > strip->end) && (strip->flag & ACTSTRIP_HOLDLASTFRAME)) { - do_modif = true; - - /* if there are any other strips active, ignore modifiers for this strip - - * 'hold' option should only hold action modifiers if there are - * no other active strips */ - for (strip2 = strip->next; strip2; strip2 = strip2->next) { - if (strip2 == strip) continue; - - if (scene_cfra >= strip2->start && scene_cfra <= strip2->end) { - if (!(strip2->flag & ACTSTRIP_MUTE)) - do_modif = false; - } - } - - /* if there are any later, activated, strips with 'hold' set, they take precedence, - * so ignore modifiers for this strip */ - for (strip2 = strip->next; strip2; strip2 = strip2->next) { - if (scene_cfra < strip2->start) continue; - if ((strip2->flag & ACTSTRIP_HOLDLASTFRAME) && !(strip2->flag & ACTSTRIP_MUTE)) { - do_modif = false; - } - } - } - - if (do_modif) { - /* temporal solution to prevent 2 strips accumulating */ - if (scene_cfra == strip->end && strip->next && strip->next->start == scene_cfra) - continue; - - for (amod = strip->modifiers.first; amod; amod = amod->next) { - switch (amod->type) { - case ACTSTRIP_MOD_DEFORM: - { - /* validate first */ - if (amod->ob && amod->ob->type == OB_CURVE && amod->channel[0]) { - - if (STREQ(pchan->name, amod->channel)) { - float mat4[4][4], mat3[3][3]; - - curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis); - copy_m4_m4(mat4, pchan->pose_mat); - mul_m4_m3m4(pchan->pose_mat, mat3, mat4); - - } - } - } - break; - case ACTSTRIP_MOD_NOISE: - { - if (STREQ(pchan->name, amod->channel)) { - float nor[3], loc[3], ofs; - float eul[3], size[3], eulo[3], sizeo[3]; - - /* calculate turbulance */ - ofs = amod->turbul / 200.0f; - - /* make a copy of starting conditions */ - copy_v3_v3(loc, pchan->pose_mat[3]); - mat4_to_eul(eul, pchan->pose_mat); - mat4_to_size(size, pchan->pose_mat); - copy_v3_v3(eulo, eul); - copy_v3_v3(sizeo, size); - - /* apply noise to each set of channels */ - if (amod->channels & 4) { - /* for scaling */ - nor[0] = BLI_gNoise(amod->noisesize, size[0] + ofs, size[1], size[2], 0, 0) - ofs; - nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1] + ofs, size[2], 0, 0) - ofs; - nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2] + ofs, 0, 0) - ofs; - add_v3_v3(size, nor); - - if (sizeo[0] != 0) - mul_v3_fl(pchan->pose_mat[0], size[0] / sizeo[0]); - if (sizeo[1] != 0) - mul_v3_fl(pchan->pose_mat[1], size[1] / sizeo[1]); - if (sizeo[2] != 0) - mul_v3_fl(pchan->pose_mat[2], size[2] / sizeo[2]); - } - if (amod->channels & 2) { - /* for rotation */ - nor[0] = BLI_gNoise(amod->noisesize, eul[0] + ofs, eul[1], eul[2], 0, 0) - ofs; - nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1] + ofs, eul[2], 0, 0) - ofs; - nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2] + ofs, 0, 0) - ofs; - - compatible_eul(nor, eulo); - add_v3_v3(eul, nor); - compatible_eul(eul, eulo); - - loc_eul_size_to_mat4(pchan->pose_mat, loc, eul, size); - } - if (amod->channels & 1) { - /* for location */ - nor[0] = BLI_gNoise(amod->noisesize, loc[0] + ofs, loc[1], loc[2], 0, 0) - ofs; - nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1] + ofs, loc[2], 0, 0) - ofs; - nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2] + ofs, 0, 0) - ofs; - - add_v3_v3v3(pchan->pose_mat[3], loc, nor); - } - } - } - break; - } - } - } - } -} - -#endif - /* calculate tail of posechannel */ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan) { @@ -2211,7 +2231,9 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan) /* pchan is validated, as having bone and parent pointer * 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers. */ -void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime, bool do_extra) +void BKE_pose_where_is_bone( + struct Depsgraph *depsgraph, Scene *scene, + Object *ob, bPoseChannel *pchan, float ctime, bool do_extra) { /* This gives a chan_mat with actions (ipos) results. */ if (do_extra) @@ -2231,11 +2253,6 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float } if (do_extra) { -#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */ - /* do NLA strip modifiers - i.e. curve follow */ - do_strip_modifiers(scene, ob, bone, pchan); -#endif - /* Do constraints */ if (pchan->constraints.first) { bConstraintOb *cob; @@ -2247,10 +2264,10 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float /* prepare PoseChannel for Constraint solving * - makes a copy of matrix, and creates temporary struct to use */ - cob = BKE_constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); + cob = BKE_constraints_make_evalob(depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); /* Solve PoseChannel's Constraints */ - BKE_constraints_solve(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */ + BKE_constraints_solve(depsgraph, &pchan->constraints, cob, ctime); /* ctime doesn't alter objects */ /* cleanup after Constraint Solving * - applies matrix back to pchan, and frees temporary struct used @@ -2272,7 +2289,7 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float /* This only reads anim data from channels, and writes to channels */ /* This is the only function adding poses */ -void BKE_pose_where_is(Scene *scene, Object *ob) +void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob) { bArmature *arm; Bone *bone; @@ -2286,8 +2303,10 @@ void BKE_pose_where_is(Scene *scene, Object *ob) if (ELEM(NULL, arm, scene)) return; - if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) - BKE_pose_rebuild(ob, arm); + if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) { + /* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */ + BKE_pose_rebuild(NULL, ob, arm, true); + } ctime = BKE_scene_frame_get(scene); /* not accurate... */ @@ -2311,7 +2330,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob) } /* 2a. construct the IK tree (standard IK) */ - BIK_initialize_tree(scene, ob, ctime); + BIK_initialize_tree(depsgraph, scene, ob, ctime); /* 2b. construct the Spline IK trees * - this is not integrated as an IK plugin, since it should be able @@ -2323,15 +2342,15 @@ void BKE_pose_where_is(Scene *scene, Object *ob) for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* 4a. if we find an IK root, we handle it separated */ if (pchan->flag & POSE_IKTREE) { - BIK_execute_tree(scene, ob, pchan, ctime); + BIK_execute_tree(depsgraph, scene, ob, pchan, ctime); } /* 4b. if we find a Spline IK root, we handle it separated too */ else if (pchan->flag & POSE_IKSPLINE) { - BKE_splineik_execute_tree(scene, ob, pchan, ctime); + BKE_splineik_execute_tree(depsgraph, scene, ob, pchan, ctime); } /* 5. otherwise just call the normal solver */ else if (!(pchan->flag & POSE_DONE)) { - BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1); } } /* 6. release the IK tree */ diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 241a842d73f..ce87050f8bf 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -26,6 +26,10 @@ * Defines and code for core node types */ +/** \file blender/blenkernel/intern/armature_update.c + * \ingroup bke + */ + #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -41,7 +45,6 @@ #include "BKE_anim.h" #include "BKE_armature.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_fcurve.h" #include "BKE_scene.h" @@ -113,9 +116,11 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos * currently for paths to work it needs to go through the bevlist/displist system (ton) */ + /* TODO: Make sure this doesn't crash. */ +#if 0 /* only happens on reload file, but violates depsgraph still... fix! */ if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { - BKE_displist_make_curveTypes(scene, ikData->tar, 0); + BKE_displist_make_curveTypes(depsgraph, scene, ikData->tar, 0); /* path building may fail in EditMode after removing verts [#33268]*/ if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { @@ -123,6 +128,9 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos return; } } +#else + (void) scene; +#endif } /* find the root bone and the chain of bones from the root to the tip @@ -197,7 +205,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos /* get the current length of the curve */ /* NOTE: this is assumed to be correct even after the curve was resized */ - splineLen = ikData->tar->curve_cache->path->totdist; + splineLen = ikData->tar->runtime.curve_cache->path->totdist; /* calculate the scale factor to multiply all the path values by so that the * bone chain retains its current length, such that @@ -261,15 +269,16 @@ static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime)) /* ----------- */ /* Evaluate spline IK for a given bone */ -static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, - int index, float ctime) +static void splineik_evaluate_bone( + struct Depsgraph *depsgraph, tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, + int index, float ctime) { bSplineIKConstraint *ikData = tree->ikData; float poseHead[3], poseTail[3], poseMat[4][4]; float splineVec[3], scaleFac, radius = 1.0f; /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ - BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1); copy_v3_v3(poseHead, pchan->pose_head); copy_v3_v3(poseTail, pchan->pose_tail); @@ -511,7 +520,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o } /* Evaluate the chain starting from the nominated bone */ -static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) +static void splineik_execute_tree(struct Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) { tSplineIK_Tree *tree; @@ -525,7 +534,7 @@ static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_ */ for (i = tree->chainlen - 1; i >= 0; i--) { bPoseChannel *pchan = tree->chain[i]; - splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime); + splineik_evaluate_bone(depsgraph, tree, scene, ob, pchan, i, ctime); } /* free the tree info specific to SplineIK trees now */ @@ -544,30 +553,44 @@ void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime) splineik_init_tree(scene, ob, ctime); } -void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) +void BKE_splineik_execute_tree( + struct Depsgraph *depsgraph, Scene *scene, + Object *ob, bPoseChannel *pchan_root, float ctime) { - splineik_execute_tree(scene, ob, pchan_root, ctime); + splineik_execute_tree(depsgraph, scene, ob, pchan_root, ctime); } /* *************** Depsgraph evaluation callbacks ************ */ +static void pose_pchan_index_create(bPose *pose) +{ + const int num_channels = BLI_listbase_count(&pose->chanbase); + pose->chan_array = MEM_malloc_arrayN( + num_channels, sizeof(bPoseChannel *), "pose->chan_array"); + int pchan_index = 0; + for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + pose->chan_array[pchan_index++] = pchan; + } +} + BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index) { bPose *pose = ob->pose; BLI_assert(pose != NULL); + BLI_assert(pose->chan_array != NULL); BLI_assert(pchan_index >= 0); BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *)); return pose->chan_array[pchan_index]; } -void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_eval_init(struct Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob) { bPose *pose = ob->pose; BLI_assert(pose != NULL); - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); @@ -578,23 +601,19 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx), /* imat is needed for solvers. */ invert_m4_m4(ob->imat, ob->obmat); - const int num_channels = BLI_listbase_count(&pose->chanbase); - pose->chan_array = MEM_malloc_arrayN( - num_channels, sizeof(bPoseChannel *), "pose->chan_array"); - /* clear flags */ - int pchan_index = 0; for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); - pose->chan_array[pchan_index++] = pchan; } + + pose_pchan_index_create(pose); } -void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, Scene *scene, Object *ob) { - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bArmature *arm = (bArmature *)ob->data; @@ -602,7 +621,7 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), return; } /* construct the IK tree (standard IK) */ - BIK_initialize_tree(scene, ob, ctime); + BIK_initialize_tree(depsgraph, scene, ob, ctime); /* construct the Spline IK trees * - this is not integrated as an IK plugin, since it should be able * to function in conjunction with standard IK @@ -610,14 +629,14 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx), BKE_pose_splineik_init_tree(scene, ob, ctime); } -void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_eval_bone(struct Depsgraph *depsgraph, Scene *scene, Object *ob, int pchan_index) { bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); DEG_debug_print_eval_subdata( - __func__, ob->id.name, ob, "pchan", pchan->name, pchan); + depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan); BLI_assert(ob->type == OB_ARMATURE); bArmature *arm = (bArmature *)ob->data; if (arm->edbo || (arm->flag & ARM_RESTPOS)) { @@ -640,21 +659,21 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), if ((pchan->flag & POSE_DONE) == 0) { /* TODO(sergey): Use time source node for time. */ float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1); } } } } } -void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph, Scene *scene, Object *ob, int pchan_index) { bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); DEG_debug_print_eval_subdata( - __func__, ob->id.name, ob, "pchan", pchan->name, pchan); + depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan); bArmature *arm = (bArmature *)ob->data; if (arm->flag & ARM_RESTPOS) { return; @@ -665,42 +684,51 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), else { if ((pchan->flag & POSE_DONE) == 0) { float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); + BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1); } } } -void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_bone_done(struct Depsgraph *depsgraph, struct Object *ob, int pchan_index) { bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index); float imat[4][4]; - DEG_debug_print_eval(__func__, pchan->name, pchan); + DEG_debug_print_eval(depsgraph, __func__, pchan->name, pchan); if (pchan->bone) { invert_m4_m4(imat, pchan->bone->arm_mat); mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat); } + bArmature *arm = (bArmature *)ob->data; + if (DEG_is_active(depsgraph) && arm->edbo == NULL) { + bPoseChannel *pchan_orig = pchan->orig_pchan; + copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat); + copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat); + copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]); + copy_m4_m4(pchan_orig->constinv, pchan->constinv); + BKE_pose_where_is_bone_tail(pchan_orig); + } } -void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph, Scene *scene, Object *ob, int rootchan_index) { bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index); DEG_debug_print_eval_subdata( - __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); + depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); BLI_assert(ob->type == OB_ARMATURE); const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bArmature *arm = (bArmature *)ob->data; if (arm->flag & ARM_RESTPOS) { return; } - BIK_execute_tree(scene, ob, rootchan, ctime); + BIK_execute_tree(depsgraph, scene, ob, rootchan, ctime); } -void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), +void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph, Scene *scene, Object *ob, int rootchan_index) @@ -708,47 +736,73 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx), { bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index); DEG_debug_print_eval_subdata( - __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); + depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); BLI_assert(ob->type == OB_ARMATURE); const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bArmature *arm = (bArmature *)ob->data; if (arm->flag & ARM_RESTPOS) { return; } - BKE_splineik_execute_tree(scene, ob, rootchan, ctime); + BKE_splineik_execute_tree(depsgraph, scene, ob, rootchan, ctime); } -void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), - Scene *scene, - Object *ob) +void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph, + Scene *scene, + Object *ob) { bPose *pose = ob->pose; BLI_assert(pose != NULL); float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); /* release the IK tree */ BIK_release_tree(scene, ob, ctime); - ob->recalc &= ~OB_RECALC_ALL; + BLI_assert(pose->chan_array != NULL); + MEM_freeN(pose->chan_array); + pose->chan_array = NULL; +} + +void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, Object *object) +{ + BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + + pose_pchan_index_create(object->pose); +} + +void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, Object *object) +{ + BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + bPose *pose = object->pose; BLI_assert(pose->chan_array != NULL); MEM_freeN(pose->chan_array); pose->chan_array = NULL; } -void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) +void BKE_pose_eval_proxy_copy_bone( + struct Depsgraph *depsgraph, + Object *object, + int pchan_index) { - BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL); - DEG_debug_print_eval(__func__, ob->id.name, ob); - 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); - } - /* Rest of operations are NO-OP in depsgraph, so can clear - * flag now. + BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index); + /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept + * around for the time while proxies are evaluating. */ - ob->recalc &= ~OB_RECALC_ALL; +#if 0 + bPoseChannel *pchan_from = pose_pchan_get_indexed( + object->proxy_from, pchan_index); +#else + bPoseChannel *pchan_from = BKE_pose_channel_find_name( + object->proxy_from->pose, pchan->name); +#endif + BLI_assert(pchan != NULL); + BLI_assert(pchan_from != NULL); + BKE_pose_copyesult_pchan_result(pchan, pchan_from); } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index ba20dbaddb0..d0dea75860e 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -48,20 +48,25 @@ #include "BKE_addon.h" #include "BKE_blender.h" /* own include */ #include "BKE_blender_version.h" /* own include */ +#include "BKE_blender_user_menu.h" #include "BKE_blendfile.h" #include "BKE_brush.h" #include "BKE_cachefile.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_node.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_sequencer.h" +#include "BKE_studiolight.h" + +#include "DEG_depsgraph.h" #include "RE_pipeline.h" #include "RE_render_ext.h" @@ -80,6 +85,8 @@ char versionstr[48] = ""; void BKE_blender_free(void) { /* samples are in a global list..., also sets G_MAIN->sound->sample NULL */ + + BKE_studiolight_free(); /* needs to run before main free as wm is still referenced for icons preview jobs */ BKE_main_free(G_MAIN); G_MAIN = NULL; @@ -92,7 +99,7 @@ void BKE_blender_free(void) IMB_exit(); BKE_cachefiles_exit(); BKE_images_exit(); - DAG_exit(); + DEG_free_node_types(); BKE_brush_system_exit(); RE_texture_rng_exit(); @@ -201,6 +208,15 @@ static void userdef_free_keymaps(UserDef *userdef) BLI_listbase_clear(&userdef->user_keymaps); } +static void userdef_free_user_menus(UserDef *userdef) +{ + for (bUserMenu *um = userdef->user_menus.first, *um_next; um; um = um_next) { + um_next = um->next; + BKE_blender_user_menu_item_free_list(&um->items); + MEM_freeN(um); + } +} + static void userdef_free_addons(UserDef *userdef) { for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) { @@ -221,6 +237,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts) #endif userdef_free_keymaps(userdef); + userdef_free_user_menus(userdef); userdef_free_addons(userdef); if (clear_fonts) { @@ -236,6 +253,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts) BLI_freelistN(&userdef->uifonts); BLI_freelistN(&userdef->themes); + #undef U } @@ -283,11 +301,13 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use DATA_SWAP(font_path_ui_mono); DATA_SWAP(keyconfigstr); + DATA_SWAP(gizmo_flag); DATA_SWAP(app_flag); /* We could add others. */ FLAG_SWAP(uiflag, int, USER_QUIT_PROMPT); +#undef SWAP_TYPELESS #undef DATA_SWAP #undef LIST_SWAP #undef FLAG_SWAP diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index e57524af546..7b149761952 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -44,12 +44,15 @@ #include "BKE_blender_copybuffer.h" /* own include */ #include "BKE_blendfile.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "BLO_readfile.h" #include "BLO_writefile.h" @@ -95,7 +98,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor /* Here appending/linking starts. */ Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname); BLO_library_link_copypaste(mainl, bh); - BLO_library_link_end(mainl, &bh, 0, NULL, NULL); + BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL); /* Mark all library linked objects to be updated. */ BKE_main_lib_objects_recalc_all(bmain_dst); IMB_colormanagement_check_file_config(bmain_dst); @@ -117,7 +120,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Main *mainl = NULL; Library *lib; BlendHandle *bh; @@ -129,7 +132,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re return false; } - BKE_scene_base_deselect_all(scene); + BKE_view_layer_base_deselect_all(view_layer); /* tag everything, all untagged data can be made local * its also generally useful to know what is new @@ -142,7 +145,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re BLO_library_link_copypaste(mainl, bh); - BLO_library_link_end(mainl, &bh, flag, scene, v3d); + BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer); /* mark all library linked objects to be updated */ BKE_main_lib_objects_recalc_all(bmain); @@ -157,7 +160,11 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); /* recreate dependency graph to include new objects */ - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); + + /* Tag update the scene to flush base collection settings, since the new object is added to a + * new (active) collection, not its original collection, thus need recalculation. */ + DEG_id_tag_update(&scene->id, 0); BLO_blendhandle_close(bh); /* remove library... */ diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index df2caba0208..a00ad5ff05f 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -46,17 +46,19 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_appdir.h" #include "BKE_blender_undo.h" /* own include */ #include "BKE_blendfile.h" -#include "BKE_appdir.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BLO_undofile.h" #include "BLO_writefile.h" +#include "DEG_depsgraph.h" + /* -------------------------------------------------------------------- */ /** \name Global Undo @@ -88,8 +90,8 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C) G.fileflags = fileflags; if (success) { - /* important not to update time here, else non keyed tranforms are lost */ - DAG_on_visible_update(bmain, false); + /* important not to update time here, else non keyed transforms are lost */ + DEG_on_visible_update(bmain, false); } return success; diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c new file mode 100644 index 00000000000..2c18de70e6d --- /dev/null +++ b/source/blender/blenkernel/intern/blender_user_menu.c @@ -0,0 +1,121 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/blender_user_menu.c + * \ingroup bke + * + * User defined menu API. + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "DNA_userdef_types.h" + +#include "BKE_blender_user_menu.h" +#include "BKE_idprop.h" + +/* -------------------------------------------------------------------- */ +/** \name Menu Type + * \{ */ + +bUserMenu *BKE_blender_user_menu_find( + ListBase *lb, char space_type, const char *context) +{ + for (bUserMenu *um = lb->first; um; um = um->next) { + if ((space_type == um->space_type) && + (STREQ(context, um->context))) + { + return um; + } + } + return NULL; +} + +bUserMenu *BKE_blender_user_menu_ensure( + ListBase *lb, char space_type, const char *context) +{ + bUserMenu *um = BKE_blender_user_menu_find(lb, space_type, context); + if (um == NULL) { + um = MEM_callocN(sizeof(bUserMenu), __func__); + um->space_type = space_type; + STRNCPY(um->context, context); + BLI_addhead(lb, um); + } + return um; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Menu Item + * \{ */ + +bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type) +{ + uint size; + + if (type == USER_MENU_TYPE_SEP) { + size = sizeof(bUserMenuItem); + } + else if (type == USER_MENU_TYPE_OPERATOR) { + size = sizeof(bUserMenuItem_Op); + } + else if (type == USER_MENU_TYPE_MENU) { + size = sizeof(bUserMenuItem_Menu); + } + else if (type == USER_MENU_TYPE_PROP) { + size = sizeof(bUserMenuItem_Prop); + } + else { + size = sizeof(bUserMenuItem); + BLI_assert(0); + } + + bUserMenuItem *umi = MEM_callocN(size, __func__); + umi->type = type; + BLI_addtail(lb, umi); + return umi; +} + +void BKE_blender_user_menu_item_free(bUserMenuItem *umi) +{ + if (umi->type == USER_MENU_TYPE_OPERATOR) { + bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi; + if (umi_op->prop) { + IDP_FreeProperty(umi_op->prop); + MEM_freeN(umi_op->prop); + } + } + MEM_freeN(umi); +} + +void BKE_blender_user_menu_item_free_list(ListBase *lb) +{ + for (bUserMenuItem *umi = lb->first, *umi_next; umi; umi = umi_next) { + umi_next = umi->next; + BKE_blender_user_menu_item_free(umi); + } + BLI_listbase_clear(lb); +} diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index c92648da67c..5f716d191e4 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -32,6 +32,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_workspace_types.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -48,11 +49,13 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_ipo.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "BLO_readfile.h" #include "BLO_writefile.h" @@ -93,7 +96,7 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene) { wmWindow *win; for (win = wm->windows.first; win; win = win->next) { - if (win->screen->scene == scene) { + if (win->scene == scene) { return true; } } @@ -164,17 +167,22 @@ static void setup_app_data( * (otherwise we'd be undoing on an off-screen scene which isn't acceptable). * see: T43424 */ + wmWindow *win; bScreen *curscreen = NULL; + ViewLayer *cur_view_layer; bool track_undo_scene; /* comes from readfile.c */ SWAP(ListBase, bmain->wm, bfd->main->wm); + SWAP(ListBase, bmain->workspaces, bfd->main->workspaces); SWAP(ListBase, bmain->screen, bfd->main->screen); - /* we re-use current screen */ + /* we re-use current window and screen */ + win = CTX_wm_window(C); curscreen = CTX_wm_screen(C); - /* but use new Scene pointer */ + /* but use Scene pointer from new file */ curscene = bfd->curscene; + cur_view_layer = bfd->cur_view_layer; track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first); @@ -185,34 +193,41 @@ static void setup_app_data( if (curscene == NULL) { curscene = BKE_scene_add(bfd->main, "Empty"); } + if (cur_view_layer == NULL) { + /* fallback to scene layer */ + cur_view_layer = BKE_view_layer_default_view(curscene); + } if (track_undo_scene) { /* keep the old (free'd) scene, let 'blo_lib_link_screen_restore' * replace it with 'curscene' if its needed */ } - else { - /* and we enforce curscene to be in current screen */ - if (curscreen) { - /* can run in bgmode */ - curscreen->scene = curscene; - } + /* and we enforce curscene to be in current screen */ + else if (win) { /* can run in bgmode */ + win->scene = curscene; } /* BKE_blender_globals_clear will free G_MAIN, here we can still restore pointers */ - blo_lib_link_screen_restore(bfd->main, curscreen, curscene); - /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */ - if (curscreen) { - curscene = curscreen->scene; + blo_lib_link_restore(bfd->main, CTX_wm_manager(C), curscene, cur_view_layer); + if (win) { + curscene = win->scene; } if (track_undo_scene) { wmWindowManager *wm = bfd->main->wm.first; if (wm_scene_is_visible(wm, bfd->curscene) == false) { curscene = bfd->curscene; - curscreen->scene = curscene; - BKE_screen_view3d_scene_sync(curscreen); + win->scene = curscene; + BKE_screen_view3d_scene_sync(curscreen, curscene); } } + + /* We need to tag this here because events may be handled immediately after. + * only the current screen is important because we wont have to handle + * events from multiple screens at once.*/ + if (curscreen) { + BKE_screen_gizmo_tag_refresh(curscreen); + } } /* free G_MAIN Main database */ @@ -227,6 +242,7 @@ static void setup_app_data( CTX_data_main_set(C, bmain); if (bfd->user) { + /* only here free userdef themes... */ BKE_blender_userdef_data_set_and_free(bfd->user); bfd->user = NULL; @@ -262,12 +278,14 @@ static void setup_app_data( /* this can happen when active scene was lib-linked, and doesn't exist anymore */ if (CTX_data_scene(C) == NULL) { + wmWindow *win = CTX_wm_window(C); + /* in case we don't even have a local scene, add one */ if (!bmain->scene.first) BKE_scene_add(bmain, "Empty"); CTX_data_scene_set(C, bmain->scene.first); - CTX_wm_screen(C)->scene = CTX_data_scene(C); + win->scene = CTX_data_scene(C); curscene = CTX_data_scene(C); } @@ -316,20 +334,27 @@ static void setup_app_data( wmWindowManager *wm = bmain->wm.first; if (wm) { - wmWindow *win; - - for (win = wm->windows.first; win; win = win->next) { - if (win->screen && win->screen->scene) /* zealous check... */ - if (win->screen->scene != curscene) - BKE_scene_set_background(bmain, win->screen->scene); + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (win->scene && win->scene != curscene) { + BKE_scene_set_background(bmain, win->scene); + } } } } + + /* Setting scene might require having a dependency graph, with copy on write + * we need to make sure we ensure scene has correct color management before + * constructing dependency graph. + */ + if (mode != LOAD_UNDO) { + IMB_colormanagement_check_file_config(bmain); + } + BKE_scene_set_background(bmain, curscene); if (mode != LOAD_UNDO) { + /* TODO(sergey): Can this be also move above? */ RE_FreeAllPersistentData(); - IMB_colormanagement_check_file_config(bmain); } MEM_freeN(bfd); @@ -392,7 +417,7 @@ bool BKE_blendfile_read_from_memory( bfd = BLO_read_from_memory(filebuf, filelength, reports, skip_flags); if (bfd) { if (update_defaults) - BLO_update_defaults_startup_blend(bfd->main); + BLO_update_defaults_startup_blend(bfd->main, NULL); setup_app_data(C, bfd, "<memory2>", reports); } else { @@ -536,6 +561,54 @@ bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList * return ok; } +WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, const void *filebuf, int filelength, ReportList *reports) +{ + BlendFileData *bfd; + WorkspaceConfigFileData *workspace_config = NULL; + + if (filepath) { + bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_USERDEF); + } + else { + bfd = BLO_read_from_memory(filebuf, filelength, reports, BLO_READ_SKIP_USERDEF); + } + + if (bfd) { + workspace_config = MEM_mallocN(sizeof(*workspace_config), __func__); + workspace_config->main = bfd->main; + workspace_config->workspaces = bfd->main->workspaces; + + MEM_freeN(bfd); + } + + return workspace_config; +} + +bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports) +{ + int fileflags = G.fileflags & ~(G_FILE_NO_UI | G_FILE_HISTORY); + bool retval = false; + + BKE_blendfile_write_partial_begin(bmain); + + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + BKE_blendfile_write_partial_tag_ID(&workspace->id, true); + } + + if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) { + retval = true; + } + + BKE_blendfile_write_partial_end(bmain); + + return retval; +} + +void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config) +{ + BKE_main_free(workspace_config->main); + MEM_freeN(workspace_config); +} /** \} */ diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c deleted file mode 100644 index b33b07e3a4f..00000000000 --- a/source/blender/blenkernel/intern/bmfont.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): 04-10-2000 frank. - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -/** \file blender/blenkernel/intern/bmfont.c - * \ingroup bke - */ - - -/** - * Two external functions: - * - * void detectBitmapFont(ImBuf *ibuf) - * detects if an image buffer contains a bitmap font. It makes the - * specific bitmap data which is stored in the bitmap invisible to blender. - * - * void matrixGlyph(ImBuf *ibuf, unsigned short unicode, *float x 7) - * returns all the information about the character (unicode) in the floats - * - * Room for improvement: - * add kerning data in the bitmap - * all calculations in matrixGlyph() are static and could be done during - * initialization - */ - -#include <stdio.h> - -#include "MEM_guardedalloc.h" -#include "IMB_imbuf_types.h" - -#include "BLI_utildefines.h" - -#include "BKE_bmfont.h" -#include "BKE_bmfont_types.h" -#include "BKE_global.h" - -void printfGlyph(bmGlyph *glyph) -{ - printf("unicode: %d '%c'\n", glyph->unicode, glyph->unicode); - printf(" locx: %4d locy: %4d\n", glyph->locx, glyph->locy); - printf(" sizex: %3d sizey: %3d\n", glyph->sizex, glyph->sizey); - printf(" ofsx: %3d ofsy: %3d\n", glyph->ofsx, glyph->ofsy); - printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved); -} - -void calcAlpha(ImBuf *ibuf) -{ - int i; - char *rect; - - if (ibuf) { - rect = (char *) ibuf->rect; - for (i = ibuf->x * ibuf->y; i > 0; i--) { - rect[3] = MAX3(rect[0], rect[1], rect[2]); - rect += 4; - } - } -} - -void readBitmapFontVersion0(ImBuf *ibuf, unsigned char *rect, int step) -{ - int glyphcount, bytes, i, index, linelength, ysize; - unsigned char *buffer; - bmFont *bmfont; - - linelength = ibuf->x * step; - - glyphcount = (rect[6 * step] << 8) | rect[7 * step]; - bytes = ((glyphcount - 1) * sizeof(bmGlyph)) + sizeof(bmFont); - - ysize = (bytes + (ibuf->x - 1)) / ibuf->x; - - if (ysize < ibuf->y) { - /* we're first going to copy all data into a linear buffer. - * step can be 4 or 1 bytes, and the data is not sequential because - * the bitmap was flipped vertically. */ - - buffer = MEM_mallocN(bytes, "readBitmapFontVersion0:buffer"); - - index = 0; - for (i = 0; i < bytes; i++) { - buffer[i] = rect[index]; - index += step; - if (index >= linelength) { - /* we've read one line, no skip to the line *before* that */ - rect -= linelength; - index -= linelength; - } - } - - /* we're now going to endian convert the data */ - - bmfont = MEM_mallocN(bytes, "readBitmapFontVersion0:bmfont"); - index = 0; - - /* first read the header */ - bmfont->magic[0] = buffer[index++]; - bmfont->magic[1] = buffer[index++]; - bmfont->magic[2] = buffer[index++]; - bmfont->magic[3] = buffer[index++]; - bmfont->version = (buffer[index] << 8) | buffer[index + 1]; index += 2; - bmfont->glyphcount = (buffer[index] << 8) | buffer[index + 1]; index += 2; - bmfont->xsize = (buffer[index] << 8) | buffer[index + 1]; index += 2; - bmfont->ysize = (buffer[index] << 8) | buffer[index + 1]; index += 2; - - for (i = 0; i < bmfont->glyphcount; i++) { - bmfont->glyphs[i].unicode = (buffer[index] << 8) | buffer[index + 1]; index += 2; - bmfont->glyphs[i].locx = (buffer[index] << 8) | buffer[index + 1]; index += 2; - bmfont->glyphs[i].locy = (buffer[index] << 8) | buffer[index + 1]; index += 2; - bmfont->glyphs[i].ofsx = buffer[index++]; - bmfont->glyphs[i].ofsy = buffer[index++]; - bmfont->glyphs[i].sizex = buffer[index++]; - bmfont->glyphs[i].sizey = buffer[index++]; - bmfont->glyphs[i].advance = buffer[index++]; - bmfont->glyphs[i].reserved = buffer[index++]; - if (G.debug & G_DEBUG) { - printfGlyph(&bmfont->glyphs[i]); - } - } - - MEM_freeN(buffer); - - if (G.debug & G_DEBUG) { - printf("Oldy = %d Newy = %d\n", ibuf->y, ibuf->y - ysize); - printf("glyphcount = %d\n", glyphcount); - printf("bytes = %d\n", bytes); - } - - /* we've read the data from the image. Now we're going - * to crop the image vertically so only the bitmap data - * remains visible */ - - ibuf->y -= ysize; - ibuf->userdata = bmfont; - ibuf->userflags |= IB_BITMAPFONT; - - if (ibuf->planes < 32) { - /* we're going to fake alpha here: */ - calcAlpha(ibuf); - } - } - else { - printf("readBitmapFontVersion0: corrupted bitmapfont\n"); - } -} - -void detectBitmapFont(ImBuf *ibuf) -{ - unsigned char *rect; - unsigned short version; - int i; - - if (ibuf != NULL && ibuf->rect != NULL) { - /* bitmap must have an x size that is a power of two */ - if (is_power_of_two(ibuf->x)) { - rect = (unsigned char *) (ibuf->rect + (ibuf->x * (ibuf->y - 1))); - /* printf ("starts with: %s %c %c %c %c\n", rect, rect[0], rect[1], rect[2], rect[3]); */ - if (rect[0] == 'B' && rect[1] == 'F' && rect[2] == 'N' && rect[3] == 'T') { - /* printf("found 8bit font !\n"); - * round y size down - * do the 8 bit font stuff. (not yet) */ - } - else { - /* we try all 4 possible combinations */ - for (i = 0; i < 4; i++) { - if (rect[0] == 'B' && rect[4] == 'F' && rect[8] == 'N' && rect[12] == 'T') { - /* printf("found 24bit font !\n"); - * We're going to parse the file: */ - - version = (rect[16] << 8) | rect[20]; - - if (version == 0) { - readBitmapFontVersion0(ibuf, rect, 4); - } - else { - printf("detectBitmapFont :Unsupported version %d\n", (int)version); - } - - /* on success ibuf->userdata points to the bitmapfont */ - if (ibuf->userdata) { - break; - } - } - rect++; - } - } - } - } -} - -int locateGlyph(bmFont *bmfont, unsigned short unicode) -{ - int min, max, current = 0; - - if (bmfont) { - min = 0; - max = bmfont->glyphcount; - while (1) { - /* look halfway for glyph */ - current = (min + max) >> 1; - - if (bmfont->glyphs[current].unicode == unicode) { - break; - } - else if (bmfont->glyphs[current].unicode < unicode) { - /* have to move up */ - min = current; - } - else { - /* have to move down */ - max = current; - } - - if (max - min <= 1) { - /* unable to locate glyph */ - current = 0; - break; - } - } - } - - return(current); -} - -void matrixGlyph( - ImBuf *ibuf, unsigned short unicode, - float *centerx, float *centery, - float *sizex, float *sizey, - float *transx, float *transy, - float *movex, float *movey, - float *advance) -{ - int index; - bmFont *bmfont; - - *centerx = *centery = 0.0; - *sizex = *sizey = 1.0; - *transx = *transy = 0.0; - *movex = *movey = 0.0; - *advance = 1.0; - - if (ibuf) { - bmfont = ibuf->userdata; - if (bmfont && (ibuf->userflags & IB_BITMAPFONT)) { - index = locateGlyph(bmfont, unicode); - if (index) { - - *sizex = (bmfont->glyphs[index].sizex) / (float) (bmfont->glyphs[0].sizex); - *sizey = (bmfont->glyphs[index].sizey) / (float) (bmfont->glyphs[0].sizey); - - *transx = bmfont->glyphs[index].locx / (float) ibuf->x; - *transy = (ibuf->y - bmfont->glyphs[index].locy) / (float) ibuf->y; - - *centerx = bmfont->glyphs[0].locx / (float) ibuf->x; - *centery = (ibuf->y - bmfont->glyphs[0].locy) / (float) ibuf->y; - - /* 2.0 units is the default size of an object */ - - *movey = 1.0f - *sizey + 2.0f * (bmfont->glyphs[index].ofsy - bmfont->glyphs[0].ofsy) / (float) bmfont->glyphs[0].sizey; - *movex = *sizex - 1.0f + 2.0f * (bmfont->glyphs[index].ofsx - bmfont->glyphs[0].ofsx) / (float) bmfont->glyphs[0].sizex; - - *advance = 2.0f * bmfont->glyphs[index].advance / (float) bmfont->glyphs[0].advance; - - // printfGlyph(&bmfont->glyphs[index]); - // printf("%c %d %0.5f %0.5f %0.5f %0.5f %0.5f\n", unicode, index, *sizex, *sizey, *transx, *transy, *advance); - } - } - } -} diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 810056f8fc7..ea62748806c 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -132,6 +132,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, if (eff == NULL && gabr->ob) { memset(&temp_eff, 0, sizeof(EffectorCache)); temp_eff.ob = gabr->ob; + temp_eff.depsgraph = bbd->sim->depsgraph; temp_eff.scene = bbd->sim->scene; eff = &temp_eff; get_effector_data(eff, &efd, &epoint, 0); @@ -1264,7 +1265,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) /* account for effectors */ pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); - pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL); + BKE_effectors_apply(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL); if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { float length = normalize_v3(force); diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 0b191e1f69b..88a4b7905ef 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -478,13 +478,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int } \ } (void)0 - /* do via modifiers instead */ -#if 0 - if (ob->fluidsimSettings) { - rewrite_path_fixed(ob->fluidsimSettings->surfdataPath, visit_cb, absbase, bpath_user_data); - } -#endif - for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Fluidsim) { FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; @@ -513,7 +506,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int } if (ob->soft) { - BPATH_TRAVERSE_POINTCACHE(ob->soft->ptcaches); + BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches); } for (psys = ob->particlesystem.first; psys; psys = psys->next) { @@ -588,14 +581,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int } break; } - case ID_TE: - { - Tex *tex = (Tex *)id; - if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format)) { - rewrite_path_fixed(tex->vd->source_path, visit_cb, absbase, bpath_user_data); - } - break; - } case ID_SCE: { Scene *scene = (Scene *)id; diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 5b76d75f261..39266eed6fe 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -29,6 +29,7 @@ #include "DNA_brush_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "DNA_gpencil_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -36,6 +37,7 @@ #include "BKE_brush.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -129,6 +131,7 @@ static void brush_defaults(Brush *brush) brush->stencil_dimension[0] = 256; brush->stencil_dimension[1] = 256; + } /* Datablock add/copy/free/make_local */ @@ -164,6 +167,374 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode) return brush; } +/* add grease pencil settings */ +void BKE_brush_init_gpencil_settings(Brush *brush) +{ + if (brush->gpencil_settings == NULL) { + brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings"); + } + + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->flag = 0; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; + + /* curves */ + brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); +} + +/* add a new gp-brush */ +Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name) +{ + Brush *brush; + Paint *paint = &ts->gp_paint->paint; + brush = BKE_brush_add(bmain, name, OB_MODE_GPENCIL_PAINT); + + BKE_paint_brush_set(paint, brush); + id_us_min(&brush->id); + + brush->size = 3; + + /* grease pencil basic settings */ + BKE_brush_init_gpencil_settings(brush); + + /* return brush */ + return brush; +} + +/* grease pencil cumapping->preset */ +typedef enum eGPCurveMappingPreset { + GPCURVE_PRESET_PENCIL = 0, + GPCURVE_PRESET_INK = 1, + GPCURVE_PRESET_INKNOISE = 2, +} eGPCurveMappingPreset; + +static void brush_gpencil_curvemap_reset(CurveMap *cuma, int preset) +{ + if (cuma->curve) + MEM_freeN(cuma->curve); + + cuma->totpoint = 3; + cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__); + + switch (preset) { + case GPCURVE_PRESET_PENCIL: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.75115f; + cuma->curve[1].y = 0.25f; + cuma->curve[2].x = 1.0f; + cuma->curve[2].y = 1.0f; + break; + case GPCURVE_PRESET_INK: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.63448f; + cuma->curve[1].y = 0.375f; + cuma->curve[2].x = 1.0f; + cuma->curve[2].y = 1.0f; + break; + case GPCURVE_PRESET_INKNOISE: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.63134f; + cuma->curve[1].y = 0.3625f; + cuma->curve[2].x = 1.0f; + cuma->curve[2].y = 1.0f; + break; + } + + if (cuma->table) { + MEM_freeN(cuma->table); + cuma->table = NULL; + } +} + +/* create a set of grease pencil presets */ +void BKE_brush_gpencil_presets(bContext *C) +{ +#define SMOOTH_STROKE_RADIUS 40 +#define SMOOTH_STROKE_FACTOR 0.9f + + ToolSettings *ts = CTX_data_tool_settings(C); + Paint *paint = &ts->gp_paint->paint; + Main *bmain = CTX_data_main(C); + + Brush *brush, *deft; + CurveMapping *custom_curve; + + /* Pencil brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil"); + brush->size = 25.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 0.6f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->draw_random_press = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Pen brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen"); + deft = brush; /* save default brush */ + brush->size = 30.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Ink brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink"); + brush->size = 60.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.6f; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->draw_random_press = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Curve */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INK); + + /* Ink Noise brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise"); + brush->size = 60.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.7f; + brush->gpencil_settings->draw_random_strength = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 2; + brush->gpencil_settings->thick_smoothfac = 0.5f; + brush->gpencil_settings->thick_smoothlvl = 2; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Curve */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INKNOISE); + + /* Block Basic brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block"); + brush->size = 150.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 0.7f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->draw_random_press = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->draw_random_sub = 0; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Marker brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker"); + brush->size = 80.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.374f; + brush->gpencil_settings->draw_random_strength = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = M_PI_4; /* 45 degrees */ + brush->gpencil_settings->draw_angle_factor = 1.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Fill brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); + brush->size = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->fill_leak = 3; + brush->gpencil_settings->fill_threshold = 0.1f; + brush->gpencil_settings->fill_simplylvl = 1; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; + brush->gpencil_tool = GPAINT_TOOL_FILL; + + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + brush->gpencil_settings->draw_strength = 1.0f; + + /* Soft Eraser brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser"); + brush->size = 30.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; + brush->gpencil_tool = GPAINT_TOOL_ERASE; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; + brush->gpencil_settings->era_strength_f = 100.0f; + brush->gpencil_settings->era_thickness_f = 0.10f; + + /* Hard Eraser brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Vertex"); + brush->size = 30.0f; + brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; + brush->gpencil_tool = GPAINT_TOOL_ERASE; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; + + /* Stroke Eraser brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke"); + brush->size = 30.0f; + brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; + brush->gpencil_tool = GPAINT_TOOL_ERASE; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; + + /* set default brush */ + BKE_paint_brush_set(paint, deft); + +} + +void BKE_brush_update_material(Main *bmain, Material *ma, Brush *exclude_brush) +{ + for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) { + if ((exclude_brush != NULL) && (brush == exclude_brush)) { + continue; + } + + if (brush->gpencil_settings != NULL) { + BrushGpencilSettings *gpencil_settings = brush->gpencil_settings; + if (((gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) == 0) && + (gpencil_settings->material != ma)) + { + gpencil_settings->material = ma; + } + } + } +} + struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode) { Brush *brush; @@ -197,6 +568,12 @@ void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *bru } brush_dst->curve = curvemapping_copy(brush_src->curve); + if (brush_src->gpencil_settings != NULL) { + brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings); + brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity); + brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength); + brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter); + } /* enable fake user by default */ id_fake_user_set(&brush_dst->id); @@ -215,11 +592,18 @@ void BKE_brush_free(Brush *brush) if (brush->icon_imbuf) { IMB_freeImBuf(brush->icon_imbuf); } - curvemapping_free(brush->curve); + if (brush->gpencil_settings != NULL) { + curvemapping_free(brush->gpencil_settings->curve_sensitivity); + curvemapping_free(brush->gpencil_settings->curve_strength); + curvemapping_free(brush->gpencil_settings->curve_jitter); + MEM_SAFE_FREE(brush->gpencil_settings); + } + MEM_SAFE_FREE(brush->gradient); + BKE_previewimg_free(&(brush->preview)); } diff --git a/source/blender/blenkernel/intern/bullet.c b/source/blender/blenkernel/intern/bullet.c deleted file mode 100644 index 9630ee389fa..00000000000 --- a/source/blender/blenkernel/intern/bullet.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/bullet.c - * \ingroup bke - */ - - -#include "MEM_guardedalloc.h" - -/* types */ -#include "DNA_object_force_types.h" /* here is the softbody struct */ - -#include "BKE_bullet.h" - - -/* ************ Object level, exported functions *************** */ - -/* allocates and initializes general main data */ -BulletSoftBody *bsbNew(void) -{ - BulletSoftBody *bsb; - - bsb = MEM_callocN(sizeof(BulletSoftBody), "bulletsoftbody"); - - bsb->flag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT; - bsb->linStiff = 0.5f; - bsb->angStiff = 1.0f; - bsb->volume = 1.0f; - - - bsb->viterations = 0; - bsb->piterations = 2; - bsb->diterations = 0; - bsb->citerations = 4; - - bsb->kSRHR_CL = 0.1f; - bsb->kSKHR_CL = 1.f; - bsb->kSSHR_CL = 0.5f; - bsb->kSR_SPLT_CL = 0.5f; - - bsb->kSK_SPLT_CL = 0.5f; - bsb->kSS_SPLT_CL = 0.5f; - bsb->kVCF = 1; - bsb->kDP = 0; - - bsb->kDG = 0; - bsb->kLF = 0; - bsb->kPR = 0; - bsb->kVC = 0; - - bsb->kDF = 0.2f; - bsb->kMT = 0.05; - bsb->kCHR = 1.0f; - bsb->kKHR = 0.1f; - - bsb->kSHR = 1.0f; - bsb->kAHR = 0.7f; - - bsb->collisionflags = 0; - //bsb->collisionflags = OB_BSB_COL_CL_RS + OB_BSB_COL_CL_SS; - bsb->numclusteriterations = 64; - bsb->welding = 0.f; - - return bsb; -} - -/* frees all */ -void bsbFree(BulletSoftBody *bsb) -{ - /* no internal data yet */ - MEM_freeN(bsb); -} diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 151d697d891..5c27b1b6207 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -34,6 +34,7 @@ #include <math.h> #include <assert.h> +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BLI_utildefines.h" @@ -41,8 +42,10 @@ #include "BLI_math.h" #include "BLI_threads.h" -#include "BKE_DerivedMesh.h" +#include "BKE_bvhutils.h" #include "BKE_editmesh.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "MEM_guardedalloc.h" @@ -423,7 +426,8 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree( const MVert *vert, const int verts_num, const BLI_bitmap *verts_mask, int verts_num_active) { - BLI_assert(vert != NULL); + BVHTree *tree = NULL; + if (verts_mask) { BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num)); } @@ -431,17 +435,19 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree( verts_num_active = verts_num; } - BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); + if (verts_num_active) { + tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); - if (tree) { - for (int i = 0; i < verts_num; i++) { - if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { - continue; + if (tree) { + for (int i = 0; i < verts_num; i++) { + if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { + continue; + } + BLI_bvhtree_insert(tree, i, vert[i].co, 1); } - BLI_bvhtree_insert(tree, i, vert[i].co, 1); + BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active); + BLI_bvhtree_balance(tree); } - BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active); - BLI_bvhtree_balance(tree); } return tree; @@ -463,7 +469,6 @@ static void bvhtree_from_mesh_verts_setup_data( data->vert = vert; data->vert_allocated = vert_allocated; - //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */ } /* Builds a bvh tree where nodes are the vertices of the given em */ @@ -489,12 +494,39 @@ BVHTree *bvhtree_from_editmesh_verts_ex( BVHTree *bvhtree_from_editmesh_verts( BVHTreeFromEditMesh *data, BMEditMesh *em, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvh_cache) { - return bvhtree_from_editmesh_verts_ex( - data, em, - NULL, -1, - epsilon, tree_type, axis); + if (bvh_cache) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); + data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree); + BLI_rw_mutex_unlock(&cache_rwlock); + + if (data->cached == false) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + data->cached = bvhcache_find( + *bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree); + if (data->cached == false) { + data->tree = bvhtree_from_editmesh_verts_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert( + bvh_cache, data->tree, BVHTREE_FROM_EM_VERTS); + } + BLI_rw_mutex_unlock(&cache_rwlock); + } + } + else { + data->tree = bvhtree_from_editmesh_verts_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + } + + return data->tree; } /** @@ -567,29 +599,31 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree( const BLI_bitmap *edges_mask, int edges_num_active, float epsilon, int tree_type, int axis) { + BVHTree *tree = NULL; + if (edges_mask) { BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num)); } else { edges_num_active = edge_num; } - BLI_assert(vert != NULL); - BLI_assert(edge != NULL); - /* Create a bvh-tree of the given target */ - BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); - if (tree) { - for (int i = 0; i < edge_num; i++) { - if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) { - continue; - } - float co[2][3]; - copy_v3_v3(co[0], vert[edge[i].v1].co); - copy_v3_v3(co[1], vert[edge[i].v2].co); + if (edges_num_active) { + /* Create a bvh-tree of the given target */ + tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + if (tree) { + for (int i = 0; i < edge_num; i++) { + if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) { + continue; + } + float co[2][3]; + copy_v3_v3(co[0], vert[edge[i].v1].co); + copy_v3_v3(co[1], vert[edge[i].v2].co); - BLI_bvhtree_insert(tree, i, co[0], 2); + BLI_bvhtree_insert(tree, i, co[0], 2); + } + BLI_bvhtree_balance(tree); } - BLI_bvhtree_balance(tree); } return tree; @@ -641,12 +675,39 @@ BVHTree *bvhtree_from_editmesh_edges_ex( BVHTree *bvhtree_from_editmesh_edges( BVHTreeFromEditMesh *data, BMEditMesh *em, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvh_cache) { - return bvhtree_from_editmesh_edges_ex( - data, em, - NULL, -1, - epsilon, tree_type, axis); + if (bvh_cache) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); + data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree); + BLI_rw_mutex_unlock(&cache_rwlock); + + if (data->cached == false) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + data->cached = bvhcache_find( + *bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree); + if (data->cached == false) { + data->tree = bvhtree_from_editmesh_edges_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert( + bvh_cache, data->tree, BVHTREE_FROM_EM_EDGES); + } + BLI_rw_mutex_unlock(&cache_rwlock); + } + } + else { + data->tree = bvhtree_from_editmesh_edges_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + } + + return data->tree; } /** @@ -833,22 +894,21 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree( const BLI_bitmap *looptri_mask, int looptri_num_active) { BVHTree *tree = NULL; - int i; - if (looptri_num) { - if (looptri_mask) { - BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num)); - } - else { - looptri_num_active = looptri_num; - } + if (looptri_mask) { + BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num)); + } + else { + looptri_num_active = looptri_num; + } + if (looptri_num_active) { /* Create a bvh-tree of the given target */ /* printf("%s: building BVH, total=%d\n", __func__, numFaces); */ tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis); if (tree) { if (vert && looptri) { - for (i = 0; i < looptri_num; i++) { + for (int i = 0; i < looptri_num; i++) { float co[3][3]; if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) { continue; @@ -902,23 +962,23 @@ BVHTree *bvhtree_from_editmesh_looptri_ex( /* BMESH specific check that we have tessfaces, * we _could_ tessellate here but rather not - campbell */ - BVHTree *tree; + BVHTree *tree = NULL; if (bvhCache) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); - tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI); + bool in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree); BLI_rw_mutex_unlock(&cache_rwlock); - if (tree == NULL) { + if (in_cache == false) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI); - if (tree == NULL) { + in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree); + if (in_cache == false) { tree = bvhtree_from_editmesh_looptri_create_tree( epsilon, tree_type, axis, em, em->tottri, looptri_mask, looptri_num_active); - if (tree) { - /* Save on cache for later use */ - /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI); - } + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI); + } BLI_rw_mutex_unlock(&cache_rwlock); } @@ -976,189 +1036,233 @@ BVHTree *bvhtree_from_mesh_looptri_ex( return tree; } +static BLI_bitmap *loose_verts_map_get( + const MEdge *medge, int edges_num, + const MVert *UNUSED(mvert), int verts_num, + int *r_loose_vert_num) +{ + BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__); + BLI_BITMAP_SET_ALL(loose_verts_mask, true, verts_num); + + const MEdge *e = medge; + int num_linked_verts = 0; + for (;edges_num--; e++) { + if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) { + BLI_BITMAP_DISABLE(loose_verts_mask, e->v1); + num_linked_verts++; + } + if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) { + BLI_BITMAP_DISABLE(loose_verts_mask, e->v2); + num_linked_verts++; + } + } + + *r_loose_vert_num = verts_num - num_linked_verts; + + return loose_verts_mask; +} + +static BLI_bitmap *loose_edges_map_get( + const MEdge *medge, const int edges_len, + int *r_loose_edge_len) +{ + BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__); + + int loose_edges_len = 0; + const MEdge *e = medge; + for (int i = 0; i < edges_len; i++, e++) { + if (e->flag & ME_LOOSEEDGE) { + BLI_BITMAP_ENABLE(loose_edges_mask, i); + loose_edges_len++; + } + else { + BLI_BITMAP_DISABLE(loose_edges_mask, i); + } + } + + *r_loose_edge_len = loose_edges_len; + + return loose_edges_mask; +} + /** * Builds or queries a bvhcache for the cache bvhtree of the request type. */ -BVHTree *bvhtree_from_mesh_get( - struct BVHTreeFromMesh *data, struct DerivedMesh *dm, +BVHTree *BKE_bvhtree_from_mesh_get( + struct BVHTreeFromMesh *data, struct Mesh *mesh, const int type, const int tree_type) { - BVHTree *tree = NULL; - - BVHTree_NearestPointCallback nearest_callback = NULL; - BVHTree_RayCastCallback raycast_callback = NULL; - - MVert *mvert = NULL; - MEdge *medge = NULL; - MFace *mface = NULL; - MLoop *mloop = NULL; - const MLoopTri *looptri = NULL; - bool vert_allocated = false; - bool edge_allocated = false; - bool face_allocated = false; - bool loop_allocated = false; - bool looptri_allocated = false; + struct BVHTreeFromMesh data_cp = {0}; BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); - tree = bvhcache_find(dm->bvhCache, type); + data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree); BLI_rw_mutex_unlock(&cache_rwlock); + if (data_cp.cached && data_cp.tree == NULL) { + memset(data, 0, sizeof(*data)); + return data_cp.tree; + } + switch (type) { case BVHTREE_FROM_VERTS: - raycast_callback = mesh_verts_spherecast; + case BVHTREE_FROM_LOOSEVERTS: + data_cp.raycast_callback = mesh_verts_spherecast; - mvert = DM_get_vert_array(dm, &vert_allocated); + data_cp.vert = mesh->mvert; - if (tree == NULL) { - /* Not in cache */ + if (data_cp.cached == false) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS); - if (tree == NULL) { - tree = bvhtree_from_mesh_verts_create_tree( - 0.0, tree_type, 6, mvert, dm->getNumVerts(dm), NULL, -1); - - if (tree) { - /* Save on cache for later use */ - /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS); + data_cp.cached = bvhcache_find( + mesh->runtime.bvh_cache, type, &data_cp.tree); + + if (data_cp.cached == false) { + BLI_bitmap *loose_verts_mask = NULL; + int loose_vert_len = -1; + int verts_len = mesh->totvert; + + if (type == BVHTREE_FROM_LOOSEVERTS) { + loose_verts_mask = loose_verts_map_get( + mesh->medge, mesh->totedge, data_cp.vert, + verts_len, &loose_vert_len); + } + + data_cp.tree = bvhtree_from_mesh_verts_create_tree( + 0.0, tree_type, 6, data_cp.vert, verts_len, + loose_verts_mask, loose_vert_len); + + if (loose_verts_mask != NULL) { + MEM_freeN(loose_verts_mask); } + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type); } BLI_rw_mutex_unlock(&cache_rwlock); } break; case BVHTREE_FROM_EDGES: - nearest_callback = mesh_edges_nearest_point; - raycast_callback = mesh_edges_spherecast; + case BVHTREE_FROM_LOOSEEDGES: + data_cp.nearest_callback = mesh_edges_nearest_point; + data_cp.raycast_callback = mesh_edges_spherecast; - mvert = DM_get_vert_array(dm, &vert_allocated); - medge = DM_get_edge_array(dm, &edge_allocated); + data_cp.vert = mesh->mvert; + data_cp.edge = mesh->medge; - if (tree == NULL) { - /* Not in cache */ + if (data_cp.cached == false) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES); - if (tree == NULL) { - tree = bvhtree_from_mesh_edges_create_tree( - mvert, medge, dm->getNumEdges(dm), - NULL, -1, 0.0, tree_type, 6); - - if (tree) { - /* Save on cache for later use */ - /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES); + data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree); + if (data_cp.cached == false) { + BLI_bitmap *loose_edges_mask = NULL; + int loose_edges_len = -1; + int edges_len = mesh->totedge; + + if (type == BVHTREE_FROM_LOOSEEDGES) { + loose_edges_mask = loose_edges_map_get( + data_cp.edge, edges_len, &loose_edges_len); } + + data_cp.tree = bvhtree_from_mesh_edges_create_tree( + data_cp.vert, data_cp.edge, edges_len, + loose_edges_mask, loose_edges_len, 0.0, tree_type, 6); + + if (loose_edges_mask != NULL) { + MEM_freeN(loose_edges_mask); + } + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type); } BLI_rw_mutex_unlock(&cache_rwlock); } break; case BVHTREE_FROM_FACES: - nearest_callback = mesh_faces_nearest_point; - raycast_callback = mesh_faces_spherecast; + data_cp.nearest_callback = mesh_faces_nearest_point; + data_cp.raycast_callback = mesh_faces_spherecast; - mvert = DM_get_vert_array(dm, &vert_allocated); - mface = DM_get_tessface_array(dm, &face_allocated); + data_cp.vert = mesh->mvert; + data_cp.face = mesh->mface; - if (tree == NULL) { - /* Not in cache */ + if (data_cp.cached == false) { BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES); - if (tree == NULL) { - int numFaces = dm->getNumTessFaces(dm); - BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0)); - - tree = bvhtree_from_mesh_faces_create_tree( - 0.0, tree_type, 6, mvert, mface, numFaces, NULL, -1); - - if (tree) { - /* Save on cache for later use */ - /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES); - } + data_cp.cached = bvhcache_find( + mesh->runtime.bvh_cache, BVHTREE_FROM_FACES, &data_cp.tree); + if (data_cp.cached == false) { + int num_faces = mesh->totface; + BLI_assert(!(num_faces == 0 && mesh->totpoly != 0)); + + data_cp.tree = bvhtree_from_mesh_faces_create_tree( + 0.0, tree_type, 6, data_cp.vert, + data_cp.face, num_faces, NULL, -1); + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert( + &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_FACES); } BLI_rw_mutex_unlock(&cache_rwlock); } break; case BVHTREE_FROM_LOOPTRI: - nearest_callback = mesh_looptri_nearest_point; - raycast_callback = mesh_looptri_spherecast; + data_cp.nearest_callback = mesh_looptri_nearest_point; + data_cp.raycast_callback = mesh_looptri_spherecast; - mvert = DM_get_vert_array(dm, &vert_allocated); - mloop = DM_get_loop_array(dm, &loop_allocated); - looptri = dm->getLoopTriArray(dm); + data_cp.vert = mesh->mvert; + data_cp.loop = mesh->mloop; - if (tree == NULL) { - /* Not in cache */ - BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); - tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI); - if (tree == NULL) { - int looptri_num = dm->getNumLoopTri(dm); + /* TODO: store looptris somewhere? */ + data_cp.looptri = BKE_mesh_runtime_looptri_ensure(mesh); + if (data_cp.cached == false) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + data_cp.cached = bvhcache_find( + mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI, &data_cp.tree); + if (data_cp.cached == false) { + int looptri_num = BKE_mesh_runtime_looptri_len(mesh); /* this assert checks we have looptris, * if not caller should use DM_ensure_looptri() */ - BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0)); + BLI_assert(!(looptri_num == 0 && mesh->totpoly != 0)); - tree = bvhtree_from_mesh_looptri_create_tree( + data_cp.tree = bvhtree_from_mesh_looptri_create_tree( 0.0, tree_type, 6, - mvert, mloop, looptri, looptri_num, NULL, -1); - if (tree) { - /* Save on cache for later use */ - /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI); - } + data_cp.vert, data_cp.loop, + data_cp.looptri, looptri_num, NULL, -1); + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert( + &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_LOOPTRI); } BLI_rw_mutex_unlock(&cache_rwlock); } break; + case BVHTREE_FROM_EM_VERTS: + case BVHTREE_FROM_EM_EDGES: + case BVHTREE_FROM_EM_LOOPTRI: + BLI_assert(false); + break; } - if (tree != NULL) { + if (data_cp.tree != NULL) { #ifdef DEBUG - if (BLI_bvhtree_get_tree_type(tree) != tree_type) { - printf("tree_type %d obtained instead of %d\n", BLI_bvhtree_get_tree_type(tree), tree_type); + if (BLI_bvhtree_get_tree_type(data_cp.tree) != tree_type) { + printf("tree_type %d obtained instead of %d\n", + BLI_bvhtree_get_tree_type(data_cp.tree), tree_type); } #endif - data->tree = tree; - - data->nearest_callback = nearest_callback; - data->raycast_callback = raycast_callback; - - data->vert = mvert; - data->edge = medge; - data->face = mface; - data->loop = mloop; - data->looptri = looptri; - data->vert_allocated = vert_allocated; - data->edge_allocated = edge_allocated; - data->face_allocated = face_allocated; - data->loop_allocated = loop_allocated; - data->looptri_allocated = looptri_allocated; - - data->cached = true; + data_cp.cached = true; + memcpy(data, &data_cp, sizeof(*data)); } else { - if (vert_allocated) { - MEM_freeN(mvert); - } - if (edge_allocated) { - MEM_freeN(medge); - } - if (face_allocated) { - MEM_freeN(mface); - } - if (loop_allocated) { - MEM_freeN(mloop); - } - if (looptri_allocated) { - MEM_freeN((void *)looptri); - } - + free_bvhtree_from_mesh(&data_cp); memset(data, 0, sizeof(*data)); } - return tree; + return data_cp.tree; } /** \} */ @@ -1216,16 +1320,17 @@ typedef struct BVHCacheItem { /** * Queries a bvhcache for the cache bvhtree of the request type */ -BVHTree *bvhcache_find(BVHCache *cache, int type) +bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree) { while (cache) { const BVHCacheItem *item = cache->link; if (item->type == type) { - return item->tree; + *r_tree = item->tree; + return true; } cache = cache->next; } - return NULL; + return false; } bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree) @@ -1251,11 +1356,9 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type) { BVHCacheItem *item = NULL; - assert(tree != NULL); - assert(bvhcache_find(*cache_p, type) == NULL); + assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false); item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem"); - assert(item != NULL); item->type = type; item->tree = tree; @@ -1264,13 +1367,8 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type) } /** - * inits and frees a bvhcache + * frees a bvhcache */ -void bvhcache_init(BVHCache **cache_p) -{ - *cache_p = NULL; -} - static void bvhcacheitem_free(void *_item) { BVHCacheItem *item = (BVHCacheItem *)_item; diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 5f7759c7b55..c7d7a3a98eb 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -89,13 +89,22 @@ void BKE_cachefile_free(CacheFile *cache_file) { BKE_animdata_free((ID *)cache_file, false); + if (cache_file->id.tag & LIB_TAG_NO_MAIN) { + /* CoW/no-main copies reuse the existing ArchiveReader and mutex */ + return; + } + + if (cache_file->handle) { #ifdef WITH_ALEMBIC - ABC_free_handle(cache_file->handle); + ABC_free_handle(cache_file->handle); #endif - + cache_file->handle = NULL; + } if (cache_file->handle_mutex) { BLI_mutex_free(cache_file->handle_mutex); + cache_file->handle_mutex = NULL; } + BLI_freelistN(&cache_file->object_paths); } @@ -110,8 +119,14 @@ void BKE_cachefile_free(CacheFile *cache_file) void BKE_cachefile_copy_data( Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag)) { + if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) { + /* CoW/no-main copies reuse the existing ArchiveReader and mutex */ + return; + } + cache_file_dst->handle = NULL; - BLI_listbase_clear(&cache_file_dst->object_paths); + cache_file_dst->handle_mutex = NULL; + BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths); } CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file) @@ -153,20 +168,24 @@ void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file) BLI_mutex_lock(cache_file->handle_mutex); if (cache_file->handle == NULL) { + /* Assigning to a CoW copy is a bad idea; assign to the original instead. */ + BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0); BKE_cachefile_reload(bmain, cache_file); } BLI_mutex_unlock(cache_file->handle_mutex); } -void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps) +void BKE_cachefile_update_frame( + Main *bmain, struct Depsgraph *depsgraph, Scene *scene, + const float ctime, const float fps) { CacheFile *cache_file; char filename[FILE_MAX]; for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) { /* Execute drivers only, as animation has already been done. */ - BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS); if (!cache_file->is_sequence) { continue; @@ -175,7 +194,7 @@ void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, co const float time = BKE_cachefile_time_offset(cache_file, ctime, fps); if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) { - BKE_cachefile_clean(scene, cache_file); + BKE_cachefile_clean(bmain, cache_file); #ifdef WITH_ALEMBIC ABC_free_handle(cache_file->handle); cache_file->handle = ABC_create_handle(filename, NULL); @@ -215,11 +234,9 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f } /* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */ -void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) +void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file) { - for (Base *base = scene->base.first; base; base = base->next) { - Object *ob = base->object; - + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); if (md) { diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index bda26c95815..54ce0d3a903 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -40,6 +40,7 @@ #include "DNA_ID.h" #include "BLI_math.h" +#include "BLI_listbase.h" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -47,6 +48,7 @@ #include "BKE_animsys.h" #include "BKE_camera.h" #include "BKE_object.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" @@ -54,7 +56,9 @@ #include "BKE_scene.h" #include "BKE_screen.h" -#include "GPU_compositing.h" +#include "DEG_depsgraph_query.h" + +#include "MEM_guardedalloc.h" /****************************** Camera Datablock *****************************/ @@ -62,17 +66,18 @@ void BKE_camera_init(Camera *cam) { BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cam, id)); - cam->lens = 35.0f; + cam->lens = 50.0f; cam->sensor_x = DEFAULT_SENSOR_WIDTH; cam->sensor_y = DEFAULT_SENSOR_HEIGHT; cam->clipsta = 0.1f; - cam->clipend = 100.0f; + cam->clipend = 1000.0f; cam->drawsize = 0.5f; cam->ortho_scale = 6.0; cam->flag |= CAM_SHOWPASSEPARTOUT; cam->passepartalpha = 0.5f; - GPU_fx_compositor_init_dof_settings(&cam->gpu_dof); + cam->gpu_dof.fstop = 128.0f; + cam->gpu_dof.ratio = 1.0f; /* stereoscopy 3d */ cam->stereo.interocular_distance = 0.065f; @@ -100,9 +105,9 @@ void *BKE_camera_add(Main *bmain, const char *name) * * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *UNUSED(cam_dst), const Camera *UNUSED(cam_src), const int UNUSED(flag)) +void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *cam_dst, const Camera *cam_src, const int UNUSED(flag)) { - /* Nothing to do! */ + BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images); } Camera *BKE_camera_copy(Main *bmain, const Camera *cam) @@ -120,22 +125,13 @@ void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local) /** Free (or release) any data used by this camera (does not free the camera itself). */ void BKE_camera_free(Camera *ca) { + BLI_freelistN(&ca->bg_images); + BKE_animdata_free((ID *)ca, false); } /******************************** Camera Usage *******************************/ -void BKE_camera_object_mode(RenderData *rd, Object *cam_ob) -{ - rd->mode &= ~(R_ORTHO | R_PANORAMA); - - if (cam_ob && cam_ob->type == OB_CAMERA) { - Camera *cam = cam_ob->data; - if (cam->type == CAM_ORTHO) rd->mode |= R_ORTHO; - if (cam->type == CAM_PANO) rd->mode |= R_PANORAMA; - } -} - /* get the camera's dof value, takes the dof object into account */ float BKE_camera_object_dof_distance(Object *ob) { @@ -143,15 +139,10 @@ float BKE_camera_object_dof_distance(Object *ob) if (ob->type != OB_CAMERA) return 0.0f; if (cam->dof_ob) { -#if 0 - /* too simple, better to return the distance on the view axis only */ - return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); -#else float view_dir[3], dof_dir[3]; normalize_v3_v3(view_dir, ob->obmat[2]); sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]); return fabsf(dot_v3v3(view_dir, dof_dir)); -#endif } return cam->YF_dofdist; } @@ -237,7 +228,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *ob) } } -void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d) +void BKE_camera_params_from_view3d(CameraParams *params, Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d) { /* common */ params->lens = v3d->lens; @@ -246,7 +237,8 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons if (rv3d->persp == RV3D_CAMOB) { /* camera view */ - BKE_camera_params_from_object(params, v3d->camera); + const Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); + BKE_camera_params_from_object(params, ob_camera_eval); params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); @@ -281,10 +273,7 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win float pixsize, viewfac, sensor_size, dx, dy; int sensor_fit; - /* fields rendering */ params->ycor = yasp / xasp; - if (params->use_fields) - params->ycor *= 2.0f; if (params->is_ortho) { /* orthographic camera */ @@ -326,18 +315,6 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win viewplane.xmax += dx; viewplane.ymax += dy; - /* fields offset */ - if (params->field_second) { - if (params->field_odd) { - viewplane.ymin -= 0.5f * params->ycor; - viewplane.ymax -= 0.5f * params->ycor; - } - else { - viewplane.ymin += 0.5f * params->ycor; - viewplane.ymax += 0.5f * params->ycor; - } - } - /* the window matrix is used for clipping, and not changed during OSA steps */ /* using an offset of +0.5 here would give clip errors on edges */ viewplane.xmin *= pixsize; @@ -641,7 +618,7 @@ static bool camera_frame_fit_calc_from_data( /* don't move the camera, just yield the fit location */ /* r_scale only valid/useful for ortho cameras */ bool BKE_camera_view_frame_fit_to_scene( - Main *bmain, Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale) + Depsgraph *depsgraph, Scene *scene, Object *camera_ob, float r_co[3], float *r_scale) { CameraParams params; CameraViewFrameData data_cb; @@ -652,22 +629,24 @@ bool BKE_camera_view_frame_fit_to_scene( camera_frame_fit_data_init(scene, camera_ob, ¶ms, &data_cb); /* run callback on all visible points */ - BKE_scene_foreach_display_point(bmain, scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb); + BKE_scene_foreach_display_point(depsgraph, camera_to_frame_view_cb, &data_cb); return camera_frame_fit_calc_from_data(¶ms, &data_cb, r_co, r_scale); } bool BKE_camera_view_frame_fit_to_coords( - const Scene *scene, const float (*cos)[3], int num_cos, const Object *camera_ob, + const Depsgraph *depsgraph, const float (*cos)[3], int num_cos, Object *camera_ob, float r_co[3], float *r_scale) { + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob); CameraParams params; CameraViewFrameData data_cb; /* just in case */ *r_scale = 1.0f; - camera_frame_fit_data_init(scene, camera_ob, ¶ms, &data_cb); + camera_frame_fit_data_init(scene_eval, camera_ob_eval, ¶ms, &data_cb); /* run callback on all given coordinates */ while (num_cos--) { @@ -679,12 +658,12 @@ bool BKE_camera_view_frame_fit_to_coords( /******************* multiview matrix functions ***********************/ -static void camera_model_matrix(Object *camera, float r_modelmat[4][4]) +static void camera_model_matrix(const Object *camera, float r_modelmat[4][4]) { copy_m4_m4(r_modelmat, camera->obmat); } -static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4]) +static void camera_stereo3d_model_matrix(const Object *camera, const bool is_left, float r_modelmat[4][4]) { Camera *data = (Camera *)camera->data; float interocular_distance, convergence_distance; @@ -782,7 +761,7 @@ static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, flo } /* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */ -void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4]) +void BKE_camera_multiview_view_matrix(RenderData *rd, const Object *camera, const bool is_left, float r_viewmat[4][4]) { BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat); invert_m4(r_viewmat); @@ -797,7 +776,7 @@ static bool camera_is_left(const char *viewname) return true; } -void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4]) +void BKE_camera_multiview_model_matrix(RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4]) { const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; @@ -814,7 +793,7 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const cha normalize_m4(r_modelmat); } -bool BKE_camera_multiview_spherical_stereo(RenderData *rd, Object *camera) +bool BKE_camera_multiview_spherical_stereo(RenderData *rd, const Object *camera) { Camera *cam; const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; @@ -861,9 +840,9 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha } if (name[0] != '\0') { - Base *base = BKE_scene_base_find_by_name(scene, name); - if (base) { - return base->object; + Object *ob = BKE_scene_object_find_by_name(scene, name); + if (ob != NULL) { + return ob; } } @@ -887,7 +866,7 @@ Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *vi } } -static float camera_stereo3d_shift_x(Object *camera, const char *viewname) +static float camera_stereo3d_shift_x(const Object *camera, const char *viewname) { Camera *data = camera->data; float shift = data->shiftx; @@ -925,7 +904,7 @@ static float camera_stereo3d_shift_x(Object *camera, const char *viewname) return shift; } -float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname) +float BKE_camera_multiview_shift_x(RenderData *rd, const Object *camera, const char *viewname) { const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0; Camera *data = camera->data; @@ -943,7 +922,7 @@ float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *v } } -void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname) +void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, const Object *camera, const char *viewname) { if (camera->type == OB_CAMERA) { params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname); @@ -960,3 +939,38 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera); } } + +CameraBGImage *BKE_camera_background_image_new(Camera *cam) +{ + CameraBGImage *bgpic = MEM_callocN(sizeof(CameraBGImage), "Background Image"); + + bgpic->scale = 1.0f; + bgpic->alpha = 0.5f; + bgpic->iuser.ok = 1; + bgpic->iuser.flag |= IMA_ANIM_ALWAYS; + bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED; + + BLI_addtail(&cam->bg_images, bgpic); + + return bgpic; +} + +void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic) +{ + BLI_remlink(&cam->bg_images, bgpic); + + MEM_freeN(bgpic); +} + +void BKE_camera_background_image_clear(Camera *cam) +{ + CameraBGImage *bgpic = cam->bg_images.first; + + while (bgpic) { + CameraBGImage *next_bgpic = bgpic->next; + + BKE_camera_background_image_remove(cam, bgpic); + + bgpic = next_bgpic; + } +} diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index ed2b8cddc14..1c3b75b1771 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -46,6 +46,7 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_object.h" #include "BKE_paint.h" #include "BKE_editmesh.h" #include "BKE_curve.h" @@ -57,12 +58,6 @@ #include "MEM_guardedalloc.h" -#include "GPU_buffers.h" -#include "GPU_draw.h" -#include "GPU_glew.h" -#include "GPU_shader.h" -#include "GPU_basic_shader.h" - #include <string.h> #include <limits.h> #include <math.h> @@ -104,7 +99,7 @@ static int cdDM_getNumTessFaces(DerivedMesh *dm) * to help debug tessfaces issues since BMESH merge. */ #if 0 if (dm->numTessFaceData == 0 && dm->numPolyData != 0) { - printf("%s: has no faces!, call DM_ensure_tessface() if you need them\n"); + printf("%s: has no faces!\n"); } #endif return dm->numTessFaceData; @@ -295,7 +290,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) * this derivedmesh is just original mesh. it's the multires subsurf dm * that this is actually for, to support a pbvh on a modified mesh */ if (!cddm->pbvh && ob->type == OB_MESH) { - Mesh *me = ob->data; + Mesh *me = BKE_object_get_original_mesh(ob); const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; bool deformed; @@ -330,7 +325,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) totvert = deformdm->getNumVerts(deformdm); vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos"); deformdm->getVertCos(deformdm, vertCos); - BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos); + BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert); MEM_freeN(vertCos); } } @@ -338,1450 +333,6 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) return cddm->pbvh; } -/* update vertex normals so that drawing smooth faces works during sculpt - * TODO: proper fix is to support the pbvh in all drawing modes */ -static void cdDM_update_normals_from_pbvh(DerivedMesh *dm) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - float (*face_nors)[3]; - - /* Some callbacks do not use optimal PBVH draw, so needs all the - * possible data (like normals) to be copied from PBVH back to DM. - * - * This is safe to do if PBVH and DM are representing the same mesh, - * which could be wrong when modifiers are enabled for sculpt. - * So here we only doing update when there's no modifiers applied - * during sculpt. - * - * It's safe to do nothing if there are modifiers, because in this - * case modifier stack is re-constructed from scratch on every - * update. - */ - if (!cddm->pbvh_draw) { - return; - } - - face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL); - - BKE_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors); -} - -static void cdDM_drawVerts(DerivedMesh *dm) -{ - GPU_vertex_setup(dm); - if (dm->drawObject->tot_loop_verts) - glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loop_verts); - else - glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loose_point); - GPU_buffers_unbind(); -} - -static void cdDM_drawUVEdges(DerivedMesh *dm) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - const MPoly *mpoly = cddm->mpoly; - int totpoly = dm->getNumPolys(dm); - int prevstart = 0; - bool prevdraw = true; - int curpos = 0; - int i; - - GPU_uvedge_setup(dm); - for (i = 0; i < totpoly; i++, mpoly++) { - const bool draw = (mpoly->flag & ME_HIDE) == 0; - - if (prevdraw != draw) { - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - prevstart = curpos; - } - - curpos += 2 * mpoly->totloop; - prevdraw = draw; - } - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - GPU_buffers_unbind(); -} - -static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - GPUDrawObject *gdo; - if (cddm->pbvh && cddm->pbvh_draw && - BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) - { - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, true, false); - - return; - } - - GPU_edge_setup(dm); - gdo = dm->drawObject; - if (gdo->edges && gdo->points) { - if (drawAllEdges && drawLooseEdges) { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->totedge * 2); - } - else if (drawAllEdges) { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2); - } - else { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2); - GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, dm->drawObject->tot_loose_edge_drawn * 2); - } - } - GPU_buffers_unbind(); -} - -static void cdDM_drawLooseEdges(DerivedMesh *dm) -{ - int start; - int count; - - GPU_edge_setup(dm); - - start = (dm->drawObject->loose_edge_offset * 2); - count = (dm->drawObject->totedge - dm->drawObject->loose_edge_offset) * 2; - - if (count) { - GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count); - } - - GPU_buffers_unbind(); -} - -static void cdDM_drawFacesSolid( - DerivedMesh *dm, - float (*partial_redraw_planes)[4], - bool UNUSED(fast), DMSetMaterial setMaterial) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - int a; - - if (cddm->pbvh) { - if (cddm->pbvh_draw && BKE_pbvh_has_faces(cddm->pbvh)) { - float (*face_nors)[3] = CustomData_get_layer(&dm->polyData, CD_NORMAL); - - BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, - setMaterial, false, false); - return; - } - } - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - for (a = 0; a < dm->drawObject->totmaterial; a++) { - if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) { - GPU_buffer_draw_elements( - dm->drawObject->triangles, GL_TRIANGLES, - dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); - } - } - GPU_buffers_unbind(); -} - -static void cdDM_drawFacesTex_common( - DerivedMesh *dm, - DMSetDrawOptionsTex drawParams, - DMSetDrawOptionsMappedTex drawParamsMapped, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - const MPoly *mpoly = cddm->mpoly; - MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); - const MLoopCol *mloopcol = NULL; - int i; - int colType, start_element, tot_drawn; - const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0; - const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0; - const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0; - int totpoly; - int next_actualFace; - int mat_index; - int tot_element; - - /* double lookup */ - const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - - /* TODO: not entirely correct, but currently dynamic topology will - * destroy UVs anyway, so textured display wouldn't work anyway - * - * this will do more like solid view with lights set up for - * textured view, but object itself will be displayed gray - * (the same as it'll display without UV maps in textured view) - */ - if (cddm->pbvh) { - if (cddm->pbvh_draw && - BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH && - BKE_pbvh_has_faces(cddm->pbvh)) - { - GPU_set_tpage(NULL, false, false); - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false); - return; - } - else { - cdDM_update_normals_from_pbvh(dm); - } - } - - if (use_colors) { - colType = CD_TEXTURE_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - if (!mloopcol) { - colType = CD_PREVIEW_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - if (!mloopcol) { - colType = CD_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - } - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - if (flag & DM_DRAW_USE_TEXPAINT_UV) - GPU_texpaint_uv_setup(dm); - else - GPU_uv_setup(dm); - if (mloopcol) { - GPU_color_setup(dm, colType); - } - - /* lastFlag = 0; */ /* UNUSED */ - for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { - GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index; - next_actualFace = bufmat->polys[0]; - totpoly = bufmat->totpolys; - - tot_element = 0; - tot_drawn = 0; - start_element = 0; - - for (i = 0; i < totpoly; i++) { - int actualFace = bufmat->polys[i]; - DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - int flush = 0; - int tot_tri_verts; - - if (i != totpoly - 1) - next_actualFace = bufmat->polys[i + 1]; - - if (use_hide && (mpoly[actualFace].flag & ME_HIDE)) { - draw_option = DM_DRAW_OPTION_SKIP; - } - else if (drawParams) { - MTexPoly *tp = use_tface && mtexpoly ? &mtexpoly[actualFace] : NULL; - draw_option = drawParams(tp, (mloopcol != NULL), mpoly[actualFace].mat_nr); - } - else { - if (index_mp_to_orig) { - const int orig = index_mp_to_orig[actualFace]; - if (orig == ORIGINDEX_NONE) { - /* XXX, this is not really correct - * it will draw the previous faces context for this one when we don't know its settings. - * but better then skipping it altogether. - campbell */ - draw_option = DM_DRAW_OPTION_NORMAL; - } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, orig, mpoly[actualFace].mat_nr); - } - } - else if (drawParamsMapped) { - draw_option = drawParamsMapped(userData, actualFace, mpoly[actualFace].mat_nr); - } - } - - /* flush buffer if current triangle isn't drawable or it's last triangle */ - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1); - - if (!flush && compareDrawOptions) { - /* also compare draw options and flush buffer if they're different - * need for face selection highlight in edit mode */ - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3; - tot_element += tot_tri_verts; - - if (flush) { - if (draw_option != DM_DRAW_OPTION_SKIP) - tot_drawn += tot_tri_verts; - - if (tot_drawn) { - if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL) - GPU_color_switch(1); - else - GPU_color_switch(0); - - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn); - tot_drawn = 0; - } - start_element = tot_element; - } - else { - tot_drawn += tot_tri_verts; - } - } - } - - GPU_buffers_unbind(); - -} - -static void cdDM_drawFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag); -} - -static void cdDM_drawMappedFaces( - DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - DMSetMaterial setMaterial, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - const MPoly *mpoly = cddm->mpoly; - const MLoopCol *mloopcol = NULL; - const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0; - const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0; - int colType; - int i, j; - int start_element = 0, tot_element, tot_drawn; - int totpoly; - int tot_tri_elem; - int mat_index; - GPUBuffer *findex_buffer = NULL; - - const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - - if (cddm->pbvh) { - if (G.debug_value == 14) - BKE_pbvh_draw_BB(cddm->pbvh); - } - - /* fist, setup common buffers */ - GPU_vertex_setup(dm); - GPU_triangle_setup(dm); - - totpoly = dm->getNumPolys(dm); - - /* if we do selection, fill the selection buffer color */ - if (G.f & G_BACKBUFSEL) { - if (!(flag & DM_DRAW_SKIP_SELECT)) { - Mesh *me = NULL; - BMesh *bm = NULL; - unsigned int *fi_map; - - if (flag & DM_DRAW_SELECT_USE_EDITMODE) - bm = userData; - else - me = userData; - - findex_buffer = GPU_buffer_alloc(dm->drawObject->tot_loop_verts * sizeof(int)); - fi_map = GPU_buffer_lock(findex_buffer, GPU_BINDING_ARRAY); - - if (fi_map) { - for (i = 0; i < totpoly; i++, mpoly++) { - int selcol = 0xFFFFFFFF; - const int orig = (index_mp_to_orig) ? index_mp_to_orig[i] : i; - bool is_hidden; - - if (orig != ORIGINDEX_NONE) { - if (use_hide) { - if (flag & DM_DRAW_SELECT_USE_EDITMODE) { - BMFace *efa = BM_face_at_index(bm, orig); - is_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0; - } - else { - is_hidden = (me->mpoly[orig].flag & ME_HIDE) != 0; - } - - if (!is_hidden) { - GPU_select_index_get(orig + 1, &selcol); - } - } - else { - GPU_select_index_get(orig + 1, &selcol); - } - } - - for (j = 0; j < mpoly->totloop; j++) - fi_map[start_element++] = selcol; - } - - start_element = 0; - mpoly = cddm->mpoly; - - GPU_buffer_unlock(findex_buffer, GPU_BINDING_ARRAY); - GPU_buffer_bind_as_color(findex_buffer); - } - } - } - else { - GPU_normal_setup(dm); - - if (use_colors) { - colType = CD_TEXTURE_MLOOPCOL; - mloopcol = DM_get_loop_data_layer(dm, colType); - if (!mloopcol) { - colType = CD_PREVIEW_MLOOPCOL; - mloopcol = DM_get_loop_data_layer(dm, colType); - } - if (!mloopcol) { - colType = CD_MLOOPCOL; - mloopcol = DM_get_loop_data_layer(dm, colType); - } - - if (use_colors && mloopcol) { - GPU_color_setup(dm, colType); - } - } - } - - tot_tri_elem = dm->drawObject->tot_triangle_point; - - if (tot_tri_elem == 0) { - /* avoid buffer problems in following code */ - } - else if (setDrawOptions == NULL) { - /* just draw the entire face array */ - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tot_tri_elem); - } - else { - for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { - GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index; - DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - int next_actualFace = bufmat->polys[0]; - totpoly = use_hide ? bufmat->totvisiblepolys : bufmat->totpolys; - - tot_element = 0; - start_element = 0; - tot_drawn = 0; - - if (setMaterial) - draw_option = setMaterial(bufmat->mat_nr + 1, NULL); - - if (draw_option != DM_DRAW_OPTION_SKIP) { - DMDrawOption last_draw_option = DM_DRAW_OPTION_NORMAL; - - for (i = 0; i < totpoly; i++) { - int actualFace = next_actualFace; - int flush = 0; - int tot_tri_verts; - - draw_option = DM_DRAW_OPTION_NORMAL; - - if (i != totpoly - 1) - next_actualFace = bufmat->polys[i + 1]; - - if (setDrawOptions) { - const int orig = (index_mp_to_orig) ? index_mp_to_orig[actualFace] : actualFace; - - if (orig != ORIGINDEX_NONE) { - draw_option = setDrawOptions(userData, orig); - } - } - - /* Goal is to draw as long of a contiguous triangle - * array as possible, so draw when we hit either an - * invisible triangle or at the end of the array */ - - /* flush buffer if current triangle isn't drawable or it's last triangle... */ - flush = (draw_option != last_draw_option) || (i == totpoly - 1); - - if (!flush && compareDrawOptions) { - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3; - tot_element += tot_tri_verts; - - if (flush) { - if (draw_option != DM_DRAW_OPTION_SKIP) { - tot_drawn += tot_tri_verts; - - if (last_draw_option != draw_option) { - if (draw_option == DM_DRAW_OPTION_STIPPLE) { - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); - } - else { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - } - } - - if (tot_drawn) { - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn); - tot_drawn = 0; - } - - last_draw_option = draw_option; - start_element = tot_element; - } - else { - if (draw_option != DM_DRAW_OPTION_SKIP) { - tot_drawn += tot_tri_verts; - } - else { - start_element = tot_element; - } - } - } - } - } - } - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - - GPU_buffers_unbind(); - - if (findex_buffer) - GPU_buffer_free(findex_buffer); - -} - -static void cdDM_drawMappedFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsMappedTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); -} - -static void cddm_draw_attrib_vertex( - DMVertexAttribs *attribs, const MVert *mvert, int a, int index, int loop, int vert, - const float *lnor, const bool smoothnormal) -{ - DM_draw_attrib_vertex(attribs, a, index, vert, loop); - - /* vertex normal */ - if (lnor) { - glNormal3fv(lnor); - } - else if (smoothnormal) { - glNormal3sv(mvert[index].no); - } - - /* vertex coordinate */ - glVertex3fv(mvert[index].co); -} - -typedef struct { - DMVertexAttribs attribs; - int numdata; - - GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/ -} GPUMaterialConv; - -static void cdDM_drawMappedFacesGLSL( - DerivedMesh *dm, - DMSetMaterial setMaterial, - DMSetDrawOptions setDrawOptions, - void *userData) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - GPUVertexAttribs gattribs; - const MVert *mvert = cddm->mvert; - const MPoly *mpoly = cddm->mpoly; - const MLoop *mloop = cddm->mloop; - const MLoopTri *lt = dm->getLoopTriArray(dm); - const int tottri = dm->getNumLoopTri(dm); - /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */ - const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL); - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - const int totpoly = dm->getNumPolys(dm); - const short dm_totmat = dm->totmat; - int a, b, matnr, new_matnr; - bool do_draw; - int orig; - - const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - - /* 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) { - if (cddm->pbvh_draw && - BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH && - BKE_pbvh_has_faces(cddm->pbvh)) - { - setMaterial(1, &gattribs); - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false); - return; - } - else { - cdDM_update_normals_from_pbvh(dm); - } - } - - matnr = -1; - do_draw = false; - - if (setDrawOptions != NULL) { - DMVertexAttribs attribs; - DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n"); - memset(&attribs, 0, sizeof(attribs)); - - glBegin(GL_TRIANGLES); - - for (a = 0; a < tottri; a++, lt++) { - const MPoly *mp = &mpoly[lt->poly]; - const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v}; - const unsigned int *ltri = lt->tri; - const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL; - const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH); - new_matnr = mp->mat_nr; - - if (new_matnr != matnr) { - glEnd(); - - matnr = new_matnr; - do_draw = setMaterial(matnr + 1, &gattribs); - if (do_draw) { - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - DM_draw_attrib_vertex_uniforms(&attribs); - } - - glBegin(GL_TRIANGLES); - } - - if (!do_draw) { - continue; - } - else /* if (setDrawOptions) */ { - orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly; - - if (orig == ORIGINDEX_NONE) { - /* since the material is set by setMaterial(), faces with no - * origin can be assumed to be generated by a modifier */ - - /* continue */ - } - else if (setDrawOptions(userData, orig) == DM_DRAW_OPTION_SKIP) - continue; - } - - if (!smoothnormal) { - if (nors) { - glNormal3fv(nors[lt->poly]); - } - else { - /* TODO ideally a normal layer should always be available */ - float nor[3]; - normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co); - glNormal3fv(nor); - } - } - else if (lnors) { - ln1 = lnors[ltri[0]]; - ln2 = lnors[ltri[1]]; - ln3 = lnors[ltri[2]]; - } - - cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal); - cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal); - cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal); - } - glEnd(); - } - else { - GPUMaterialConv *matconv; - int offset; - int *mat_orig_to_new; - int tot_active_mat; - GPUBuffer *buffer = NULL; - unsigned char *varray; - size_t max_element_size = 0; - int tot_loops = 0; - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - - tot_active_mat = dm->drawObject->totmaterial; - - matconv = MEM_calloc_arrayN(tot_active_mat, sizeof(*matconv), - "cdDM_drawMappedFacesGLSL.matconv"); - mat_orig_to_new = MEM_malloc_arrayN(dm->totmat, sizeof(*mat_orig_to_new), - "cdDM_drawMappedFacesGLSL.mat_orig_to_new"); - - /* part one, check what attributes are needed per material */ - for (a = 0; a < tot_active_mat; a++) { - new_matnr = dm->drawObject->materials[a].mat_nr; - - /* map from original material index to new - * GPUBufferMaterial index */ - mat_orig_to_new[new_matnr] = a; - do_draw = setMaterial(new_matnr + 1, &gattribs); - - if (do_draw) { - int numdata = 0; - DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs); - - if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index; - matconv[a].datatypes[numdata].size = 3; - matconv[a].datatypes[numdata].type = GL_FLOAT; - numdata++; - } - for (b = 0; b < matconv[a].attribs.tottface; b++) { - if (matconv[a].attribs.tface[b].array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index; - matconv[a].datatypes[numdata].size = 2; - matconv[a].datatypes[numdata].type = GL_FLOAT; - numdata++; - } - } - for (b = 0; b < matconv[a].attribs.totmcol; b++) { - if (matconv[a].attribs.mcol[b].array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index; - matconv[a].datatypes[numdata].size = 4; - matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE; - numdata++; - } - } - for (b = 0; b < matconv[a].attribs.tottang; b++) { - if (matconv[a].attribs.tang[b].array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index; - matconv[a].datatypes[numdata].size = 4; - matconv[a].datatypes[numdata].type = GL_FLOAT; - numdata++; - } - } - if (numdata != 0) { - matconv[a].numdata = numdata; - max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size); - } - } - } - - /* part two, generate and fill the arrays with the data */ - if (max_element_size > 0) { - buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts); - - varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY); - if (varray == NULL) { - GPU_buffers_unbind(); - GPU_buffer_free(buffer); - MEM_freeN(mat_orig_to_new); - MEM_freeN(matconv); - fprintf(stderr, "Out of memory, can't draw object\n"); - return; - } - - for (a = 0; a < totpoly; a++, mpoly++) { - const short mat_nr = ME_MAT_NR_TEST(mpoly->mat_nr, dm_totmat); - int j; - int i = mat_orig_to_new[mat_nr]; - offset = tot_loops * max_element_size; - - if (matconv[i].numdata != 0) { - if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) { - for (j = 0; j < mpoly->totloop; j++) - copy_v3_v3((float *)&varray[offset + j * max_element_size], - (float *)matconv[i].attribs.orco.array[mloop[mpoly->loopstart + j].v]); - offset += sizeof(float) * 3; - } - for (b = 0; b < matconv[i].attribs.tottface; b++) { - if (matconv[i].attribs.tface[b].array) { - const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array; - for (j = 0; j < mpoly->totloop; j++) - copy_v2_v2((float *)&varray[offset + j * max_element_size], mloopuv[mpoly->loopstart + j].uv); - offset += sizeof(float) * 2; - } - } - for (b = 0; b < matconv[i].attribs.totmcol; b++) { - if (matconv[i].attribs.mcol[b].array) { - const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array; - for (j = 0; j < mpoly->totloop; j++) - copy_v4_v4_uchar(&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r); - offset += sizeof(unsigned char) * 4; - } - } - for (b = 0; b < matconv[i].attribs.tottang; b++) { - if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) { - const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array; - for (j = 0; j < mpoly->totloop; j++) - copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]); - offset += sizeof(float) * 4; - } - } - } - - tot_loops += mpoly->totloop; - } - GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY); - } - - for (a = 0; a < tot_active_mat; a++) { - new_matnr = dm->drawObject->materials[a].mat_nr; - - do_draw = setMaterial(new_matnr + 1, &gattribs); - - if (do_draw) { - if (matconv[a].numdata) { - GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size); - } - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, - dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); - if (matconv[a].numdata) { - GPU_interleaved_attrib_unbind(); - } - } - } - - GPU_buffers_unbind(); - if (buffer) - GPU_buffer_free(buffer); - - MEM_freeN(mat_orig_to_new); - MEM_freeN(matconv); - } -} - -static void cdDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial) -{ - dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL); -} - -static void cdDM_drawMappedFacesMat( - DerivedMesh *dm, - void (*setMaterial)(void *userData, int matnr, void *attribs), - bool (*setFace)(void *userData, int index), void *userData) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - GPUVertexAttribs gattribs; - DMVertexAttribs attribs; - MVert *mvert = cddm->mvert; - const MPoly *mpoly = cddm->mpoly; - const MLoop *mloop = cddm->mloop; - const MLoopTri *lt = dm->getLoopTriArray(dm); - const int tottri = dm->getNumLoopTri(dm); - const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL); - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - int a, matnr, new_matnr; - int orig; - - const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - - /* 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) { - if (cddm->pbvh_draw && - BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH && - BKE_pbvh_has_faces(cddm->pbvh)) - { - setMaterial(userData, 1, &gattribs); - BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false); - return; - } - else { - cdDM_update_normals_from_pbvh(dm); - } - } - - matnr = -1; - - memset(&attribs, 0, sizeof(attribs)); - - glBegin(GL_TRIANGLES); - - for (a = 0; a < tottri; a++, lt++) { - const MPoly *mp = &mpoly[lt->poly]; - const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v}; - const unsigned int *ltri = lt->tri; - const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH); - const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL; - - /* material */ - new_matnr = mp->mat_nr + 1; - - if (new_matnr != matnr) { - glEnd(); - - setMaterial(userData, matnr = new_matnr, &gattribs); - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - DM_draw_attrib_vertex_uniforms(&attribs); - - glBegin(GL_TRIANGLES); - } - - /* skipping faces */ - if (setFace) { - orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly; - - if (orig != ORIGINDEX_NONE && !setFace(userData, orig)) - continue; - } - - /* smooth normal */ - if (!smoothnormal) { - if (nors) { - glNormal3fv(nors[lt->poly]); - } - else { - /* TODO ideally a normal layer should always be available */ - float nor[3]; - normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co); - glNormal3fv(nor); - } - } - else if (lnors) { - ln1 = lnors[ltri[0]]; - ln2 = lnors[ltri[1]]; - ln3 = lnors[ltri[2]]; - } - - /* vertices */ - cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal); - cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal); - cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal); - } - glEnd(); -} - -static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *) dm; - MVert *vert = cddm->mvert; - MEdge *edge = cddm->medge; - int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX); - - glBegin(GL_LINES); - for (i = 0; i < dm->numEdgeData; i++, edge++) { - if (index) { - orig = *index++; - if (setDrawOptions && orig == ORIGINDEX_NONE) continue; - } - else - orig = i; - - if (!setDrawOptions || (setDrawOptions(userData, orig) != DM_DRAW_OPTION_SKIP)) { - glVertex3fv(vert[edge->v1].co); - glVertex3fv(vert[edge->v2].co); - } - } - glEnd(); -} - -typedef struct FaceCount { - unsigned int i_visible; - unsigned int i_hidden; - unsigned int i_tri_visible; - unsigned int i_tri_hidden; -} FaceCount; - -static void cdDM_buffer_copy_triangles( - DerivedMesh *dm, unsigned int *varray, - const int *mat_orig_to_new) -{ - GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials; - int i, j, start; - - const int gpu_totmat = dm->drawObject->totmaterial; - const short dm_totmat = dm->totmat; - const MPoly *mpoly = dm->getPolyArray(dm); - const MLoopTri *lt = dm->getLoopTriArray(dm); - const int totpoly = dm->getNumPolys(dm); - - FaceCount *fc = MEM_malloc_arrayN(gpu_totmat, sizeof(*fc), "gpumaterial.facecount"); - - for (i = 0; i < gpu_totmat; i++) { - fc[i].i_visible = 0; - fc[i].i_tri_visible = 0; - fc[i].i_hidden = gpumaterials[i].totpolys - 1; - fc[i].i_tri_hidden = gpumaterials[i].totelements - 1; - } - - for (i = 0; i < totpoly; i++) { - const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat); - int tottri = ME_POLY_TRI_TOT(&mpoly[i]); - int mati = mat_orig_to_new[mat_nr]; - gpumat = gpumaterials + mati; - - if (mpoly[i].flag & ME_HIDE) { - for (j = 0; j < tottri; j++, lt++) { - start = gpumat->start + fc[mati].i_tri_hidden; - /* v1 v2 v3 */ - varray[start--] = lt->tri[2]; - varray[start--] = lt->tri[1]; - varray[start--] = lt->tri[0]; - fc[mati].i_tri_hidden -= 3; - } - gpumat->polys[fc[mati].i_hidden--] = i; - } - else { - for (j = 0; j < tottri; j++, lt++) { - start = gpumat->start + fc[mati].i_tri_visible; - /* v1 v2 v3 */ - varray[start++] = lt->tri[0]; - varray[start++] = lt->tri[1]; - varray[start++] = lt->tri[2]; - fc[mati].i_tri_visible += 3; - } - gpumat->polys[fc[mati].i_visible++] = i; - } - } - - /* set the visible polygons */ - for (i = 0; i < gpu_totmat; i++) { - gpumaterials[i].totvisiblepolys = fc[i].i_visible; - } - - MEM_freeN(fc); -} - -static void cdDM_buffer_copy_vertex( - DerivedMesh *dm, float *varray) -{ - const MVert *mvert; - const MPoly *mpoly; - const MLoop *mloop; - - int i, j, start, totpoly; - - mvert = dm->getVertArray(dm); - mpoly = dm->getPolyArray(dm); - mloop = dm->getLoopArray(dm); - totpoly = dm->getNumPolys(dm); - - start = 0; - - for (i = 0; i < totpoly; i++, mpoly++) { - for (j = 0; j < mpoly->totloop; j++) { - copy_v3_v3(&varray[start], mvert[mloop[mpoly->loopstart + j].v].co); - start += 3; - } - } - - /* copy loose points */ - j = dm->drawObject->tot_loop_verts * 3; - for (i = 0; i < dm->drawObject->totvert; i++) { - if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_loop_verts) { - copy_v3_v3(&varray[j], mvert[i].co); - j += 3; - } - } -} - -static void cdDM_buffer_copy_normal( - DerivedMesh *dm, short *varray) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - int i, j, totpoly; - int start; - - const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL); - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - - const MVert *mvert; - const MPoly *mpoly; - const MLoop *mloop; - - mvert = dm->getVertArray(dm); - mpoly = dm->getPolyArray(dm); - mloop = dm->getLoopArray(dm); - totpoly = dm->getNumPolys(dm); - - /* we are in sculpt mode, disable loop normals (since they won't get updated) */ - if (cddm->pbvh) - lnors = NULL; - - start = 0; - for (i = 0; i < totpoly; i++, mpoly++) { - const bool smoothnormal = (mpoly->flag & ME_SMOOTH) != 0; - - if (lnors) { - /* Copy loop normals */ - for (j = 0; j < mpoly->totloop; j++, start += 4) { - normal_float_to_short_v3(&varray[start], lnors[mpoly->loopstart + j]); - } - } - else if (smoothnormal) { - /* Copy vertex normal */ - for (j = 0; j < mpoly->totloop; j++, start += 4) { - copy_v3_v3_short(&varray[start], mvert[mloop[mpoly->loopstart + j].v].no); - } - } - else { - /* Copy cached OR calculated face normal */ - short f_no_s[3]; - - if (nors) { - normal_float_to_short_v3(f_no_s, nors[i]); - } - else { - float f_no[3]; - BKE_mesh_calc_poly_normal(mpoly, &mloop[mpoly->loopstart], mvert, f_no); - normal_float_to_short_v3(f_no_s, f_no); - } - - for (j = 0; j < mpoly->totloop; j++, start += 4) { - copy_v3_v3_short(&varray[start], f_no_s); - } - } - } -} - -static void cdDM_buffer_copy_uv( - DerivedMesh *dm, float *varray) -{ - int i, j, totpoly; - int start; - - const MPoly *mpoly; - const MLoopUV *mloopuv; - - if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) { - return; - } - - mpoly = dm->getPolyArray(dm); - totpoly = dm->getNumPolys(dm); - - start = 0; - for (i = 0; i < totpoly; i++, mpoly++) { - for (j = 0; j < mpoly->totloop; j++) { - copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv); - start += 2; - } - } -} - -static void cdDM_buffer_copy_uv_texpaint( - DerivedMesh *dm, float *varray) -{ - int i, j, totpoly; - int start; - - const MPoly *mpoly; - - int totmaterial = dm->totmat; - const MLoopUV **uv_base; - const MLoopUV *uv_stencil_base; - int stencil; - - totpoly = dm->getNumPolys(dm); - - /* should have been checked for before, reassert */ - BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV)); - uv_base = MEM_malloc_arrayN(totmaterial, sizeof(*uv_base), "texslots"); - - for (i = 0; i < totmaterial; i++) { - uv_base[i] = DM_paint_uvlayer_active_get(dm, i); - } - - stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV); - uv_stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil); - - mpoly = dm->getPolyArray(dm); - start = 0; - - for (i = 0; i < totpoly; i++, mpoly++) { - int mat_i = mpoly->mat_nr; - - for (j = 0; j < mpoly->totloop; j++) { - copy_v2_v2(&varray[start], uv_base[mat_i][mpoly->loopstart + j].uv); - copy_v2_v2(&varray[start + 2], uv_stencil_base[mpoly->loopstart + j].uv); - start += 4; - } - } - - MEM_freeN((void *)uv_base); -} - -/* treat varray_ as an array of MCol, four MCol's per face */ -static void cdDM_buffer_copy_mcol( - DerivedMesh *dm, unsigned char *varray, - const void *user_data) -{ - int i, j, totpoly; - int start; - - const MLoopCol *mloopcol = user_data; - const MPoly *mpoly = dm->getPolyArray(dm); - - totpoly = dm->getNumPolys(dm); - - start = 0; - - for (i = 0; i < totpoly; i++, mpoly++) { - for (j = 0; j < mpoly->totloop; j++) { - copy_v4_v4_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r); - start += 4; - } - } -} - -static void cdDM_buffer_copy_edge( - DerivedMesh *dm, unsigned int *varray) -{ - MEdge *medge, *medge_base; - int i, totedge, iloose, inorm, iloosehidden, inormhidden; - int tot_loose_hidden = 0, tot_loose = 0; - int tot_hidden = 0, tot = 0; - - medge_base = medge = dm->getEdgeArray(dm); - totedge = dm->getNumEdges(dm); - - for (i = 0; i < totedge; i++, medge++) { - if (medge->flag & ME_EDGEDRAW) { - if (medge->flag & ME_LOOSEEDGE) tot_loose++; - else tot++; - } - else { - if (medge->flag & ME_LOOSEEDGE) tot_loose_hidden++; - else tot_hidden++; - } - } - - inorm = 0; - inormhidden = tot; - iloose = tot + tot_hidden; - iloosehidden = iloose + tot_loose; - - medge = medge_base; - for (i = 0; i < totedge; i++, medge++) { - if (medge->flag & ME_EDGEDRAW) { - if (medge->flag & ME_LOOSEEDGE) { - varray[iloose * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[iloose * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - iloose++; - } - else { - varray[inorm * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[inorm * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - inorm++; - } - } - else { - if (medge->flag & ME_LOOSEEDGE) { - varray[iloosehidden * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[iloosehidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - iloosehidden++; - } - else { - varray[inormhidden * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[inormhidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - inormhidden++; - } - } - } - - dm->drawObject->tot_loose_edge_drawn = tot_loose; - dm->drawObject->loose_edge_offset = tot + tot_hidden; - dm->drawObject->tot_edge_drawn = tot; -} - -static void cdDM_buffer_copy_uvedge( - DerivedMesh *dm, float *varray) -{ - int i, j, totpoly; - int start; - const MLoopUV *mloopuv; - const MPoly *mpoly = dm->getPolyArray(dm); - - if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) { - return; - } - - totpoly = dm->getNumPolys(dm); - start = 0; - - for (i = 0; i < totpoly; i++, mpoly++) { - for (j = 0; j < mpoly->totloop; j++) { - copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv); - copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv); - start += 4; - } - } -} - -static void cdDM_copy_gpu_data( - DerivedMesh *dm, int type, void *varray_p, - const int *mat_orig_to_new, const void *user_data) -{ - /* 'varray_p' cast is redundant but include for self-documentation */ - switch (type) { - case GPU_BUFFER_VERTEX: - cdDM_buffer_copy_vertex(dm, (float *)varray_p); - break; - case GPU_BUFFER_NORMAL: - cdDM_buffer_copy_normal(dm, (short *)varray_p); - break; - case GPU_BUFFER_COLOR: - cdDM_buffer_copy_mcol(dm, (unsigned char *)varray_p, user_data); - break; - case GPU_BUFFER_UV: - cdDM_buffer_copy_uv(dm, (float *)varray_p); - break; - case GPU_BUFFER_UV_TEXPAINT: - cdDM_buffer_copy_uv_texpaint(dm, (float *)varray_p); - break; - case GPU_BUFFER_EDGE: - cdDM_buffer_copy_edge(dm, (unsigned int *)varray_p); - break; - case GPU_BUFFER_UVEDGE: - cdDM_buffer_copy_uvedge(dm, (float *)varray_p); - break; - case GPU_BUFFER_TRIANGLES: - cdDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new); - break; - default: - break; - } -} - -/* add a new point to the list of points related to a particular - * vertex */ -#ifdef USE_GPU_POINT_LINK - -static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index) -{ - GPUVertPointLink *lnk; - - lnk = &gdo->vert_points[vert_index]; - - /* if first link is in use, add a new link at the end */ - if (lnk->point_index != -1) { - /* get last link */ - for (; lnk->next; lnk = lnk->next) ; - - /* add a new link from the pool */ - lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage]; - gdo->vert_points_usage++; - } - - lnk->point_index = point_index; -} - -#else - -static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index) -{ - GPUVertPointLink *lnk; - lnk = &gdo->vert_points[vert_index]; - if (lnk->point_index == -1) { - lnk->point_index = point_index; - } -} - -#endif /* USE_GPU_POINT_LINK */ - -/* for each vertex, build a list of points related to it; these lists - * are stored in an array sized to the number of vertices */ -static void cdDM_drawobject_init_vert_points( - GPUDrawObject *gdo, - const MPoly *mpoly, const MLoop *mloop, - int tot_poly) -{ - int i; - int tot_loops = 0; - - /* allocate the array and space for links */ - gdo->vert_points = MEM_malloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink), - "GPUDrawObject.vert_points"); -#ifdef USE_GPU_POINT_LINK - gdo->vert_points_mem = MEM_calloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink), - "GPUDrawObject.vert_points_mem"); - gdo->vert_points_usage = 0; -#endif - - /* -1 indicates the link is not yet used */ - for (i = 0; i < gdo->totvert; i++) { -#ifdef USE_GPU_POINT_LINK - gdo->vert_points[i].link = NULL; -#endif - gdo->vert_points[i].point_index = -1; - } - - for (i = 0; i < tot_poly; i++) { - int j; - const MPoly *mp = &mpoly[i]; - - /* assign unique indices to vertices of the mesh */ - for (j = 0; j < mp->totloop; j++) { - cdDM_drawobject_add_vert_point(gdo, mloop[mp->loopstart + j].v, tot_loops + j); - } - tot_loops += mp->totloop; - } - - /* map any unused vertices to loose points */ - for (i = 0; i < gdo->totvert; i++) { - if (gdo->vert_points[i].point_index == -1) { - gdo->vert_points[i].point_index = gdo->tot_loop_verts + gdo->tot_loose_point; - gdo->tot_loose_point++; - } - } -} - -/* see GPUDrawObject's structure definition for a description of the - * data being initialized here */ -static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm) -{ - GPUDrawObject *gdo; - const MPoly *mpoly; - const MLoop *mloop; - const short dm_totmat = dm->totmat; - GPUBufferMaterial *mat_info; - int i, totloops, totpolys; - - /* object contains at least one material (default included) so zero means uninitialized dm */ - BLI_assert(dm_totmat != 0); - - mpoly = dm->getPolyArray(dm); - mloop = dm->getLoopArray(dm); - - totpolys = dm->getNumPolys(dm); - totloops = dm->getNumLoops(dm); - - /* get the number of points used by each material, treating - * each quad as two triangles */ - mat_info = MEM_calloc_arrayN(dm_totmat, sizeof(*mat_info), "GPU_drawobject_new.mat_orig_to_new"); - - for (i = 0; i < totpolys; i++) { - const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat); - mat_info[mat_nr].totpolys++; - mat_info[mat_nr].totelements += 3 * ME_POLY_TRI_TOT(&mpoly[i]); - mat_info[mat_nr].totloops += mpoly[i].totloop; - } - /* create the GPUDrawObject */ - gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject"); - gdo->totvert = dm->getNumVerts(dm); - gdo->totedge = dm->getNumEdges(dm); - - GPU_buffer_material_finalize(gdo, mat_info, dm_totmat); - - gdo->tot_loop_verts = totloops; - - /* store total number of points used for triangles */ - gdo->tot_triangle_point = poly_to_tri_count(totpolys, totloops) * 3; - - cdDM_drawobject_init_vert_points(gdo, mpoly, mloop, totpolys); - - return gdo; -} - static void cdDM_foreachMappedVert( DerivedMesh *dm, void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]), @@ -1913,7 +464,7 @@ void CDDM_recalc_tessellation_ex(DerivedMesh *dm, const bool do_face_nor_cpy) /* Tessellation recreated faceData, and the active layer indices need to get re-propagated * from loops and polys to faces */ - CustomData_bmesh_update_active_layers(&dm->faceData, &dm->polyData, &dm->loopData); + CustomData_bmesh_update_active_layers(&dm->faceData, &dm->loopData); } void CDDM_recalc_tessellation(DerivedMesh *dm) @@ -2005,24 +556,6 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->getPBVH = cdDM_getPBVH; dm->getPolyMap = cdDM_getPolyMap; - dm->drawVerts = cdDM_drawVerts; - - dm->drawUVEdges = cdDM_drawUVEdges; - dm->drawEdges = cdDM_drawEdges; - dm->drawLooseEdges = cdDM_drawLooseEdges; - dm->drawMappedEdges = cdDM_drawMappedEdges; - - dm->drawFacesSolid = cdDM_drawFacesSolid; - dm->drawFacesTex = cdDM_drawFacesTex; - dm->drawFacesGLSL = cdDM_drawFacesGLSL; - dm->drawMappedFaces = cdDM_drawMappedFaces; - dm->drawMappedFacesTex = cdDM_drawMappedFacesTex; - dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL; - dm->drawMappedFacesMat = cdDM_drawMappedFacesMat; - - dm->gpuObjectNew = cdDM_GPUobject_new; - dm->copy_gpu_data = cdDM_copy_gpu_data; - dm->foreachMappedVert = cdDM_foreachMappedVert; dm->foreachMappedEdge = cdDM_foreachMappedEdge; dm->foreachMappedLoop = cdDM_foreachMappedLoop; @@ -2062,20 +595,31 @@ DerivedMesh *CDDM_new(int numVerts, int numEdges, int numTessFaces, int numLoops DerivedMesh *CDDM_from_mesh(Mesh *mesh) { + return CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_MESH); +} + +DerivedMesh *CDDM_from_mesh_ex(Mesh *mesh, eCDAllocType alloctype, CustomDataMask mask) +{ CDDerivedMesh *cddm = cdDM_create(__func__); DerivedMesh *dm = &cddm->dm; - CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS); - int alloctype; + + mask &= ~CD_MASK_MDISPS; /* this does a referenced copy, with an exception for fluidsim */ DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, 0 /* mesh->totface */, mesh->totloop, mesh->totpoly); + /* This should actually be dm->deformedOnly = mesh->runtime.deformed_only, + * but only if the original mesh had its deformed_only flag correctly set + * (which isn't generally the case). */ dm->deformedOnly = 1; dm->cd_flag = mesh->cd_flag; - alloctype = CD_REFERENCE; + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + dm->dirty |= DM_DIRTY_NORMALS; + } + /* TODO DM_DIRTY_TESS_CDLAYERS ? Maybe not though, since we probably want to switch to looptris ? */ CustomData_merge(&mesh->vdata, &dm->vertData, mask, alloctype, mesh->totvert); @@ -2111,8 +655,8 @@ DerivedMesh *CDDM_from_curve(Object *ob) { ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } return CDDM_from_curve_displist(ob, &disp); @@ -2153,7 +697,6 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase) if (alluv) { const char *uvname = "Orco"; - CustomData_add_layer_named(&cddm->dm.polyData, CD_MTEXPOLY, CD_DEFAULT, NULL, totpoly, uvname); CustomData_add_layer_named(&cddm->dm.loopData, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname); } @@ -2168,22 +711,18 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase) static void loops_to_customdata_corners( BMesh *bm, CustomData *facedata, int cdindex, const BMLoop *l3[3], - int numCol, int numTex) + int numCol, int numUV) { const BMLoop *l; - BMFace *f = l3[0]->f; +// BMFace *f = l3[0]->f; MTFace *texface; - MTexPoly *texpoly; MCol *mcol; MLoopCol *mloopcol; MLoopUV *mloopuv; int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL); - for (i = 0; i < numTex; i++) { + for (i = 0; i < numUV; i++) { texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i); - texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i); - - ME_MTEXFACE_CPY(texface, texpoly); for (j = 0; j < 3; j++) { l = l3[j]; @@ -2213,6 +752,8 @@ static void loops_to_customdata_corners( } } +/* TODO(campbell): remove, use BKE_mesh_from_bmesh_for_eval_nomain instead. */ + /* used for both editbmesh and bmesh */ static DerivedMesh *cddm_from_bmesh_ex( struct BMesh *bm, const bool use_mdisps, @@ -2237,7 +778,7 @@ static DerivedMesh *cddm_from_bmesh_ex( MLoop *mloop = cddm->mloop; MPoly *mpoly = cddm->mpoly; int numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); - int numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + int numUV = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV); int *index, add_orig; CustomDataMask mask; unsigned int i, j; @@ -2267,7 +808,7 @@ static DerivedMesh *cddm_from_bmesh_ex( /* add tessellation mface layers */ if (use_tessface) { - CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em_tottri); + CustomData_from_bmeshpoly(&dm->faceData, &dm->loopData, em_tottri); } index = dm->getVertDataArray(dm, CD_ORIGINDEX); @@ -2339,7 +880,7 @@ static DerivedMesh *cddm_from_bmesh_ex( /* map mfaces to polygons in the same cddm intentionally */ *index++ = BM_elem_index_get(efa); - loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex); + loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numUV); test_index_face(mf, &dm->faceData, i, 3); } } @@ -2397,16 +938,13 @@ DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bo use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris); } -static DerivedMesh *cddm_copy_ex(DerivedMesh *source, - const bool need_tessface_data, - const bool faces_from_tessfaces) +DerivedMesh *CDDM_copy(DerivedMesh *source) { - const bool copy_tessface_data = (faces_from_tessfaces || need_tessface_data); CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm"); DerivedMesh *dm = &cddm->dm; int numVerts = source->numVertData; int numEdges = source->numEdgeData; - int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0; + int numTessFaces = 0; int numLoops = source->numLoopData; int numPolys = source->numPolyData; @@ -2416,9 +954,6 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, source->getVertDataArray(source, CD_ORIGINDEX); source->getEdgeDataArray(source, CD_ORIGINDEX); source->getPolyDataArray(source, CD_ORIGINDEX); - if (copy_tessface_data) { - source->getTessFaceDataArray(source, CD_ORIGINDEX); - } /* this initializes dm, and copies all non mvert/medge/mface layers */ DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, @@ -2430,15 +965,10 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, /* Tessellation data is never copied, so tag it here. * Only tag dirty layers if we really ignored tessellation faces. */ - if (!copy_tessface_data) { - dm->dirty |= DM_DIRTY_TESS_CDLAYERS; - } + dm->dirty |= DM_DIRTY_TESS_CDLAYERS; CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts); CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges); - if (copy_tessface_data) { - CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces); - } /* now add mvert/medge/mface layers */ cddm->mvert = source->dupVertArray(source); @@ -2447,17 +977,7 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts); CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges); - if (faces_from_tessfaces || copy_tessface_data) { - cddm->mface = source->dupTessFaceArray(source); - CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces); - } - - if (!faces_from_tessfaces) { - DM_DupPolys(source, dm); - } - else { - CDDM_tessfaces_to_faces(dm); - } + DM_DupPolys(source, dm); cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); @@ -2465,21 +985,6 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, return dm; } -DerivedMesh *CDDM_copy(DerivedMesh *source) -{ - return cddm_copy_ex(source, false, false); -} - -DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source) -{ - return cddm_copy_ex(source, false, true); -} - -DerivedMesh *CDDM_copy_with_tessface(DerivedMesh *source) -{ - return cddm_copy_ex(source, true, false); -} - /* note, the CD_ORIGINDEX layers are all 0, so if there is a direct * relationship between mesh data this needs to be set by the caller. */ DerivedMesh *CDDM_from_template_ex( @@ -2748,813 +1253,6 @@ void CDDM_calc_loop_normals_spacearr( #endif } - -void CDDM_calc_normals_tessface(DerivedMesh *dm) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - float (*face_nors)[3]; - - if (dm->numVertData == 0) return; - - /* we don't want to overwrite any referenced layers */ - cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData); - - /* fill in if it exists */ - face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL); - if (!face_nors) { - face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numTessFaceData); - } - - BKE_mesh_calc_normals_tessface(cddm->mvert, dm->numVertData, - cddm->mface, dm->numTessFaceData, face_nors); - - cddm->dm.dirty &= ~DM_DIRTY_NORMALS; -} - -#if 1 - -/** - * Poly compare with vtargetmap - * Function used by #CDDM_merge_verts. - * The function compares poly_source after applying vtargetmap, with poly_target. - * The two polys are identical if they share the same vertices in the same order, or in reverse order, - * but starting position loopstart may be different. - * The function is called with direct_reverse=1 for same order (i.e. same normal), - * and may be called again with direct_reverse=-1 for reverse order. - * \return 1 if polys are identical, 0 if polys are different. - */ -static int cddm_poly_compare( - MLoop *mloop_array, - MPoly *mpoly_source, MPoly *mpoly_target, - const int *vtargetmap, const int direct_reverse) -{ - int vert_source, first_vert_source, vert_target; - int i_loop_source; - int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted; - bool compare_completed = false; - bool same_loops = false; - - MLoop *mloop_source, *mloop_target; - - BLI_assert(direct_reverse == 1 || direct_reverse == -1); - - i_loop_source = 0; - mloop_source = mloop_array + mpoly_source->loopstart; - vert_source = mloop_source->v; - - if (vtargetmap[vert_source] != -1) { - vert_source = vtargetmap[vert_source]; - } - else { - /* All source loop vertices should be mapped */ - BLI_assert(false); - } - - /* Find same vertex within mpoly_target's loops */ - mloop_target = mloop_array + mpoly_target->loopstart; - for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) { - if (mloop_target->v == vert_source) { - break; - } - } - - /* If same vertex not found, then polys cannot be equal */ - if (i_loop_target >= mpoly_target->totloop) { - return false; - } - - /* Now mloop_source and m_loop_target have one identical vertex */ - /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */ - /* Go around the loop and check that all vertices match in same order */ - /* Skipping source loops when consecutive source vertices are mapped to same target vertex */ - - i_loop_target_start = i_loop_target; - i_loop_target_offset = 0; - first_vert_source = vert_source; - - compare_completed = false; - same_loops = false; - - while (!compare_completed) { - - vert_target = mloop_target->v; - - /* First advance i_loop_source, until it points to different vertex, after mapping applied */ - do { - i_loop_source++; - - if (i_loop_source == mpoly_source->totloop) { - /* End of loops for source, must match end of loop for target. */ - if (i_loop_target_offset == mpoly_target->totloop - 1) { - compare_completed = true; - same_loops = true; - break; /* Polys are identical */ - } - else { - compare_completed = true; - same_loops = false; - break; /* Polys are different */ - } - } - - mloop_source++; - vert_source = mloop_source->v; - - if (vtargetmap[vert_source] != -1) { - vert_source = vtargetmap[vert_source]; - } - else { - /* All source loop vertices should be mapped */ - BLI_assert(false); - } - - } while (vert_source == vert_target); - - if (compare_completed) { - break; - } - - /* Now advance i_loop_target as well */ - i_loop_target_offset++; - - if (i_loop_target_offset == mpoly_target->totloop) { - /* End of loops for target only, that means no match */ - /* except if all remaining source vertices are mapped to first target */ - for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) { - vert_source = vtargetmap[mloop_source->v]; - if (vert_source != first_vert_source) { - compare_completed = true; - same_loops = false; - break; - } - } - if (!compare_completed) { - same_loops = true; - } - break; - } - - /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */ - i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop; - if (i_loop_target_adjusted < 0) { - i_loop_target_adjusted += mpoly_target->totloop; - } - mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted; - vert_target = mloop_target->v; - - if (vert_target != vert_source) { - same_loops = false; /* Polys are different */ - break; - } - } - return same_loops; -} - -/* Utility stuff for using GHash with polys */ - -typedef struct PolyKey { - int poly_index; /* index of the MPoly within the derived mesh */ - int totloops; /* number of loops in the poly */ - unsigned int hash_sum; /* Sum of all vertices indices */ - unsigned int hash_xor; /* Xor of all vertices indices */ -} PolyKey; - - -static unsigned int poly_gset_hash_fn(const void *key) -{ - const PolyKey *pk = key; - return pk->hash_sum; -} - -static bool poly_gset_compare_fn(const void *k1, const void *k2) -{ - const PolyKey *pk1 = k1; - const PolyKey *pk2 = k2; - if ((pk1->hash_sum == pk2->hash_sum) && - (pk1->hash_xor == pk2->hash_xor) && - (pk1->totloops == pk2->totloops)) - { - /* Equality - note that this does not mean equality of polys */ - return false; - } - else { - return true; - } -} - -/** - * Merge Verts - * - * This frees dm, and returns a new one. - * - * \param vtargetmap The table that maps vertices to target vertices. a value of -1 - * indicates a vertex is a target, and is to be kept. - * This array is aligned with 'dm->numVertData' - * \warning \a vtergatmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported - * and will likely generate corrupted geometry. - * - * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size) - * - * \param merge_mode enum with two modes. - * - #CDDM_MERGE_VERTS_DUMP_IF_MAPPED - * When called by the Mirror Modifier, - * In this mode it skips any faces that have all vertices merged (to avoid creating pairs - * of faces sharing the same set of vertices) - * - #CDDM_MERGE_VERTS_DUMP_IF_EQUAL - * When called by the Array Modifier, - * In this mode, faces where all vertices are merged are double-checked, - * to see whether all target vertices actually make up a poly already. - * Indeed it could be that all of a poly's vertices are merged, - * but merged to vertices that do not make up a single poly, - * in which case the original poly should not be dumped. - * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are - * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror. - * - * \note #CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces. - */ -DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode) -{ -// #define USE_LOOPS - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - CDDerivedMesh *cddm2 = NULL; - - const int totvert = dm->numVertData; - const int totedge = dm->numEdgeData; - const int totloop = dm->numLoopData; - const int totpoly = dm->numPolyData; - - const int totvert_final = totvert - tot_vtargetmap; - - MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__); - int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__); - int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__); - STACK_DECLARE(mvert); - STACK_DECLARE(oldv); - - /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require - * generating new edges, and while in 99% cases we'll still end with less final edges than totedge, - * cases can be forged that would end requiring more... */ - MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__); - int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__); - int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__); - STACK_DECLARE(medge); - STACK_DECLARE(olde); - - MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__); - int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__); -#ifdef USE_LOOPS - int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__); -#endif - STACK_DECLARE(mloop); - STACK_DECLARE(oldl); - - MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__); - int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__); - STACK_DECLARE(mpoly); - STACK_DECLARE(oldp); - - EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge); - - int i, j, c; - - PolyKey *poly_keys; - GSet *poly_gset = NULL; - - STACK_INIT(oldv, totvert_final); - STACK_INIT(olde, totedge); - STACK_INIT(oldl, totloop); - STACK_INIT(oldp, totpoly); - - STACK_INIT(mvert, totvert_final); - STACK_INIT(medge, totedge); - STACK_INIT(mloop, totloop); - STACK_INIT(mpoly, totpoly); - - /* fill newv with destination vertex indices */ - mv = cddm->mvert; - c = 0; - for (i = 0; i < totvert; i++, mv++) { - if (vtargetmap[i] == -1) { - STACK_PUSH(oldv, i); - STACK_PUSH(mvert, *mv); - newv[i] = c++; - } - else { - /* dummy value */ - newv[i] = 0; - } - } - - /* now link target vertices to destination indices */ - for (i = 0; i < totvert; i++) { - if (vtargetmap[i] != -1) { - newv[i] = newv[vtargetmap[i]]; - } - } - - /* Don't remap vertices in cddm->mloop, because we need to know the original - * indices in order to skip faces with all vertices merged. - * The "update loop indices..." section further down remaps vertices in mloop. - */ - - /* now go through and fix edges and faces */ - med = cddm->medge; - c = 0; - for (i = 0; i < totedge; i++, med++) { - const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; - const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; - if (LIKELY(v1 != v2)) { - void **val_p; - - if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) { - newe[i] = POINTER_AS_INT(*val_p); - } - else { - STACK_PUSH(olde, i); - STACK_PUSH(medge, *med); - newe[i] = c; - *val_p = POINTER_FROM_INT(c); - c++; - } - } - else { - newe[i] = -1; - } - } - - if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) { - /* In this mode, we need to determine, whenever a poly' vertices are all mapped */ - /* if the targets already make up a poly, in which case the new poly is dropped */ - /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */ - PolyKey *mpgh; - poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__); - poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly); - /* Duplicates allowed because our compare function is not pure equality */ - BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES); - - mp = cddm->mpoly; - mpgh = poly_keys; - for (i = 0; i < totpoly; i++, mp++, mpgh++) { - mpgh->poly_index = i; - mpgh->totloops = mp->totloop; - ml = cddm->mloop + mp->loopstart; - mpgh->hash_sum = mpgh->hash_xor = 0; - for (j = 0; j < mp->totloop; j++, ml++) { - mpgh->hash_sum += ml->v; - mpgh->hash_xor ^= ml->v; - } - BLI_gset_insert(poly_gset, mpgh); - } - - if (cddm->pmap) { - MEM_freeN(cddm->pmap); - MEM_freeN(cddm->pmap_mem); - } - /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */ - /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */ - BKE_mesh_vert_poly_map_create(&cddm->pmap, &cddm->pmap_mem, - cddm->mpoly, cddm->mloop, - totvert, totpoly, totloop); - } /* done preparing for fast poly compare */ - - - mp = cddm->mpoly; - mv = cddm->mvert; - for (i = 0; i < totpoly; i++, mp++) { - MPoly *mp_new; - - ml = cddm->mloop + mp->loopstart; - - /* check faces with all vertices merged */ - bool all_vertices_merged = true; - - for (j = 0; j < mp->totloop; j++, ml++) { - if (vtargetmap[ml->v] == -1) { - all_vertices_merged = false; - /* This will be used to check for poly using several time the same vert. */ - mv[ml->v].flag &= ~ME_VERT_TMP_TAG; - } - else { - /* This will be used to check for poly using several time the same vert. */ - mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG; - } - } - - if (UNLIKELY(all_vertices_merged)) { - if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_MAPPED) { - /* In this mode, all vertices merged is enough to dump face */ - continue; - } - else if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) { - /* Additional condition for face dump: target vertices must make up an identical face */ - /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */ - /* (2) second step is thorough but more costly poly compare */ - int i_poly, v_target; - bool found = false; - PolyKey pkey; - - /* Use poly_gset for fast (although not 100% certain) identification of same poly */ - /* First, make up a poly_summary structure */ - ml = cddm->mloop + mp->loopstart; - pkey.hash_sum = pkey.hash_xor = 0; - pkey.totloops = 0; - for (j = 0; j < mp->totloop; j++, ml++) { - v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */ - pkey.hash_sum += v_target; - pkey.hash_xor ^= v_target; - pkey.totloops++; - } - if (BLI_gset_haskey(poly_gset, &pkey)) { - - /* There might be a poly that matches this one. - * We could just leave it there and say there is, and do a "continue". - * ... but we are checking whether there is an exact poly match. - * It's not so costly in terms of CPU since it's very rare, just a lot of complex code. - */ - - /* Consider current loop again */ - ml = cddm->mloop + mp->loopstart; - /* Consider the target of the loop's first vert */ - v_target = vtargetmap[ml->v]; - /* Now see if v_target belongs to a poly that shares all vertices with source poly, - * in same order, or reverse order */ - - for (i_poly = 0; i_poly < cddm->pmap[v_target].count; i_poly++) { - MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly); - - if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) || - cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1)) - { - found = true; - break; - } - } - if (found) { - /* Current poly's vertices are mapped to a poly that is strictly identical */ - /* Current poly is dumped */ - continue; - } - } - } - } - - - /* Here either the poly's vertices were not all merged - * or they were all merged, but targets do not make up an identical poly, - * the poly is retained. - */ - ml = cddm->mloop + mp->loopstart; - - c = 0; - MLoop *last_valid_ml = NULL; - MLoop *first_valid_ml = NULL; - bool need_edge_from_last_valid_ml = false; - bool need_edge_to_first_valid_ml = false; - int created_edges = 0; - for (j = 0; j < mp->totloop; j++, ml++) { - const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v; -#ifndef NDEBUG - { - MLoop *next_ml = cddm->mloop + mp->loopstart + ((j + 1) % mp->totloop); - uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v; - med = cddm->medge + ml->e; - uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; - uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; - BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1)); - } -#endif - /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */ - if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) { - mv[mlv].flag |= ME_VERT_TMP_TAG; - - if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) { - /* We need to create a new edge between last valid loop and this one! */ - void **val_p; - - uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v; - uint v2 = mlv; - BLI_assert(v1 != v2); - if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) { - last_valid_ml->e = POINTER_AS_INT(*val_p); - } - else { - const int new_eidx = STACK_SIZE(medge); - STACK_PUSH(olde, olde[last_valid_ml->e]); - STACK_PUSH(medge, cddm->medge[last_valid_ml->e]); - medge[new_eidx].v1 = last_valid_ml->v; - medge[new_eidx].v2 = ml->v; - /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */ - *val_p = POINTER_FROM_INT(new_eidx); - created_edges++; - - last_valid_ml->e = new_eidx; - } - need_edge_from_last_valid_ml = false; - } - -#ifdef USE_LOOPS - newl[j + mp->loopstart] = STACK_SIZE(mloop); -#endif - STACK_PUSH(oldl, j + mp->loopstart); - last_valid_ml = STACK_PUSH_RET_PTR(mloop); - *last_valid_ml = *ml; - if (first_valid_ml == NULL) { - first_valid_ml = last_valid_ml; - } - c++; - - /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges - * in that part of code make remapping later totally unreliable. */ - BLI_assert(newe[ml->e] != -1); - last_valid_ml->e = newe[ml->e]; - } - else { - if (last_valid_ml != NULL) { - need_edge_from_last_valid_ml = true; - } - else { - need_edge_to_first_valid_ml = true; - } - } - } - if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) && - (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml))) - { - /* We need to create a new edge between last valid loop and first valid one! */ - void **val_p; - - uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v; - uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v; - BLI_assert(v1 != v2); - if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) { - last_valid_ml->e = POINTER_AS_INT(*val_p); - } - else { - const int new_eidx = STACK_SIZE(medge); - STACK_PUSH(olde, olde[last_valid_ml->e]); - STACK_PUSH(medge, cddm->medge[last_valid_ml->e]); - medge[new_eidx].v1 = last_valid_ml->v; - medge[new_eidx].v2 = first_valid_ml->v; - /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */ - *val_p = POINTER_FROM_INT(new_eidx); - created_edges++; - - last_valid_ml->e = new_eidx; - } - need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false; - } - - if (UNLIKELY(c == 0)) { - BLI_assert(created_edges == 0); - continue; - } - else if (UNLIKELY(c < 3)) { - STACK_DISCARD(oldl, c); - STACK_DISCARD(mloop, c); - if (created_edges > 0) { - for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) { - BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL); - } - STACK_DISCARD(olde, created_edges); - STACK_DISCARD(medge, created_edges); - } - continue; - } - - mp_new = STACK_PUSH_RET_PTR(mpoly); - *mp_new = *mp; - mp_new->totloop = c; - BLI_assert(mp_new->totloop >= 3); - mp_new->loopstart = STACK_SIZE(mloop) - c; - - STACK_PUSH(oldp, i); - } /* end of the loop that tests polys */ - - - if (poly_gset) { - // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset)); - - BLI_gset_free(poly_gset, NULL); - MEM_freeN(poly_keys); - } - - /*create new cddm*/ - cddm2 = (CDDerivedMesh *)CDDM_from_template( - (DerivedMesh *)cddm, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly)); - - /*update edge indices and copy customdata*/ - med = medge; - for (i = 0; i < cddm2->dm.numEdgeData; i++, med++) { - BLI_assert(newv[med->v1] != -1); - med->v1 = newv[med->v1]; - BLI_assert(newv[med->v2] != -1); - med->v2 = newv[med->v2]; - - /* Can happen in case vtargetmap contains some double chains, we do not support that. */ - BLI_assert(med->v1 != med->v2); - - CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1); - } - - /*update loop indices and copy customdata*/ - ml = mloop; - for (i = 0; i < cddm2->dm.numLoopData; i++, ml++) { - /* Edge remapping has already be done in main loop handling part above. */ - BLI_assert(newv[ml->v] != -1); - ml->v = newv[ml->v]; - - CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1); - } - - /*copy vertex customdata*/ - mv = mvert; - for (i = 0; i < cddm2->dm.numVertData; i++, mv++) { - CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1); - } - - /*copy poly customdata*/ - mp = mpoly; - for (i = 0; i < cddm2->dm.numPolyData; i++, mp++) { - CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1); - } - - /*copy over data. CustomData_add_layer can do this, need to look it up.*/ - memcpy(cddm2->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert)); - memcpy(cddm2->medge, medge, sizeof(MEdge) * STACK_SIZE(medge)); - memcpy(cddm2->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop)); - memcpy(cddm2->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly)); - - MEM_freeN(mvert); - MEM_freeN(medge); - MEM_freeN(mloop); - MEM_freeN(mpoly); - - MEM_freeN(newv); - MEM_freeN(newe); -#ifdef USE_LOOPS - MEM_freeN(newl); -#endif - - MEM_freeN(oldv); - MEM_freeN(olde); - MEM_freeN(oldl); - MEM_freeN(oldp); - - BLI_edgehash_free(ehash, NULL); - - /*free old derivedmesh*/ - dm->needsFree = 1; - dm->release(dm); - - return (DerivedMesh *)cddm2; -} -#endif - -void CDDM_calc_edges_tessface(DerivedMesh *dm) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - CustomData edgeData; - EdgeSetIterator *ehi; - MFace *mf = cddm->mface; - MEdge *med; - EdgeSet *eh; - int i, *index, numEdges, numFaces = dm->numTessFaceData; - - eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces)); - - for (i = 0; i < numFaces; i++, mf++) { - BLI_edgeset_add(eh, mf->v1, mf->v2); - BLI_edgeset_add(eh, mf->v2, mf->v3); - - if (mf->v4) { - BLI_edgeset_add(eh, mf->v3, mf->v4); - BLI_edgeset_add(eh, mf->v4, mf->v1); - } - else { - BLI_edgeset_add(eh, mf->v3, mf->v1); - } - } - - numEdges = BLI_edgeset_len(eh); - - /* write new edges into a temporary CustomData */ - CustomData_reset(&edgeData); - CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); - CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges); - - med = CustomData_get_layer(&edgeData, CD_MEDGE); - index = CustomData_get_layer(&edgeData, CD_ORIGINDEX); - - for (ehi = BLI_edgesetIterator_new(eh), i = 0; - BLI_edgesetIterator_isDone(ehi) == false; - BLI_edgesetIterator_step(ehi), i++, med++, index++) - { - BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2); - - med->flag = ME_EDGEDRAW | ME_EDGERENDER; - *index = ORIGINDEX_NONE; - } - BLI_edgesetIterator_free(ehi); - - /* free old CustomData and assign new one */ - CustomData_free(&dm->edgeData, dm->numEdgeData); - dm->edgeData = edgeData; - dm->numEdgeData = numEdges; - - cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); - - BLI_edgeset_free(eh); -} - -/* warning, this uses existing edges but CDDM_calc_edges_tessface() doesn't */ -void CDDM_calc_edges(DerivedMesh *dm) -{ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - CustomData edgeData; - EdgeHashIterator *ehi; - MPoly *mp = cddm->mpoly; - MLoop *ml; - MEdge *med, *origmed; - EdgeHash *eh; - unsigned int eh_reserve; - int v1, v2; - const int *eindex; - int i, j, *index; - const int numFaces = dm->numPolyData; - const int numLoops = dm->numLoopData; - int numEdges = dm->numEdgeData; - - eindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX); - med = cddm->medge; - - eh_reserve = max_ii(med ? numEdges : 0, BLI_EDGEHASH_SIZE_GUESS_FROM_LOOPS(numLoops)); - eh = BLI_edgehash_new_ex(__func__, eh_reserve); - if (med) { - for (i = 0; i < numEdges; i++, med++) { - BLI_edgehash_insert(eh, med->v1, med->v2, POINTER_FROM_INT(i + 1)); - } - } - - for (i = 0; i < numFaces; i++, mp++) { - ml = cddm->mloop + mp->loopstart; - for (j = 0; j < mp->totloop; j++, ml++) { - v1 = ml->v; - v2 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->v; - BLI_edgehash_reinsert(eh, v1, v2, NULL); - } - } - - numEdges = BLI_edgehash_len(eh); - - /* write new edges into a temporary CustomData */ - CustomData_reset(&edgeData); - CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); - CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges); - - origmed = cddm->medge; - med = CustomData_get_layer(&edgeData, CD_MEDGE); - index = CustomData_get_layer(&edgeData, CD_ORIGINDEX); - - for (ehi = BLI_edgehashIterator_new(eh), i = 0; - BLI_edgehashIterator_isDone(ehi) == false; - BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) - { - BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2); - j = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi)); - - if (j == 0 || !eindex) { - med->flag = ME_EDGEDRAW | ME_EDGERENDER; - *index = ORIGINDEX_NONE; - } - else { - med->flag = ME_EDGEDRAW | ME_EDGERENDER | origmed[j - 1].flag; - *index = eindex[j - 1]; - } - - BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(i)); - } - BLI_edgehashIterator_free(ehi); - - /* free old CustomData and assign new one */ - CustomData_free(&dm->edgeData, dm->numEdgeData); - dm->edgeData = edgeData; - dm->numEdgeData = numEdges; - - cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); - - mp = cddm->mpoly; - for (i = 0; i < numFaces; i++, mp++) { - ml = cddm->mloop + mp->loopstart; - for (j = 0; j < mp->totloop; j++, ml++) { - v1 = ml->v; - v2 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->v; - ml->e = POINTER_AS_INT(BLI_edgehash_lookup(eh, v1, v2)); - } - } - - BLI_edgehash_free(eh, NULL); -} - void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts) { BLI_assert(numVerts >= 0); @@ -3654,20 +1352,6 @@ MPoly *CDDM_get_polys(DerivedMesh *dm) return ((CDDerivedMesh *)dm)->mpoly; } -void CDDM_tessfaces_to_faces(DerivedMesh *dm) -{ - /* converts mfaces to mpolys/mloops */ - CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - - BKE_mesh_convert_mfaces_to_mpolys_ex( - NULL, &cddm->dm.faceData, &cddm->dm.loopData, &cddm->dm.polyData, - cddm->dm.numEdgeData, cddm->dm.numTessFaceData, - cddm->dm.numLoopData, cddm->dm.numPolyData, - cddm->medge, cddm->mface, - &cddm->dm.numLoopData, &cddm->dm.numPolyData, - &cddm->mloop, &cddm->mpoly); -} - void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert) { CDDerivedMesh *cddm = (CDDerivedMesh *)dm; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 88d4766048f..e10cfc38164 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -33,6 +33,7 @@ #include "DNA_cloth_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BLI_utildefines.h" @@ -40,10 +41,14 @@ #include "BLI_edgehash.h" #include "BLI_linklist.h" -#include "BKE_cdderivedmesh.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "BKE_bvhutils.h" #include "BKE_cloth.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_pointcache.h" @@ -55,13 +60,19 @@ /* Prototypes for internal functions. */ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*vertexCos)[3]); -static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ); -static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first); +static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh ); +static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float framenr, int first); static void cloth_update_springs( ClothModifierData *clmd ); -static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ); -static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm ); -static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ); -static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ); +static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh ); +static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh ); +static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ); +static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh ); + +typedef struct BendSpringRef { + int index; + int polys; + ClothSpring *spring; +} BendSpringRef; /****************************************************************************** * @@ -80,13 +91,18 @@ void cloth_init(ClothModifierData *clmd ) clmd->sim_parms->gravity[0] = 0.0; clmd->sim_parms->gravity[1] = 0.0; clmd->sim_parms->gravity[2] = -9.81; - clmd->sim_parms->structural = 15.0; - clmd->sim_parms->max_struct = 15.0; - clmd->sim_parms->shear = 15.0; + clmd->sim_parms->tension = 15.0; + clmd->sim_parms->max_tension = 15.0; + clmd->sim_parms->compression = 15.0; + clmd->sim_parms->max_compression = 15.0; + clmd->sim_parms->shear = 5.0; + clmd->sim_parms->max_shear = 5.0; clmd->sim_parms->bending = 0.5; clmd->sim_parms->max_bend = 0.5; + clmd->sim_parms->tension_damp = 5.0; + clmd->sim_parms->compression_damp = 5.0; + clmd->sim_parms->shear_damp = 5.0; clmd->sim_parms->bending_damping = 0.5; - clmd->sim_parms->Cdis = 5.0; clmd->sim_parms->Cvi = 1.0; clmd->sim_parms->mass = 0.3f; clmd->sim_parms->stepsPerFrame = 5; @@ -101,7 +117,6 @@ void cloth_init(ClothModifierData *clmd ) clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */ clmd->sim_parms->time_scale = 1.0f; /* multiplies cloth speed */ clmd->sim_parms->reset = 0; - clmd->sim_parms->vel_damping = 1.0f; /* 1.0 = no damping, 0.0 = fully dampened */ clmd->coll_parms->self_friction = 5.0; clmd->coll_parms->friction = 5.0; @@ -109,8 +124,7 @@ void cloth_init(ClothModifierData *clmd ) clmd->coll_parms->epsilon = 0.015f; clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED; clmd->coll_parms->collision_list = NULL; - clmd->coll_parms->self_loop_count = 1.0; - clmd->coll_parms->selfepsilon = 0.75; + clmd->coll_parms->selfepsilon = 0.015; clmd->coll_parms->vgroup_selfcol = 0; /* These defaults are copied from softbody.c's @@ -129,6 +143,8 @@ void cloth_init(ClothModifierData *clmd ) clmd->sim_parms->voxel_cell_size = 0.1f; + clmd->sim_parms->bending_model = CLOTH_BENDING_ANGULAR; + if (!clmd->sim_parms->effector_weights) clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL); @@ -136,44 +152,6 @@ void cloth_init(ClothModifierData *clmd ) clmd->point_cache->step = 1; } -static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon) -{ - unsigned int i; - BVHTree *bvhtree; - Cloth *cloth; - ClothVertex *verts; - - if (!clmd) - return NULL; - - cloth = clmd->clothObject; - - if (!cloth) - return NULL; - - verts = cloth->verts; - - /* in the moment, return zero if no faces there */ - if (!cloth->mvert_num) - return NULL; - - /* create quadtree with k=26 */ - bvhtree = BLI_bvhtree_new(cloth->mvert_num, epsilon, 4, 6); - - /* fill tree */ - for (i = 0; i < cloth->mvert_num; i++, verts++) { - const float *co; - co = verts->xold; - - BLI_bvhtree_insert(bvhtree, i, co, 1); - } - - /* balance tree */ - BLI_bvhtree_balance(bvhtree); - - return bvhtree; -} - static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon) { unsigned int i; @@ -217,14 +195,21 @@ static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon return bvhtree; } -void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving) +void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self) { unsigned int i = 0; Cloth *cloth = clmd->clothObject; - BVHTree *bvhtree = cloth->bvhtree; + BVHTree *bvhtree; ClothVertex *verts = cloth->verts; const MVertTri *vt; + if (self) { + bvhtree = cloth->bvhselftree; + } + else { + bvhtree = cloth->bvhtree; + } + if (!bvhtree) return; @@ -236,12 +221,12 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving) float co[3][3], co_moving[3][3]; bool ret; - copy_v3_v3(co[0], verts[vt->tri[0]].txold); - copy_v3_v3(co[1], verts[vt->tri[1]].txold); - copy_v3_v3(co[2], verts[vt->tri[2]].txold); - /* copy new locations into array */ if (moving) { + copy_v3_v3(co[0], verts[vt->tri[0]].txold); + copy_v3_v3(co[1], verts[vt->tri[1]].txold); + copy_v3_v3(co[2], verts[vt->tri[2]].txold); + /* update moving positions */ copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx); copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx); @@ -250,48 +235,11 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving) ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3); } else { - ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); - } + copy_v3_v3(co[0], verts[vt->tri[0]].tx); + copy_v3_v3(co[1], verts[vt->tri[1]].tx); + copy_v3_v3(co[2], verts[vt->tri[2]].tx); - /* check if tree is already full */ - if (ret == false) { - break; - } - } - - BLI_bvhtree_update_tree(bvhtree); - } -} - -void bvhselftree_update_from_cloth(ClothModifierData *clmd, bool moving) -{ - unsigned int i = 0; - Cloth *cloth = clmd->clothObject; - BVHTree *bvhtree = cloth->bvhselftree; - ClothVertex *verts = cloth->verts; - const MVertTri *vt; - - if (!bvhtree) - return; - - vt = cloth->tri; - - /* update vertex position in bvh tree */ - if (verts && vt) { - for (i = 0; i < cloth->mvert_num; i++, verts++) { - const float *co, *co_moving; - bool ret; - - co = verts->txold; - - /* copy new locations into array */ - if (moving) { - /* update moving positions */ - co_moving = verts->tx; - ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1); - } - else { - ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1); + ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); } /* check if tree is already full */ @@ -317,7 +265,7 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr) BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr); } -static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) +static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int framenr) { PointCache *cache; @@ -340,12 +288,13 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul BKE_cloth_solver_set_positions(clmd); clmd->clothObject->last_frame= MINFRAME-1; + clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame; } return 1; } -static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) +static int do_step_cloth(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, Mesh *result, int framenr) { ClothVertex *verts = NULL; Cloth *cloth; @@ -357,7 +306,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul /* simulate 1 frame forward */ cloth = clmd->clothObject; verts = cloth->verts; - mvert = result->getVertArray(result); + mvert = result->mvert; /* force any pinned verts to their constrained location. */ for (i = 0; i < clmd->clothObject->mvert_num; i++, verts++) { @@ -370,7 +319,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul mul_m4_v3(ob->obmat, verts->xconst); } - effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true); + effectors = BKE_effectors_create(depsgraph, ob, NULL, clmd->sim_parms->effector_weights); if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) cloth_update_verts ( ob, clmd, result ); @@ -378,19 +327,22 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul /* Support for dynamic vertex groups, changing from frame to frame */ cloth_apply_vgroup ( clmd, result ); - if ( clmd->sim_parms->flags & (CLOTH_SIMSETTINGS_FLAG_SEW | CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ) + if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) || + (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min > 0.0f)) + { cloth_update_spring_lengths ( clmd, result ); + } cloth_update_springs( clmd ); // TIMEIT_START(cloth_step) /* call the solver. */ - ret = BPH_cloth_solve(ob, framenr, clmd, effectors); + ret = BPH_cloth_solve(depsgraph, ob, framenr, clmd, effectors); // TIMEIT_END(cloth_step) - pdEndEffectors(&effectors); + BKE_effectors_free(effectors); // printf ( "%f\n", ( float ) tval() ); @@ -400,7 +352,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul /************************************************ * clothModifier_do - main simulation function ************************************************/ -void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3]) +void clothModifier_do(ClothModifierData *clmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh, float (*vertexCos)[3]) { PointCache *cache; PTCacheID pid; @@ -408,15 +360,14 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived int framenr, startframe, endframe; int cache_result; - clmd->scene= scene; /* nice to pass on later :) */ - framenr= (int)scene->r.cfra; + framenr = DEG_get_ctime(depsgraph); cache= clmd->point_cache; BKE_ptcache_id_from_cloth(&pid, ob, clmd); BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); clmd->sim_parms->timescale= timescale * clmd->sim_parms->time_scale; - if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) { + if (clmd->sim_parms->reset || (clmd->clothObject && mesh->totvert != clmd->clothObject->mvert_num)) { clmd->sim_parms->reset = 0; cache->flag |= PTCACHE_OUTDATED; BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); @@ -425,9 +376,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived cache->flag &= ~PTCACHE_REDO_NEEDED; } - // unused in the moment, calculated separately in implicit.c - clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame; - /* simulation is only active during a specific period */ if (framenr < startframe) { BKE_ptcache_invalidate(cache); @@ -438,12 +386,12 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived } /* initialize simulation data if it didn't exist already */ - if (!do_init_cloth(ob, clmd, dm, framenr)) + if (!do_init_cloth(ob, clmd, mesh, framenr)) return; if (framenr == startframe) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); - do_init_cloth(ob, clmd, dm, framenr); + do_init_cloth(ob, clmd, mesh, framenr); BKE_ptcache_validate(cache, framenr); cache->flag &= ~PTCACHE_REDO_NEEDED; clmd->clothObject->last_frame= framenr; @@ -479,9 +427,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived return; } - if (!can_simulate) - return; - /* if on second frame, write cache for first frame */ if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) BKE_ptcache_write(&pid, startframe); @@ -491,7 +436,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived /* do simulation */ BKE_ptcache_validate(cache, framenr); - if (!do_step_cloth(ob, clmd, dm, framenr)) { + if (!do_step_cloth(depsgraph, ob, clmd, mesh, framenr)) { BKE_ptcache_invalidate(cache); } else @@ -528,6 +473,9 @@ void cloth_free_modifier(ClothModifierData *clmd ) while (search) { ClothSpring *spring = search->link; + MEM_SAFE_FREE(spring->pa); + MEM_SAFE_FREE(spring->pb); + MEM_freeN ( spring ); search = search->next; } @@ -594,6 +542,9 @@ void cloth_free_modifier_extern(ClothModifierData *clmd ) while (search) { ClothSpring *spring = search->link; + MEM_SAFE_FREE(spring->pa); + MEM_SAFE_FREE(spring->pb); + MEM_freeN ( spring ); search = search->next; } @@ -659,15 +610,11 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte int cloth_uses_vgroup(ClothModifierData *clmd) { - return (((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) || - (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) || - (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW) || - (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF)) && - ((clmd->sim_parms->vgroup_mass>0) || - (clmd->sim_parms->vgroup_struct>0)|| - (clmd->sim_parms->vgroup_bend>0) || - (clmd->sim_parms->vgroup_shrink>0) || - (clmd->coll_parms->vgroup_selfcol>0))); + return (((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) && (clmd->coll_parms->vgroup_selfcol > 0)) || + (clmd->sim_parms->vgroup_struct > 0) || + (clmd->sim_parms->vgroup_bend > 0) || + (clmd->sim_parms->vgroup_shrink > 0) || + (clmd->sim_parms->vgroup_mass > 0)); } /** @@ -675,7 +622,7 @@ int cloth_uses_vgroup(ClothModifierData *clmd) * **/ /* can be optimized to do all groups in one loop */ -static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) +static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh ) { int i = 0; int j = 0; @@ -685,11 +632,11 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) /* float goalfac = 0; */ /* UNUSED */ ClothVertex *verts = NULL; - if (!clmd || !dm) return; + if (!clmd || !mesh) return; clothObj = clmd->clothObject; - mvert_num = dm->getNumVerts(dm); + mvert_num = mesh->totvert; verts = clothObj->verts; @@ -697,7 +644,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) for (i = 0; i < mvert_num; i++, verts++) { /* Reset Goal values to standard */ - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) + if (clmd->sim_parms->vgroup_mass > 0) verts->goal= clmd->sim_parms->defgoal; else verts->goal= 0.0f; @@ -709,10 +656,10 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) verts->flags &= ~CLOTH_VERT_FLAG_PINNED; verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL; - dvert = dm->getVertData ( dm, i, CD_MDEFORMVERT ); + dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT); if ( dvert ) { for ( j = 0; j < dvert->totweight; j++ ) { - if (( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass-1)) && (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )) { + if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) { verts->goal = dvert->dw [j].weight; /* goalfac= 1.0f; */ /* UNUSED */ @@ -725,15 +672,16 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) verts->flags |= CLOTH_VERT_FLAG_PINNED; } - if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) { - if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct-1)) { - verts->struct_stiff = dvert->dw [j].weight; - verts->shear_stiff = dvert->dw [j].weight; - } + if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct - 1)) { + verts->struct_stiff = dvert->dw[j].weight; + } - if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend-1)) { - verts->bend_stiff = dvert->dw [j].weight; - } + if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shear - 1)) { + verts->shear_stiff = dvert->dw[j].weight; + } + + if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend - 1)) { + verts->bend_stiff = dvert->dw[j].weight; } if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) { @@ -743,12 +691,10 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) } } } - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) { - if (clmd->sim_parms->vgroup_shrink > 0) { - if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) { - /* used for linear interpolation between min and max shrink factor based on weight */ - verts->shrink_factor = dvert->dw[j].weight; - } + if (clmd->sim_parms->vgroup_shrink > 0) { + if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) { + /* Used for linear interpolation between min and max shrink factor based on weight. */ + verts->shrink_factor = dvert->dw[j].weight; } } } @@ -759,31 +705,25 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, int i1, int i2) { - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) { - /* linear interpolation between min and max shrink factor based on weight */ - float base = 1.0f - clmd->sim_parms->shrink_min; - float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max; + /* Linear interpolation between min and max shrink factor based on weight. */ + float base = 1.0f - clmd->sim_parms->shrink_min; + float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max; - float k1 = base + delta * verts[i1].shrink_factor; - float k2 = base + delta * verts[i2].shrink_factor; + float k1 = base + delta * verts[i1].shrink_factor; + float k2 = base + delta * verts[i2].shrink_factor; - /* Use geometrical mean to average two factors since it behaves better - for diagonals when a rectangle transforms into a trapezoid. */ - return sqrtf(k1 * k2); - } - else - return 1.0f; + /* Use geometrical mean to average two factors since it behaves better + for diagonals when a rectangle transforms into a trapezoid. */ + return sqrtf(k1 * k2); } -static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first) +static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float UNUSED(framenr), int first) { int i = 0; MVert *mvert = NULL; ClothVertex *verts = NULL; float (*shapekey_rest)[3] = NULL; float tnull[3] = {0, 0, 0}; - Cloth *cloth = NULL; - float maxdist = 0; // If we have a clothObject, free it. if ( clmd->clothObject != NULL ) { @@ -796,8 +736,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" ); if ( clmd->clothObject ) { clmd->clothObject->old_solver_type = 255; - // clmd->clothObject->old_collision_type = 255; - cloth = clmd->clothObject; clmd->clothObject->edgeset = NULL; } else if (!clmd->clothObject) { @@ -805,25 +743,25 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d return 0; } - // mesh input objects need DerivedMesh - if ( !dm ) + // mesh input objects need Mesh + if ( !mesh ) return 0; - cloth_from_mesh ( clmd, dm ); + cloth_from_mesh ( clmd, mesh ); // create springs clmd->clothObject->springs = NULL; clmd->clothObject->numsprings = -1; if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) ) - shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO ); + shapekey_rest = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO); - mvert = dm->getVertArray (dm); + mvert = mesh->mvert; verts = clmd->clothObject->verts; // set initial values - for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { + for ( i = 0; i < mesh->totvert; i++, verts++ ) { if (first) { copy_v3_v3(verts->x, mvert[i].co); @@ -841,7 +779,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d verts->mass = clmd->sim_parms->mass; verts->impulse_count = 0; - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) + if (clmd->sim_parms->vgroup_mass > 0) verts->goal= clmd->sim_parms->defgoal; else verts->goal= 0.0f; @@ -861,9 +799,9 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d // apply / set vertex groups // has to be happen before springs are build! - cloth_apply_vgroup (clmd, dm); + cloth_apply_vgroup (clmd, mesh); - if ( !cloth_build_springs ( clmd, dm ) ) { + if ( !cloth_build_springs ( clmd, mesh ) ) { cloth_free_modifier ( clmd ); modifier_setError(&(clmd->modifier), "Cannot build springs"); printf("cloth_free_modifier cloth_build_springs\n"); @@ -876,23 +814,18 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d if (!first) BKE_cloth_solver_set_positions(clmd); - clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) ); - - for (i = 0; i < dm->getNumVerts(dm); i++) { - maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f)); - } - - clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist ); + clmd->clothObject->bvhtree = bvhtree_build_from_cloth (clmd, clmd->coll_parms->epsilon); + clmd->clothObject->bvhselftree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->selfepsilon); return 1; } -static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ) +static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh ) { - const MLoop *mloop = dm->getLoopArray(dm); - const MLoopTri *looptri = dm->getLoopTriArray(dm); - const unsigned int mvert_num = dm->getNumVerts(dm); - const unsigned int looptri_num = dm->getNumLoopTri(dm); + const MLoop *mloop = mesh->mloop; + const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh); + const unsigned int mvert_num = mesh->totvert; + const unsigned int looptri_num = mesh->runtime.looptris.len; /* Allocate our vertices. */ clmd->clothObject->mvert_num = mvert_num; @@ -913,7 +846,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ) printf("cloth_free_modifier clmd->clothObject->looptri\n"); return; } - DM_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num); + BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num); /* Free the springs since they can't be correct if the vertices * changed. @@ -924,7 +857,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ) } /*************************************************************************************** - * SPRING NETWORK BUILDING IMPLEMENTATION BEGIN + * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION BEGIN ***************************************************************************************/ BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1) @@ -951,13 +884,16 @@ static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num) } } -static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist) +static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist, BendSpringRef *spring_ref) { if ( cloth->springs != NULL ) { LinkNode *search = cloth->springs; while (search) { ClothSpring *spring = search->link; + MEM_SAFE_FREE(spring->pa); + MEM_SAFE_FREE(spring->pb); + MEM_freeN ( spring ); search = search->next; } @@ -968,12 +904,49 @@ static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist) cloth_free_edgelist(edgelist, cloth->mvert_num); + MEM_SAFE_FREE(spring_ref); + if (cloth->edgeset) { BLI_edgeset_free(cloth->edgeset); cloth->edgeset = NULL; } } +BLI_INLINE void cloth_bend_poly_dir(ClothVertex *verts, int i, int j, int *inds, int len, float r_dir[3]) +{ + float cent[3] = {0}; + float fact = 1.0f / len; + + for (int x = 0; x < len; x++) { + madd_v3_v3fl(cent, verts[inds[x]].xrest, fact); + } + + normal_tri_v3(r_dir, verts[i].xrest, verts[j].xrest, cent); +} + +static float cloth_spring_angle(ClothVertex *verts, int i, int j, int *i_a, int *i_b, int len_a, int len_b) +{ + float dir_a[3], dir_b[3]; + float tmp[3], vec_e[3]; + float sin, cos; + + /* Poly vectors. */ + cloth_bend_poly_dir(verts, j, i, i_a, len_a, dir_a); + cloth_bend_poly_dir(verts, i, j, i_b, len_b, dir_b); + + /* Edge vector. */ + sub_v3_v3v3(vec_e, verts[i].xrest, verts[j].xrest); + normalize_v3(vec_e); + + /* Compute angle. */ + cos = dot_v3v3(dir_a, dir_b); + + cross_v3_v3v3(tmp, dir_a, dir_b); + sin = dot_v3v3(tmp, vec_e); + + return atan2f(sin, cos); +} + static void cloth_hair_update_bending_targets(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; @@ -998,7 +971,7 @@ static void cloth_hair_update_bending_targets(ClothModifierData *clmd) ClothHairData *hair_ij, *hair_kl; bool is_root = spring->kl != prev_mn; - if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) { + if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) { continue; } @@ -1017,24 +990,6 @@ static void cloth_hair_update_bending_targets(ClothModifierData *clmd) sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x); normalize_v3(dir_new); -#if 0 - if (clmd->debug_data && (spring->ij == 0 || spring->ij == 1)) { - float a[3], b[3]; - - copy_v3_v3(a, cloth->verts[spring->kl].x); -// BKE_sim_debug_data_add_dot(clmd->debug_data, cloth_vert ? cloth_vert->x : key->co, 1, 1, 0, "frames", 8246, p, k); - - mul_v3_v3fl(b, hair_frame[0], clmd->sim_parms->avg_spring_len); - BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 1, 0, 0, "frames", 8247, spring->kl, spring->mn); - - mul_v3_v3fl(b, hair_frame[1], clmd->sim_parms->avg_spring_len); - BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 1, 0, "frames", 8248, spring->kl, spring->mn); - - mul_v3_v3fl(b, hair_frame[2], clmd->sim_parms->avg_spring_len); - BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 0, 1, "frames", 8249, spring->kl, spring->mn); - } -#endif - /* get local targets for kl/mn vertices by putting rest targets into the current frame, * then multiply with the rest length to get the actual goals */ @@ -1073,7 +1028,7 @@ static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd) ClothHairData *hair_ij, *hair_kl; bool is_root = spring->kl != prev_mn; - if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) { + if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) { continue; } @@ -1113,18 +1068,24 @@ static void cloth_update_springs( ClothModifierData *clmd ) while (search) { ClothSpring *spring = search->link; - spring->stiffness = 0.0f; + spring->lin_stiffness = 0.0f; + + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + if (spring->type & CLOTH_SPRING_TYPE_BENDING) { + spring->ang_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + } + } - if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { - spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; + if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) { + spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; } - else if (spring->type == CLOTH_SPRING_TYPE_SHEAR) { - spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; + else if (spring->type & CLOTH_SPRING_TYPE_SHEAR) { + spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; } else if (spring->type == CLOTH_SPRING_TYPE_BENDING) { - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; } - else if (spring->type == CLOTH_SPRING_TYPE_BENDING_ANG) { + else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) { ClothVertex *v1 = &cloth->verts[spring->ij]; ClothVertex *v2 = &cloth->verts[spring->kl]; if (clmd->hairdata) { @@ -1132,7 +1093,7 @@ static void cloth_update_springs( ClothModifierData *clmd ) v1->bend_stiff = clmd->hairdata[spring->ij].bending_stiffness; v2->bend_stiff = clmd->hairdata[spring->kl].bending_stiffness; } - spring->stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f; + spring->lin_stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f; } else if (spring->type == CLOTH_SPRING_TYPE_GOAL) { /* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */ @@ -1155,27 +1116,27 @@ static void cloth_update_springs( ClothModifierData *clmd ) } /* Update rest verts, for dynamically deformable cloth */ -static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ) +static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh ) { unsigned int i = 0; - MVert *mvert = dm->getVertArray (dm); + MVert *mvert = mesh->mvert; ClothVertex *verts = clmd->clothObject->verts; /* vertex count is already ensured to match */ - for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { + for ( i = 0; i < mesh->totvert; i++, verts++ ) { copy_v3_v3(verts->xrest, mvert[i].co); mul_m4_v3(ob->obmat, verts->xrest); } } -/* Update spring rest lenght, for dynamically deformable cloth */ -static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm ) +/* Update spring rest length, for dynamically deformable cloth */ +static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh ) { Cloth *cloth = clmd->clothObject; LinkNode *search = cloth->springs; unsigned int struct_springs = 0; unsigned int i = 0; - unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm); + unsigned int mvert_num = (unsigned int)mesh->totvert; float shrink_factor; clmd->sim_parms->avg_spring_len = 0.0f; @@ -1187,16 +1148,23 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *d while (search) { ClothSpring *spring = search->link; - if ( spring->type != CLOTH_SPRING_TYPE_SEWING ) { - if ( spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING) ) + if (spring->type != CLOTH_SPRING_TYPE_SEWING) { + if (spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) { shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); - else + } + else { shrink_factor = 1.0f; + } spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; + + if (spring->type & CLOTH_SPRING_TYPE_BENDING) { + spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl, + spring->pa, spring->pb, spring->la, spring->lb); + } } - if ( spring->type == CLOTH_SPRING_TYPE_STRUCTURAL ) { + if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) { clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; cloth->verts[spring->kl].avg_spring_len += spring->restlen; @@ -1206,12 +1174,14 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *d search = search->next; } - if (struct_springs > 0) + if (struct_springs > 0) { clmd->sim_parms->avg_spring_len /= struct_springs; + } for (i = 0; i < mvert_num; i++) { - if (cloth->verts[i].spring_count > 0) + if (cloth->verts[i].spring_count > 0) { cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); + } } } @@ -1250,23 +1220,115 @@ void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3] mul_m3_m3m3(mat, rot, mat); } -static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) +/* Add a shear and a bend spring between two verts within a poly. */ +static bool cloth_add_shear_bend_spring(ClothModifierData *clmd, LinkNodePair *edgelist, + const MLoop *mloop, const MPoly *mpoly, int i, int j, int k) +{ + Cloth *cloth = clmd->clothObject; + ClothSpring *spring; + const MLoop *tmp_loop; + float shrink_factor; + int x, y; + + /* Combined shear/bend properties. */ + spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); + + if (!spring) { + return false; + } + + spring_verts_ordered_set(spring, + mloop[mpoly[i].loopstart + j].v, + mloop[mpoly[i].loopstart + k].v); + + shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); + spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; + spring->type |= CLOTH_SPRING_TYPE_SHEAR; + spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; + + if (edgelist) { + BLI_linklist_append(&edgelist[spring->ij], spring); + BLI_linklist_append(&edgelist[spring->kl], spring); + } + + /* Bending specific properties. */ + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + spring->type |= CLOTH_SPRING_TYPE_BENDING; + + spring->la = k - j + 1; + spring->lb = mpoly[i].totloop - k + j + 1; + + spring->pa = MEM_mallocN(sizeof(*spring->pa) * spring->la, "spring poly"); + if (!spring->pa) { + return false; + } + + spring->pb = MEM_mallocN(sizeof(*spring->pb) * spring->lb, "spring poly"); + if (!spring->pb) { + return false; + } + + tmp_loop = mloop + mpoly[i].loopstart; + + for (x = 0; x < spring->la; x++) { + spring->pa[x] = tmp_loop[j + x].v; + } + + for (x = 0; x <= j; x++) { + spring->pb[x] = tmp_loop[x].v; + } + + for (y = k; y < mpoly[i].totloop; x++, y++) { + spring->pb[x] = tmp_loop[y].v; + } + + spring->mn = -1; + + spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl, + spring->pa, spring->pb, spring->la, spring->lb); + + spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f; + } + + BLI_linklist_prepend(&cloth->springs, spring); + + return true; +} + +BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop *mloop) +{ + int *p = MEM_mallocN(sizeof(int) * len, "spring poly"); + + if (!p) { + return false; + } + + for (int i = 0; i < len; i++, mloop++) { + p[i] = mloop->v; + } + + *poly = p; + + return true; +} + +static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh ) { Cloth *cloth = clmd->clothObject; ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL; unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0; - unsigned int i = 0; - unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm); - unsigned int numedges = (unsigned int)dm->getNumEdges (dm); - unsigned int numpolys = (unsigned int)dm->getNumPolys(dm); + unsigned int mvert_num = (unsigned int)mesh->totvert; + unsigned int numedges = (unsigned int)mesh->totedge; + unsigned int numpolys = (unsigned int)mesh->totpoly; float shrink_factor; - const MEdge *medge = dm->getEdgeArray(dm); - const MPoly *mpoly = dm->getPolyArray(dm); - const MLoop *mloop = dm->getLoopArray(dm); + const MEdge *medge = mesh->medge; + const MPoly *mpoly = mesh->mpoly; + const MLoop *mloop = mesh->mloop; int index2 = 0; // our second vertex index - LinkNodePair *edgelist; + LinkNodePair *edgelist = NULL; EdgeSet *edgeset = NULL; LinkNode *search = NULL, *search2 = NULL; + BendSpringRef *spring_ref = NULL; // error handling if ( numedges==0 ) @@ -1280,13 +1342,23 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) cloth->springs = NULL; cloth->edgeset = NULL; - edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" ); + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + spring_ref = MEM_callocN(sizeof(*spring_ref) * numedges, "temp bend spring reference"); - if (!edgelist) - return 0; + if (!spring_ref) { + return 0; + } + } + else { + edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" ); + + if (!edgelist) { + return 0; + } + } - // structural springs - for ( i = 0; i < numedges; i++ ) { + /* Structural springs. */ + for (int i = 0; i < numedges; i++) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { @@ -1294,13 +1366,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) { // handle sewing (loose edges will be pulled together) spring->restlen = 0.0f; - spring->stiffness = 1.0f; + spring->lin_stiffness = 1.0f; spring->type = CLOTH_SPRING_TYPE_SEWING; } else { shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; - spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; + spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; clmd->sim_parms->avg_spring_len += spring->restlen; @@ -1315,9 +1387,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) struct_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); + + if (spring_ref) { + spring_ref[i].spring = spring; + } } else { - cloth_free_errorsprings(cloth, edgelist); + cloth_free_errorsprings(cloth, edgelist, spring_ref); return 0; } } @@ -1325,86 +1401,147 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) if (struct_springs_real > 0) clmd->sim_parms->avg_spring_len /= struct_springs_real; - for (i = 0; i < mvert_num; i++) { + for (int i = 0; i < mvert_num; i++) { if (cloth->verts[i].spring_count > 0) cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count); } - // shear springs - for (i = 0; i < numpolys; i++) { - /* triangle faces already have shear springs due to structural geometry */ - if (mpoly[i].totloop == 4) { - int j; + edgeset = BLI_edgeset_new_ex(__func__, numedges); + cloth->edgeset = edgeset; - for (j = 0; j != 2; j++) { - spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); + if (numpolys) { + for (int i = 0; i < numpolys; i++) { + /* Shear springs. */ + /* Triangle faces already have shear springs due to structural geometry. */ + if (mpoly[i].totloop > 3) { + for (int j = 1; j < mpoly[i].totloop - 1; j++) { + if (j > 1) { + if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, 0, j)) { + shear_springs++; + + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + bend_springs++; + } + } + else { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } + } + + for (int k = j + 2; k < mpoly[i].totloop; k++) { + if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, j, k)) { + shear_springs++; - if (!spring) { - cloth_free_errorsprings(cloth, edgelist); - return 0; + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + bend_springs++; + } + } + else { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } + } } + } - spring_verts_ordered_set( - spring, - mloop[mpoly[i].loopstart + (j + 0)].v, - mloop[mpoly[i].loopstart + (j + 2)].v); + /* Angular bending springs along struct springs. */ + if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) { + const MLoop *ml = mloop + mpoly[i].loopstart; - shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); - spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; - spring->type = CLOTH_SPRING_TYPE_SHEAR; - spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; + for (int j = 0; j < mpoly[i].totloop; j++, ml++) { + BendSpringRef *curr_ref = &spring_ref[ml->e]; + curr_ref->polys++; - BLI_linklist_append(&edgelist[spring->ij], spring); - BLI_linklist_append(&edgelist[spring->kl], spring); + /* First poly found for this edge, store poly index. */ + if (curr_ref->polys == 1) { + curr_ref->index = i; + } + /* Second poly found for this edge, add bending data. */ + else if (curr_ref->polys == 2) { + spring = curr_ref->spring; + + spring->type |= CLOTH_SPRING_TYPE_BENDING; - shear_springs++; + spring->la = mpoly[curr_ref->index].totloop; + spring->lb = mpoly[i].totloop; - BLI_linklist_prepend(&cloth->springs, spring); + if (!cloth_bend_set_poly_vert_array(&spring->pa, spring->la, &mloop[mpoly[curr_ref->index].loopstart]) || + !cloth_bend_set_poly_vert_array(&spring->pb, spring->lb, &mloop[mpoly[i].loopstart])) + { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } + + spring->mn = ml->e; + + spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl, + spring->pa, spring->pb, spring->la, spring->lb); + + spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f; + + bend_springs++; + } + /* Third poly found for this edge, remove bending data. */ + else if (curr_ref->polys == 3) { + spring = curr_ref->spring; + + spring->type &= ~CLOTH_SPRING_TYPE_BENDING; + MEM_freeN(spring->pa); + MEM_freeN(spring->pb); + spring->pa = NULL; + spring->pb = NULL; + + bend_springs--; + } + } } } - } - edgeset = BLI_edgeset_new_ex(__func__, numedges); - cloth->edgeset = edgeset; + /* Linear bending springs. */ + if (clmd->sim_parms->bending_model == CLOTH_BENDING_LINEAR) { + search2 = cloth->springs; - if (numpolys) { - // bending springs - search2 = cloth->springs; - for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) { - if ( !search2 ) - break; + for (int i = struct_springs; i < struct_springs+shear_springs; i++) { + if (!search2) { + break; + } - tspring2 = search2->link; - search = edgelist[tspring2->kl].list; - while ( search ) { - tspring = search->link; - index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) ); + tspring2 = search2->link; + search = edgelist[tspring2->kl].list; + + while (search) { + tspring = search->link; + index2 = ((tspring->ij == tspring2->kl) ? (tspring->kl) : (tspring->ij)); + + /* Check for existing spring. */ + /* Check also if startpoint is equal to endpoint. */ + if ((index2 != tspring2->ij) && + !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) + { + spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); + + if (!spring) { + cloth_free_errorsprings(cloth, edgelist, spring_ref); + return 0; + } - // check for existing spring - // check also if startpoint is equal to endpoint - if ((index2 != tspring2->ij) && - !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) - { - spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + spring_verts_ordered_set(spring, tspring2->ij, index2); + shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); + spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; + spring->type = CLOTH_SPRING_TYPE_BENDING; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + BLI_edgeset_insert(edgeset, spring->ij, spring->kl); + bend_springs++; - if (!spring) { - cloth_free_errorsprings(cloth, edgelist); - return 0; + BLI_linklist_prepend(&cloth->springs, spring); } - spring_verts_ordered_set(spring, tspring2->ij, index2); - shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl); - spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor; - spring->type = CLOTH_SPRING_TYPE_BENDING; - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; - BLI_edgeset_insert(edgeset, spring->ij, spring->kl); - bend_springs++; - - BLI_linklist_prepend ( &cloth->springs, spring ); + search = search->next; } - search = search->next; + + search2 = search2->next; } - search2 = search2->next; } } else if (struct_springs > 2) { @@ -1419,7 +1556,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { - cloth_free_errorsprings(cloth, edgelist); + cloth_free_errorsprings(cloth, edgelist, spring_ref); return 0; } @@ -1427,8 +1564,8 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) spring->kl = tspring->ij; spring->mn = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); - spring->type = CLOTH_SPRING_TYPE_BENDING_ANG; - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + spring->type = CLOTH_SPRING_TYPE_BENDING_HAIR; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); @@ -1456,7 +1593,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { - cloth_free_errorsprings(cloth, edgelist); + cloth_free_errorsprings(cloth, edgelist, spring_ref); return 0; } @@ -1464,7 +1601,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) spring->kl = tspring->kl; spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; - spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; + spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; bend_springs++; BLI_linklist_prepend ( &cloth->springs, spring ); @@ -1481,17 +1618,18 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) /* note: the edges may already exist so run reinsert */ /* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */ - for (i = 0; i < numedges; i++) { /* struct springs */ + for (int i = 0; i < numedges; i++) { /* struct springs */ BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2); } - for (i = 0; i < numpolys; i++) { /* edge springs */ + for (int i = 0; i < numpolys; i++) { /* edge springs */ if (mpoly[i].totloop == 4) { BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 0].v, mloop[mpoly[i].loopstart + 2].v); BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 1].v, mloop[mpoly[i].loopstart + 3].v); } } + MEM_SAFE_FREE(spring_ref); cloth->numsprings = struct_springs + shear_springs + bend_springs; @@ -1506,5 +1644,5 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) } /* cloth_build_springs */ /*************************************************************************************** - * SPRING NETWORK BUILDING IMPLEMENTATION END + * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION END ***************************************************************************************/ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c new file mode 100644 index 00000000000..47fb3622c66 --- /dev/null +++ b/source/blender/blenkernel/intern/collection.c @@ -0,0 +1,1203 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/collection.c + * \ingroup bke + */ + +#include <string.h> + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_iterator.h" +#include "BLI_listbase.h" +#include "BLI_math_base.h" +#include "BLI_threads.h" +#include "BLT_translation.h" +#include "BLI_string_utils.h" + +#include "BKE_collection.h" +#include "BKE_icons.h" +#include "BKE_idprop.h" +#include "BKE_layer.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_scene.h" + +#include "DNA_ID.h" +#include "DNA_collection_types.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "MEM_guardedalloc.h" + +/******************************** Prototypes ********************************/ + +static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us); +static bool collection_child_remove(Collection *parent, Collection *collection); +static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us); +static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us); + +static CollectionChild *collection_find_child(Collection *parent, Collection *collection); +static CollectionParent *collection_find_parent(Collection *child, Collection *collection); + +static bool collection_find_child_recursive(Collection *parent, Collection *collection); + +/***************************** Add Collection *******************************/ + +/* Add new collection, without view layer syncing. */ +static Collection *collection_add(Main *bmain, Collection *collection_parent, const char *name_custom) +{ + /* Determine new collection name. */ + char name[MAX_NAME]; + + if (name_custom) { + STRNCPY(name, name_custom); + } + else { + BKE_collection_new_name_get(collection_parent, name); + } + + /* Create new collection. */ + Collection *collection = BKE_libblock_alloc(bmain, ID_GR, name, 0); + + /* We increase collection user count when linking to Collections. */ + id_us_min(&collection->id); + + /* Optionally add to parent collection. */ + if (collection_parent) { + collection_child_add(collection_parent, collection, 0, true); + } + + return collection; +} + +/** + * Add a collection to a collection ListBase and synchronize all render layers + * The ListBase is NULL when the collection is to be added to the master collection + */ +Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom) +{ + Collection *collection = collection_add(bmain, collection_parent, name_custom); + BKE_main_collection_sync(bmain); + return collection; +} + +/*********************** Free and Delete Collection ****************************/ + +/** Free (or release) any data used by this collection (does not free the collection itself). */ +void BKE_collection_free(Collection *collection) +{ + /* No animdata here. */ + BKE_previewimg_free(&collection->preview); + + BLI_freelistN(&collection->gobject); + BLI_freelistN(&collection->children); + BLI_freelistN(&collection->parents); + + BKE_collection_object_cache_free(collection); +} + +/** + * Remove a collection, optionally removing its child objects or moving + * them to parent collections. + */ +bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy) +{ + /* Master collection is not real datablock, can't be removed. */ + if (collection->flag & COLLECTION_IS_MASTER) { + BLI_assert(!"Scene master collection can't be deleted"); + return false; + } + + if (hierarchy) { + /* Remove child objects. */ + CollectionObject *cob = collection->gobject.first; + while (cob != NULL) { + collection_object_remove(bmain, collection, cob->ob, true); + cob = collection->gobject.first; + } + + /* Delete all child collections recursively. */ + CollectionChild *child = collection->children.first; + while (child != NULL) { + BKE_collection_delete(bmain, child->collection, hierarchy); + child = collection->children.first; + } + } + else { + /* Link child collections into parent collection. */ + for (CollectionChild *child = collection->children.first; child; child = child->next) { + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + Collection *parent = cparent->collection; + collection_child_add(parent, child->collection, 0, true); + } + } + + CollectionObject *cob = collection->gobject.first; + while (cob != NULL) { + /* Link child object into parent collections. */ + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + Collection *parent = cparent->collection; + collection_object_add(bmain, parent, cob->ob, 0, true); + } + + /* Remove child object. */ + collection_object_remove(bmain, collection, cob->ob, true); + cob = collection->gobject.first; + } + } + + BKE_libblock_delete(bmain, collection); + + BKE_main_collection_sync(bmain); + + return true; +} + +/***************************** Collection Copy *******************************/ + +/** + * Only copy internal data of Collection ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_collection_copy_data( + Main *bmain, Collection *collection_dst, const Collection *collection_src, const int flag) +{ + /* Do not copy collection's preview (same behavior as for objects). */ + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ + BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id); + } + else { + collection_dst->preview = NULL; + } + + collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE; + BLI_listbase_clear(&collection_dst->object_cache); + + BLI_listbase_clear(&collection_dst->gobject); + BLI_listbase_clear(&collection_dst->children); + BLI_listbase_clear(&collection_dst->parents); + + for (CollectionChild *child = collection_src->children.first; child; child = child->next) { + collection_child_add(collection_dst, child->collection, flag, false); + } + for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) { + collection_object_add(bmain, collection_dst, cob->ob, flag, false); + } +} + +/** + * Makes a shallow copy of a Collection + * + * Add a new collection in the same level as the old one, copy any nested collections + * but link the objects to the new collection (as oppose to copy them). + */ +Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection) +{ + /* It's not allowed to copy the master collection. */ + if (collection->flag & COLLECTION_IS_MASTER) { + BLI_assert("!Master collection can't be copied"); + return NULL; + } + + Collection *collection_new; + BKE_id_copy_ex(bmain, &collection->id, (ID **)&collection_new, 0, false); + id_us_min(&collection_new->id); /* Copying add one user by default, need to get rid of that one. */ + + /* Optionally add to parent. */ + if (parent) { + if (collection_child_add(parent, collection_new, 0, true)) { + /* Put collection right after existing one. */ + CollectionChild *child = collection_find_child(parent, collection); + CollectionChild *child_new = collection_find_child(parent, collection_new); + + if (child && child_new) { + BLI_remlink(&parent->children, child_new); + BLI_insertlinkafter(&parent->children, child, child_new); + } + } + } + + BKE_main_collection_sync(bmain); + + return collection_new; +} + +Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag) +{ + BLI_assert(collection->flag & COLLECTION_IS_MASTER); + + Collection *collection_dst = MEM_dupallocN(collection); + BKE_collection_copy_data(bmain, collection_dst, collection, flag); + return collection_dst; +} + +void BKE_collection_copy_full(Main *UNUSED(bmain), Collection *UNUSED(collection)) +{ + // TODO: implement full scene copy +} + +void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &collection->id, true, lib_local); +} + +/********************************* Naming *******************************/ + +/** + * The automatic/fallback name of a new collection. + */ +void BKE_collection_new_name_get(Collection *collection_parent, char *rname) +{ + char *name; + + if (!collection_parent) { + name = BLI_sprintfN("Collection"); + } + else if (collection_parent->flag & COLLECTION_IS_MASTER) { + name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1); + } + else { + const int number = BLI_listbase_count(&collection_parent->children) + 1; + const int digits = integer_digits_i(number); + const int max_len = + sizeof(collection_parent->id.name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */ - 2 /* ID */; + name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number); + } + + BLI_strncpy(rname, name, MAX_NAME); + MEM_freeN(name); +} + +/** + * The name to show in the interface. + */ +const char *BKE_collection_ui_name_get(struct Collection *collection) +{ + if (collection->flag & COLLECTION_IS_MASTER) { + return IFACE_("Scene Collection"); + } + else { + return collection->id.name + 2; + } +} + +/* **************** Object List Cache *******************/ + +static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict) +{ + int child_restrict = collection->flag | parent_restrict; + + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object)); + + if (base == NULL) { + base = MEM_callocN(sizeof(Base), "Object Base"); + base->object = cob->ob; + BLI_addtail(lb, base); + } + + int object_restrict = base->object->restrictflag; + + if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) && + ((object_restrict & OB_RESTRICT_VIEW) == 0)) + { + base->flag |= BASE_ENABLED_VIEWPORT; + } + + if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) && + ((object_restrict & OB_RESTRICT_RENDER) == 0)) + { + base->flag |= BASE_ENABLED_RENDER; + } + } + + for (CollectionChild *child = collection->children.first; child; child = child->next) { + collection_object_cache_fill(lb, child->collection, child_restrict); + } +} + +ListBase BKE_collection_object_cache_get(Collection *collection) +{ + if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) { + static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER; + + BLI_mutex_lock(&cache_lock); + if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) { + collection_object_cache_fill(&collection->object_cache, collection, 0); + collection->flag |= COLLECTION_HAS_OBJECT_CACHE; + } + BLI_mutex_unlock(&cache_lock); + } + + return collection->object_cache; +} + +static void collection_object_cache_free(Collection *collection) +{ + /* Clear own cache an for all parents, since those are affected by changes as well. */ + collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE; + BLI_freelistN(&collection->object_cache); + + for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) { + collection_object_cache_free(parent->collection); + } +} + +void BKE_collection_object_cache_free(Collection *collection) +{ + collection_object_cache_free(collection); +} + +Base *BKE_collection_or_layer_objects(const ViewLayer *view_layer, Collection *collection) +{ + if (collection) { + return BKE_collection_object_cache_get(collection).first; + } + else { + return FIRSTBASE(view_layer); + } +} + +/*********************** Scene Master Collection ***************/ + +Collection *BKE_collection_master_add() +{ + /* Not an actual datablock, but owned by scene. */ + Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection"); + STRNCPY(master_collection->id.name, "GRMaster Collection"); + master_collection->flag |= COLLECTION_IS_MASTER; + return master_collection; +} + +Collection *BKE_collection_master(const Scene *scene) +{ + return scene->master_collection; +} + +/*********************** Cyclic Checks ************************/ + +static bool collection_object_cyclic_check_internal(Object *object, Collection *collection) +{ + if (object->dup_group) { + Collection *dup_collection = object->dup_group; + if ((dup_collection->id.tag & LIB_TAG_DOIT) == 0) { + /* Cycle already exists in collections, let's prevent further crappyness */ + return true; + } + /* flag the object to identify cyclic dependencies in further dupli collections */ + dup_collection->id.tag &= ~LIB_TAG_DOIT; + + if (dup_collection == collection) { + return true; + } + else { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(dup_collection, collection_object) + { + if (collection_object_cyclic_check_internal(collection_object, dup_collection)) { + return true; + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + + /* un-flag the object, it's allowed to have the same collection multiple times in parallel */ + dup_collection->id.tag |= LIB_TAG_DOIT; + } + + return false; +} + +bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection *collection) +{ + /* first flag all collections */ + BKE_main_id_tag_listbase(&bmain->collection, LIB_TAG_DOIT, true); + + return collection_object_cyclic_check_internal(object, collection); +} + +/******************* Collection Object Membership *******************/ + +bool BKE_collection_has_object(Collection *collection, Object *ob) +{ + if (ELEM(NULL, collection, ob)) { + return false; + } + + return (BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob))); +} + +bool BKE_collection_has_object_recursive(Collection *collection, Object *ob) +{ + if (ELEM(NULL, collection, ob)) { + return false; + } + + const ListBase objects = BKE_collection_object_cache_get(collection); + return (BLI_findptr(&objects, ob, offsetof(Base, object))); +} + +Collection *BKE_collection_object_find(Main *bmain, Collection *collection, Object *ob) +{ + if (collection) + collection = collection->id.next; + else + collection = bmain->collection.first; + + while (collection) { + if (BKE_collection_has_object(collection, ob)) + return collection; + collection = collection->id.next; + } + return NULL; +} + +bool BKE_collection_is_empty(Collection *collection) +{ + return BLI_listbase_is_empty(&collection->gobject) && BLI_listbase_is_empty(&collection->children); +} + +/********************** Collection Objects *********************/ + +static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us) +{ + if (ob->dup_group) { + /* Cyclic dependency check. */ + if (collection_find_child_recursive(ob->dup_group, collection)) { + return false; + } + } + + CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)); + if (cob) { + return false; + } + + cob = MEM_callocN(sizeof(CollectionObject), __func__); + cob->ob = ob; + BLI_addtail(&collection->gobject, cob); + BKE_collection_object_cache_free(collection); + + if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus(&ob->id); + } + + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE); + } + + return true; +} + +static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us) +{ + CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)); + if (cob == NULL) { + return false; + } + + BLI_freelinkN(&collection->gobject, cob); + BKE_collection_object_cache_free(collection); + + if (free_us) { + BKE_libblock_free_us(bmain, ob); + } + else { + id_us_min(&ob->id); + } + + DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE); + + return true; +} + +/** + * Add object to collection + */ +bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob) +{ + if (ELEM(NULL, collection, ob)) { + return false; + } + + if (!collection_object_add(bmain, collection, ob, 0, true)) { + return false; + } + + if (BKE_collection_is_in_scene(collection)) { + BKE_main_collection_sync(bmain); + } + + return true; +} + +/** + * Add object to all scene collections that reference objects is in + * (used to copy objects) + */ +void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst) +{ + FOREACH_SCENE_COLLECTION_BEGIN(scene, collection) + { + if (BKE_collection_has_object(collection, ob_src)) { + collection_object_add(bmain, collection, ob_dst, 0, true); + } + } + FOREACH_SCENE_COLLECTION_END; + + BKE_main_collection_sync(bmain); +} + +/** + * Remove object from collection. + */ +bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us) +{ + if (ELEM(NULL, collection, ob)) { + return false; + } + + if (!collection_object_remove(bmain, collection, ob, free_us)) { + return false; + } + + if (BKE_collection_is_in_scene(collection)) { + BKE_main_collection_sync(bmain); + } + + return true; +} + +/** + * Remove object from all collections of scene + * \param scene_collection_skip: Don't remove base from this collection. + */ +static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us, + Collection *collection_skip) +{ + bool removed = false; + + BKE_scene_remove_rigidbody_object(bmain, scene, ob); + + FOREACH_SCENE_COLLECTION_BEGIN(scene, collection) + { + if (collection != collection_skip) { + removed |= collection_object_remove(bmain, collection, ob, free_us); + } + } + FOREACH_SCENE_COLLECTION_END; + + BKE_main_collection_sync(bmain); + + return removed; +} + +/** + * Remove object from all collections of scene + */ +bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us) +{ + return scene_collections_object_remove(bmain, scene, ob, free_us, NULL); +} + +/* + * Remove all NULL objects from collections. + * This is used for library remapping, where these pointers have been set to NULL. + * Otherwise this should never happen. + */ +static void collection_object_remove_nulls(Collection *collection) +{ + bool changed = false; + + for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) { + cob_next = cob->next; + + if (cob->ob == NULL) { + BLI_freelinkN(&collection->gobject, cob); + changed = true; + } + } + + if (changed) { + BKE_collection_object_cache_free(collection); + } +} + +void BKE_collections_object_remove_nulls(Main *bmain) +{ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + collection_object_remove_nulls(scene->master_collection); + } + + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + collection_object_remove_nulls(collection); + } +} + +static void collection_null_children_remove(Collection *collection) +{ + for (CollectionChild *child = collection->children.first, *child_next = NULL; child; child = child_next) { + child_next = child->next; + + if (child->collection == NULL) { + BLI_freelinkN(&collection->children, child); + } + } +} + +static void collection_missing_parents_remove(Collection *collection) +{ + for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL; parent = parent_next) { + parent_next = parent->next; + + if (!collection_find_child(parent->collection, collection)) { + BLI_freelinkN(&collection->parents, parent); + } + } +} + +/** + * Remove all NULL children from parent collections of changed \a collection. + * This is used for library remapping, where these pointers have been set to NULL. + * Otherwise this should never happen. + * + * \note caller must ensure BKE_main_collection_sync_remap() is called afterwards! + * + * \param collection may be \a NULL, in which case whole \a bmain database of collections is checked. + */ +void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection) +{ + if (collection == NULL) { + /* We need to do the checks in two steps when more than one collection may be involved, + * otherwise we can miss some cases... + * Also, master collections are not in bmain, so we also need to loop over scenes. + */ + for (collection = bmain->collection.first; collection != NULL; collection = collection->id.next) { + collection_null_children_remove(collection); + } + for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) { + collection_null_children_remove(BKE_collection_master(scene)); + } + + for (collection = bmain->collection.first; collection != NULL; collection = collection->id.next) { + collection_missing_parents_remove(collection); + } + for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) { + collection_missing_parents_remove(BKE_collection_master(scene)); + } + } + else { + for (CollectionParent *parent = collection->parents.first, *parent_next; parent; parent = parent_next) { + parent_next = parent->next; + + collection_null_children_remove(parent->collection); + + if (!collection_find_child(parent->collection, collection)) { + BLI_freelinkN(&collection->parents, parent); + } + } + } +} + +/** + * Move object from a collection into another + * + * If source collection is NULL move it from all the existing collections. + */ +void BKE_collection_object_move( + Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob) +{ + /* In both cases we first add the object, then remove it from the other collections. + * Otherwise we lose the original base and whether it was active and selected. */ + if (collection_src != NULL) { + if (BKE_collection_object_add(bmain, collection_dst, ob)) { + BKE_collection_object_remove(bmain, collection_src, ob, false); + } + } + else { + /* Adding will fail if object is already in collection. + * However we still need to remove it from the other collections. */ + BKE_collection_object_add(bmain, collection_dst, ob); + scene_collections_object_remove(bmain, scene, ob, false, collection_dst); + } +} + +/***************** Collection Scene Membership ****************/ + +bool BKE_collection_is_in_scene(Collection *collection) +{ + if (collection->flag & COLLECTION_IS_MASTER) { + return true; + } + + for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { + if (BKE_collection_is_in_scene(cparent->collection)) { + return true; + } + } + + return false; +} + +void BKE_collections_after_lib_link(Main *bmain) +{ + /* Update view layer collections to match any changes in linked + * collections after file load. */ + BKE_main_collection_sync(bmain); +} + +/********************** Collection Children *******************/ + +bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection) +{ + if (collection == new_ancestor) { + return true; + } + + for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) { + if (BKE_collection_find_cycle(parent->collection, collection)) { + return true; + } + } + + return false; +} + +static CollectionChild *collection_find_child(Collection *parent, Collection *collection) +{ + return BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection)); +} + +static bool collection_find_child_recursive(Collection *parent, Collection *collection) +{ + for (CollectionChild *child = parent->children.first; child; child = child->next) { + if (child->collection == collection) { + return true; + } + + if (collection_find_child_recursive(child->collection, collection)) { + return true; + } + } + + return false; +} + +static CollectionParent *collection_find_parent(Collection *child, Collection *collection) +{ + return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection)); +} + +static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us) +{ + CollectionChild *child = collection_find_child(parent, collection); + if (child) { + return false; + } + if (BKE_collection_find_cycle(parent, collection)) { + return false; + } + + child = MEM_callocN(sizeof(CollectionChild), "CollectionChild"); + child->collection = collection; + BLI_addtail(&parent->children, child); + + /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */ + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent"); + cparent->collection = parent; + BLI_addtail(&collection->parents, cparent); + } + + if (add_us) { + id_us_plus(&collection->id); + } + + BKE_collection_object_cache_free(parent); + + return true; +} + +static bool collection_child_remove(Collection *parent, Collection *collection) +{ + CollectionChild *child = collection_find_child(parent, collection); + if (child == NULL) { + return false; + } + + CollectionParent *cparent = collection_find_parent(collection, parent); + BLI_freelinkN(&collection->parents, cparent); + BLI_freelinkN(&parent->children, child); + + id_us_min(&collection->id); + + BKE_collection_object_cache_free(parent); + + return true; +} + +bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child) +{ + if (!collection_child_add(parent, child, 0, true)) { + return false; + } + + BKE_main_collection_sync(bmain); + return true; +} + +bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child) +{ + if (!collection_child_remove(parent, child)) { + return false; + } + + BKE_main_collection_sync(bmain); + return true; +} + +/********************** Collection index *********************/ + +static Collection *collection_from_index_recursive(Collection *collection, const int index, int *index_current) +{ + if (index == (*index_current)) { + return collection; + } + + (*index_current)++; + + for (CollectionChild *child = collection->children.first; child; child = child->next) { + Collection *nested = collection_from_index_recursive(child->collection, index, index_current); + if (nested != NULL) { + return nested; + } + } + return NULL; +} + +/** + * Return Scene Collection for a given index. + * + * The index is calculated from top to bottom counting the children before the siblings. + */ +Collection *BKE_collection_from_index(Scene *scene, const int index) +{ + int index_current = 0; + Collection *master_collection = BKE_collection_master(scene); + return collection_from_index_recursive(master_collection, index, &index_current); +} + +static bool collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect) +{ + bool changed = false; + + if (collection->flag & COLLECTION_RESTRICT_SELECT) { + return false; + } + + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); + + if (base) { + if (deselect) { + if (base->flag & BASE_SELECTED) { + base->flag &= ~BASE_SELECTED; + changed = true; + } + } + else { + if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) { + base->flag |= BASE_SELECTED; + changed = true; + } + } + } + } + + for (CollectionChild *child = collection->children.first; child; child = child->next) { + if (collection_objects_select(view_layer, collection, deselect)) { + changed = true; + } + } + + return changed; +} + +/** + * Select all the objects in this Collection (and its nested collections) for this ViewLayer. + * Return true if any object was selected. + */ +bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect) +{ + LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, collection); + + if (layer_collection != NULL) { + return BKE_layer_collection_objects_select(view_layer, layer_collection, deselect); + } + else { + return collection_objects_select(view_layer, collection, deselect); + } +} + +/***************** Collection move (outliner drag & drop) *********************/ + +bool BKE_collection_move(Main *bmain, + Collection *to_parent, + Collection *from_parent, + Collection *relative, + bool relative_after, + Collection *collection) +{ + if (collection->flag & COLLECTION_IS_MASTER) { + return false; + } + if (BKE_collection_find_cycle(to_parent, collection)) { + return false; + } + + /* Move to new parent collection */ + if (from_parent) { + collection_child_remove(from_parent, collection); + } + + collection_child_add(to_parent, collection, 0, true); + + /* Move to specified location under parent. */ + if (relative) { + CollectionChild *child = collection_find_child(to_parent, collection); + CollectionChild *relative_child = collection_find_child(to_parent, relative); + + if (relative_child) { + BLI_remlink(&to_parent->children, child); + + if (relative_after) { + BLI_insertlinkafter(&to_parent->children, relative_child, child); + } + else { + BLI_insertlinkbefore(&to_parent->children, relative_child, child); + } + + BKE_collection_object_cache_free(to_parent); + } + } + + BKE_main_collection_sync(bmain); + + return true; +} + +/**************************** Iterators ******************************/ + +/* scene collection iteractor */ + +typedef struct CollectionsIteratorData { + Scene *scene; + void **array; + int tot, cur; +} CollectionsIteratorData; + +static void scene_collection_callback(Collection *collection, BKE_scene_collections_Cb callback, void *data) +{ + callback(collection, data); + + for (CollectionChild *child = collection->children.first; child; child = child->next) { + scene_collection_callback(child->collection, callback, data); + } +} + +static void scene_collections_count(Collection *UNUSED(collection), void *data) +{ + int *tot = data; + (*tot)++; +} + +static void scene_collections_build_array(Collection *collection, void *data) +{ + Collection ***array = data; + **array = collection; + (*array)++; +} + +static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot) +{ + Collection *collection; + Collection **array; + + *collections_array = NULL; + *tot = 0; + + if (scene == NULL) { + return; + } + + collection = BKE_collection_master(scene); + BLI_assert(collection != NULL); + scene_collection_callback(collection, scene_collections_count, tot); + + if (*tot == 0) + return; + + *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + scene_collection_callback(collection, scene_collections_build_array, &array); +} + +/** + * Only use this in non-performance critical situations + * (it iterates over all scene collections twice) + */ +void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__); + + data->scene = scene; + iter->data = data; + iter->valid = true; + + scene_collections_array(scene, (Collection ***)&data->array, &data->tot); + BLI_assert(data->tot != 0); + + data->cur = 0; + iter->current = data->array[data->cur]; +} + +void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter) +{ + CollectionsIteratorData *data = iter->data; + + if (++data->cur < data->tot) { + iter->current = data->array[data->cur]; + } + else { + iter->valid = false; + } +} + +void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter) +{ + CollectionsIteratorData *data = iter->data; + + if (data) { + if (data->array) { + MEM_freeN(data->array); + } + MEM_freeN(data); + } + iter->valid = false; +} + + +/* scene objects iteractor */ + +typedef struct SceneObjectsIteratorData { + GSet *visited; + CollectionObject *cob_next; + BLI_Iterator scene_collection_iter; +} SceneObjectsIteratorData; + +void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__); + iter->data = data; + + /* lookup list ot make sure each object is object called once */ + data->visited = BLI_gset_ptr_new(__func__); + + /* we wrap the scenecollection iterator here to go over the scene collections */ + BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene); + + Collection *collection = data->scene_collection_iter.current; + if (collection->gobject.first != NULL) { + iter->current = ((CollectionObject *)collection->gobject.first)->ob; + } + else { + BKE_scene_objects_iterator_next(iter); + } +} + +/** + * Gets the first unique object in the sequence + */ +static CollectionObject *object_base_unique(GSet *gs, CollectionObject *cob) +{ + for (; cob != NULL; cob = cob->next) { + Object *ob = cob->ob; + void **ob_key_p; + if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) { + *ob_key_p = ob; + return cob; + } + } + return NULL; +} + +void BKE_scene_objects_iterator_next(BLI_Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) : NULL; + + if (cob) { + data->cob_next = cob->next; + iter->current = cob->ob; + } + else { + /* if this is the last object of this ListBase look at the next Collection */ + Collection *collection; + BKE_scene_collections_iterator_next(&data->scene_collection_iter); + do { + collection = data->scene_collection_iter.current; + /* get the first unique object of this collection */ + CollectionObject *new_cob = object_base_unique(data->visited, collection->gobject.first); + if (new_cob) { + data->cob_next = new_cob->next; + iter->current = new_cob->ob; + return; + } + BKE_scene_collections_iterator_next(&data->scene_collection_iter); + } while (data->scene_collection_iter.valid); + + if (!data->scene_collection_iter.valid) { + iter->valid = false; + } + } +} + +void BKE_scene_objects_iterator_end(BLI_Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + if (data) { + BKE_scene_collections_iterator_end(&data->scene_collection_iter); + BLI_gset_free(data->visited, NULL); + MEM_freeN(data); + } +} diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 84490ba3ee2..d868a06d134 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -33,8 +33,8 @@ #include "MEM_guardedalloc.h" #include "DNA_cloth_types.h" +#include "DNA_collection_types.h" #include "DNA_effect_types.h" -#include "DNA_group_types.h" #include "DNA_object_types.h" #include "DNA_object_force_types.h" #include "DNA_scene_types.h" @@ -43,24 +43,45 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLI_edgehash.h" +#include "BLI_task.h" +#include "BLI_threads.h" #include "BKE_cloth.h" +#include "BKE_collection.h" #include "BKE_effect.h" +#include "BKE_layer.h" #include "BKE_modifier.h" #include "BKE_scene.h" -#ifdef WITH_BULLET -#include "Bullet-C-Api.h" -#endif #include "BLI_kdopbvh.h" #include "BKE_collision.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_physics.h" +#include "DEG_depsgraph_query.h" + #ifdef WITH_ELTOPO #include "eltopo-capi.h" #endif +typedef struct ColDetectData { + ClothModifierData *clmd; + CollisionModifierData *collmd; + BVHTreeOverlap *overlap; + CollPair *collisions; + bool culling; + bool use_normal; + bool collided; +} ColDetectData; + +typedef struct SelfColDetectData { + ClothModifierData *clmd; + BVHTreeOverlap *overlap; + CollPair *collisions; + bool collided; +} SelfColDetectData; + /*********************************** Collision modifier code start ***********************************/ @@ -68,7 +89,7 @@ Collision modifier code start /* step is limited from 0 (frame start position) to 1 (frame end position) */ void collision_move_object(CollisionModifierData *collmd, float step, float prevstep) { - float tv[3] = {0, 0, 0}; + float oldx[3]; unsigned int i = 0; /* the collider doesn't move this frame */ @@ -81,15 +102,14 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev } for (i = 0; i < collmd->mvert_num; i++) { - sub_v3_v3v3(tv, collmd->xnew[i].co, collmd->x[i].co); - VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep); - VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step); - sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co); + interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep); + interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step); + sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx); } bvhtree_update_from_mvert( - collmd->bvhtree, collmd->current_x, collmd->current_xnew, - collmd->tri, collmd->tri_num, true); + collmd->bvhtree, collmd->current_x, NULL, + collmd->tri, collmd->tri_num, false); } BVHTree *bvhtree_build_from_mvert( @@ -172,6 +192,233 @@ void bvhtree_update_from_mvert( Collision modifier code end ***********************************/ +BLI_INLINE int next_ind(int i) +{ + return (++i < 3) ? i : 0; +} + +static float compute_collision_point(float a1[3], float a2[3], float a3[3], float b1[3], float b2[3], float b3[3], + bool culling, bool use_normal, float r_a[3], float r_b[3], float r_vec[3]) +{ + float a[3][3]; + float b[3][3]; + float dist = FLT_MAX; + float tmp_co1[3], tmp_co2[3]; + float isect_a[3], isect_b[3]; + int isect_count = 0; + float tmp, tmp_vec[3]; + float normal[3], cent[3]; + bool backside = false; + + copy_v3_v3(a[0], a1); + copy_v3_v3(a[1], a2); + copy_v3_v3(a[2], a3); + + copy_v3_v3(b[0], b1); + copy_v3_v3(b[1], b2); + copy_v3_v3(b[2], b3); + + /* Find intersections. */ + for (int i = 0; i < 3; i++) { + if (isect_line_segment_tri_v3(a[i], a[next_ind(i)], b[0], b[1], b[2], &tmp, NULL)) { + interp_v3_v3v3(isect_a, a[i], a[next_ind(i)], tmp); + isect_count++; + } + } + + if (isect_count == 0) { + for (int i = 0; i < 3; i++) { + if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) { + isect_count++; + } + } + } + else if (isect_count == 1) { + for (int i = 0; i < 3; i++) { + if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) { + interp_v3_v3v3(isect_b, b[i], b[next_ind(i)], tmp); + break; + } + } + } + + /* Determine collision side. */ + if (culling) { + normal_tri_v3(normal, b[0], b[1], b[2]); + mid_v3_v3v3v3(cent, b[0], b[1], b[2]); + + if (isect_count == 2) { + backside = true; + } + else if (isect_count == 0) { + for (int i = 0; i < 3; i++) { + sub_v3_v3v3(tmp_vec, a[i], cent); + if (dot_v3v3(tmp_vec, normal) < 0.0f) { + backside = true; + break; + } + } + } + } + else if (use_normal) { + normal_tri_v3(normal, b[0], b[1], b[2]); + } + + if (isect_count == 1) { + /* Edge intersection. */ + copy_v3_v3(r_a, isect_a); + copy_v3_v3(r_b, isect_b); + + if (use_normal) { + copy_v3_v3(r_vec, normal); + } + else { + sub_v3_v3v3(r_vec, r_b, r_a); + } + + return 0.0f; + } + + if (backside) { + float maxdist = 0.0f; + bool found = false; + + /* Point projections. */ + for (int i = 0; i < 3; i++) { + if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) { + if (tmp > maxdist) { + maxdist = tmp; + copy_v3_v3(r_a, a[i]); + madd_v3_v3v3fl(r_b, a[i], normal, tmp); + found = true; + } + } + } + + negate_v3(normal); + + for (int i = 0; i < 3; i++) { + if (isect_ray_tri_v3(b[i], normal, a[0], a[1], a[2], &tmp, NULL)) { + if (tmp > maxdist) { + maxdist = tmp; + madd_v3_v3v3fl(r_a, b[i], normal, tmp); + copy_v3_v3(r_b, b[i]); + found = true; + } + } + } + + negate_v3(normal); + + /* Edge projections. */ + for (int i = 0; i < 3; i++) { + float dir[3]; + + sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]); + cross_v3_v3v3(dir, tmp_vec, normal); + + for (int j = 0; j < 3; j++) { + if (isect_line_plane_v3(tmp_co1, a[j], a[next_ind(j)], b[i], dir) && + point_in_slice_seg(tmp_co1, a[j], a[next_ind(j)]) && + point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)])) + { + closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]); + sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2); + tmp = len_v3(tmp_vec); + + if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) { + maxdist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + found = true; + } + } + } + } + + /* If no point is found, will fallback onto regular proximity test below. */ + if (found) { + sub_v3_v3v3(r_vec, r_b, r_a); + + if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + + return 0.0f; + } + } + + /* Closest point. */ + for (int i = 0; i < 3; i++) { + closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]); + tmp = len_squared_v3v3(tmp_co1, a[i]); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, a[i]); + copy_v3_v3(r_b, tmp_co1); + } + } + + for (int i = 0; i < 3; i++) { + closest_on_tri_to_point_v3(tmp_co1, b[i], a[0], a[1], a[2]); + tmp = len_squared_v3v3(tmp_co1, b[i]); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, b[i]); + } + } + + /* Closest edge. */ + if (isect_count == 0) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + isect_seg_seg_v3(a[i], a[next_ind(i)], b[j], b[next_ind(j)], tmp_co1, tmp_co2); + tmp = len_squared_v3v3(tmp_co1, tmp_co2); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + } + } + } + } + + if (isect_count == 0) { + sub_v3_v3v3(r_vec, r_a, r_b); + dist = sqrtf(dist); + } + else { + sub_v3_v3v3(r_vec, r_b, r_a); + dist = 0.0f; + } + + if (culling && use_normal) { + copy_v3_v3(r_vec, normal); + } + else if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) { + return FLT_MAX; + } + + return dist; +} + // w3 is not perfect static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 ) { @@ -226,141 +473,131 @@ DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float VECADDMUL(to, v3, w3); } -static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end ) +static int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, Object *collob, + CollPair *collpair, uint collision_count, const float dt) { int result = 0; Cloth *cloth1; float w1, w2, w3, u1, u2, u3; float v1[3], v2[3], relativeVelocity[3]; float magrelVel; - float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree ); + float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); cloth1 = clmd->clothObject; - for ( ; collpair != collision_end; collpair++ ) { + for (int i = 0; i < collision_count; i++, collpair++) { float i1[3], i2[3], i3[3]; zero_v3(i1); zero_v3(i2); zero_v3(i3); - /* only handle static collisions here */ - if ( collpair->flag & COLLISION_IN_FUTURE ) + /* Only handle static collisions here. */ + if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) { continue; + } - /* compute barycentric coordinates for both collision points */ - collision_compute_barycentric ( collpair->pa, - cloth1->verts[collpair->ap1].txold, - cloth1->verts[collpair->ap2].txold, - cloth1->verts[collpair->ap3].txold, - &w1, &w2, &w3 ); + /* Compute barycentric coordinates for both collision points. */ + collision_compute_barycentric(collpair->pa, + cloth1->verts[collpair->ap1].tx, + cloth1->verts[collpair->ap2].tx, + cloth1->verts[collpair->ap3].tx, + &w1, &w2, &w3); - /* was: txold */ - collision_compute_barycentric ( collpair->pb, - collmd->current_x[collpair->bp1].co, - collmd->current_x[collpair->bp2].co, - collmd->current_x[collpair->bp3].co, - &u1, &u2, &u3 ); + collision_compute_barycentric(collpair->pb, + collmd->current_x[collpair->bp1].co, + collmd->current_x[collpair->bp2].co, + collmd->current_x[collpair->bp3].co, + &u1, &u2, &u3); /* Calculate relative "velocity". */ - collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 ); + collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3); - collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 ); + collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3); sub_v3_v3v3(relativeVelocity, v2, v1); /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */ magrelVel = dot_v3v3(relativeVelocity, collpair->normal); - /* printf("magrelVel: %f\n", magrelVel); */ - - /* Calculate masses of points. - * TODO */ - - /* If v_n_mag < 0 the edges are approaching each other. */ - if ( magrelVel > ALMOST_ZERO ) { + /* If magrelVel < 0 the edges are approaching each other. */ + if (magrelVel > 0.0f) { /* Calculate Impulse magnitude to stop all motion in normal direction. */ float magtangent = 0, repulse = 0, d = 0; double impulse = 0.0; float vrel_t_pre[3]; - float temp[3], spf; + float temp[3]; + float time_multiplier; - /* calculate tangential velocity */ - copy_v3_v3 ( temp, collpair->normal ); + /* Calculate tangential velocity. */ + copy_v3_v3(temp, collpair->normal); mul_v3_fl(temp, magrelVel); sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp); /* Decrease in magnitude of relative tangential velocity due to coulomb friction - * in original formula "magrelVel" should be the "change of relative velocity in normal direction" */ - magtangent = min_ff(clmd->coll_parms->friction * 0.01f * magrelVel, len_v3(vrel_t_pre)); + * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */ + magtangent = min_ff(collob->pd->pdef_cfrict * 0.01f * magrelVel, len_v3(vrel_t_pre)); /* Apply friction impulse. */ if ( magtangent > ALMOST_ZERO ) { normalize_v3(vrel_t_pre); - impulse = magtangent / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* 2.0 * */ - VECADDMUL ( i1, vrel_t_pre, w1 * impulse ); - VECADDMUL ( i2, vrel_t_pre, w2 * impulse ); - VECADDMUL ( i3, vrel_t_pre, w3 * impulse ); + impulse = magtangent / 1.5; + + VECADDMUL(i1, vrel_t_pre, w1 * impulse); + VECADDMUL(i2, vrel_t_pre, w2 * impulse); + VECADDMUL(i3, vrel_t_pre, w3 * impulse); } - /* Apply velocity stopping impulse - * I_c = m * v_N / 2.0 - * no 2.0 * magrelVel normally, but looks nicer DG */ - impulse = magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); + /* Apply velocity stopping impulse. */ + impulse = magrelVel / 1.5f; - VECADDMUL ( i1, collpair->normal, w1 * impulse ); + VECADDMUL(i1, collpair->normal, w1 * impulse); cloth1->verts[collpair->ap1].impulse_count++; - VECADDMUL ( i2, collpair->normal, w2 * impulse ); + VECADDMUL(i2, collpair->normal, w2 * impulse); cloth1->verts[collpair->ap2].impulse_count++; - VECADDMUL ( i3, collpair->normal, w3 * impulse ); + VECADDMUL(i3, collpair->normal, w3 * impulse); cloth1->verts[collpair->ap3].impulse_count++; - /* Apply repulse impulse if distance too short - * I_r = -min(dt*kd, m(0, 1d/dt - v_n)) - * DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this: - * v += impulse; x_new = x + v; - * We don't use dt!! - * DG TODO: Fix usage of dt here! */ - spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; + time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance; - if ( ( magrelVel < 0.1f*d*spf ) && ( d > ALMOST_ZERO ) ) { - repulse = MIN2 ( d*1.0f/spf, 0.1f*d*spf - magrelVel ); - /* stay on the safe side and clamp repulse */ - if ( impulse > ALMOST_ZERO ) - repulse = min_ff( repulse, 5.0*impulse ); + if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) { + repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel); + + /* Stay on the safe side and clamp repulse. */ + if (impulse > ALMOST_ZERO) { + repulse = min_ff(repulse, 5.0f * impulse); + } + repulse = max_ff(impulse, repulse); - impulse = repulse / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* original 2.0 / 0.25 */ - VECADDMUL ( i1, collpair->normal, impulse ); - VECADDMUL ( i2, collpair->normal, impulse ); - VECADDMUL ( i3, collpair->normal, impulse ); + impulse = repulse / 1.5f; + + VECADDMUL(i1, collpair->normal, impulse); + VECADDMUL(i2, collpair->normal, impulse); + VECADDMUL(i3, collpair->normal, impulse); } result = 1; } else { - /* Apply repulse impulse if distance too short - * I_r = -min(dt*kd, max(0, 1d/dt - v_n)) - * DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this: - * v += impulse; x_new = x + v; - * We don't use dt!! */ - float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale; - - float d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - (float)collpair->distance; - if ( d > ALMOST_ZERO) { - /* stay on the safe side and clamp repulse */ - float repulse = d*1.0f/spf; + float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); + float d; + + d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance; - float impulse = repulse / ( 3.0f * ( 1.0f + w1*w1 + w2*w2 + w3*w3 )); /* original 2.0 / 0.25 */ + if (d > ALMOST_ZERO) { + /* Stay on the safe side and clamp repulse. */ + float repulse = d / time_multiplier; + float impulse = repulse / 4.5f; - VECADDMUL ( i1, collpair->normal, impulse ); - VECADDMUL ( i2, collpair->normal, impulse ); - VECADDMUL ( i3, collpair->normal, impulse ); + VECADDMUL(i1, collpair->normal, w1 * impulse); + VECADDMUL(i2, collpair->normal, w2 * impulse); + VECADDMUL(i3, collpair->normal, w3 * impulse); cloth1->verts[collpair->ap1].impulse_count++; cloth1->verts[collpair->ap2].impulse_count++; @@ -371,20 +608,190 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM } if (result) { - int i = 0; + float clamp = clmd->coll_parms->clamp * dt; - for (i = 0; i < 3; i++) { - if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[i]) < ABS(i1[i])) - cloth1->verts[collpair->ap1].impulse[i] = i1[i]; + if ((clamp > 0.0f) && + ((len_v3(i1) > clamp) || + (len_v3(i2) > clamp) || + (len_v3(i3) > clamp))) + { + return 0; + } - if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[i]) < ABS(i2[i])) - cloth1->verts[collpair->ap2].impulse[i] = i2[i]; + for (int j = 0; j < 3; j++) { + if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j])) + cloth1->verts[collpair->ap1].impulse[j] = i1[j]; - if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[i]) < ABS(i3[i])) - cloth1->verts[collpair->ap3].impulse[i] = i3[i]; + if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j])) + cloth1->verts[collpair->ap2].impulse[j] = i2[j]; + + if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) + cloth1->verts[collpair->ap3].impulse[j] = i3[j]; } } } + + return result; +} + +static int cloth_selfcollision_response_static(ClothModifierData *clmd, CollPair *collpair, + uint collision_count, const float dt) +{ + int result = 0; + Cloth *cloth1; + float w1, w2, w3, u1, u2, u3; + float v1[3], v2[3], relativeVelocity[3]; + float magrelVel; + + cloth1 = clmd->clothObject; + + for (int i = 0; i < collision_count; i++, collpair++) { + float i1[3], i2[3], i3[3]; + + zero_v3(i1); + zero_v3(i2); + zero_v3(i3); + + /* Only handle static collisions here. */ + if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) { + continue; + } + + /* Compute barycentric coordinates for both collision points. */ + collision_compute_barycentric(collpair->pa, + cloth1->verts[collpair->ap1].tx, + cloth1->verts[collpair->ap2].tx, + cloth1->verts[collpair->ap3].tx, + &w1, &w2, &w3); + + collision_compute_barycentric(collpair->pb, + cloth1->verts[collpair->bp1].tx, + cloth1->verts[collpair->bp2].tx, + cloth1->verts[collpair->bp3].tx, + &u1, &u2, &u3); + + /* Calculate relative "velocity". */ + collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3); + + collision_interpolateOnTriangle(v2, cloth1->verts[collpair->bp1].tv, cloth1->verts[collpair->bp2].tv, cloth1->verts[collpair->bp3].tv, u1, u2, u3); + + sub_v3_v3v3(relativeVelocity, v2, v1); + + /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */ + magrelVel = dot_v3v3(relativeVelocity, collpair->normal); + + /* TODO: Impulses should be weighed by mass as this is self col, + * this has to be done after mass distribution is implemented. */ + + /* If magrelVel < 0 the edges are approaching each other. */ + if (magrelVel > 0.0f) { + /* Calculate Impulse magnitude to stop all motion in normal direction. */ + float magtangent = 0, repulse = 0, d = 0; + double impulse = 0.0; + float vrel_t_pre[3]; + float temp[3], time_multiplier; + + /* Calculate tangential velocity. */ + copy_v3_v3(temp, collpair->normal); + mul_v3_fl(temp, magrelVel); + sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp); + + /* Decrease in magnitude of relative tangential velocity due to coulomb friction + * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */ + magtangent = min_ff(clmd->coll_parms->self_friction * 0.01f * magrelVel, len_v3(vrel_t_pre)); + + /* Apply friction impulse. */ + if (magtangent > ALMOST_ZERO) { + normalize_v3(vrel_t_pre); + + impulse = magtangent / 1.5; + + VECADDMUL(i1, vrel_t_pre, w1 * impulse); + VECADDMUL(i2, vrel_t_pre, w2 * impulse); + VECADDMUL(i3, vrel_t_pre, w3 * impulse); + } + + /* Apply velocity stopping impulse. */ + impulse = magrelVel / 3.0f; + + VECADDMUL(i1, collpair->normal, w1 * impulse); + cloth1->verts[collpair->ap1].impulse_count++; + + VECADDMUL(i2, collpair->normal, w2 * impulse); + cloth1->verts[collpair->ap2].impulse_count++; + + VECADDMUL(i3, collpair->normal, w3 * impulse); + cloth1->verts[collpair->ap3].impulse_count++; + + time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); + + d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance; + + if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) { + repulse = MIN2 (d / time_multiplier, 0.1f * d * time_multiplier - magrelVel); + + if (impulse > ALMOST_ZERO) { + repulse = min_ff(repulse, 5.0*impulse); + } + + repulse = max_ff(impulse, repulse); + + impulse = repulse / 1.5f; + + VECADDMUL(i1, collpair->normal, w1 * impulse); + VECADDMUL(i2, collpair->normal, w2 * impulse); + VECADDMUL(i3, collpair->normal, w3 * impulse); + } + + result = 1; + } + else { + float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); + float d; + + d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance; + + if ( d > ALMOST_ZERO) { + /* Stay on the safe side and clamp repulse. */ + float repulse = d*1.0f/time_multiplier; + float impulse = repulse / 9.0f; + + VECADDMUL(i1, collpair->normal, w1 * impulse); + VECADDMUL(i2, collpair->normal, w2 * impulse); + VECADDMUL(i3, collpair->normal, w3 * impulse); + + cloth1->verts[collpair->ap1].impulse_count++; + cloth1->verts[collpair->ap2].impulse_count++; + cloth1->verts[collpair->ap3].impulse_count++; + + result = 1; + } + } + + if (result) { + float clamp = clmd->coll_parms->self_clamp * dt; + + if ((clamp > 0.0f) && + ((len_v3(i1) > clamp) || + (len_v3(i2) > clamp) || + (len_v3(i3) > clamp))) + { + return 0; + } + + for (int j = 0; j < 3; j++) { + if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j])) + cloth1->verts[collpair->ap1].impulse[j] = i1[j]; + + if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j])) + cloth1->verts[collpair->ap2].impulse[j] = i2[j]; + + if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) + cloth1->verts[collpair->ap3].impulse[j] = i3[j]; + } + } + } + return result; } @@ -392,224 +799,257 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM # pragma GCC diagnostic pop #endif -//Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned -static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2, - BVHTreeOverlap *overlap, CollPair *collpair, float UNUSED(dt)) +static void cloth_collision( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - ClothModifierData *clmd = (ClothModifierData *)md1; - CollisionModifierData *collmd = (CollisionModifierData *) md2; - /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */ + ColDetectData *data = (ColDetectData *)userdata; + + ClothModifierData *clmd = data->clmd; + CollisionModifierData *collmd = data->collmd; + CollPair *collpair = data->collisions; const MVertTri *tri_a, *tri_b; -#ifdef WITH_BULLET ClothVertex *verts1 = clmd->clothObject->verts; -#endif - double distance = 0; + float distance = 0.0f; float epsilon1 = clmd->coll_parms->epsilon; - float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree ); + float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + float pa[3], pb[3], vect[3]; - tri_a = &clmd->clothObject->tri[overlap->indexA]; - tri_b = &collmd->tri[overlap->indexB]; + tri_a = &clmd->clothObject->tri[data->overlap[index].indexA]; + tri_b = &collmd->tri[data->overlap[index].indexB]; - /* fill face_a */ - collpair->ap1 = tri_a->tri[0]; - collpair->ap2 = tri_a->tri[1]; - collpair->ap3 = tri_a->tri[2]; + /* Compute distance and normal. */ + distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx, + collmd->current_x[tri_b->tri[0]].co, collmd->current_x[tri_b->tri[1]].co, collmd->current_x[tri_b->tri[2]].co, + data->culling, data->use_normal, pa, pb, vect); - /* fill face_b */ - collpair->bp1 = tri_b->tri[0]; - collpair->bp2 = tri_b->tri[1]; - collpair->bp3 = tri_b->tri[2]; + if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { + collpair[index].ap1 = tri_a->tri[0]; + collpair[index].ap2 = tri_a->tri[1]; + collpair[index].ap3 = tri_a->tri[2]; - { + collpair[index].bp1 = tri_b->tri[0]; + collpair[index].bp2 = tri_b->tri[1]; + collpair[index].bp3 = tri_b->tri[2]; -#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 ); -#else - // just be sure that we don't add anything - distance = 2.0 * (double)( epsilon1 + epsilon2 + ALMOST_ZERO ); -#endif + copy_v3_v3(collpair[index].pa, pa); + copy_v3_v3(collpair[index].pb, pb); + copy_v3_v3(collpair[index].vector, vect); - // distance -1 means no collision result - if (distance != -1.0 && (distance <= (double)(epsilon1 + epsilon2 + ALMOST_ZERO))) { - normalize_v3_v3(collpair->normal, collpair->vector); + normalize_v3_v3(collpair[index].normal, collpair[index].vector); - collpair->distance = distance; - collpair->flag = 0; - collpair++; - }/* - else { - float w1, w2, w3, u1, u2, u3; - float v1[3], v2[3], relativeVelocity[3]; + collpair[index].distance = distance; + collpair[index].flag = 0; + + data->collided = true; + } + else { + collpair[index].flag = COLLISION_INACTIVE; + } +} + +static void cloth_selfcollision( + void *__restrict userdata, + const int index, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + SelfColDetectData *data = (SelfColDetectData *)userdata; + + ClothModifierData *clmd = data->clmd; + CollPair *collpair = data->collisions; + const MVertTri *tri_a, *tri_b; + ClothVertex *verts1 = clmd->clothObject->verts; + float distance = 0.0f; + float epsilon = clmd->coll_parms->selfepsilon; + float pa[3], pb[3], vect[3]; + + tri_a = &clmd->clothObject->tri[data->overlap[index].indexA]; + tri_b = &clmd->clothObject->tri[data->overlap[index].indexB]; + + for (uint i = 0; i < 3; i++) { + for (uint j = 0; j < 3; j++) { + if (tri_a->tri[i] == tri_b->tri[j]) { + collpair[index].flag = COLLISION_INACTIVE; + return; + } + } + } - // calc relative velocity + if (((verts1[tri_a->tri[0]].flags & verts1[tri_a->tri[1]].flags & verts1[tri_a->tri[2]].flags) | + (verts1[tri_b->tri[0]].flags & verts1[tri_b->tri[1]].flags & verts1[tri_b->tri[2]].flags)) & CLOTH_VERT_FLAG_NOSELFCOLL) + { + collpair[index].flag = COLLISION_INACTIVE; + return; + } - // compute barycentric coordinates for both collision points - collision_compute_barycentric ( collpair->pa, - verts1[collpair->ap1].txold, - verts1[collpair->ap2].txold, - verts1[collpair->ap3].txold, - &w1, &w2, &w3 ); + /* Compute distance and normal. */ + distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx, + verts1[tri_b->tri[0]].tx, verts1[tri_b->tri[1]].tx, verts1[tri_b->tri[2]].tx, + false, false, pa, pb, vect); - // was: txold - collision_compute_barycentric ( collpair->pb, - collmd->current_x[collpair->bp1].co, - collmd->current_x[collpair->bp2].co, - collmd->current_x[collpair->bp3].co, - &u1, &u2, &u3 ); + if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { + collpair[index].ap1 = tri_a->tri[0]; + collpair[index].ap2 = tri_a->tri[1]; + collpair[index].ap3 = tri_a->tri[2]; - // Calculate relative "velocity". - collision_interpolateOnTriangle ( v1, verts1[collpair->ap1].tv, verts1[collpair->ap2].tv, verts1[collpair->ap3].tv, w1, w2, w3 ); + collpair[index].bp1 = tri_b->tri[0]; + collpair[index].bp2 = tri_b->tri[1]; + collpair[index].bp3 = tri_b->tri[2]; - collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 ); + copy_v3_v3(collpair[index].pa, pa); + copy_v3_v3(collpair[index].pb, pb); + copy_v3_v3(collpair[index].vector, vect); - sub_v3_v3v3(relativeVelocity, v2, v1); + normalize_v3_v3(collpair[index].normal, collpair[index].vector); - if (sqrt(dot_v3v3(relativeVelocity, relativeVelocity)) >= distance) - { - // check for collision in the future - collpair->flag |= COLLISION_IN_FUTURE; - collpair++; - } - }*/ + collpair[index].distance = distance; + collpair[index].flag = 0; + + data->collided = true; + } + else { + collpair[index].flag = COLLISION_INACTIVE; } - return collpair; } -static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned int *maxobj, Object *ob, Object *self, int level, unsigned int modifier_type) +static void add_collision_object(ListBase *relations, Object *ob, int level, unsigned int modifier_type) { CollisionModifierData *cmd= NULL; - if (ob == self) - return; - /* only get objects with collision modifier */ if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) || (modifier_type != eModifierType_Collision)) cmd= (CollisionModifierData *)modifiers_findByType(ob, modifier_type); if (cmd) { - /* extend array */ - if (*numobj >= *maxobj) { - *maxobj *= 2; - *objs= MEM_reallocN(*objs, sizeof(Object *)*(*maxobj)); - } - - (*objs)[*numobj] = ob; - (*numobj)++; + CollisionRelation *relation = MEM_callocN(sizeof(CollisionRelation), "CollisionRelation"); + relation->ob = ob; + BLI_addtail(relations, relation); } /* objects in dupli groups, one level only for now */ + /* TODO: this doesn't really work, we are not taking into account the + * dupli transforms and can get objects in the list multiple times. */ if (ob->dup_group && level == 0) { - GroupObject *go; - Group *group= ob->dup_group; + Collection *collection= ob->dup_group; /* add objects */ - for (go= group->gobject.first; go; go= go->next) - add_collision_object(objs, numobj, maxobj, go->ob, self, level+1, modifier_type); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object) + { + add_collision_object(relations, object, level+1, modifier_type); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } -// return all collision objects in scene -// collision object will exclude self -Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) +/* Create list of collision relations in the collection or entire scene. + * This is used by the depsgraph to build relations, as well as faster + * lookup of colliders during evaluation. */ +ListBase *BKE_collision_relations_create(Depsgraph *depsgraph, Collection *collection, unsigned int modifier_type) { - Base *base; - Object **objs; - GroupObject *go; - unsigned int numobj= 0, maxobj= 100; - int level = dupli ? 0 : 1; - - objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray"); - - /* gather all collision objects */ - if (group) { - /* use specified group */ - for (go= group->gobject.first; go; go= go->next) - add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type); - } - else { - Scene *sce_iter; - /* add objects in same layer in scene */ - for (SETLOOPER(scene, sce_iter, base)) { - if ( base->lay & layer ) - add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + Base *base = BKE_collection_or_layer_objects(view_layer, collection); + const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT; + ListBase *relations = MEM_callocN(sizeof(ListBase), "CollisionRelation list"); + + for (; base; base = base->next) { + if (base->flag & base_flag) { + add_collision_object(relations, base->object, 0, modifier_type); } } - *numcollobj= numobj; - - return objs; + return relations; } -Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type) +void BKE_collision_relations_free(ListBase *relations) { - /* Need to check for active layers, too. - Otherwise this check fails if the objects are not on the same layer - DG */ - return get_collisionobjects_ext(scene, self, group, self->lay | scene->lay, numcollobj, modifier_type, true); + if (relations) { + BLI_freelistN(relations); + MEM_freeN(relations); + } } -static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level) +/* Create effective list of colliders from relations built beforehand. + * Self will be excluded. */ +Object **BKE_collision_objects_create(Depsgraph *depsgraph, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type) { - CollisionModifierData *cmd= NULL; - ColliderCache *col; + ListBase *relations = DEG_get_collision_relations(depsgraph, collection, modifier_type); - if (ob == self) - return; + if (!relations) { + *numcollobj = 0; + return NULL; + } - if (ob->pd && ob->pd->deflect) - cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); + int maxnum = BLI_listbase_count(relations); + int num = 0; + Object **objects = MEM_callocN(sizeof(Object*) * maxnum, __func__); - if (cmd && cmd->bvhtree) { - if (*objs == NULL) - *objs = MEM_callocN(sizeof(ListBase), "ColliderCache array"); + for (CollisionRelation *relation = relations->first; relation; relation = relation->next) { + /* Get evaluated object. */ + Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id); - col = MEM_callocN(sizeof(ColliderCache), "ColliderCache"); - col->ob = ob; - col->collmd = cmd; - /* make sure collider is properly set up */ - collision_move_object(cmd, 1.0, 0.0); - BLI_addtail(*objs, col); + if (ob != self) { + objects[num] = ob; + num++; + } } - /* objects in dupli groups, one level only for now */ - if (ob->dup_group && level == 0) { - GroupObject *go; - Group *group= ob->dup_group; + if (num == 0) { + MEM_freeN(objects); + objects = NULL; + } - /* add objects */ - for (go= group->gobject.first; go; go= go->next) - add_collider_cache_object(objs, go->ob, self, level+1); + *numcollobj = num; + return objects; +} + +void BKE_collision_objects_free(Object **objects) +{ + if (objects) { + MEM_freeN(objects); } } -ListBase *get_collider_cache(Scene *scene, Object *self, Group *group) +/* Create effective list of colliders from relations built beforehand. + * Self will be excluded. */ +ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection) { - GroupObject *go; - ListBase *objs= NULL; + ListBase *relations = DEG_get_collision_relations(depsgraph, collection, eModifierType_Collision); + ListBase *cache = NULL; - /* add object in same layer in scene */ - if (group) { - for (go= group->gobject.first; go; go= go->next) - add_collider_cache_object(&objs, go->ob, self, 0); + if (!relations) { + return NULL; } - else { - Scene *sce_iter; - Base *base; - /* add objects in same layer in scene */ - for (SETLOOPER(scene, sce_iter, base)) { - if (!self || (base->lay & self->lay)) - add_collider_cache_object(&objs, base->object, self, 0); + for (CollisionRelation *relation = relations->first; relation; relation = relation->next) { + /* Get evaluated object. */ + Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id); + + if (ob == self) { + continue; + } + + CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); + if (cmd && cmd->bvhtree) { + if (cache == NULL) { + cache = MEM_callocN(sizeof(ListBase), "ColliderCache array"); + } + ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache"); + col->ob = ob; + col->collmd = cmd; + /* make sure collider is properly set up */ + collision_move_object(cmd, 1.0, 0.0); + BLI_addtail(cache, col); } } - return objs; + return cache; } -void free_collider_cache(ListBase **colliders) +void BKE_collider_cache_free(ListBase **colliders) { if (*colliders) { BLI_freelistN(*colliders); @@ -618,25 +1058,49 @@ void free_collider_cache(ListBase **colliders) } } +static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData * clmd, CollisionModifierData *collmd, + CollPair **collisions, int numresult, + BVHTreeOverlap *overlap, bool culling, bool use_normal) +{ + *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array"); + + ColDetectData data = {.clmd = clmd, + .collmd = collmd, + .overlap = overlap, + .collisions = *collisions, + .culling = culling, + .use_normal = use_normal, + .collided = false}; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = true; + BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings); + + return data.collided; +} -static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, - CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap, double dt) +static bool cloth_bvh_selfcollisions_nearcheck(ClothModifierData * clmd, CollPair *collisions, + int numresult, BVHTreeOverlap *overlap) { - int i; + SelfColDetectData data = {.clmd = clmd, + .overlap = overlap, + .collisions = collisions, + .collided = false}; - *collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 4, "collision array" ); // * 4 since cloth_collision_static can return more than 1 collision - *collisions_index = *collisions; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = true; + BLI_task_parallel_range(0, numresult, &data, cloth_selfcollision, &settings); - for ( i = 0; i < numresult; i++ ) { - *collisions_index = cloth_collision((ModifierData *)clmd, (ModifierData *)collmd, - overlap+i, *collisions_index, dt); - } + return data.collided; } -static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index) +static int cloth_bvh_objcollisions_resolve(ClothModifierData * clmd, Object **collobjs, CollPair **collisions, + uint *collision_counts, const uint numcollobj, const float dt) { Cloth *cloth = clmd->clothObject; - int i=0, j = 0, /*numfaces = 0, */ mvert_num = 0; + int i = 0, j = 0, mvert_num = 0; ClothVertex *verts = NULL; int ret = 0; int result = 0; @@ -644,26 +1108,68 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision mvert_num = clmd->clothObject->mvert_num; verts = cloth->verts; - // process all collisions (calculate impulses, TODO: also repulses if distance too short) result = 1; - for ( j = 0; j < 2; j++ ) { /* 5 is just a value that ensures convergence */ + + for (j = 0; j < 2; j++) { result = 0; - if ( collmd->bvhtree ) { - result += cloth_collision_response_static ( clmd, collmd, collisions, collisions_index ); + for (i = 0; i < numcollobj; i++) { + Object *collob= collobjs[i]; + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); - // apply impulses in parallel - if (result) { - for (i = 0; i < mvert_num; i++) { - // calculate "velocities" (just xnew = xold + v; no dt in v) - if (verts[i].impulse_count) { - // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); - VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse); - zero_v3(verts[i].impulse); - verts[i].impulse_count = 0; + if ( collmd->bvhtree ) { + result += cloth_collision_response_static(clmd, collmd, collob, collisions[i], collision_counts[i], dt); + } + } - ret++; - } + /* Apply impulses in parallel. */ + if (result) { + for (i = 0; i < mvert_num; i++) { + // calculate "velocities" (just xnew = xold + v; no dt in v) + if (verts[i].impulse_count) { + VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse); + VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse); + zero_v3(verts[i].impulse); + verts[i].impulse_count = 0; + + ret++; + } + } + } + else { + break; + } + } + return ret; +} + +static int cloth_bvh_selfcollisions_resolve(ClothModifierData * clmd, CollPair *collisions, int collision_count, const float dt) +{ + Cloth *cloth = clmd->clothObject; + int i = 0, j = 0, mvert_num = 0; + ClothVertex *verts = NULL; + int ret = 0; + int result = 0; + + mvert_num = clmd->clothObject->mvert_num; + verts = cloth->verts; + + for (j = 0; j < 2; j++) { + result = 0; + + result += cloth_selfcollision_response_static(clmd, collisions, collision_count, dt); + + /* Apply impulses in parallel. */ + if (result) { + for (i = 0; i < mvert_num; i++) { + if (verts[i].impulse_count) { + // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); + VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse); + VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse); + zero_v3(verts[i].impulse); + verts[i].impulse_count = 0; + + ret++; } } } @@ -675,219 +1181,149 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision return ret; } -// cloth - object collisions -int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt ) +int cloth_bvh_collision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt) { - Cloth *cloth= clmd->clothObject; - BVHTree *cloth_bvh= cloth->bvhtree; - unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ mvert_num = 0, k, l, j; - int rounds = 0; // result counts applied collisions; ic is for debug output; + Cloth *cloth = clmd->clothObject; + BVHTree *cloth_bvh = cloth->bvhtree; + uint i = 0, mvert_num = 0; + int rounds = 0; ClothVertex *verts = NULL; int ret = 0, ret2 = 0; Object **collobjs = NULL; unsigned int numcollobj = 0; + uint *coll_counts_obj = NULL; + BVHTreeOverlap **overlap_obj = NULL; + uint coll_count_self = 0; + BVHTreeOverlap *overlap_self = NULL; if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh==NULL) return 0; verts = cloth->verts; - /* numfaces = cloth->numfaces; */ /* UNUSED */ mvert_num = cloth->mvert_num; - //////////////////////////////////////////////////////////// - // static collisions - //////////////////////////////////////////////////////////// + if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { + bvhtree_update_from_cloth(clmd, false, false); - // update cloth bvh - bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function) - bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function) + collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); - collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); + if (collobjs) { + coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts"); + overlap_obj = MEM_callocN(sizeof(*overlap_obj) * numcollobj, "BVHOverlap"); - if (!collobjs) - return 0; + for (i = 0; i < numcollobj; i++) { + Object *collob = collobjs[i]; + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); - /* move object to position (step) in time */ - for (i = 0; i < numcollobj; i++) { - Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); + if (!collmd->bvhtree) { + continue; + } - if (!collmd->bvhtree) - continue; + /* Move object to position (step) in time. */ + collision_move_object(collmd, step + dt, step); - /* move object to position (step) in time */ - collision_move_object ( collmd, step + dt, step ); + overlap_obj[i] = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL); + } + } } - do { - CollPair **collisions, **collisions_index; + if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) { + bvhtree_update_from_cloth(clmd, false, true); + + overlap_self = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &coll_count_self, NULL, NULL); + } + do { ret2 = 0; - collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair"); - collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair"); + /* Object collisions. */ + if ((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) && collobjs) { + CollPair **collisions; + bool collided = false; - // check all collision objects - for (i = 0; i < numcollobj; i++) { - Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); - BVHTreeOverlap *overlap = NULL; - unsigned int result = 0; + collisions = MEM_callocN(sizeof(CollPair *) * numcollobj, "CollPair"); - if (!collmd->bvhtree) - continue; + for (i = 0; i < numcollobj; i++) { + Object *collob = collobjs[i]; + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); - /* search for overlapping collision pairs */ - overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL); + if (!collmd->bvhtree) { + continue; + } - // go to next object if no overlap is there - if ( result && overlap ) { - /* check if collisions really happen (costly near check) */ - cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i], - &collisions_index[i], result, overlap, dt/(float)clmd->coll_parms->loop_count); + if (coll_counts_obj[i] && overlap_obj[i]) { + collided = cloth_bvh_objcollisions_nearcheck(clmd, collmd, &collisions[i], coll_counts_obj[i], overlap_obj[i], + (collob->pd->flag & PFIELD_CLOTH_USE_CULLING), + (collob->pd->flag & PFIELD_CLOTH_USE_NORMAL)) || collided; + } + } - // resolve nearby collisions - ret += cloth_bvh_objcollisions_resolve ( clmd, collmd, collisions[i], collisions_index[i]); + if (collided) { + ret += cloth_bvh_objcollisions_resolve(clmd, collobjs, collisions, coll_counts_obj, numcollobj, dt); ret2 += ret; } - if ( overlap ) - MEM_freeN ( overlap ); - } - rounds++; + for (i = 0; i < numcollobj; i++) { + MEM_SAFE_FREE(collisions[i]); + } - for (i = 0; i < numcollobj; i++) { - if ( collisions[i] ) MEM_freeN ( collisions[i] ); + MEM_freeN(collisions); } - MEM_freeN(collisions); - MEM_freeN(collisions_index); + /* Self collisions. */ + if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) { + CollPair *collisions = NULL; - //////////////////////////////////////////////////////////// - // update positions - // this is needed for bvh_calc_DOP_hull_moving() [kdop.c] - //////////////////////////////////////////////////////////// + verts = cloth->verts; + mvert_num = cloth->mvert_num; - /* verts come from clmd */ - for (i = 0; i < mvert_num; i++) { - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) { - if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) { - continue; + if (cloth->bvhselftree) { + if (coll_count_self && overlap_self) { + collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * coll_count_self, "collision array"); + + if (cloth_bvh_selfcollisions_nearcheck(clmd, collisions, coll_count_self, overlap_self)) { + ret += cloth_bvh_selfcollisions_resolve(clmd, collisions, coll_count_self, dt); + ret2 += ret; + } } + } - VECADD ( verts[i].tx, verts[i].txold, verts[i].tv ); + MEM_SAFE_FREE(collisions); } - //////////////////////////////////////////////////////////// - - - //////////////////////////////////////////////////////////// - // Test on *simple* selfcollisions - //////////////////////////////////////////////////////////// - if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) { - for (l = 0; l < (unsigned int)clmd->coll_parms->self_loop_count; l++) { - /* TODO: add coll quality rounds again */ - BVHTreeOverlap *overlap = NULL; - unsigned int result = 0; - - // collisions = 1; - verts = cloth->verts; // needed for openMP - - /* numfaces = cloth->numfaces; */ /* UNUSED */ - mvert_num = cloth->mvert_num; - - verts = cloth->verts; - - if ( cloth->bvhselftree ) { - // search for overlapping collision pairs - overlap = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &result, NULL, NULL); - - /* Could be parallelized (using BLI_task)... */ - for ( k = 0; k < result; k++ ) { - float temp[3]; - float length = 0; - float mindistance; - - i = overlap[k].indexA; - j = overlap[k].indexB; - - mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); - - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) { - if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) && - ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) - { - continue; - } - } - - if ((cloth->verts[i].flags & CLOTH_VERT_FLAG_NOSELFCOLL) || - (cloth->verts[j].flags & CLOTH_VERT_FLAG_NOSELFCOLL)) - { - continue; - } - - sub_v3_v3v3(temp, verts[i].tx, verts[j].tx); - - if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; - - if (BLI_edgeset_haskey(cloth->edgeset, i, j)) { - continue; - } - - length = normalize_v3(temp ); - - if ( length < mindistance ) { - float correction = mindistance - length; - - if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) { - mul_v3_fl(temp, -correction); - VECADD ( verts[j].tx, verts[j].tx, temp ); - } - else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) { - mul_v3_fl(temp, correction); - VECADD ( verts[i].tx, verts[i].tx, temp ); - } - else { - mul_v3_fl(temp, correction * -0.5f); - VECADD ( verts[j].tx, verts[j].tx, temp ); - - sub_v3_v3v3(verts[i].tx, verts[i].tx, temp); - } - ret = 1; - ret2 += ret; - } - else { - // check for approximated time collisions - } - } - - if ( overlap ) - MEM_freeN ( overlap ); - } - } - //////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////// - // SELFCOLLISIONS: update velocities - //////////////////////////////////////////////////////////// - if (ret2) { - for (i = 0; i < cloth->mvert_num; i++) { - if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) { - sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold); + /* Apply all collision resolution. */ + if (ret2) { + for (i = 0; i < mvert_num; i++) { + if (clmd->sim_parms->vgroup_mass > 0) { + if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) { + continue; } } + + VECADD(verts[i].tx, verts[i].txold, verts[i].tv); } - //////////////////////////////////////////////////////////// } + + rounds++; } - while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) ); + while (ret2 && (clmd->coll_parms->loop_count > rounds)); - if (collobjs) - MEM_freeN(collobjs); + if (overlap_obj) { + for (i = 0; i < numcollobj; i++) { + MEM_SAFE_FREE(overlap_obj[i]); + } + + MEM_freeN(overlap_obj); + } - return 1|MIN2 ( ret, 1 ); + MEM_SAFE_FREE(coll_counts_obj); + + MEM_SAFE_FREE(overlap_self); + + BKE_collision_objects_free(collobjs); + + return MIN2(ret, 1); } BLI_INLINE void max_v3_v3v3(float r[3], const float a[3], const float b[3]) @@ -913,106 +1349,6 @@ void collision_get_collider_velocity(float vel_old[3], float vel_new[3], Collisi copy_v3_v3(vel_old, vel_new); } -static bool cloth_points_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd, - CollPair *collpair, CollPair *collision_end, float dt) -{ - bool result = false; - float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - pd->pdef_sbdamp); - float inv_dt = 1.0f / dt; - Cloth *cloth1 = clmd->clothObject; - - // float w1, w2; - float u1, u2, u3; - float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3]; - float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree ); - - for ( ; collpair != collision_end; collpair++ ) { - float margin_distance = (float)(collpair->distance - (double)epsilon2); - float impulse[3]; - float mag_v_rel; - - if (margin_distance > 0.0f) - continue; - - zero_v3(impulse); - - /* only handle static collisions here */ - if ( collpair->flag & COLLISION_IN_FUTURE ) - continue; - - /* compute barycentric coordinates for both collision points */ - // w1 = 1.0f - collpair->time; - // w2 = collpair->time; - - /* was: txold */ - collision_compute_barycentric ( collpair->pb, - collmd->current_x[collpair->bp1].co, - collmd->current_x[collpair->bp2].co, - collmd->current_x[collpair->bp3].co, - &u1, &u2, &u3 ); - - /* Calculate relative velocity */ - copy_v3_v3(v1, cloth1->verts[collpair->ap1].tv); - - collision_interpolateOnTriangle ( v2_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 ); - /* XXX assume constant velocity of the collider for now */ - copy_v3_v3(v2_old, v2_new); - - sub_v3_v3v3(v_rel_old, v1, v2_old); - sub_v3_v3v3(v_rel_new, v1, v2_new); - - /* normal component of the relative velocity */ - mag_v_rel = dot_v3v3(v_rel_old, collpair->normal); - - /**** DEBUG ****/ - BKE_sim_debug_data_add_dot(collpair->pa, 0.9, 0.2, 0.2, "collision", 833, collpair->face1, collpair->face2); - BKE_sim_debug_data_add_dot(collpair->pb, 0.2, 0.9, 0.2, "collision", 834, collpair->face1, collpair->face2); - BKE_sim_debug_data_add_line(collpair->pa, collpair->pb, 0.8, 0.8, 0.8, "collision", 835, collpair->face1, collpair->face2); - /********/ - - if (mag_v_rel < -ALMOST_ZERO) { - float v_nor_old, v_nor_new; - float v_tan_old[3], v_tan_new[3]; - float bounce, repulse; - - /* Collision response based on - * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005) - * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf - */ - - v_nor_old = mag_v_rel; - v_nor_new = dot_v3v3(v_rel_new, collpair->normal); - - madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old); - madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new); - - repulse = -margin_distance * inv_dt + dot_v3v3(v1, collpair->normal); - - if (margin_distance < -epsilon2) { - bounce = -v_nor_new + v_nor_old * restitution; - mul_v3_v3fl(impulse, collpair->normal, max_ff(repulse, bounce)); - } - else { - bounce = 0.0f; - mul_v3_v3fl(impulse, collpair->normal, repulse); - } - cloth1->verts[collpair->ap1].impulse_count++; - - result = true; - } - - if (result) { - int i = 0; - - for (i = 0; i < 3; i++) { - if (cloth1->verts[collpair->ap1].impulse_count > 0 && fabsf(cloth1->verts[collpair->ap1].impulse[i]) < fabsf(impulse[i])) - cloth1->verts[collpair->ap1].impulse[i] = impulse[i]; - } - } - } - return result; -} - BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float r_nor[3], float *r_lambda, float r_w[3]) { @@ -1024,60 +1360,16 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float cross_v3_v3v3(r_nor, edge1, edge2); normalize_v3(r_nor); + sub_v3_v3v3(v0p2, p2, v0); nor_v0p2 = dot_v3v3(v0p2, r_nor); madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2); interp_weights_tri_v3(r_w, v0, v1, v2, p2face); sub_v3_v3v3(p1p2, p2, p1); - sub_v3_v3v3(v0p2, p2, v0); nor_p1p2 = dot_v3v3(p1p2, r_nor); *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f); return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f; - -#if 0 /* XXX this method uses the intersection point, but is broken and doesn't work well in general */ - float p[3], vec1[3], line[3], edge1[3], edge2[3], q[3]; - float a, f, u, v; - - sub_v3_v3v3(edge1, v1, v0); - sub_v3_v3v3(edge2, v2, v0); - sub_v3_v3v3(line, p2, p1); - - cross_v3_v3v3(p, line, edge2); - a = dot_v3v3(edge1, p); - if (a == 0.0f) return 0; - f = 1.0f / a; - - sub_v3_v3v3(vec1, p1, v0); - - u = f * dot_v3v3(vec1, p); - if ((u < 0.0f) || (u > 1.0f)) - return false; - - cross_v3_v3v3(q, vec1, edge1); - - v = f * dot_v3v3(line, q); - if ((v < 0.0f) || ((u + v) > 1.0f)) - return false; - - *r_lambda = f * dot_v3v3(edge2, q); - /* don't care about 0..1 lambda range here */ -#if 0 - if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) { - return 0; - } -#endif - - r_w[0] = 1.0f - u - v; - r_w[1] = u; - r_w[2] = v; - r_w[3] = 0.0f; - - cross_v3_v3v3(r_nor, edge1, edge2); - normalize_v3(r_nor); - - return true; -#endif } static CollPair *cloth_point_collpair( @@ -1166,162 +1458,7 @@ static void cloth_points_objcollisions_nearcheck( } } -static int cloth_points_objcollisions_resolve( - ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd, - CollPair *collisions, CollPair *collisions_index, float dt) -{ - Cloth *cloth = clmd->clothObject; - int i = 0, mvert_num = clmd->clothObject->mvert_num; - ClothVertex *verts = cloth->verts; - int ret = 0; - - // process all collisions - if ( collmd->bvhtree ) { - bool result = cloth_points_collision_response_static(clmd, collmd, pd, collisions, collisions_index, dt); - - // apply impulses in parallel - if (result) { - for (i = 0; i < mvert_num; i++) { - // calculate "velocities" (just xnew = xold + v; no dt in v) - if (verts[i].impulse_count) { - // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); - VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse); - zero_v3(verts[i].impulse); - verts[i].impulse_count = 0; - - ret++; - } - } - } - } - - return ret; -} - -// cloth - object collisions -int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt) -{ - Cloth *cloth= clmd->clothObject; - BVHTree *cloth_bvh; - int rounds = 0; // result counts applied collisions; ic is for debug output; - float round_dt = dt / (float)clmd->coll_parms->loop_count; - unsigned int i = 0, mvert_num = 0; - ClothVertex *verts = NULL; - int ret = 0, ret2 = 0; - Object **collobjs = NULL; - unsigned int numcollobj = 0; - - verts = cloth->verts; - mvert_num = cloth->mvert_num; - - //////////////////////////////////////////////////////////// - // static collisions - //////////////////////////////////////////////////////////// - - // create temporary cloth points bvh - cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6); - /* fill tree */ - for (i = 0; i < mvert_num; i++) { - float co[2][3]; - - copy_v3_v3(co[0], verts[i].x); - copy_v3_v3(co[1], verts[i].tx); - - BLI_bvhtree_insert(cloth_bvh, i, co[0], 2); - } - /* balance tree */ - BLI_bvhtree_balance(cloth_bvh); - - collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); - if (!collobjs) - return 0; - - /* move object to position (step) in time */ - for (i = 0; i < numcollobj; i++) { - Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); - if (!collmd->bvhtree) - continue; - - /* move object to position (step) in time */ - collision_move_object ( collmd, step + dt, step ); - } - - do { - CollPair **collisions, **collisions_index; - - ret2 = 0; - - collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair"); - collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair"); - - // check all collision objects - for (i = 0; i < numcollobj; i++) { - Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); - BVHTreeOverlap *overlap = NULL; - unsigned int result = 0; - float epsilon; - - if (!collmd->bvhtree) - continue; - - /* search for overlapping collision pairs */ - overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL); - epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree); - - // go to next object if no overlap is there - if (result && overlap) { - /* check if collisions really happen (costly near check) */ - cloth_points_objcollisions_nearcheck(clmd, collmd, &collisions[i], &collisions_index[i], - result, overlap, epsilon, round_dt); - - // resolve nearby collisions - ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], round_dt); - ret2 += ret; - } - - if (overlap) - MEM_freeN ( overlap ); - } - rounds++; - - for (i = 0; i < numcollobj; i++) { - if (collisions[i]) - MEM_freeN(collisions[i]); - } - - MEM_freeN(collisions); - MEM_freeN(collisions_index); - - //////////////////////////////////////////////////////////// - // update positions - // this is needed for bvh_calc_DOP_hull_moving() [kdop.c] - //////////////////////////////////////////////////////////// - - // verts come from clmd - for (i = 0; i < mvert_num; i++) { - if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) { - if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) { - continue; - } - } - - VECADD ( verts[i].tx, verts[i].txold, verts[i].tv ); - } - //////////////////////////////////////////////////////////// - } - while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) ); - - if (collobjs) - MEM_freeN(collobjs); - - BLI_bvhtree_free(cloth_bvh); - - return 1|MIN2 ( ret, 1 ); -} - -void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, float dt, +void cloth_find_point_contacts(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt, ColliderContacts **r_collider_contacts, int *r_totcolliders) { Cloth *cloth= clmd->clothObject; @@ -1342,7 +1479,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, //////////////////////////////////////////////////////////// /* Check we do have collision objects to test against, before doing anything else. */ - collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); + collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); if (!collobjs) { *r_collider_contacts = NULL; *r_totcolliders = 0; @@ -1350,7 +1487,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, } // create temporary cloth points bvh - cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6); + cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6); /* fill tree */ for (i = 0; i < mvert_num; i++) { float co[6]; @@ -1414,8 +1551,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, MEM_freeN(overlap); } - if (collobjs) - MEM_freeN(collobjs); + BKE_collision_objects_free(collobjs); BLI_bvhtree_free(cloth_bvh); @@ -1426,7 +1562,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, // verts come from clmd for (i = 0; i < mvert_num; i++) { - if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { + if (clmd->sim_parms->vgroup_mass > 0) { if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) { continue; } diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c index f72d4df725a..38631c76009 100644 --- a/source/blender/blenkernel/intern/colorband.c +++ b/source/blender/blenkernel/intern/colorband.c @@ -208,7 +208,7 @@ static void colorband_init_from_table_rgba_resample( } while ((carr_len > 1 && !BLI_heap_is_empty(heap)) && - ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x))) + ((carr_len >= MAXCOLORBAND) || (BLI_heap_top_value(heap) <= eps_2x))) { c = BLI_heap_pop_min(heap); struct ColorResampleElem *c_next = c->next, *c_prev = c->prev; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index ff4795afe87..108e188fe92 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -282,6 +282,7 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) case CURVE_PRESET_MID9: cuma->totpoint = 9; break; case CURVE_PRESET_ROUND: cuma->totpoint = 4; break; case CURVE_PRESET_ROOT: cuma->totpoint = 4; break; + case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break; } cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points"); @@ -352,6 +353,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) cuma->curve[3].x = 1; cuma->curve[3].y = 0; break; + case CURVE_PRESET_GAUSS: + cuma->curve[0].x = 0; + cuma->curve[0].y = 0.025f; + cuma->curve[1].x = 0.16f; + cuma->curve[1].y = 0.135f; + cuma->curve[2].x = 0.298f; + cuma->curve[2].y = 0.36f; + + cuma->curve[3].x = 0.50f; + cuma->curve[3].y = 1.0f; + + cuma->curve[4].x = 0.70f; + cuma->curve[4].y = 0.36f; + cuma->curve[5].x = 0.84f; + cuma->curve[5].y = 0.135f; + cuma->curve[6].x = 1.0f; + cuma->curve[6].y = 0.025f; + break; } /* mirror curve in x direction to have positive slope @@ -919,6 +938,22 @@ void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const vecout[2] = curvemap_evaluateF(&cumap->cm[2], curvemap_evaluateF(&cumap->cm[3], vecin[2])); } +static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap, float vecout[3], const float vecin[3], + const int channel_offset[3]) +{ + const float v0in = vecin[channel_offset[0]]; + const float v1in = vecin[channel_offset[1]]; + const float v2in = vecin[channel_offset[2]]; + + const float v0 = curvemap_evaluateF(&cumap->cm[channel_offset[0]], v0in); + const float v2 = curvemap_evaluateF(&cumap->cm[channel_offset[2]], v2in); + const float v1 = v2 + ((v0 - v2) * (v1in - v2in) / (v0in - v2in)); + + vecout[channel_offset[0]] = v0; + vecout[channel_offset[1]] = v1; + vecout[channel_offset[2]] = v2; +} + /** same as #curvemapping_evaluate_premulRGBF * but black/bwmul are passed as args for the compositor * where they can change per pixel. @@ -928,20 +963,73 @@ void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const * \param black Use instead of cumap->black * \param bwmul Use instead of cumap->bwmul */ -void curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap, float vecout[3], const float vecin[3], - const float black[3], const float bwmul[3]) +void curvemapping_evaluate_premulRGBF_ex( + const CurveMapping *cumap, float vecout[3], const float vecin[3], + const float black[3], const float bwmul[3]) { - vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - black[0]) * bwmul[0]); - vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - black[1]) * bwmul[1]); - vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - black[2]) * bwmul[2]); + const float r = (vecin[0] - black[0]) * bwmul[0]; + const float g = (vecin[1] - black[1]) * bwmul[1]; + const float b = (vecin[2] - black[2]) * bwmul[2]; + + switch (cumap->tone) { + default: + case CURVE_TONE_STANDARD: + { + vecout[0] = curvemap_evaluateF(&cumap->cm[0], r); + vecout[1] = curvemap_evaluateF(&cumap->cm[1], g); + vecout[2] = curvemap_evaluateF(&cumap->cm[2], b); + break; + } + case CURVE_TONE_FILMLIKE: + { + if (r >= g) { + if (g > b) { + /* Case 1: r >= g > b */ + const int shuffeled_channels[] = {0, 1, 2}; + curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels); + } + else if (b > r) { + /* Case 2: b > r >= g */ + const int shuffeled_channels[] = {2, 0, 1}; + curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels); + } + else if (b > g) { + /* Case 3: r >= b > g */ + const int shuffeled_channels[] = {0, 2, 1}; + curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels); + } + else { + /* Case 4: r >= g == b */ + copy_v2_fl2(vecout, curvemap_evaluateF(&cumap->cm[0], r), curvemap_evaluateF(&cumap->cm[1], g)); + vecout[2] = vecout[1]; + } + } + else { + if (r >= b) { + /* Case 5: g > r >= b */ + const int shuffeled_channels[] = {1, 0, 2}; + curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels); + } + else if (b > g) { + /* Case 6: b > g > r */ + const int shuffeled_channels[] = {2, 1, 0}; + curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels); + } + else { + /* Case 7: g >= b > r */ + const int shuffeled_channels[] = {1, 2, 0}; + curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels); + } + } + break; + } + } } /* RGB with black/white points and premult. tables are checked */ void curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3]) { - vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - cumap->black[0]) * cumap->bwmul[0]); - vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - cumap->black[1]) * cumap->bwmul[1]); - vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - cumap->black[2]) * cumap->bwmul[2]); + curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul); } /* same as above, byte version */ @@ -1401,17 +1489,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * scopes_update_cb, &settings); - /* test for nicer distribution even - non standard, leave it out for a while */ -#if 0 - for (a = 0; a < 256; a++) { - bin_lum[a] = sqrt (bin_lum[a]); - bin_r[a] = sqrt(bin_r[a]); - bin_g[a] = sqrt(bin_g[a]); - bin_b[a] = sqrt(bin_b[a]); - bin_a[a] = sqrt(bin_a[a]); - } -#endif - /* convert hist data to float (proportional to max count) */ nl = na = nr = nb = ng = 0; for (a = 0; a < 256; a++) { diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 66147c44352..e16117745c9 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -52,6 +52,7 @@ #include "DNA_object_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_lattice_types.h" @@ -68,22 +69,24 @@ #include "BKE_camera.h" #include "BKE_constraint.h" #include "BKE_curve.h" -#include "BKE_displist.h" #include "BKE_deform.h" -#include "BKE_DerivedMesh.h" /* for geometry targets */ -#include "BKE_cdderivedmesh.h" /* for geometry targets */ -#include "BKE_object.h" +#include "BKE_displist.h" +#include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_library.h" #include "BKE_idprop.h" -#include "BKE_shrinkwrap.h" -#include "BKE_editmesh.h" +#include "BKE_library.h" +#include "BKE_mesh_runtime.h" +#include "BKE_movieclip.h" +#include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_shrinkwrap.h" #include "BKE_tracking.h" -#include "BKE_movieclip.h" #include "BIK_api.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #ifdef WITH_PYTHON # include "BPY_extern.h" #endif @@ -98,17 +101,14 @@ /* Constraint Target Macros */ #define VALID_CONS_TARGET(ct) ((ct) && (ct->tar)) -/* Workaround for cyclic depenndnecy with curves. - * In such case curve_cache might not be ready yet, - */ -#define CYCLIC_DEPENDENCY_WORKAROUND - /* ************************ Constraints - General Utilities *************************** */ /* These functions here don't act on any specific constraints, and are therefore should/will * not require any of the special function-pointers afforded by the relevant constraint * type-info structs. */ +static void damptrack_do_transform(float matrix[4][4], const float tarvec[3], int track_axis); + /* -------------- Naming -------------- */ /* Find the first available, non-duplicate name for a given constraint */ @@ -121,7 +121,7 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list) /* package an object/bone for use in constraint evaluation */ /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ -bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype) +bConstraintOb *BKE_constraints_make_evalob(Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype) { bConstraintOb *cob; @@ -130,6 +130,7 @@ bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subda /* for system time, part of deglobalization, code nicer later with local time (ton) */ cob->scene = scene; + cob->depsgraph = depsgraph; /* based on type of available data */ switch (datatype) { @@ -392,99 +393,104 @@ void BKE_constraint_mat_convertspace( /* function that sets the given matrix based on given vertex group in mesh */ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4]) { - DerivedMesh *dm = NULL; + /* when not in EditMode, use the 'final' evaluated mesh, depsgraph + * ensures we build with CD_MDEFORMVERT layer + */ + Mesh *me_eval = ob->runtime.mesh_eval; BMEditMesh *em = BKE_editmesh_from_object(ob); - float vec[3] = {0.0f, 0.0f, 0.0f}; - float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3]; + float plane[3]; float imat[3][3], tmat[3][3]; const int defgroup = defgroup_name_index(ob, substring); - short freeDM = 0; /* initialize target matrix using target matrix */ copy_m4_m4(mat, ob->obmat); /* get index of vertex group */ - if (defgroup == -1) return; - - /* get DerivedMesh */ - if (em) { - /* target is in editmode, so get a special derived mesh */ - dm = CDDM_from_editbmesh(em, false, false); - freeDM = 1; - } - else { - /* when not in EditMode, use the 'final' derived mesh, depsgraph - * ensures we build with CD_MDEFORMVERT layer - */ - dm = (DerivedMesh *)ob->derivedFinal; + if (defgroup == -1) { + return; } - /* only continue if there's a valid DerivedMesh */ - if (dm) { - MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); - int numVerts = dm->getNumVerts(dm); - int i; - float co[3], nor[3]; + float vec[3] = {0.0f, 0.0f, 0.0f}; + float normal[3] = {0.0f, 0.0f, 0.0f}; + float weightsum = 0.0f; + if (me_eval) { + MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT); + int numVerts = me_eval->totvert; /* check that dvert is a valid pointers (just in case) */ if (dvert) { MDeformVert *dv = dvert; - float weightsum = 0.0f; + MVert *mv = me_eval->mvert; /* get the average of all verts with that are in the vertex-group */ - for (i = 0; i < numVerts; i++, dv++) { + for (int i = 0; i < numVerts; i++, dv++, mv++) { MDeformWeight *dw = defvert_find_index(dv, defgroup); if (dw && dw->weight > 0.0f) { - dm->getVertCo(dm, i, co); - dm->getVertNo(dm, i, nor); - madd_v3_v3fl(vec, co, dw->weight); + float nor[3]; + normal_short_to_float_v3(nor, mv->no); + madd_v3_v3fl(vec, mv->co, dw->weight); madd_v3_v3fl(normal, nor, dw->weight); weightsum += dw->weight; } } + } + } + else if (em) { + if (CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) { + BMVert *v; + BMIter iter; - /* calculate averages of normal and coordinates */ - if (weightsum > 0) { - mul_v3_fl(vec, 1.0f / weightsum); - mul_v3_fl(normal, 1.0f / weightsum); - } - + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, v->head.data, CD_MDEFORMVERT); + MDeformWeight *dw = defvert_find_index(dv, defgroup); - /* derive the rotation from the average normal: - * - code taken from transform_manipulator.c, - * calc_manipulator_stats, V3D_MANIP_NORMAL case - */ - /* we need the transpose of the inverse for a normal... */ - copy_m3_m4(imat, ob->obmat); + if (dw && dw->weight > 0.0f) { + madd_v3_v3fl(vec, v->co, dw->weight); + madd_v3_v3fl(normal, v->no, dw->weight); + weightsum += dw->weight; + } + } + } + } + else { + /* No valid edit or evaluated mesh, just abort. */ + return; + } - invert_m3_m3(tmat, imat); - transpose_m3(tmat); - mul_m3_v3(tmat, normal); + /* calculate averages of normal and coordinates */ + if (weightsum > 0) { + mul_v3_fl(vec, 1.0f / weightsum); + mul_v3_fl(normal, 1.0f / weightsum); + } - normalize_v3(normal); - copy_v3_v3(plane, tmat[1]); + /* derive the rotation from the average normal: + * - code taken from transform_gizmo.c, + * calc_gizmo_stats, V3D_MANIP_NORMAL case + */ + /* we need the transpose of the inverse for a normal... */ + copy_m3_m4(imat, ob->obmat); - cross_v3_v3v3(mat[0], normal, plane); - if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) { - copy_v3_v3(plane, tmat[0]); - cross_v3_v3v3(mat[0], normal, plane); - } + invert_m3_m3(tmat, imat); + transpose_m3(tmat); + mul_m3_v3(tmat, normal); - copy_v3_v3(mat[2], normal); - cross_v3_v3v3(mat[1], mat[2], mat[0]); + normalize_v3(normal); + copy_v3_v3(plane, tmat[1]); - normalize_m4(mat); + cross_v3_v3v3(mat[0], normal, plane); + if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) { + copy_v3_v3(plane, tmat[0]); + cross_v3_v3v3(mat[0], normal, plane); + } + copy_v3_v3(mat[2], normal); + cross_v3_v3v3(mat[1], mat[2], mat[0]); - /* apply the average coordinate as the new location */ - mul_v3_m4v3(mat[3], ob->obmat, vec); - } - } + normalize_m4(mat); - /* free temporary DerivedMesh created (in EditMode case) */ - if (dm && freeDM) - dm->release(dm); + /* apply the average coordinate as the new location */ + mul_v3_m4v3(mat[3], ob->obmat, vec); } /* function that sets the given matrix based on given vertex group in lattice */ @@ -492,7 +498,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m { Lattice *lt = (Lattice *)ob->data; - DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL; const float *co = dl ? dl->verts : NULL; BPoint *bp = lt->def; @@ -575,18 +581,21 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m * PoseChannel by the Armature Object's Matrix to get a worldspace * matrix. */ - if (headtail < 0.000001f) { + bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE); + bool full_bbone = (flag & CONSTRAINT_BBONE_SHAPE_FULL) != 0; + + if (headtail < 0.000001f && !(is_bbone && full_bbone)) { /* skip length interpolation if set to head */ mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat); } - else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) { + else if (is_bbone) { /* use point along bbone */ Mat4 bbone[MAX_BBONE_SUBDIV]; float tempmat[4][4]; float loc[3], fac; /* get bbone segments */ - b_bone_spline_setup(pchan, 0, bbone); + b_bone_spline_setup(pchan, false, bbone); /* figure out which segment(s) the headtail value falls in */ fac = (float)pchan->bone->segments * headtail; @@ -625,8 +634,18 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m mul_v3_m4v3(loc, pchan->pose_mat, pt); } + /* apply full transformation of the segment if requested */ + if (full_bbone) { + int index = floorf(fac); + CLAMP(index, 0, pchan->bone->segments - 1); + + mul_m4_m4m4(tempmat, pchan->pose_mat, bbone[index].mat); + } + else { + copy_m4_m4(tempmat, pchan->pose_mat); + } + /* use interpolated distance for subtarget */ - copy_m4_m4(tempmat, pchan->pose_mat); copy_v3_v3(tempmat[3], loc); mul_m4_m4m4(mat, ob->obmat, tempmat); @@ -689,7 +708,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = { /* This function should be used for the get_target_matrix member of all * constraints that are not picky about what happens to their target matrix. */ -static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime)) +static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime)) { if (VALID_CONS_TARGET(ct)) constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail); @@ -697,6 +716,16 @@ static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bCo unit_m4(ct->matrix); } +/* This is a variant that extracts full transformation from B-Bone segments. + */ +static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime)) +{ + if (VALID_CONS_TARGET(ct)) + constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag | CONSTRAINT_BBONE_SHAPE_FULL, con->headtail); + else if (ct) + unit_m4(ct->matrix); +} + /* This following macro should be used for all standard single-target *_get_tars functions * to save typing and reduce maintenance woes. * (Hopefully all compilers will be happy with the lines with just a space on them. Those are @@ -1158,7 +1187,7 @@ static void kinematic_flush_tars(bConstraint *con, ListBase *list, bool no_copy) } } -static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { bKinematicConstraint *data = con->data; @@ -1245,7 +1274,9 @@ static void followpath_flush_tars(bConstraint *con, ListBase *list, bool no_copy } } -static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *con, bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, float UNUSED(ctime)) { bFollowPathConstraint *data = con->data; @@ -1260,13 +1291,7 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra * currently for paths to work it needs to go through the bevlist/displist system (ton) */ -#ifdef CYCLIC_DEPENDENCY_WORKAROUND - if (ct->tar->curve_cache == NULL) { - BKE_displist_make_curveTypes(cob->scene, ct->tar, false); - } -#endif - - if (ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) { + if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && ct->tar->runtime.curve_cache->path->data) { float quat[4]; if ((data->followflag & FOLLOWPATH_STATIC) == 0) { /* animated position along curve depending on time */ @@ -1303,21 +1328,7 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra unit_m4(totmat); if (data->followflag & FOLLOWPATH_FOLLOW) { -#if 0 - float x1, q[4]; - vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag); - - normalize_v3(dir); - q[0] = cosf(0.5 * vec[3]); - x1 = sinf(0.5 * vec[3]); - q[1] = -x1 * dir[0]; - q[2] = -x1 * dir[1]; - q[3] = -x1 * dir[2]; - mul_qt_qtqt(quat, q, quat); -#else quat_apply_track(quat, data->trackflag, data->upflag); -#endif - quat_to_mat4(totmat, quat); } @@ -1760,7 +1771,7 @@ static void sizelike_new_data(void *cdata) { bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata; - data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z; + data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY; } static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -1808,29 +1819,28 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta mat4_to_size(size, ct->matrix); mat4_to_size(obsize, cob->matrix); - if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) { - if (data->flag & SIZELIKE_OFFSET) { - size[0] += (obsize[0] - 1.0f); - mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); + if (data->flag & SIZELIKE_OFFSET) { + /* Scale is a multiplicative quantity, so adding it makes no sense. + * However, the additive mode has to stay for backward compatibility. */ + if (data->flag & SIZELIKE_MULTIPLY) { + /* size[i] *= obsize[i] */ + mul_v3_v3(size, obsize); + } + else { + /* 2.7 compatibility mode: size[i] += (obsize[i] - 1.0f) */ + add_v3_v3(size, obsize); + add_v3_fl(size, -1.0f); } - else - mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); + } + + if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) { + mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); } if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) { - if (data->flag & SIZELIKE_OFFSET) { - size[1] += (obsize[1] - 1.0f); - mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); - } - else - mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); + mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); } if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) { - if (data->flag & SIZELIKE_OFFSET) { - size[2] += (obsize[2] - 1.0f); - mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); - } - else - mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); + mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); } } } @@ -1907,7 +1917,7 @@ static bConstraintTypeInfo CTI_TRANSLIKE = { NULL, /* new data */ translike_get_tars, /* get constraint targets */ translike_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ + default_get_tarmat_full_bbone, /* get target matrix */ translike_evaluate /* evaluate */ }; @@ -2028,21 +2038,19 @@ static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userd } /* Whether this approach is maintained remains to be seen (aligorith) */ -static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *con, bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, float UNUSED(ctime)) { #ifdef WITH_PYTHON bPythonConstraint *data = con->data; #endif if (VALID_CONS_TARGET(ct)) { -#ifdef CYCLIC_DEPENDENCY_WORKAROUND - /* special exception for curves - depsgraph issues */ - if (ct->tar->type == OB_CURVE) { - if (ct->tar->curve_cache == NULL) { - BKE_displist_make_curveTypes(cob->scene, ct->tar, false); - } + if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) { + unit_m4(ct->matrix); + return; } -#endif /* firstly calculate the matrix the normal way, then let the py-function override * this matrix if it needs to do so @@ -2070,15 +2078,6 @@ static void pycon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targe /* only evaluate in python if we're allowed to do so */ if ((G.f & G_SCRIPT_AUTOEXEC) == 0) return; -/* currently removed, until I this can be re-implemented for multiple targets */ -#if 0 - /* Firstly, run the 'driver' function which has direct access to the objects involved - * Technically, this is potentially dangerous as users may abuse this and cause dependency-problems, - * but it also allows certain 'clever' rigging hacks to work. - */ - BPY_pyconstraint_driver(data, cob, targets); -#endif - /* Now, run the actual 'constraint' function, which should only access the matrices */ BPY_pyconstraint_exec(data, cob, targets); #endif /* WITH_PYTHON */ @@ -2099,6 +2098,206 @@ static bConstraintTypeInfo CTI_PYTHON = { pycon_evaluate /* evaluate */ }; +/* ----------- Armature Constraint -------------- */ + +static void armdef_free(bConstraint *con) +{ + bArmatureConstraint *data = con->data; + + /* Target list. */ + BLI_freelistN(&data->targets); +} + +static void armdef_copy(bConstraint *con, bConstraint *srccon) +{ + bArmatureConstraint *pcon = (bArmatureConstraint *)con->data; + bArmatureConstraint *opcon = (bArmatureConstraint *)srccon->data; + + BLI_duplicatelist(&pcon->targets, &opcon->targets); +} + +static int armdef_get_tars(bConstraint *con, ListBase *list) +{ + if (con && list) { + bArmatureConstraint *data = con->data; + + *list = data->targets; + + return BLI_listbase_count(&data->targets); + } + + return 0; +} + +static void armdef_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) +{ + bArmatureConstraint *data = con->data; + bConstraintTarget *ct; + + /* Target list. */ + for (ct = data->targets.first; ct; ct = ct->next) { + func(con, (ID **)&ct->tar, false, userdata); + } +} + +/* Compute the world space pose matrix of the target bone. */ +static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, float UNUSED(ctime)) +{ + if (ct != NULL) { + if (ct->tar && ct->tar->type == OB_ARMATURE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); + + if (pchan != NULL) { + mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat); + return; + } + } + + unit_m4(ct->matrix); + } +} + +/* Compute and accumulate transformation for a single target bone. */ +static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, const float wco[3], bool force_envelope, float *r_totweight, float r_sum_mat[4][4], DualQuat *r_sum_dq) +{ + float mat[4][4], iobmat[4][4], iamat[4][4], basemat[4][4], co[3]; + Bone *bone = pchan->bone; + float weight = ct->weight; + + /* Our object's location in target pose space. */ + invert_m4_m4(iobmat, ct->tar->obmat); + mul_v3_m4v3(co, iobmat, wco); + + /* Inverted rest pose matrix: bone->chan_mat may not be final yet. */ + invert_m4_m4(iamat, bone->arm_mat); + + /* Multiply by the envelope weight when appropriate. */ + if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) { + weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail, + bone->rad_head, bone->rad_tail, bone->dist); + } + + /* Find the correct bone transform matrix in world space. */ + if (bone->segments > 1) { + /* The target is a B-Bone: + * FIRST: find the segment (see b_bone_deform in armature.c) + * Need to transform co back to bonespace, only need y. */ + float y = iamat[0][1] * co[0] + iamat[1][1] * co[1] + iamat[2][1] * co[2] + iamat[3][1]; + + float segment = bone->length / ((float)bone->segments); + int a = (int)(y / segment); + + CLAMP(a, 0, bone->segments - 1); + + /* SECOND: compute the matrix (see pchan_b_bone_defmats in armature.c) */ + Mat4 b_bone[MAX_BBONE_SUBDIV], b_bone_rest[MAX_BBONE_SUBDIV]; + float irmat[4][4]; + + b_bone_spline_setup(pchan, false, b_bone); + b_bone_spline_setup(pchan, true, b_bone_rest); + + invert_m4_m4(irmat, b_bone_rest[a].mat); + mul_m4_series(mat, ct->matrix, b_bone[a].mat, irmat, iamat, iobmat); + } + else { + /* Simple bone. */ + mul_m4_series(mat, ct->matrix, iamat, iobmat); + } + + /* Accumulate the transformation. */ + *r_totweight += weight; + + if (r_sum_dq != NULL) { + DualQuat tmpdq; + + mul_m4_series(basemat, ct->tar->obmat, bone->arm_mat, iobmat); + + mat4_to_dquat(&tmpdq, basemat, mat); + add_weighted_dq_dq(r_sum_dq, &tmpdq, weight); + } + else { + mul_m4_fl(mat, weight); + add_m4_m4m4(r_sum_mat, r_sum_mat, mat); + } +} + +static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) +{ + bArmatureConstraint *data = con->data; + + float sum_mat[4][4], input_co[3]; + DualQuat sum_dq; + float weight = 0.0f; + + /* Prepare for blending. */ + zero_m4(sum_mat); + memset(&sum_dq, 0, sizeof(sum_dq)); + + DualQuat *pdq = (data->flag & CONSTRAINT_ARMATURE_QUATERNION) ? &sum_dq : NULL; + bool use_envelopes = (data->flag & CONSTRAINT_ARMATURE_ENVELOPE) != 0; + + if (cob->pchan && cob->pchan->bone && !(data->flag & CONSTRAINT_ARMATURE_CUR_LOCATION)) { + /* For constraints on bones, use the rest position to bind b-bone segments + * and envelopes, to allow safely changing the bone location as if parented. */ + copy_v3_v3(input_co, cob->pchan->bone->arm_head); + mul_m4_v3(cob->ob->obmat, input_co); + } + else { + copy_v3_v3(input_co, cob->matrix[3]); + } + + /* Process all targets. */ + for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) { + if (ct->weight <= 0.0f) { + continue; + } + + /* Lookup the bone and abort if failed. */ + if (!VALID_CONS_TARGET(ct) || ct->tar->type != OB_ARMATURE) { + return; + } + + bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget); + + if (pchan == NULL || pchan->bone == NULL) { + return; + } + + armdef_accumulate_bone(ct, pchan, input_co, use_envelopes, &weight, sum_mat, pdq); + } + + /* Compute the final transform. */ + if (weight > 0.0f) { + if (pdq != NULL) { + normalize_dq(pdq, weight); + dquat_to_mat4(sum_mat, pdq); + } + else { + mul_m4_fl(sum_mat, 1.0f / weight); + } + + /* Apply the transform to the result matrix. */ + mul_m4_m4m4(cob->matrix, sum_mat, cob->matrix); + } +} + +static bConstraintTypeInfo CTI_ARMATURE = { + CONSTRAINT_TYPE_ARMATURE, /* type */ + sizeof(bArmatureConstraint), /* size */ + "Armature", /* name */ + "bArmatureConstraint", /* struct name */ + armdef_free, /* free data */ + armdef_id_looper, /* id looper */ + armdef_copy, /* copy data */ + NULL, /* new data */ + armdef_get_tars, /* get constraint targets */ + NULL, /* flush constraint targets */ + armdef_get_tarmat, /* get target matrix */ + armdef_evaluate /* evaluate */ +}; + /* -------- Action Constraint ----------- */ static void actcon_new_data(void *cdata) @@ -2146,7 +2345,7 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy) } } -static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { bActionConstraint *data = con->data; @@ -3041,66 +3240,6 @@ static bConstraintTypeInfo CTI_MINMAX = { minmax_evaluate /* evaluate */ }; -/* ------- RigidBody Joint ---------- */ - -static void rbj_new_data(void *cdata) -{ - bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)cdata; - - /* removed code which set target of this constraint */ - data->type = 1; -} - -static void rbj_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) -{ - bRigidBodyJointConstraint *data = con->data; - - /* target only */ - func(con, (ID **)&data->tar, false, userdata); - func(con, (ID **)&data->child, false, userdata); -} - -static int rbj_get_tars(bConstraint *con, ListBase *list) -{ - if (con && list) { - bRigidBodyJointConstraint *data = con->data; - bConstraintTarget *ct; - - /* standard target-getting macro for single-target constraints without subtargets */ - SINGLETARGETNS_GET_TARS(con, data->tar, ct, list); - - return 1; - } - - return 0; -} - -static void rbj_flush_tars(bConstraint *con, ListBase *list, bool no_copy) -{ - if (con && list) { - bRigidBodyJointConstraint *data = con->data; - bConstraintTarget *ct = list->first; - - /* the following macro is used for all standard single-target constraints */ - SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy); - } -} - -static bConstraintTypeInfo CTI_RIGIDBODYJOINT = { - CONSTRAINT_TYPE_RIGIDBODYJOINT, /* type */ - sizeof(bRigidBodyJointConstraint), /* size */ - "Rigid Body Joint", /* name */ - "bRigidBodyJointConstraint", /* struct name */ - NULL, /* free data */ - rbj_id_looper, /* id looper */ - NULL, /* copy data */ - rbj_new_data, /* new data */ - rbj_get_tars, /* get constraint targets */ - rbj_flush_tars, /* flush constraint targets */ - default_get_tarmat, /* get target matrix */ - NULL /* evaluate - this is not solved here... is just an interface for game-engine */ -}; - /* -------- Clamp To ---------- */ static void clampto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -3137,16 +3276,10 @@ static void clampto_flush_tars(bConstraint *con, ListBase *list, bool no_copy) } } -static void clampto_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void clampto_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, float UNUSED(ctime)) { -#ifdef CYCLIC_DEPENDENCY_WORKAROUND - if (VALID_CONS_TARGET(ct)) { - if (ct->tar->curve_cache == NULL) { - BKE_displist_make_curveTypes(cob->scene, ct->tar, false); - } - } -#endif - /* technically, this isn't really needed for evaluation, but we don't know what else * might end up calling this... */ @@ -3174,7 +3307,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar BKE_object_minmax(ct->tar, curveMin, curveMax, true); /* get targetmatrix */ - if (data->tar->curve_cache && data->tar->curve_cache->path && data->tar->curve_cache->path->data) { + if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && data->tar->runtime.curve_cache->path->data) { float vec[4], dir[3], totmat[4][4]; float curvetime; short clamp_axis; @@ -3480,53 +3613,64 @@ static void shrinkwrap_flush_tars(bConstraint *con, ListBase *list, bool no_copy } -static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) { + bool fail = false; float co[3] = {0.0f, 0.0f, 0.0f}; + bool track_normal = false; + float track_no[3] = {0.0f, 0.0f, 0.0f}; SpaceTransform transform; - /* TODO(sergey): use proper for_render flag here when known. */ - DerivedMesh *target = object_get_derived_final(ct->tar, false); + Mesh *target_eval = ct->tar->runtime.mesh_eval; - BVHTreeFromMesh treeData = {NULL}; + copy_m4_m4(ct->matrix, cob->matrix); - unit_m4(ct->matrix); + bool do_track_normal = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; + ShrinkwrapTreeData tree; - if (target != NULL) { + if (BKE_shrinkwrap_init_tree(&tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) { BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat); switch (scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: case MOD_SHRINKWRAP_NEAREST_VERTEX: + case MOD_SHRINKWRAP_TARGET_PROJECT: { BVHTreeNearest nearest; - float dist; nearest.index = -1; nearest.dist_sq = FLT_MAX; - if (scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) - bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_VERTS, 2); - else - bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 2); + BLI_space_transform_apply(&transform, co); + + BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType); - if (treeData.tree == NULL) { + if (nearest.index < 0) { fail = true; break; } - BLI_space_transform_apply(&transform, co); + if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) { + if (do_track_normal) { + track_normal = true; + BKE_shrinkwrap_compute_smooth_normal(&tree, NULL, nearest.index, nearest.co, nearest.no, track_no); + BLI_space_transform_invert_normal(&transform, track_no); + } - BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); + BKE_shrinkwrap_snap_point_to_surface(&tree, NULL, scon->shrinkMode, nearest.index, nearest.co, nearest.no, scon->dist, co, co); + } + else { + const float dist = len_v3v3(co, nearest.co); - dist = len_v3v3(co, nearest.co); - if (dist != 0.0f) { - interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */ + if (dist != 0.0f) { + interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */ + } } + BLI_space_transform_invert(&transform, co); break; } @@ -3564,24 +3708,37 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra break; } - bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 4); - if (treeData.tree == NULL) { - fail = true; - break; + char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK; + + BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, &tree, &hit); + + if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) { + float inv_no[3]; + negate_v3_v3(inv_no, no); + + if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) { + cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK; + } + + BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, &tree, &hit); } - if (BKE_shrinkwrap_project_normal(0, co, no, scon->dist, &transform, treeData.tree, - &hit, treeData.raycast_callback, &treeData) == false) - { + if (hit.index < 0) { fail = true; break; } - copy_v3_v3(co, hit.co); + + if (do_track_normal) { + track_normal = true; + BKE_shrinkwrap_compute_smooth_normal(&tree, &transform, hit.index, hit.co, hit.no, track_no); + } + + BKE_shrinkwrap_snap_point_to_surface(&tree, &transform, scon->shrinkMode, hit.index, hit.co, hit.no, scon->dist, co, co); break; } } - free_bvhtree_from_mesh(&treeData); + BKE_shrinkwrap_free_tree(&tree); if (fail == true) { /* Don't move the point */ @@ -3591,6 +3748,11 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra /* co is in local object coordinates, change it to global and update target position */ mul_m4_v3(cob->matrix, co); copy_v3_v3(ct->matrix[3], co); + + if (track_normal) { + mul_mat3_m4_v3(cob->matrix, track_no); + damptrack_do_transform(ct->matrix, track_no, scon->trackAxis); + } } } } @@ -3601,7 +3763,7 @@ static void shrinkwrap_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, Li /* only evaluate if there is a target */ if (VALID_CONS_TARGET(ct)) { - copy_v3_v3(cob->matrix[3], ct->matrix[3]); + copy_m4_m4(cob->matrix, ct->matrix); } } @@ -3675,7 +3837,22 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t bConstraintTarget *ct = targets->first; if (VALID_CONS_TARGET(ct)) { - float obvec[3], tarvec[3], obloc[3]; + float tarvec[3]; + + /* find the (unit) direction vector going from the owner to the target */ + sub_v3_v3v3(tarvec, ct->matrix[3], cob->matrix[3]); + + damptrack_do_transform(cob->matrix, tarvec, data->trackflag); + } +} + +static void damptrack_do_transform(float matrix[4][4], const float tarvec_in[3], int track_axis) +{ + /* find the (unit) direction vector going from the owner to the target */ + float tarvec[3]; + + if (normalize_v3_v3(tarvec, tarvec_in) != 0.0f) { + float obvec[3], obloc[3]; float raxis[3], rangle; float rmat[3][3], tmat[4][4]; @@ -3684,24 +3861,15 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t * - the normalization step at the end should take care of any unwanted scaling * left over in the 3x3 matrix we used */ - copy_v3_v3(obvec, track_dir_vecs[data->trackflag]); - mul_mat3_m4_v3(cob->matrix, obvec); + copy_v3_v3(obvec, track_dir_vecs[track_axis]); + mul_mat3_m4_v3(matrix, obvec); if (normalize_v3(obvec) == 0.0f) { /* exceptional case - just use the track vector as appropriate */ - copy_v3_v3(obvec, track_dir_vecs[data->trackflag]); + copy_v3_v3(obvec, track_dir_vecs[track_axis]); } - /* find the (unit) direction vector going from the owner to the target */ - copy_v3_v3(obloc, cob->matrix[3]); - sub_v3_v3v3(tarvec, ct->matrix[3], obloc); - - if (normalize_v3(tarvec) == 0.0f) { - /* the target is sitting on the owner, so just make them use the same direction vectors */ - /* FIXME: or would it be better to use the pure direction vector? */ - copy_v3_v3(tarvec, obvec); - //copy_v3_v3(tarvec, track_dir_vecs[data->trackflag]); - } + copy_v3_v3(obloc, matrix[3]); /* determine the axis-angle rotation, which represents the smallest possible rotation * between the two rotation vectors (i.e. the 'damping' referred to in the name) @@ -3734,8 +3902,8 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t } rangle = M_PI; - copy_v3_v3(tmpvec, track_dir_vecs[(data->trackflag + 1) % 6]); - mul_mat3_m4_v3(cob->matrix, tmpvec); + copy_v3_v3(tmpvec, track_dir_vecs[(track_axis + 1) % 6]); + mul_mat3_m4_v3(matrix, tmpvec); cross_v3_v3v3(raxis, obvec, tmpvec); if (normalize_v3(raxis) == 0.0f) { @@ -3753,10 +3921,10 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t * we may have destroyed that in the process of multiplying the matrix */ unit_m4(tmat); - mul_m4_m3m4(tmat, rmat, cob->matrix); // m1, m3, m2 + mul_m4_m3m4(tmat, rmat, matrix); // m1, m3, m2 - copy_m4_m4(cob->matrix, tmat); - copy_v3_v3(cob->matrix[3], obloc); + copy_m4_m4(matrix, tmat); + copy_v3_v3(matrix[3], obloc); } } @@ -3839,16 +4007,10 @@ static void splineik_flush_tars(bConstraint *con, ListBase *list, bool no_copy) } } -static void splineik_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) +static void splineik_get_tarmat(struct Depsgraph *UNUSED(depsgraph), + bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob), + bConstraintTarget *ct, float UNUSED(ctime)) { -#ifdef CYCLIC_DEPENDENCY_WORKAROUND - if (VALID_CONS_TARGET(ct)) { - if (ct->tar->curve_cache == NULL) { - BKE_displist_make_curveTypes(cob->scene, ct->tar, false); - } - } -#endif - /* technically, this isn't really needed for evaluation, but we don't know what else * might end up calling this... */ @@ -4016,20 +4178,25 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { + Depsgraph *depsgraph = cob->depsgraph; Scene *scene = cob->scene; bFollowTrackConstraint *data = con->data; MovieClip *clip = data->clip; MovieTracking *tracking; MovieTrackingTrack *track; MovieTrackingObject *tracking_object; - Object *camob = data->camera ? data->camera : scene->camera; - float ctime = BKE_scene_frame_get(scene); + + Object *camob_eval = DEG_get_evaluated_object( + depsgraph, + data->camera ? data->camera : scene->camera); + + float ctime = DEG_get_ctime(depsgraph); float framenr; if (data->flag & FOLLOWTRACK_ACTIVECLIP) clip = scene->clip; - if (!clip || !data->track[0] || !camob) + if (!clip || !data->track[0] || !camob_eval) return; tracking = &clip->tracking; @@ -4058,7 +4225,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { float imat[4][4]; - copy_m4_m4(mat, camob->obmat); + copy_m4_m4(mat, camob_eval->obmat); BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat); invert_m4(imat); @@ -4067,7 +4234,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); } else { - BKE_tracking_get_camera_object_matrix(cob->scene, camob, mat); + BKE_tracking_get_camera_object_matrix(depsgraph, cob->scene, camob_eval, mat); mul_m4_m4m4(cob->matrix, obmat, mat); translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); @@ -4079,7 +4246,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp); float len, d; - BKE_object_where_is_calc_mat4(scene, camob, mat); + BKE_object_where_is_calc_mat4(depsgraph, scene, camob_eval, mat); /* camera axis */ vec[0] = 0.0f; @@ -4147,7 +4314,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase } BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, camob); + BKE_camera_params_from_object(¶ms, camob_eval); if (params.is_ortho) { vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx); @@ -4159,9 +4326,9 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase else vec[0] *= aspect; - mul_v3_m4v3(disp, camob->obmat, vec); + mul_v3_m4v3(disp, camob_eval->obmat, vec); - copy_m4_m4(rmat, camob->obmat); + copy_m4_m4(rmat, camob_eval->obmat); zero_v3(rmat[3]); mul_m4_m4m4(cob->matrix, cob->matrix, rmat); @@ -4179,10 +4346,10 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase else vec[0] *= aspect; - mul_v3_m4v3(disp, camob->obmat, vec); + mul_v3_m4v3(disp, camob_eval->obmat, vec); /* apply camera rotation so Z-axis would be co-linear */ - copy_m4_m4(rmat, camob->obmat); + copy_m4_m4(rmat, camob_eval->obmat); zero_v3(rmat[3]); mul_m4_m4m4(cob->matrix, cob->matrix, rmat); @@ -4191,9 +4358,8 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase if (data->depth_ob) { Object *depth_ob = data->depth_ob; - /* TODO(sergey): use proper for_render flag here when known. */ - DerivedMesh *target = object_get_derived_final(depth_ob, false); - if (target) { + Mesh *target_eval = depth_ob->runtime.mesh_eval; + if (target_eval) { BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeRayHit hit; float ray_start[3], ray_end[3], ray_nor[3], imat[4][4]; @@ -4201,25 +4367,25 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase invert_m4_m4(imat, depth_ob->obmat); - mul_v3_m4v3(ray_start, imat, camob->obmat[3]); + mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]); mul_v3_m4v3(ray_end, imat, cob->matrix[3]); sub_v3_v3v3(ray_nor, ray_end, ray_start); normalize_v3(ray_nor); - bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 4); + BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4); hit.dist = BVH_RAYCAST_DIST_MAX; hit.index = -1; - result = BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData); + result = BLI_bvhtree_ray_cast( + treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData); if (result != -1) { mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co); } free_bvhtree_from_mesh(&treeData); - target->release(target); } } } @@ -4260,6 +4426,7 @@ static void camerasolver_id_looper(bConstraint *con, ConstraintIDFunc func, void static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { + Depsgraph *depsgraph = cob->depsgraph; Scene *scene = cob->scene; bCameraSolverConstraint *data = con->data; MovieClip *clip = data->clip; @@ -4271,7 +4438,7 @@ static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase float mat[4][4], obmat[4][4]; MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking); - float ctime = BKE_scene_frame_get(scene); + float ctime = DEG_get_ctime(depsgraph); float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); @@ -4318,6 +4485,7 @@ static void objectsolver_id_looper(bConstraint *con, ConstraintIDFunc func, void static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) { + Depsgraph *depsgraph = cob->depsgraph; Scene *scene = cob->scene; bObjectSolverConstraint *data = con->data; MovieClip *clip = data->clip; @@ -4337,10 +4505,10 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase if (object) { float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4]; - float ctime = BKE_scene_frame_get(scene); + float ctime = DEG_get_ctime(depsgraph); float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); - BKE_object_where_is_calc_mat4(scene, camob, cammat); + BKE_object_where_is_calc_mat4(depsgraph, scene, camob, cammat); BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat); @@ -4392,7 +4560,7 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa return; } - const float frame = BKE_scene_frame_get(scene); + const float frame = DEG_get_ctime(cob->depsgraph); const float time = BKE_cachefile_time_offset(cache_file, frame, FPS); BKE_cachefile_ensure_handle(G.main, cache_file); @@ -4490,7 +4658,7 @@ static void constraints_init_typeinfo(void) constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */ constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */ constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */ - constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */ + /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */ constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */ constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */ constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */ @@ -4503,6 +4671,7 @@ static void constraints_init_typeinfo(void) constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */ constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */ constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */ + constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */ } /* This function should be used for getting the appropriate type-info when only @@ -4642,7 +4811,7 @@ static bConstraint *add_new_constraint_internal(const char *name, short type) /* Set up a generic constraint datablock */ con->type = type; - con->flag |= CONSTRAINT_EXPAND; + con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL; con->enforce = 1.0f; /* Determine a basic name, and info */ @@ -4718,6 +4887,11 @@ static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const ch return con; } +bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *UNUSED(ct)) +{ + return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE); +} + /* ......... */ /* Add new constraint for the given bone */ @@ -4769,6 +4943,43 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i id_us_plus(*idpoin); } +/** Copies a single constraint's data (\a dst must already be a shallow copy of \a src). */ +static void constraint_copy_data_ex(bConstraint *dst, bConstraint *src, const int flag, const bool do_extern) +{ + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src); + + /* make a new copy of the constraint's data */ + dst->data = MEM_dupallocN(dst->data); + + /* only do specific constraints if required */ + if (cti) { + /* perform custom copying operations if needed */ + if (cti->copy_data) + cti->copy_data(dst, src); + + /* Fix usercounts for all referenced data that need it. */ + if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + cti->id_looper(dst, con_fix_copied_refs_cb, NULL); + } + + /* for proxies we don't want to make extern */ + if (do_extern) { + /* go over used ID-links for this constraint to ensure that they are valid for proxies */ + if (cti->id_looper) + cti->id_looper(dst, con_extern_cb, NULL); + } + } +} + +/** Allocate and duplicate a single constraint, ouside of any object/pose context. */ +bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern) +{ + bConstraint *dst = MEM_dupallocN(src); + constraint_copy_data_ex(dst, src, flag, do_extern); + dst->next = dst->prev = NULL; + return dst; +} + /* duplicate all of the constraints in a constraint stack */ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern) { @@ -4778,29 +4989,7 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, BLI_duplicatelist(dst, src); for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - - /* make a new copy of the constraint's data */ - con->data = MEM_dupallocN(con->data); - - /* only do specific constraints if required */ - if (cti) { - /* perform custom copying operations if needed */ - if (cti->copy_data) - cti->copy_data(con, srccon); - - /* Fix usercounts for all referenced data that need it. */ - if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - cti->id_looper(con, con_fix_copied_refs_cb, NULL); - } - - /* for proxies we don't want to make extern */ - if (do_extern) { - /* go over used ID-links for this constraint to ensure that they are valid for proxies */ - if (cti->id_looper) - cti->id_looper(con, con_extern_cb, NULL); - } - } + constraint_copy_data_ex(con, srccon, flag, do_extern); } } @@ -4848,6 +5037,48 @@ void BKE_constraints_active_set(ListBase *list, bConstraint *con) } } +static bConstraint *constraint_list_find_from_target(ListBase *constraints, bConstraintTarget *tgt) +{ + for (bConstraint *con = constraints->first; con; con = con->next) { + ListBase *targets = NULL; + + if (con->type == CONSTRAINT_TYPE_PYTHON) { + targets = &((bPythonConstraint *)con->data)->targets; + } + else if (con->type == CONSTRAINT_TYPE_ARMATURE) { + targets = &((bArmatureConstraint *)con->data)->targets; + } + + if (targets && BLI_findindex(targets, tgt) != -1) { + return con; + } + } + + return NULL; +} + +/* Finds the constraint that owns the given target within the object. */ +bConstraint *BKE_constraint_find_from_target(Object *ob, bConstraintTarget *tgt) +{ + bConstraint *result = constraint_list_find_from_target(&ob->constraints, tgt); + + if (result != NULL) { + return result; + } + + if (ob->pose != NULL) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + result = constraint_list_find_from_target(&pchan->constraints, tgt); + + if (result != NULL) { + return result; + } + } + } + + return NULL; +} + /* -------- Constraints and Proxies ------- */ /* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */ @@ -4897,7 +5128,7 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan) * None of the actual calculations of the matrices should be done here! Also, this function is * not to be used by any new constraints, particularly any that have multiple targets. */ -void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime) +void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); ListBase targets = {NULL, NULL}; @@ -4909,6 +5140,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb"); cob->type = ownertype; cob->scene = scene; + cob->depsgraph = depsgraph; switch (ownertype) { case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */ { @@ -4948,7 +5180,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, if (ct) { if (cti->get_target_matrix) - cti->get_target_matrix(con, cob, ct, ctime); + cti->get_target_matrix(depsgraph, con, cob, ct, ctime); copy_m4_m4(mat, ct->matrix); } @@ -4964,7 +5196,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, } /* Get the list of targets required for solving a constraint */ -void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) +void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); @@ -4982,7 +5214,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob */ if (cti->get_target_matrix) { for (ct = targets->first; ct; ct = ct->next) - cti->get_target_matrix(con, cob, ct, ctime); + cti->get_target_matrix(depsgraph, con, cob, ct, ctime); } else { for (ct = targets->first; ct; ct = ct->next) @@ -4999,7 +5231,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob * BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and * after running this function, to sort out cob */ -void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime) +void BKE_constraints_solve(struct Depsgraph *depsgraph, ListBase *conlist, bConstraintOb *cob, float ctime) { bConstraint *con; float oldmat[4][4]; @@ -5034,7 +5266,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime) BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); /* prepare targets for constraint solving */ - BKE_constraint_targets_for_solving_get(con, cob, &targets, ctime); + BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime); /* Solve the constraint and put result in cob->matrix */ cti->evaluate_constraint(con, cob, &targets); diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index c9468c7d95c..b3a26087dd0 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -30,6 +30,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_collection_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -38,6 +39,9 @@ #include "DNA_object_types.h" #include "DNA_linestyle_types.h" #include "DNA_gpencil_types.h" +#include "DNA_workspace_types.h" + +#include "DEG_depsgraph.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -47,9 +51,14 @@ #include "BLT_translation.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_sound.h" +#include "BKE_workspace.h" + +#include "RE_engine.h" #include "RNA_access.h" @@ -66,10 +75,12 @@ struct bContext { struct { struct wmWindowManager *manager; struct wmWindow *window; + struct WorkSpace *workspace; struct bScreen *screen; struct ScrArea *area; struct ARegion *region; struct ARegion *menu; + struct wmGizmoGroup *gizmo_group; struct bContextStore *store; const char *operator_poll_msg; /* reason for poll failing */ } wm; @@ -83,13 +94,6 @@ struct bContext { int py_init; /* true if python is initialized */ void *py_context; } data; - - /* data evaluation */ -#if 0 - struct { - int render; - } eval; -#endif }; /* context */ @@ -627,6 +631,11 @@ wmWindow *CTX_wm_window(const bContext *C) return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window); } +WorkSpace *CTX_wm_workspace(const bContext *C) +{ + return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace); +} + bScreen *CTX_wm_screen(const bContext *C) { return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen); @@ -659,6 +668,16 @@ struct ARegion *CTX_wm_menu(const bContext *C) return C->wm.menu; } +struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C) +{ + return C->wm.gizmo_group; +} + +struct wmMsgBus *CTX_wm_message_bus(const bContext *C) +{ + return C->wm.manager ? C->wm.manager->message_bus : NULL; +} + struct ReportList *CTX_wm_reports(const bContext *C) { if (C->wm.manager) @@ -750,14 +769,6 @@ struct SpaceNla *CTX_wm_space_nla(const bContext *C) return NULL; } -struct SpaceTime *CTX_wm_space_time(const bContext *C) -{ - ScrArea *sa = CTX_wm_area(C); - if (sa && sa->spacetype == SPACE_TIME) - return sa->spacedata.first; - return NULL; -} - struct SpaceNode *CTX_wm_space_node(const bContext *C) { ScrArea *sa = CTX_wm_area(C); @@ -766,14 +777,6 @@ struct SpaceNode *CTX_wm_space_node(const bContext *C) return NULL; } -struct SpaceLogic *CTX_wm_space_logic(const bContext *C) -{ - ScrArea *sa = CTX_wm_area(C); - if (sa && sa->spacetype == SPACE_LOGIC) - return sa->spacedata.first; - return NULL; -} - struct SpaceIpo *CTX_wm_space_graph(const bContext *C) { ScrArea *sa = CTX_wm_area(C); @@ -814,6 +817,14 @@ struct SpaceClip *CTX_wm_space_clip(const bContext *C) return NULL; } +struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C) +{ + ScrArea *sa = CTX_wm_area(C); + if (sa && sa->spacetype == SPACE_TOPBAR) + return sa->spacedata.first; + return NULL; +} + void CTX_wm_manager_set(bContext *C, wmWindowManager *wm) { C->wm.manager = wm; @@ -826,9 +837,11 @@ void CTX_wm_manager_set(bContext *C, wmWindowManager *wm) void CTX_wm_window_set(bContext *C, wmWindow *win) { C->wm.window = win; - C->wm.screen = (win) ? win->screen : NULL; - if (C->wm.screen) - C->data.scene = C->wm.screen->scene; + if (win) { + C->data.scene = win->scene; + } + C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL; + C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL; C->wm.area = NULL; C->wm.region = NULL; } @@ -836,8 +849,6 @@ void CTX_wm_window_set(bContext *C, wmWindow *win) void CTX_wm_screen_set(bContext *C, bScreen *screen) { C->wm.screen = screen; - if (C->wm.screen) - C->data.scene = C->wm.screen->scene; C->wm.area = NULL; C->wm.region = NULL; } @@ -858,6 +869,11 @@ void CTX_wm_menu_set(bContext *C, ARegion *menu) C->wm.menu = menu; } +void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup) +{ + C->wm.gizmo_group = gzgroup; +} + void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg) { C->wm.operator_poll_msg = msg; @@ -896,10 +912,74 @@ Scene *CTX_data_scene(const bContext *C) return C->data.scene; } -int CTX_data_mode_enum(const bContext *C) +ViewLayer *CTX_data_view_layer(const bContext *C) { - Object *obedit = CTX_data_edit_object(C); + ViewLayer *view_layer; + + if (ctx_data_pointer_verify(C, "view_layer", (void *)&view_layer)) { + return view_layer; + } + + wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); + if (win) { + view_layer = BKE_view_layer_find(scene, win->view_layer_name); + if (view_layer) { + return view_layer; + } + } + + return BKE_view_layer_default_view(scene); +} +RenderEngineType *CTX_data_engine_type(const bContext *C) +{ + Scene *scene = CTX_data_scene(C); + return RE_engines_find(scene->r.engine); +} + +/** + * This is tricky. Sometimes the user overrides the render_layer + * but not the scene_collection. In this case what to do? + * + * If the scene_collection is linked to the ViewLayer we use it. + * Otherwise we fallback to the active one of the ViewLayer. + */ +LayerCollection *CTX_data_layer_collection(const bContext *C) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *layer_collection; + + if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) { + if (BKE_view_layer_has_collection(view_layer, layer_collection->collection)) { + return layer_collection; + } + } + + /* fallback */ + return BKE_layer_collection_get_active(view_layer); +} + +Collection *CTX_data_collection(const bContext *C) +{ + Collection *collection; + if (ctx_data_pointer_verify(C, "collection", (void *)&collection)) { + return collection; + } + + LayerCollection *layer_collection = CTX_data_layer_collection(C); + if (layer_collection) { + return layer_collection->collection; + } + + /* fallback */ + Scene *scene = CTX_data_scene(C); + return BKE_collection_master(scene); +} + +int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectMode object_mode) +{ + // Object *obedit = CTX_data_edit_object(C); if (obedit) { switch (obedit->type) { case OB_MESH: @@ -919,21 +999,30 @@ int CTX_data_mode_enum(const bContext *C) } } else { - Object *ob = CTX_data_active_object(C); - + // Object *ob = CTX_data_active_object(C); if (ob) { - if (ob->mode & OB_MODE_POSE) return CTX_MODE_POSE; - else if (ob->mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT; - else if (ob->mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT; - else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX; - else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE; - else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE; + if (object_mode & OB_MODE_POSE) return CTX_MODE_POSE; + else if (object_mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT; + else if (object_mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT; + else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX; + else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE; + else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE; + else if (object_mode & OB_MODE_GPENCIL_PAINT) return CTX_MODE_GPENCIL_PAINT; + else if (object_mode & OB_MODE_GPENCIL_EDIT) return CTX_MODE_GPENCIL_EDIT; + else if (object_mode & OB_MODE_GPENCIL_SCULPT) return CTX_MODE_GPENCIL_SCULPT; + else if (object_mode & OB_MODE_GPENCIL_WEIGHT) return CTX_MODE_GPENCIL_WEIGHT; } } return CTX_MODE_OBJECT; } +int CTX_data_mode_enum(const bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + Object *obact = obedit ? NULL : CTX_data_active_object(C); + return CTX_data_mode_enum_ex(obedit, obact, obact ? obact->mode : OB_MODE_OBJECT); +} /* would prefer if we can use the enum version below over this one - Campbell */ /* must be aligned with above enum */ @@ -952,8 +1041,13 @@ static const char *data_mode_strings[] = { "imagepaint", "particlemode", "objectmode", + "greasepencil_paint", + "greasepencil_edit", + "greasepencil_sculpt", + "greasepencil_weight", NULL }; +BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode") const char *CTX_data_mode_string(const bContext *C) { return data_mode_strings[CTX_data_mode_enum(C)]; @@ -1104,6 +1198,11 @@ int CTX_data_selected_pose_bones(const bContext *C, ListBase *list) return ctx_data_collection_get(C, "selected_pose_bones", list); } +int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list); +} + int CTX_data_visible_pose_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_pose_bones", list); @@ -1119,17 +1218,7 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C) return ctx_data_pointer_get(C, "active_gpencil_layer"); } -bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C) -{ - return ctx_data_pointer_get(C, "active_gpencil_palette"); -} - -bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C) -{ - return ctx_data_pointer_get(C, "active_gpencil_palettecolor"); -} - -bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C) +Brush *CTX_data_active_gpencil_brush(const bContext *C) { return ctx_data_pointer_get(C, "active_gpencil_brush"); } @@ -1153,3 +1242,17 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "editable_gpencil_strokes", list); } + +Depsgraph *CTX_data_depsgraph(const bContext *C) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + return BKE_scene_get_depsgraph(scene, view_layer, true); +} + +Depsgraph *CTX_data_depsgraph_on_load(const bContext *C) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + return BKE_scene_get_depsgraph(scene, view_layer, false); +} diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 56df8e51eba..354cc4926f1 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -48,6 +48,7 @@ #include "BKE_multires.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" +#include "BKE_library.h" BLI_INLINE void tan_calc_quat_v3( float r_quat[4], @@ -99,27 +100,26 @@ static int modifiers_disable_subsurf_temporary(Object *ob) } /* disable subsurf temporal, get mapped cos, and enable it */ -float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3] +float (*BKE_crazyspace_get_mapped_editverts( + struct Depsgraph *depsgraph, Scene *scene, Object *obedit))[3] { Mesh *me = obedit->data; - DerivedMesh *dm; + Mesh *me_eval; float (*vertexcos)[3]; int nverts = me->edit_btmesh->bm->totvert; /* disable subsurf temporal, get mapped cos, and enable it */ if (modifiers_disable_subsurf_temporary(obedit)) { /* need to make new derivemesh */ - makeDerivedMesh(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false); + makeDerivedMesh(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false); } /* now get the cage */ vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map"); - dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH); + me_eval = editbmesh_get_eval_cage(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH); - mesh_get_mapped_verts_coords(dm, vertexcos, nverts); - - dm->release(dm); + mesh_get_mapped_verts_coords(me_eval, vertexcos, nverts); /* set back the flag, no new cage needs to be built, transform does it */ modifiers_disable_subsurf_temporary(obedit); @@ -250,19 +250,21 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, float (*origcos)[3], float (*mapped /** returns an array of deform matrices for crazyspace correction, and the * number of modifiers left */ -int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, BMEditMesh *em, - float (**deformmats)[3][3], float (**deformcos)[3]) +int BKE_crazyspace_get_first_deform_matrices_editbmesh( + struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em, + float (**deformmats)[3][3], float (**deformcos)[3]) { ModifierData *md; - DerivedMesh *dm; + Mesh *me; int i, a, numleft = 0, numVerts = 0; int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; VirtualModifierData virtualModifierData; + ModifierEvalContext mectx = {depsgraph, ob, 0}; modifiers_clearErrors(ob); - dm = NULL; + me = NULL; md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* compute the deformation matrices and coordinates for the first @@ -271,7 +273,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, for (i = 0; md && i <= cageIndex; i++, md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!editbmesh_modifier_is_enabled(scene, md, dm)) + if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) continue; if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { @@ -282,27 +284,26 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, data_mask = datamasks->mask; BLI_linklist_free((LinkNode *)datamasks, NULL); - dm = getEditDerivedBMesh(em, ob, data_mask, NULL); + me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, data_mask, NULL); deformedVerts = editbmesh_get_vertex_cos(em, &numVerts); defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats"); for (a = 0; a < numVerts; a++) unit_m3(defmats[a]); } - - mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats, - numVerts); + mti->deformMatricesEM(md, &mectx, em, me, deformedVerts, defmats, numVerts); } else break; } for (; md && i <= cageIndex; md = md->next, i++) - if (editbmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md)) + if (editbmesh_modifier_is_enabled(scene, md, me != NULL) && modifier_isCorrectableDeformed(md)) numleft++; - if (dm) - dm->release(dm); + if (me) { + BKE_id_free(NULL, me); + } *deformmats = defmats; *deformcos = deformedVerts; @@ -310,16 +311,19 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, return numleft; } -int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]) +int BKE_sculpt_get_first_deform_matrices( + struct Depsgraph *depsgraph, Scene *scene, + Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]) { ModifierData *md; - DerivedMesh *dm; + Mesh *me_eval; int a, numVerts = 0; float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); const bool has_multires = mmd != NULL && mmd->sculptlvl > 0; int numleft = 0; VirtualModifierData virtualModifierData; + const ModifierEvalContext mectx = {depsgraph, ob, 0}; if (has_multires) { *deformmats = NULL; @@ -327,7 +331,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo return numleft; } - dm = NULL; + me_eval = NULL; md = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (; md; md = md->next) { @@ -337,8 +341,8 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo if (mti->type == eModifierTypeType_OnlyDeform) { if (!defmats) { - Mesh *me = (Mesh *)ob->data; - dm = mesh_create_derived(me, NULL); + Mesh *me = ob->data; + me_eval = BKE_mesh_copy_for_eval(me, true); deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts); defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats"); @@ -346,7 +350,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo unit_m3(defmats[a]); } - if (mti->deformMatrices) mti->deformMatrices(md, ob, dm, deformedVerts, defmats, numVerts); + if (mti->deformMatrices) { + mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts); + } else break; } } @@ -360,8 +366,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo numleft++; } - if (dm) - dm->release(dm); + if (me_eval) { + BKE_id_free(NULL, me_eval); + } *deformmats = defmats; *deformcos = deformedVerts; @@ -369,9 +376,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo return numleft; } -void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]) +void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]) { - int totleft = BKE_sculpt_get_first_deform_matrices(scene, ob, deformmats, deformcos); + int totleft = BKE_sculpt_get_first_deform_matrices(depsgraph, scene, ob, deformmats, deformcos); if (totleft) { /* there are deformation modifier which doesn't support deformation matrices @@ -383,6 +390,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[ int i, deformed = 0; VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + const ModifierEvalContext mectx = {depsgraph, ob, 0}; Mesh *me = (Mesh *)ob->data; for (; md; md = md->next) { @@ -396,7 +404,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[ if (mti->deformMatrices && !deformed) continue; - mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0); + mti->deformVerts(md, &mectx, NULL, deformedVerts, me->totvert); deformed = 1; } } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index b395df49061..2f960a3a349 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -53,7 +53,6 @@ #include "BKE_animsys.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" @@ -129,6 +128,8 @@ void BKE_curve_free(Curve *cu) { BKE_animdata_free((ID *)cu, false); + BKE_curve_batch_cache_free(cu); + BKE_nurbList_free(&cu->nurb); BKE_curve_editfont_free(cu); @@ -209,8 +210,9 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo); cu_dst->tb = MEM_dupallocN(cu_src->tb); cu_dst->bb = MEM_dupallocN(cu_src->bb); + cu_dst->batch_cache = NULL; - if (cu_src->key) { + if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false); } @@ -221,7 +223,7 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const Curve *BKE_curve_copy(Main *bmain, const Curve *cu) { Curve *cu_copy; - BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false); + BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, LIB_ID_COPY_SHAPEKEY, false); return cu_copy; } @@ -1725,7 +1727,7 @@ float *BKE_curve_surf_make_orco(Object *ob) /* NOTE: This routine is tied to the order of vertex * built by displist and as passed to the renderer. */ -float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts) +float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts) { Curve *cu = ob->data; DispList *dl; @@ -1733,7 +1735,7 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts) float *fp, *coord_array; ListBase disp = {NULL, NULL}; - BKE_displist_make_curveTypes_forOrco(scene, ob, &disp); + BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp); numVerts = 0; for (dl = disp.first; dl; dl = dl->next) { @@ -1824,8 +1826,9 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts) /* ***************** BEVEL ****************** */ -void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp, - const bool for_render, const bool use_render_resolution) +void BKE_curve_bevel_make( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *disp, + const bool for_render, const bool use_render_resolution) { DispList *dl, *dlnew; Curve *bevcu, *cu; @@ -1849,14 +1852,14 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp, facy = cu->bevobj->size[1]; if (for_render) { - BKE_displist_make_curveTypes_forRender(scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution); + BKE_displist_make_curveTypes_forRender(depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution); dl = bevdisp.first; } - else if (cu->bevobj->curve_cache) { - dl = cu->bevobj->curve_cache->disp.first; + else if (cu->bevobj->runtime.curve_cache) { + dl = cu->bevobj->runtime.curve_cache->disp.first; } else { - BLI_assert(cu->bevobj->curve_cache != NULL); + BLI_assert(cu->bevobj->runtime.curve_cache != NULL); dl = NULL; } @@ -2769,14 +2772,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE); - bev = &ob->curve_cache->bev; + bev = &ob->runtime.curve_cache->bev; /* do we need to calculate the radius for each point? */ /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */ /* STEP 1: MAKE POLYS */ - BKE_curve_bevelList_free(&ob->curve_cache->bev); + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); nu = nurbs->first; if (cu->editnurb && ob->type != OB_FONT) { is_editmode = 1; @@ -3407,44 +3410,16 @@ static void calchandleNurb_intern( } if (leftviolate || rightviolate) { /* align left handle */ BLI_assert(is_fcurve); -#if 0 - if (is_fcurve) -#endif - { - /* simple 2d calculation */ - float h1_x = p2_h1[0] - p2[0]; - float h2_x = p2[0] - p2_h2[0]; - - if (leftviolate) { - p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x; - } - else { - p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x; - } + /* simple 2d calculation */ + float h1_x = p2_h1[0] - p2[0]; + float h2_x = p2[0] - p2_h2[0]; + + if (leftviolate) { + p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x; } -#if 0 else { - float h1[3], h2[3]; - float dot; - - sub_v3_v3v3(h1, p2_h1, p2); - sub_v3_v3v3(h2, p2, p2_h2); - - len_a = normalize_v3(h1); - len_b = normalize_v3(h2); - - dot = dot_v3v3(h1, h2); - - if (leftviolate) { - mul_v3_fl(h1, dot * len_b); - sub_v3_v3v3(p2_h2, p2, h1); - } - else { - mul_v3_fl(h2, dot * len_a); - add_v3_v3v3(p2_h1, p2, h2); - } + p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x; } -#endif } } } @@ -4654,18 +4629,18 @@ float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3] BezTriple *bezt = nu->bezt; for (i = 0; i < nu->pntsu; i++, bezt++) { - copy_v3_v3(co, key); co += 3; key += 3; - copy_v3_v3(co, key); co += 3; key += 3; - copy_v3_v3(co, key); co += 3; key += 3; - key += 3; /* skip tilt */ + copy_v3_v3(co, &key[0]); co += 3; + copy_v3_v3(co, &key[3]); co += 3; + copy_v3_v3(co, &key[6]); co += 3; + key += KEYELEM_FLOAT_LEN_BEZTRIPLE; } } else { BPoint *bp = nu->bp; for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { - copy_v3_v3(co, key); co += 3; key += 3; - key++; /* skip tilt */ + copy_v3_v3(co, key); co += 3; + key += KEYELEM_FLOAT_LEN_BPOINT; } } } @@ -4683,18 +4658,18 @@ void BKE_curve_nurbs_keyVertexTilts_apply(ListBase *lb, float *key) BezTriple *bezt = nu->bezt; for (i = 0; i < nu->pntsu; i++, bezt++) { - key += 3 * 3; - bezt->alfa = *key; - key += 3; + bezt->alfa = key[9]; + bezt->radius = key[10]; + key += KEYELEM_FLOAT_LEN_BEZTRIPLE; } } else { BPoint *bp = nu->bp; for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) { - key += 3; - bp->alfa = *key; - key++; + bp->alfa = key[3]; + bp->radius = key[4]; + key += KEYELEM_FLOAT_LEN_BPOINT; } } } @@ -4864,11 +4839,6 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles) nu->orderv = 1; nu->type = type; -#if 0 /* UNUSED */ - if (nu->flagu & CU_NURB_CYCLIC) c = nu->orderu - 1; - else c = 0; -#endif - if (type == CU_NURBS) { nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */ nu->flagu |= CU_NURB_BEZIER; @@ -5010,12 +4980,6 @@ bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert) vert = &nu->bp[cu->actvert]; } } - /* get functions should never set! */ -#if 0 - else { - cu->actnu = cu->actvert = CU_ACT_NONE; - } -#endif } *r_nu = nu; @@ -5164,8 +5128,29 @@ void BKE_curve_transform_ex( KeyBlock *kb; for (kb = cu->key->block.first; kb; kb = kb->next) { float *fp = kb->data; - for (i = kb->totelem; i--; fp += 3) { - mul_m4_v3(mat, fp); + int n = kb->totelem; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) { + mul_m4_v3(mat, &fp[0]); + mul_m4_v3(mat, &fp[3]); + mul_m4_v3(mat, &fp[6]); + if (do_props) { + fp[10] *= unit_scale; /* radius */ + } + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; + } + } + else { + for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) { + mul_m4_v3(mat, fp); + if (do_props) { + fp[4] *= unit_scale; /* radius */ + } + fp += KEYELEM_FLOAT_LEN_BPOINT; + } + } } } } @@ -5209,8 +5194,23 @@ void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys) KeyBlock *kb; for (kb = cu->key->block.first; kb; kb = kb->next) { float *fp = kb->data; - for (i = kb->totelem; i--; fp += 3) { - add_v3_v3(fp, offset); + int n = kb->totelem; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) { + add_v3_v3(&fp[0], offset); + add_v3_v3(&fp[3], offset); + add_v3_v3(&fp[6], offset); + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; + } + } + else { + for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) { + add_v3_v3(fp, offset); + fp += KEYELEM_FLOAT_LEN_BPOINT; + } + } } } } @@ -5288,7 +5288,7 @@ bool BKE_curve_material_index_validate(Curve *cu) } if (!is_valid) { - DAG_id_tag_update(&cu->id, OB_RECALC_DATA); + DEG_id_tag_update(&cu->id, OB_RECALC_DATA); return true; } else { @@ -5355,11 +5355,28 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t /* **** Depsgraph evaluation **** */ -void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx), +void BKE_curve_eval_geometry(Depsgraph *depsgraph, Curve *curve) { - DEG_debug_print_eval(__func__, curve->id.name, curve); + DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve); if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { BKE_curve_texspace_calc(curve); } } + +/* Draw Engine */ +void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = NULL; +void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL; + +void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode) +{ + if (cu->batch_cache) { + BKE_curve_batch_cache_dirty_tag_cb(cu, mode); + } +} +void BKE_curve_batch_cache_free(Curve *cu) +{ + if (cu->batch_cache) { + BKE_curve_batch_cache_free_cb(cu); + } +} diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 8fa117dfce1..a0fa08708b1 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -53,6 +53,7 @@ #include "BKE_customdata.h" #include "BKE_customdata_file.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" @@ -390,37 +391,19 @@ static void layerSwap_tface(void *data, const int *corner_indices) { MTFace *tf = data; float uv[4][2]; - static const short pin_flags[4] = { TF_PIN1, TF_PIN2, TF_PIN3, TF_PIN4 }; - static const char sel_flags[4] = { TF_SEL1, TF_SEL2, TF_SEL3, TF_SEL4 }; - short unwrap = tf->unwrap & ~(TF_PIN1 | TF_PIN2 | TF_PIN3 | TF_PIN4); - char flag = tf->flag & ~(TF_SEL1 | TF_SEL2 | TF_SEL3 | TF_SEL4); int j; for (j = 0; j < 4; ++j) { const int source_index = corner_indices[j]; - copy_v2_v2(uv[j], tf->uv[source_index]); - - /* swap pinning flags around */ - if (tf->unwrap & pin_flags[source_index]) { - unwrap |= pin_flags[j]; - } - - /* swap selection flags around */ - if (tf->flag & sel_flags[source_index]) { - flag |= sel_flags[j]; - } } memcpy(tf->uv, uv, sizeof(tf->uv)); - tf->unwrap = unwrap; - tf->flag = flag; } static void layerDefault_tface(void *data, int count) { - static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, NULL, - 0, 0, TF_DYNAMIC | TF_CONVERTED, 0, 0}; + static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}}; MTFace *tf = (MTFace *)data; int i; @@ -489,11 +472,7 @@ static void layerInterp_origspace_face( } } - /* delay writing to the destination incase dest is in sources */ - -#if 0 /* no need, this ONLY contains UV's */ - *osf = *(OrigSpaceFace *)(*sources); -#endif + /* delay writing to the destination in case dest is in sources */ memcpy(osf->uv, uv, sizeof(osf->uv)); } @@ -1190,6 +1169,15 @@ static void layerSwap_flnor(void *data, const int *corner_indices) memcpy(flnors, nors, sizeof(nors)); } +static void layerDefault_fmap(void *data, int count) +{ + int *fmap_num = (int *)data; + int i; + for (i = 0; i < count; i++) { + *fmap_num = -1; + } +} + static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 0: CD_MVERT */ {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL}, @@ -1215,8 +1203,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 3 floats per normal vector */ {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal}, - /* 9: CD_POLYINDEX */ /* DEPRECATED */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + /* 9: CD_FACEMAP */ + {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL}, /* 10: CD_PROP_FLT */ {sizeof(MFloatProperty), "MFloatProperty", 1, N_("Float"), layerCopy_propFloat, NULL, NULL, NULL}, /* 11: CD_PROP_INT */ @@ -1228,10 +1216,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face}, /* 14: CD_ORCO */ {sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, - /* 15: CD_MTEXPOLY */ + /* 15: CD_MTEXPOLY */ /* DEPRECATED */ /* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */ - {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface}, + {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, /* 16: CD_MLOOPUV */ {sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL, layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv, @@ -1310,7 +1297,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { static const char *LAYERTYPENAMES[CD_NUMTYPES] = { /* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", - /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags", + /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFaceMap", /* 10-14 */ "CDMFloatProperty", "CDMIntProperty", "CDMStringProperty", "CDOrigSpace", "CDOrco", /* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps", /* 20-24 */ "CDPreviewMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast", @@ -1325,41 +1312,41 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { const CustomDataMask CD_MASK_BAREMESH = - CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT; + CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_MESH = CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP | - CD_MASK_MTEXPOLY | CD_MASK_RECAST | CD_MASK_PAINT_MASK | + CD_MASK_RECAST | CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_EDITMESH = CD_MASK_MDEFORMVERT | CD_MASK_MLOOPUV | - CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX | + CD_MASK_MLOOPCOL | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_PAINT_MASK | - CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_DERIVEDMESH = CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO | - CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL | + CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_PREVIEW_MCOL | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; const CustomDataMask CD_MASK_BMESH = - CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | + CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS | CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; /** * cover values copied by #BKE_mesh_loops_to_tessdata */ const CustomDataMask CD_MASK_FACECORNERS = - CD_MASK_MTFACE | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | + CD_MASK_MTFACE | CD_MASK_MLOOPUV | CD_MASK_MCOL | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | @@ -1368,7 +1355,7 @@ const CustomDataMask CD_MASK_FACECORNERS = const CustomDataMask CD_MASK_EVERYTHING = CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT | - CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | + CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_TANGENT | CD_MASK_MDISPS | CD_MASK_PREVIEW_MCOL | CD_MASK_CLOTH_ORCO | CD_MASK_RECAST | /* BMESH ONLY START */ CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_SHAPE_KEYINDEX | CD_MASK_SHAPEKEY | CD_MASK_BWEIGHT | CD_MASK_CREASE | @@ -1376,7 +1363,7 @@ const CustomDataMask CD_MASK_EVERYTHING = /* BMESH ONLY END */ CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL; + CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; static const LayerTypeInfo *layerType_getInfo(int type) { @@ -1407,8 +1394,9 @@ void customData_mask_layers__print(CustomDataMask mask) /********************* CustomData functions *********************/ static void customData_update_offsets(CustomData *data); -static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata, - int totelem, const char *name); +static CustomDataLayer *customData_add_layer__internal( + CustomData *data, int type, eCDAllocType alloctype, void *layerdata, + int totelem, const char *name); void CustomData_update_typemap(CustomData *data) { @@ -1437,8 +1425,9 @@ static bool customdata_typemap_is_valid(const CustomData *data) } #endif -bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, int alloctype, int totelem) +bool CustomData_merge( + const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, eCDAllocType alloctype, int totelem) { /*const LayerTypeInfo *typeInfo;*/ CustomDataLayer *layer, *newlayer; @@ -1520,8 +1509,9 @@ void CustomData_realloc(CustomData *data, int totelem) } } -void CustomData_copy(const struct CustomData *source, struct CustomData *dest, - CustomDataMask mask, int alloctype, int totelem) +void CustomData_copy( + const struct CustomData *source, struct CustomData *dest, + CustomDataMask mask, eCDAllocType alloctype, int totelem) { CustomData_reset(dest); @@ -1820,8 +1810,9 @@ static int customData_resize(CustomData *data, int amount) return 1; } -static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata, - int totelem, const char *name) +static CustomDataLayer *customData_add_layer__internal( + CustomData *data, int type, eCDAllocType alloctype, void *layerdata, + int totelem, const char *name) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); int flag = 0, index = data->totlayer; @@ -1908,8 +1899,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ return &data->layers[index]; } -void *CustomData_add_layer(CustomData *data, int type, int alloctype, - void *layerdata, int totelem) +void *CustomData_add_layer( + CustomData *data, int type, eCDAllocType alloctype, + void *layerdata, int totelem) { CustomDataLayer *layer; const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -1925,8 +1917,9 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype, } /*same as above but accepts a name*/ -void *CustomData_add_layer_named(CustomData *data, int type, int alloctype, - void *layerdata, int totelem, const char *name) +void *CustomData_add_layer_named( + CustomData *data, int type, eCDAllocType alloctype, + void *layerdata, int totelem, const char *name) { CustomDataLayer *layer; @@ -2243,6 +2236,27 @@ void CustomData_copy_data(const CustomData *source, CustomData *dest, } } +void CustomData_copy_layer_type_data(const CustomData *source, + CustomData *destination, + int type, + int source_index, int destination_index, + int count) +{ + const int source_layer_index = CustomData_get_layer_index(source, type); + if (source_layer_index == -1) { + return; + } + const int destinaiton_layer_index = + CustomData_get_layer_index(destination, type); + if (destinaiton_layer_index == -1) { + return; + } + CustomData_copy_data_layer(source, destination, + source_layer_index, destinaiton_layer_index, + source_index, destination_index, + count); +} + void CustomData_free_elem(CustomData *data, int index, int count) { int i; @@ -2501,13 +2515,10 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou /* BMesh functions */ /* needed to convert to/from different face reps */ -void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, - int totloop, int totpoly) +void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop) { - int i; - for (i = 0; i < fdata->totlayer; i++) { + for (int i = 0; i < fdata->totlayer; i++) { if (fdata->layers[i].type == CD_MTFACE) { - CustomData_add_layer_named(pdata, CD_MTEXPOLY, CD_CALLOC, NULL, totpoly, fdata->layers[i].name); CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MCOL) { @@ -2522,19 +2533,18 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *l } } -void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total) +void CustomData_from_bmeshpoly( + CustomData *fdata, CustomData *ldata, int total) { int i; /* avoid accumulating extra layers */ - BLI_assert(!CustomData_from_bmeshpoly_test(fdata, pdata, ldata, false)); + BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false)); - for (i = 0; i < pdata->totlayer; i++) { - if (pdata->layers[i].type == CD_MTEXPOLY) { - CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name); - } - } for (i = 0; i < ldata->totlayer; i++) { + if (ldata->layers[i].type == CD_MLOOPUV) { + CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name); + } if (ldata->layers[i].type == CD_MLOOPCOL) { CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name); } @@ -2552,7 +2562,7 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData } } - CustomData_bmesh_update_active_layers(fdata, pdata, ldata); + CustomData_bmesh_update_active_layers(fdata, ldata); } #ifndef NDEBUG @@ -2562,13 +2572,13 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData * \param fallback: Use when there are no layers to handle, * since callers may expect success or failure. */ -bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback) +bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback) { int a_num = 0, b_num = 0; #define LAYER_CMP(l_a, t_a, l_b, t_b) \ ((a_num += CustomData_number_of_layers(l_a, t_a)) == (b_num += CustomData_number_of_layers(l_b, t_b))) - if (!LAYER_CMP(pdata, CD_MTEXPOLY, fdata, CD_MTFACE)) + if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE)) return false; if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL)) return false; @@ -2590,25 +2600,21 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom #endif -void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata) +void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata) { int act; - if (CustomData_has_layer(pdata, CD_MTEXPOLY)) { - act = CustomData_get_active_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_active(ldata, CD_MLOOPUV, act); + if (CustomData_has_layer(ldata, CD_MLOOPUV)) { + act = CustomData_get_active_layer(ldata, CD_MLOOPUV); CustomData_set_layer_active(fdata, CD_MTFACE, act); - act = CustomData_get_render_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_render(ldata, CD_MLOOPUV, act); + act = CustomData_get_render_layer(ldata, CD_MLOOPUV); CustomData_set_layer_render(fdata, CD_MTFACE, act); - act = CustomData_get_clone_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_clone(ldata, CD_MLOOPUV, act); + act = CustomData_get_clone_layer(ldata, CD_MLOOPUV); CustomData_set_layer_clone(fdata, CD_MTFACE, act); - act = CustomData_get_stencil_layer(pdata, CD_MTEXPOLY); - CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act); + act = CustomData_get_stencil_layer(ldata, CD_MLOOPUV); CustomData_set_layer_stencil(fdata, CD_MTFACE, act); } @@ -2632,25 +2638,21 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, * used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files */ -void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata) +void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata) { int act; if (CustomData_has_layer(fdata, CD_MTFACE)) { act = CustomData_get_active_layer(fdata, CD_MTFACE); - CustomData_set_layer_active(pdata, CD_MTEXPOLY, act); CustomData_set_layer_active(ldata, CD_MLOOPUV, act); act = CustomData_get_render_layer(fdata, CD_MTFACE); - CustomData_set_layer_render(pdata, CD_MTEXPOLY, act); CustomData_set_layer_render(ldata, CD_MLOOPUV, act); act = CustomData_get_clone_layer(fdata, CD_MTFACE); - CustomData_set_layer_clone(pdata, CD_MTEXPOLY, act); CustomData_set_layer_clone(ldata, CD_MLOOPUV, act); act = CustomData_get_stencil_layer(fdata, CD_MTFACE); - CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, act); CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act); } @@ -2695,7 +2697,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) bool CustomData_bmesh_merge( const CustomData *source, CustomData *dest, - CustomDataMask mask, int alloctype, BMesh *bm, const char htype) + CustomDataMask mask, eCDAllocType alloctype, BMesh *bm, const char htype) { BMHeader *h; BMIter iter; @@ -3741,19 +3743,6 @@ void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem) CustomData_external_read(data, id, CD_TYPE_AS_MASK(layer->type), totelem); layer->flag &= ~CD_FLAG_EXTERNAL; - -#if 0 - remove_file = 1; - for (i = 0; i < data->totlayer; i++) - if (data->layers[i].flag & CD_FLAG_EXTERNAL) - remove_file = 0; - - if (remove_file) { - customdata_external_filename(filename, id, external); - cdf_remove(filename); - CustomData_external_free(data); - } -#endif } } @@ -3769,21 +3758,6 @@ bool CustomData_external_test(CustomData *data, int type) return (layer->flag & CD_FLAG_EXTERNAL) != 0; } -#if 0 -void CustomData_external_remove_object(CustomData *data, ID *id) -{ - CustomDataExternal *external = data->external; - char filename[FILE_MAX]; - - if (!external) - return; - - customdata_external_filename(filename, id, external); - cdf_remove(filename); - CustomData_external_free(data); -} -#endif - /* ********** Mesh-to-mesh data transfer ********** */ static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag) { diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c index 3fee2ef6021..3350d8e7b2f 100644 --- a/source/blender/blenkernel/intern/customdata_file.c +++ b/source/blender/blenkernel/intern/customdata_file.c @@ -110,16 +110,6 @@ static int cdf_endian(void) return CDF_ENDIAN_BIG; } -#if 0 -static int cdf_data_type_size(int datatype) -{ - if (datatype == CDF_DATA_FLOAT) - return sizeof(float); - - return 0; -} -#endif - CDataFile *cdf_create(int type) { CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile"); diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 7407fc2051f..73c5f6cecdf 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -42,14 +42,13 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BKE_cdderivedmesh.h" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_data_transfer.h" #include "BKE_deform.h" -#include "BKE_DerivedMesh.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_mesh_remap.h" #include "BKE_object.h" #include "BKE_object_deform.h" @@ -79,7 +78,7 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types cddata_mask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */ } else if (cddata_type == CD_FAKE_UV) { - cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV; + cddata_mask |= CD_MASK_MLOOPUV; } else if (cddata_type == CD_FAKE_LNOR) { cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; @@ -256,77 +255,76 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type) /* Generic pre/post processing, only used by custom loop normals currently. */ static void data_transfer_dtdata_type_preprocess( - Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst, - const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src) + Mesh *me_src, Mesh *me_dst, + const int dtdata_type, const bool dirty_nors_dst) { if (dtdata_type == DT_TYPE_LNOR) { /* Compute custom normals into regular loop normals, which will be used for the transfer. */ - MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; - const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; - MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; - const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; - MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; - const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; - MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; - const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; - CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; - CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + MVert *verts_dst = me_dst->mvert; + const int num_verts_dst = me_dst->totvert; + MEdge *edges_dst = me_dst->medge; + const int num_edges_dst = me_dst->totedge; + MPoly *polys_dst = me_dst->mpoly; + const int num_polys_dst = me_dst->totpoly; + MLoop *loops_dst = me_dst->mloop; + const int num_loops_dst = me_dst->totloop; + CustomData *pdata_dst = &me_dst->pdata; + CustomData *ldata_dst = &me_dst->ldata; const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0; const float split_angle_dst = me_dst->smoothresh; - dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src); + BKE_mesh_calc_normals_split(me_src); - if (dm_dst) { - dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst); - } - else { - float (*poly_nors_dst)[3]; - float (*loop_nors_dst)[3]; - short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); - - /* Cache poly nors into a temp CDLayer. */ - poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); - if (dirty_nors_dst || !poly_nors_dst) { - if (!poly_nors_dst) { - poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst); - CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); - } - BKE_mesh_calc_normals_poly(verts_dst, NULL, num_verts_dst, loops_dst, polys_dst, - num_loops_dst, num_polys_dst, poly_nors_dst, true); - } - /* Cache loop nors into a temp CDLayer. */ - loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); - if (dirty_nors_dst || loop_nors_dst) { - if (!loop_nors_dst) { - loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst); - CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); - } - BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst, - loops_dst, loop_nors_dst, num_loops_dst, - polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst, - use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL); - } + float (*poly_nors_dst)[3]; + float (*loop_nors_dst)[3]; + short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL); + + /* Cache poly nors into a temp CDLayer. */ + poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); + const bool do_poly_nors_dst = (poly_nors_dst == NULL); + if (do_poly_nors_dst) { + poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst); + CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst || do_poly_nors_dst) { + BKE_mesh_calc_normals_poly( + verts_dst, NULL, num_verts_dst, loops_dst, polys_dst, + num_loops_dst, num_polys_dst, poly_nors_dst, true); + } + /* Cache loop nors into a temp CDLayer. */ + loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); + const bool do_loop_nors_dst = (loop_nors_dst == NULL); + if (do_loop_nors_dst) { + loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst); + CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst || do_loop_nors_dst) { + BKE_mesh_normals_loop_split( + verts_dst, num_verts_dst, edges_dst, num_edges_dst, + loops_dst, loop_nors_dst, num_loops_dst, + polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst, + use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL); } } } static void data_transfer_dtdata_type_postprocess( - Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst, + Object *UNUSED(ob_src), Object *UNUSED(ob_dst), Mesh *UNUSED(me_src), Mesh *me_dst, const int dtdata_type, const bool changed) { if (dtdata_type == DT_TYPE_LNOR) { /* Bake edited destination loop normals into custom normals again. */ - MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; - const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; - MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; - const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; - MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; - const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; - MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; - const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; - CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; - CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + MVert *verts_dst = me_dst->mvert; + const int num_verts_dst = me_dst->totvert; + MEdge *edges_dst = me_dst->medge; + const int num_edges_dst = me_dst->totedge; + MPoly *polys_dst = me_dst->mpoly; + const int num_polys_dst = me_dst->totpoly; + MLoop *loops_dst = me_dst->mloop; + const int num_loops_dst = me_dst->totloop; + CustomData *pdata_dst = &me_dst->pdata; + CustomData *ldata_dst = &me_dst->ldata; const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL); float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL); @@ -530,7 +528,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst( continue; } data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src); - /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + /* If dest is a evaluated mesh (fro; ;odifier), we do not want to overwrite cdlayers of orig mesh! */ if (use_dupref_dst) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst); } @@ -574,7 +572,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst( data_dst_to_delete[idx_dst] = false; } if (r_map) { - /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */ if (use_dupref_dst) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } @@ -632,7 +630,7 @@ static bool data_transfer_layersmapping_cdlayers( data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); } else if (use_dupref_dst && r_map) { - /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */ data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst); } @@ -659,7 +657,7 @@ static bool data_transfer_layersmapping_cdlayers( if (tolayers >= 0) { /* Real-layer index */ idx_dst = tolayers; - /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } @@ -675,7 +673,7 @@ static bool data_transfer_layersmapping_cdlayers( data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); } else { - /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } @@ -696,7 +694,7 @@ static bool data_transfer_layersmapping_cdlayers( CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); } } - /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } @@ -713,7 +711,7 @@ static bool data_transfer_layersmapping_cdlayers( CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } - /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */ + /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */ if (use_dupref_dst && r_map) { data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst); } @@ -762,7 +760,7 @@ static bool data_transfer_layersmapping_cdlayers( } static bool data_transfer_layersmapping_generate( - ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst, + ListBase *r_map, Object *ob_src, Object *ob_dst, Mesh *me_src, Mesh *me_dst, const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights, const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers, SpaceTransform *space_transform) @@ -774,12 +772,12 @@ static bool data_transfer_layersmapping_generate( if (elem_type == ME_VERT) { if (!(cddata_type & CD_FAKE)) { - cd_src = dm_src->getVertDataLayout(dm_src); - cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata; + cd_src = &me_src->vdata; + cd_dst = &me_dst->vdata; if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, - cd_src, cd_dst, dm_dst != NULL, + cd_src, cd_dst, me_dst != ob_dst->data, fromlayers, tolayers, interp, interp_data)) { @@ -794,24 +792,17 @@ static bool data_transfer_layersmapping_generate( const size_t data_offset = offsetof(MVert, bweight); const uint64_t data_flag = 0; - if (!(dm_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) { - if (use_delete && !dm_dst) { + if (!(me_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) { + if (use_delete) { me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT; } return true; } - if (dm_dst) { - dm_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; - } - else { - me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; - } + me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT; if (r_map) { data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights, - dm_src->getVertArray(dm_src), - dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert, - dm_src->getNumVerts(dm_src), - dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert, + me_src->mvert, me_dst->mvert, + me_src->totvert, me_dst->totvert, elem_size, data_size, data_offset, data_flag, data_transfer_interp_char, interp_data); } @@ -820,12 +811,12 @@ static bool data_transfer_layersmapping_generate( else if (cddata_type == CD_FAKE_MDEFORMVERT) { bool ret; - cd_src = dm_src->getVertDataLayout(dm_src); - cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata; + cd_src = &me_src->vdata; + cd_dst = &me_dst->vdata; ret = data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, - ob_src, ob_dst, cd_src, cd_dst, dm_dst != NULL, + ob_src, ob_dst, cd_src, cd_dst, me_dst != ob_dst->data, fromlayers, tolayers); /* Mesh stores its dvert in a specific pointer too. :( */ @@ -839,12 +830,12 @@ static bool data_transfer_layersmapping_generate( } else if (elem_type == ME_EDGE) { if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */ - cd_src = dm_src->getEdgeDataLayout(dm_src); - cd_dst = dm_dst ? dm_dst->getEdgeDataLayout(dm_dst) : &me_dst->edata; + cd_src = &me_src->edata; + cd_dst = &me_dst->edata; if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete, - cd_src, cd_dst, dm_dst != NULL, + cd_src, cd_dst, me_dst != ob_dst->data, fromlayers, tolayers, interp, interp_data)) { @@ -859,24 +850,17 @@ static bool data_transfer_layersmapping_generate( const size_t data_offset = offsetof(MEdge, crease); const uint64_t data_flag = 0; - if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) { - if (use_delete && !dm_dst) { + if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) { + if (use_delete && !me_dst) { me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE; } return true; } - if (dm_dst) { - dm_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE; - } - else { - me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE; - } + me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE; if (r_map) { data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights, - dm_src->getEdgeArray(dm_src), - dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge, - dm_src->getNumEdges(dm_src), - dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, + me_src->medge, me_dst->medge, + me_src->totedge, me_dst->totedge, elem_size, data_size, data_offset, data_flag, data_transfer_interp_char, interp_data); } @@ -888,24 +872,17 @@ static bool data_transfer_layersmapping_generate( const size_t data_offset = offsetof(MEdge, bweight); const uint64_t data_flag = 0; - if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) { - if (use_delete && !dm_dst) { + if (!(me_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) { + if (use_delete && !me_dst) { me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT; } return true; } - if (dm_dst) { - dm_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; - } - else { - me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; - } + me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT; if (r_map) { data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights, - dm_src->getEdgeArray(dm_src), - dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge, - dm_src->getNumEdges(dm_src), - dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, + me_src->medge, me_dst->medge, + me_src->totedge, me_dst->totedge, elem_size, data_size, data_offset, data_flag, data_transfer_interp_char, interp_data); } @@ -919,10 +896,8 @@ static bool data_transfer_layersmapping_generate( data_transfer_layersmapping_add_item( r_map, cddata_type, mix_mode, mix_factor, mix_weights, - dm_src->getEdgeArray(dm_src), - dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge, - dm_src->getNumEdges(dm_src), - dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge, + me_src->medge, me_dst->medge, + me_src->totedge, me_dst->totedge, elem_size, data_size, data_offset, data_flag, NULL, interp_data); return true; } @@ -942,12 +917,12 @@ static bool data_transfer_layersmapping_generate( } if (!(cddata_type & CD_FAKE)) { - cd_src = dm_src->getLoopDataLayout(dm_src); - cd_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + cd_src = &me_src->ldata; + cd_dst = &me_dst->ldata; if (!data_transfer_layersmapping_cdlayers( r_map, cddata_type, mix_mode, mix_factor, mix_weights, - num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, + num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data, fromlayers, tolayers, interp, interp_data)) { @@ -962,16 +937,16 @@ static bool data_transfer_layersmapping_generate( } else if (elem_type == ME_POLY) { if (cddata_type == CD_FAKE_UV) { - cddata_type = CD_MTEXPOLY; + cddata_type = CD_MLOOPUV; } if (!(cddata_type & CD_FAKE)) { - cd_src = dm_src->getPolyDataLayout(dm_src); - cd_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; + cd_src = &me_src->pdata; + cd_dst = &me_dst->pdata; if (!data_transfer_layersmapping_cdlayers( r_map, cddata_type, mix_mode, mix_factor, mix_weights, - num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL, + num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data, fromlayers, tolayers, interp, interp_data)) { @@ -988,10 +963,8 @@ static bool data_transfer_layersmapping_generate( data_transfer_layersmapping_add_item( r_map, cddata_type, mix_mode, mix_factor, mix_weights, - dm_src->getPolyArray(dm_src), - dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly, - dm_src->getNumPolys(dm_src), - dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly, + me_src->mpoly, me_dst->mpoly, + me_src->totpoly, me_dst->totpoly, elem_size, data_size, data_offset, data_flag, NULL, interp_data); return true; } @@ -1010,25 +983,26 @@ static bool data_transfer_layersmapping_generate( * to get (as much as possible) exact copy of source data layout. */ void BKE_object_data_transfer_layout( - Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete, + struct Depsgraph *depsgraph, Scene *scene, + Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]) { - DerivedMesh *dm_src; + Mesh *me_src; Mesh *me_dst; int i; const bool use_create = true; /* We always create needed layers here. */ - CustomDataMask dm_src_mask = CD_MASK_BAREMESH; + CustomDataMask me_src_mask = CD_MASK_BAREMESH; BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); me_dst = ob_dst->data; - /* Get source DM.*/ - dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); - dm_src = mesh_get_derived_final(scene, ob_src, dm_src_mask); - if (!dm_src) { + /* Get source evaluated mesh.*/ + me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); + me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask); + if (!me_src) { return; } @@ -1057,37 +1031,37 @@ void BKE_object_data_transfer_layout( const int num_elem_dst = me_dst->totvert; data_transfer_layersmapping_generate( - NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL, + NULL, ob_src, ob_dst, me_src, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { const int num_elem_dst = me_dst->totedge; data_transfer_layersmapping_generate( - NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL, + NULL, ob_src, ob_dst, me_src, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { const int num_elem_dst = me_dst->totloop; data_transfer_layersmapping_generate( - NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL, + NULL, ob_src, ob_dst, me_src, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } if (DT_DATATYPE_IS_POLY(dtdata_type)) { const int num_elem_dst = me_dst->totpoly; data_transfer_layersmapping_generate( - NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL, + NULL, ob_src, ob_dst, me_src, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL, num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL); } } } -bool BKE_object_data_transfer_dm( - Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create, - const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, - SpaceTransform *space_transform, const bool auto_transform, +bool BKE_object_data_transfer_ex( + struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, Mesh *me_dst, + const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode, + const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform, const float max_distance, const float ray_radius, const float islands_handling_precision, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, @@ -1101,9 +1075,8 @@ bool BKE_object_data_transfer_dm( SpaceTransform auto_space_transform; - DerivedMesh *dm_src; - Mesh *me_dst, *me_src; - bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */ + Mesh *me_src; + bool dirty_nors_dst = true; /* Assumed always true if not using an evaluated mesh as destination. */ int i; MDeformVert *mdef = NULL; @@ -1117,53 +1090,40 @@ bool BKE_object_data_transfer_dm( const bool use_delete = false; /* We never delete data layers from destination here. */ - CustomDataMask dm_src_mask = CD_MASK_BAREMESH; + CustomDataMask me_src_mask = CD_MASK_BAREMESH; BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); - me_dst = ob_dst->data; - me_src = ob_src->data; - if (dm_dst) { - dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0; - use_create = false; /* Never create needed custom layers on DM (modifier case). */ + if (me_dst) { + dirty_nors_dst = (me_dst->runtime.cd_dirty_vert & CD_NORMAL) != 0; + /* Never create needed custom layers on passed destination mesh + * (assumed to *not* be ob_dst->data, aka modifier case). */ + use_create = false; + } + else { + me_dst = ob_dst->data; } if (vgroup_name) { - if (dm_dst) { - mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT); - } - else { - mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT); - } + mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT); if (mdef) { vg_idx = defgroup_name_index(ob_dst, vgroup_name); } } - /* Get source DM.*/ - dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); - /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm, - * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers... - * Issue is, this means we cannot be sure to have requested cd layers in source. - * - * Also, we need to make a local copy of dm_src, otherwise we may end with concurrent creation - * of data in it (multi-threaded evaluation of the modifier stack, see T46672). - */ - dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask); - if (!dm_src) { + /* Get source evaluated mesh.*/ + me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types); + me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask); + if (!me_src) { return changed; } - dm_src = CDDM_copy(dm_src); if (auto_transform) { - MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; - const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; - if (space_transform == NULL) { space_transform = &auto_space_transform; } - BKE_mesh_remap_find_best_match_from_dm(verts_dst, num_verts_dst, dm_src, space_transform); + BKE_mesh_remap_find_best_match_from_mesh(me_dst->mvert, me_dst->totvert, me_src, space_transform); } /* Check all possible data types. @@ -1177,9 +1137,7 @@ bool BKE_object_data_transfer_dm( continue; } - data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, - dtdata_type, dirty_nors_dst, - (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh); + data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst); cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); @@ -1193,11 +1151,11 @@ bool BKE_object_data_transfer_dm( } if (DT_DATATYPE_IS_VERT(dtdata_type)) { - MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; - const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; + MVert *verts_dst = me_dst->mvert; + const int num_verts_dst = me_dst->totvert; if (!geom_map_init[VDATA]) { - const int num_verts_src = dm_src->getNumVerts(dm_src); + const int num_verts_src = me_src->totvert; if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) { BKE_report(reports, RPT_ERROR, @@ -1205,13 +1163,13 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } - if ((map_vert_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) { + if ((map_vert_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) { BKE_report(reports, RPT_ERROR, "Source mesh doesn't have any edges, " "None of the 'Edge' mappings can be used in this case"); continue; } - if ((map_vert_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) { + if ((map_vert_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) { BKE_report(reports, RPT_ERROR, "Source mesh doesn't have any faces, " "None of the 'Face' mappings can be used in this case"); @@ -1223,9 +1181,9 @@ bool BKE_object_data_transfer_dm( continue; } - BKE_mesh_remap_calc_verts_from_dm( + BKE_mesh_remap_calc_verts_from_mesh( map_vert_mode, space_transform, max_distance, ray_radius, - verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]); + verts_dst, num_verts_dst, dirty_nors_dst, me_src, &geom_map[VDATA]); geom_map_init[VDATA] = true; } @@ -1235,7 +1193,7 @@ bool BKE_object_data_transfer_dm( } if (data_transfer_layersmapping_generate( - &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT, + &lay_map, ob_src, ob_dst, me_src, me_dst, ME_VERT, cddata_type, mix_mode, mix_factor, weights[VDATA], num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { @@ -1251,13 +1209,13 @@ bool BKE_object_data_transfer_dm( } } if (DT_DATATYPE_IS_EDGE(dtdata_type)) { - MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; - const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; - MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; - const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; + MVert *verts_dst = me_dst->mvert; + const int num_verts_dst = me_dst->totvert; + MEdge *edges_dst = me_dst->medge; + const int num_edges_dst = me_dst->totedge; if (!geom_map_init[EDATA]) { - const int num_edges_src = dm_src->getNumEdges(dm_src); + const int num_edges_src = me_src->totedge; if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) { BKE_report(reports, RPT_ERROR, @@ -1265,7 +1223,7 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } - if ((map_edge_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) { + if ((map_edge_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) { BKE_report(reports, RPT_ERROR, "Source mesh doesn't have any faces, " "None of the 'Face' mappings can be used in this case"); @@ -1277,10 +1235,10 @@ bool BKE_object_data_transfer_dm( continue; } - BKE_mesh_remap_calc_edges_from_dm( + BKE_mesh_remap_calc_edges_from_mesh( map_edge_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst, - dm_src, &geom_map[EDATA]); + me_src, &geom_map[EDATA]); geom_map_init[EDATA] = true; } @@ -1292,7 +1250,7 @@ bool BKE_object_data_transfer_dm( } if (data_transfer_layersmapping_generate( - &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE, + &lay_map, ob_src, ob_dst, me_src, me_dst, ME_EDGE, cddata_type, mix_mode, mix_factor, weights[EDATA], num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { @@ -1308,21 +1266,21 @@ bool BKE_object_data_transfer_dm( } } if (DT_DATATYPE_IS_LOOP(dtdata_type)) { - MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; - const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; - MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge; - const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge; - MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; - const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; - MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; - const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; - CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; - CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata; + MVert *verts_dst = me_dst->mvert; + const int num_verts_dst = me_dst->totvert; + MEdge *edges_dst = me_dst->medge; + const int num_edges_dst = me_dst->totedge; + MPoly *polys_dst = me_dst->mpoly; + const int num_polys_dst = me_dst->totpoly; + MLoop *loops_dst = me_dst->mloop; + const int num_loops_dst = me_dst->totloop; + CustomData *pdata_dst = &me_dst->pdata; + CustomData *ldata_dst = &me_dst->ldata; MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type); if (!geom_map_init[LDATA]) { - const int num_loops_src = dm_src->getNumLoops(dm_src); + const int num_loops_src = me_src->totloop; if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) { BKE_report(reports, RPT_ERROR, @@ -1330,7 +1288,7 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } - if ((map_loop_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) { + if ((map_loop_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) { BKE_report(reports, RPT_ERROR, "Source mesh doesn't have any edges, " "None of the 'Edge' mappings can be used in this case"); @@ -1342,13 +1300,13 @@ bool BKE_object_data_transfer_dm( continue; } - BKE_mesh_remap_calc_loops_from_dm( + BKE_mesh_remap_calc_loops_from_mesh( map_loop_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, edges_dst, num_edges_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, ldata_dst, pdata_dst, (me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst, - dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh, + me_src, island_callback, islands_handling_precision, &geom_map[LDATA]); geom_map_init[LDATA] = true; } @@ -1361,7 +1319,7 @@ bool BKE_object_data_transfer_dm( } if (data_transfer_layersmapping_generate( - &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP, + &lay_map, ob_src, ob_dst, me_src, me_dst, ME_LOOP, cddata_type, mix_mode, mix_factor, weights[LDATA], num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { @@ -1377,16 +1335,16 @@ bool BKE_object_data_transfer_dm( } } if (DT_DATATYPE_IS_POLY(dtdata_type)) { - MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert; - const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert; - MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly; - const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly; - MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop; - const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop; - CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata; + MVert *verts_dst = me_dst->mvert; + const int num_verts_dst = me_dst->totvert; + MPoly *polys_dst = me_dst->mpoly; + const int num_polys_dst = me_dst->totpoly; + MLoop *loops_dst = me_dst->mloop; + const int num_loops_dst = me_dst->totloop; + CustomData *pdata_dst = &me_dst->pdata; if (!geom_map_init[PDATA]) { - const int num_polys_src = dm_src->getNumPolys(dm_src); + const int num_polys_src = me_src->totpoly; if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) { BKE_report(reports, RPT_ERROR, @@ -1394,7 +1352,7 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } - if ((map_poly_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) { + if ((map_poly_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) { BKE_report(reports, RPT_ERROR, "Source mesh doesn't have any edges, " "None of the 'Edge' mappings can be used in this case"); @@ -1406,11 +1364,11 @@ bool BKE_object_data_transfer_dm( continue; } - BKE_mesh_remap_calc_polys_from_dm( + BKE_mesh_remap_calc_polys_from_mesh( map_poly_mode, space_transform, max_distance, ray_radius, verts_dst, num_verts_dst, loops_dst, num_loops_dst, polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst, - dm_src, &geom_map[PDATA]); + me_src, &geom_map[PDATA]); geom_map_init[PDATA] = true; } @@ -1422,7 +1380,7 @@ bool BKE_object_data_transfer_dm( } if (data_transfer_layersmapping_generate( - &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY, + &lay_map, ob_src, ob_dst, me_src, me_dst, ME_POLY, cddata_type, mix_mode, mix_factor, weights[PDATA], num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform)) { @@ -1438,14 +1396,13 @@ bool BKE_object_data_transfer_dm( } } - data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed); + data_transfer_dtdata_type_postprocess(ob_src, ob_dst, me_src, me_dst, dtdata_type, changed); } for (i = 0; i < DATAMAX; i++) { BKE_mesh_remap_free(&geom_map[i]); MEM_SAFE_FREE(weights[i]); } - dm_src->release(dm_src); return changed; @@ -1457,16 +1414,16 @@ bool BKE_object_data_transfer_dm( } bool BKE_object_data_transfer_mesh( - Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_create, - const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode, - SpaceTransform *space_transform, const bool auto_transform, + struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, + const bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, + const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform, const float max_distance, const float ray_radius, const float islands_handling_precision, const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX], const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup, ReportList *reports) { - return BKE_object_data_transfer_dm( - scene, ob_src, ob_dst, NULL, data_types, use_create, + return BKE_object_data_transfer_ex( + depsgraph, scene, ob_src, ob_dst, NULL, data_types, use_create, map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, space_transform, auto_transform, max_distance, ray_radius, islands_handling_precision, diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index f33f17019b3..bbb7fc4b3bd 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -54,7 +54,9 @@ #include "BKE_customdata.h" #include "BKE_data_transfer.h" #include "BKE_deform.h" /* own include */ +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_object.h" #include "BKE_object_deform.h" #include "data_transfer_intern.h" @@ -73,6 +75,8 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name) BLI_addtail(&ob->defbase, defgroup); defgroup_unique_name(defgroup, ob); + BKE_object_batch_cache_dirty_tag(ob); + return defgroup; } @@ -1290,3 +1294,43 @@ bool data_transfer_layersmapping_vgroups( } /** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Various utils & helpers. + * \{ */ + +void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight) +{ + const float blend = ((weight / 2.0f) + 0.5f); + + if (weight <= 0.25f) { /* blue->cyan */ + r_rgb[0] = 0.0f; + r_rgb[1] = blend * weight * 4.0f; + r_rgb[2] = blend; + } + else if (weight <= 0.50f) { /* cyan->green */ + r_rgb[0] = 0.0f; + r_rgb[1] = blend; + r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f)); + } + else if (weight <= 0.75f) { /* green->yellow */ + r_rgb[0] = blend * ((weight - 0.50f) * 4.0f); + r_rgb[1] = blend; + r_rgb[2] = 0.0f; + } + else if (weight <= 1.0f) { /* yellow->red */ + r_rgb[0] = blend; + r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f)); + r_rgb[2] = 0.0f; + } + else { + /* exceptional value, unclamped or nan, + * avoid uninitialized memory use */ + r_rgb[0] = 1.0f; + r_rgb[1] = 0.0f; + r_rgb[2] = 1.0f; + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c deleted file mode 100644 index 734aac8a1f7..00000000000 --- a/source/blender/blenkernel/intern/depsgraph.c +++ /dev/null @@ -1,3745 +0,0 @@ -/* - * ***** 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) 2004 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/depsgraph.c - * \ingroup bke - */ - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#ifdef WIN32 -# include "BLI_winstuff.h" -#endif - -#include "BLI_utildefines.h" -#include "BLI_listbase.h" -#include "BLI_ghash.h" -#include "BLI_threads.h" - -#include "DNA_anim_types.h" -#include "DNA_camera_types.h" -#include "DNA_cachefile_types.h" -#include "DNA_group_types.h" -#include "DNA_lamp_types.h" -#include "DNA_lattice_types.h" -#include "DNA_key_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_node_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_windowmanager_types.h" -#include "DNA_movieclip_types.h" -#include "DNA_mask_types.h" -#include "DNA_modifier_types.h" -#include "DNA_rigidbody_types.h" - -#include "BKE_anim.h" -#include "BKE_animsys.h" -#include "BKE_action.h" -#include "BKE_DerivedMesh.h" -#include "BKE_collision.h" -#include "BKE_curve.h" -#include "BKE_effect.h" -#include "BKE_fcurve.h" -#include "BKE_global.h" -#include "BKE_idcode.h" -#include "BKE_image.h" -#include "BKE_key.h" -#include "BKE_library.h" -#include "BKE_main.h" -#include "BKE_node.h" -#include "BKE_material.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" -#include "BKE_pointcache.h" -#include "BKE_scene.h" -#include "BKE_screen.h" -#include "BKE_tracking.h" - -#include "GPU_buffers.h" - -#include "atomic_ops.h" - -#include "depsgraph_private.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_build.h" -#include "DEG_depsgraph_debug.h" -#include "DEG_depsgraph_query.h" - -#ifdef WITH_LEGACY_DEPSGRAPH - -static SpinLock threaded_update_lock; - -void DAG_init(void) -{ - BLI_spin_init(&threaded_update_lock); - DEG_register_node_types(); -} - -void DAG_exit(void) -{ - BLI_spin_end(&threaded_update_lock); - DEG_free_node_types(); -} - -/* Queue and stack operations for dag traversal - * - * the queue store a list of freenodes to avoid successive alloc/dealloc - */ - -DagNodeQueue *queue_create(int slots) -{ - DagNodeQueue *queue; - DagNodeQueueElem *elem; - int i; - - queue = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue"); - queue->freenodes = MEM_mallocN(sizeof(DagNodeQueue), "DAG queue"); - queue->count = 0; - queue->maxlevel = 0; - queue->first = queue->last = NULL; - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem3"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < slots; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem4"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = slots; - return queue; -} - -void queue_raz(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - - elem = queue->first; - if (queue->freenodes->last) - queue->freenodes->last->next = elem; - else - queue->freenodes->first = queue->freenodes->last = elem; - - elem->node = NULL; - queue->freenodes->count++; - while (elem->next) { - elem = elem->next; - elem->node = NULL; - queue->freenodes->count++; - } - queue->freenodes->last = elem; - queue->count = 0; -} - -void queue_delete(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - DagNodeQueueElem *temp; - - elem = queue->first; - while (elem) { - temp = elem; - elem = elem->next; - MEM_freeN(temp); - } - - elem = queue->freenodes->first; - while (elem) { - temp = elem; - elem = elem->next; - MEM_freeN(temp); - } - - MEM_freeN(queue->freenodes); - MEM_freeN(queue); -} - -/* insert in queue, remove in front */ -void push_queue(DagNodeQueue *queue, DagNode *node) -{ - DagNodeQueueElem *elem; - int i; - - if (node == NULL) { - fprintf(stderr, "pushing null node\n"); - return; - } - /*fprintf(stderr, "BFS push : %s %d\n", ((ID *) node->ob)->name, queue->count);*/ - - elem = queue->freenodes->first; - if (elem != NULL) { - queue->freenodes->first = elem->next; - if (queue->freenodes->last == elem) { - queue->freenodes->last = NULL; - queue->freenodes->first = NULL; - } - queue->freenodes->count--; - } - else { /* alllocating more */ - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < DAGQUEUEALLOC; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = DAGQUEUEALLOC; - - elem = queue->freenodes->first; - queue->freenodes->first = elem->next; - } - elem->next = NULL; - elem->node = node; - if (queue->last != NULL) - queue->last->next = elem; - queue->last = elem; - if (queue->first == NULL) { - queue->first = elem; - } - queue->count++; -} - - -/* insert in front, remove in front */ -void push_stack(DagNodeQueue *queue, DagNode *node) -{ - DagNodeQueueElem *elem; - int i; - - elem = queue->freenodes->first; - if (elem != NULL) { - queue->freenodes->first = elem->next; - if (queue->freenodes->last == elem) { - queue->freenodes->last = NULL; - queue->freenodes->first = NULL; - } - queue->freenodes->count--; - } - else { /* alllocating more */ - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem1"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->first = queue->freenodes->last = elem; - - for (i = 1; i < DAGQUEUEALLOC; i++) { - elem = MEM_mallocN(sizeof(DagNodeQueueElem), "DAG queue elem2"); - elem->node = NULL; - elem->next = NULL; - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - } - queue->freenodes->count = DAGQUEUEALLOC; - - elem = queue->freenodes->first; - queue->freenodes->first = elem->next; - } - elem->next = queue->first; - elem->node = node; - queue->first = elem; - if (queue->last == NULL) - queue->last = elem; - queue->count++; -} - - -DagNode *pop_queue(DagNodeQueue *queue) -{ - DagNodeQueueElem *elem; - DagNode *node; - - elem = queue->first; - if (elem) { - queue->first = elem->next; - if (queue->last == elem) { - queue->last = NULL; - queue->first = NULL; - } - queue->count--; - if (queue->freenodes->last) - queue->freenodes->last->next = elem; - queue->freenodes->last = elem; - if (queue->freenodes->first == NULL) - queue->freenodes->first = elem; - node = elem->node; - elem->node = NULL; - elem->next = NULL; - queue->freenodes->count++; - return node; - } - else { - fprintf(stderr, "return null\n"); - return NULL; - } -} - -DagNode *get_top_node_queue(DagNodeQueue *queue) -{ - return queue->first->node; -} - -DagForest *dag_init(void) -{ - DagForest *forest; - /* use callocN to init all zero */ - forest = MEM_callocN(sizeof(DagForest), "DAG root"); - forest->ugly_hack_sorry = true; - return forest; -} - -/* isdata = object data... */ -/* XXX this needs to be extended to be more flexible (so that not only objects are evaluated via depsgraph)... */ -static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node, int isdata) -{ - FCurve *fcu; - DagNode *node1; - - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - int isdata_fcu = (isdata) || (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")); - - /* loop over variables to get the target relationships */ - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* only used targets */ - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id) { - /* FIXME: other data types need to be added here so that they can work! */ - if (GS(dtar->id->name) == ID_OB) { - Object *ob = (Object *)dtar->id; - - /* normal channel-drives-channel */ - node1 = dag_get_node(dag, dtar->id); - - /* check if bone... */ - if ((ob->type == OB_ARMATURE) && - ( ((dtar->rna_path) && strstr(dtar->rna_path, "pose.bones[")) || - ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) )) - { - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver"); - } - /* check if ob data */ - else if (dtar->rna_path && strstr(dtar->rna_path, "data.")) - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_DATA_DATA : DAG_RL_DATA_OB, "Driver"); - /* normal */ - else - dag_add_relation(dag, node1, node, isdata_fcu ? DAG_RL_OB_DATA : DAG_RL_OB_OB, "Driver"); - } - } - } - DRIVER_TARGETS_LOOPER_END - } - } -} - -/* XXX: forward def for material driver handling... */ -static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma); - -/* recursive handling for shader nodetree drivers */ -static void dag_add_shader_nodetree_driver_relations(DagForest *dag, DagNode *node, bNodeTree *ntree) -{ - bNode *n; - - /* nodetree itself */ - if (ntree->adt) { - dag_add_driver_relation(ntree->adt, dag, node, 1); - } - - /* nodetree's nodes... */ - for (n = ntree->nodes.first; n; n = n->next) { - if (n->id) { - if (GS(n->id->name) == ID_MA) { - dag_add_material_driver_relations(dag, node, (Material *)n->id); - } - else if (n->type == NODE_GROUP) { - dag_add_shader_nodetree_driver_relations(dag, node, (bNodeTree *)n->id); - } - } - } -} - -/* recursive handling for material drivers */ -static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma) -{ - /* Prevent infinite recursion by checking (and tagging the material) as having been visited - * already (see build_dag()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (ma->id.tag & LIB_TAG_DOIT) - return; - - ma->id.tag |= LIB_TAG_DOIT; - - /* material itself */ - if (ma->adt) - dag_add_driver_relation(ma->adt, dag, node, 1); - - /* textures */ - // TODO... - //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); - - /* material's nodetree */ - if (ma->nodetree) - dag_add_shader_nodetree_driver_relations(dag, node, ma->nodetree); - - ma->id.tag &= ~LIB_TAG_DOIT; -} - -/* recursive handling for lamp drivers */ -static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *la) -{ - /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited - * already (see build_dag()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (la->id.tag & LIB_TAG_DOIT) - return; - - la->id.tag |= LIB_TAG_DOIT; - - /* lamp itself */ - if (la->adt) - dag_add_driver_relation(la->adt, dag, node, 1); - - /* textures */ - // TODO... - //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); - - /* lamp's nodetree */ - if (la->nodetree) - dag_add_shader_nodetree_driver_relations(dag, node, la->nodetree); - - la->id.tag &= ~LIB_TAG_DOIT; -} - -static void create_collision_relation(DagForest *dag, DagNode *node, Object *ob1, const char *name) -{ - DagNode *node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, name); -} - -void dag_add_collision_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name) -{ - unsigned int numcollobj; - Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli); - - for (unsigned int i = 0; i < numcollobj; i++) { - Object *ob1 = collobjs[i]; - - if (!fn || fn(ob1, modifiers_findByType(ob1, modifier_type))) { - create_collision_relation(dag, node, ob1, name); - } - } - - if (collobjs) - MEM_freeN(collobjs); -} - -void dag_add_forcefield_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name) -{ - ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false); - - if (effectors) { - for (EffectorCache *eff = effectors->first; eff; eff = eff->next) { - if (eff->ob != ob && eff->pd->forcefield != skip_forcefield) { - create_collision_relation(dag, node, eff->ob, name); - - if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) { - create_collision_relation(dag, node, eff->pd->f_source, "Smoke Force Domain"); - } - - if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) { - /* Actual code uses get_collider_cache */ - dag_add_collision_relations(dag, scene, ob, node, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption"); - } - } - } - } - - pdEndEffectors(&effectors); -} - -static bool build_deg_tracking_constraints(DagForest *dag, - Scene *scene, - DagNode *scenenode, - bConstraint *con, - const bConstraintTypeInfo *cti, - DagNode *node, - bool is_data) -{ - if (!ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, - CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER)) - { - return false; - } - bool depends_on_camera = false; - if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; - if ((data->clip || data->flag & FOLLOWTRACK_ACTIVECLIP) && data->track[0]) { - depends_on_camera = true; - } - if (data->depth_ob != NULL) { - DagNode *node2 = dag_get_node(dag, data->depth_ob); - dag_add_relation(dag, - node2, node, - (is_data) ? (DAG_RL_DATA_DATA | DAG_RL_OB_DATA) - : (DAG_RL_DATA_OB | DAG_RL_OB_OB), - cti->name); - } - } - else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - depends_on_camera = true; - } - if (depends_on_camera && scene->camera != NULL) { - DagNode *node2 = dag_get_node(dag, scene->camera); - dag_add_relation(dag, - node2, node, - (is_data) ? (DAG_RL_DATA_DATA | DAG_RL_OB_DATA) - : (DAG_RL_DATA_OB | DAG_RL_OB_OB), - cti->name); - } - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); - return true; -} - -static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, Object *ob, int mask) -{ - bConstraint *con; - DagNode *node; - DagNode *node2; - DagNode *node3; - Key *key; - ParticleSystem *psys; - int addtoroot = 1; - - node = dag_get_node(dag, ob); - - if ((ob->data) && (mask & DAG_RL_DATA)) { - node2 = dag_get_node(dag, ob->data); - dag_add_relation(dag, node, node2, DAG_RL_DATA, "Object-Data Relation"); - node2->first_ancestor = ob; - node2->ancestor_count += 1; - } - - /* also build a custom data mask for dependencies that need certain layers */ - - if (ob->type == OB_ARMATURE) { - if (ob->pose) { - bPoseChannel *pchan; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (!cti) { - continue; - } - - if (build_deg_tracking_constraints(dag, scene, scenenode, con, cti, node, true)) { - /* pass */ - } - else if (cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar && ct->tar != ob) { - // fprintf(stderr, "armature %s target :%s\n", ob->id.name, target->id.name); - node3 = dag_get_node(dag, ct->tar); - - if (ct->subtarget[0]) { - dag_add_relation(dag, node3, node, DAG_RL_OB_DATA | DAG_RL_DATA_DATA, cti->name); - if (ct->tar->type == OB_MESH) - node3->customdata_mask |= CD_MASK_MDEFORMVERT; - } - else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, - CONSTRAINT_TYPE_CLAMPTO, - CONSTRAINT_TYPE_SPLINEIK, - CONSTRAINT_TYPE_SHRINKWRAP)) - { - dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name); - } - else { - dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name); - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - - } - } - } - } - - /* driver dependencies, nla modifiers */ -#if 0 // XXX old animation system - if (ob->nlastrips.first) { - bActionStrip *strip; - bActionChannel *chan; - for (strip = ob->nlastrips.first; strip; strip = strip->next) { - if (strip->modifiers.first) { - bActionModifier *amod; - for (amod = strip->modifiers.first; amod; amod = amod->next) { - if (amod->ob) { - node2 = dag_get_node(dag, amod->ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "NLA Strip Modifier"); - } - } - } - } - } -#endif // XXX old animation system - if (ob->adt) - dag_add_driver_relation(ob->adt, dag, node, (ob->type == OB_ARMATURE)); // XXX isdata arg here doesn't give an accurate picture of situation - - key = BKE_key_from_object(ob); - if (key && key->adt) - dag_add_driver_relation(key->adt, dag, node, 1); - - if (ob->modifiers.first) { - ModifierData *md; - ModifierUpdateDepsgraphContext ctx = { - .scene = scene, - .object = ob, - - .forest = dag, - .obNode = node, - }; - for (md = ob->modifiers.first; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - - if (mti->updateDepgraph) mti->updateDepgraph(md, &ctx); - } - } - if (ob->parent) { - node2 = dag_get_node(dag, ob->parent); - - switch (ob->partype) { - case PARSKEL: - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Parent"); - break; - case PARVERT1: case PARVERT3: - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Vertex Parent"); - node2->customdata_mask |= CD_MASK_ORIGINDEX; - break; - case PARBONE: - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Bone Parent"); - break; - default: - if (ob->parent->type == OB_LATTICE) - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Lattice Parent"); - else if (ob->parent->type == OB_CURVE) { - Curve *cu = ob->parent->data; - if (cu->flag & CU_PATH) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, "Curve Parent"); - else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Curve Parent"); - } - else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Parent"); - break; - } - /* exception case: parent is duplivert */ - if (ob->type == OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert"); - } - - addtoroot = 0; - } - if (ob->proxy) { - node2 = dag_get_node(dag, ob->proxy); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Proxy"); - /* inverted relation, so addtoroot shouldn't be set to zero */ - } - - if (ob->transflag & OB_DUPLI) { - if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { - GroupObject *go; - for (go = ob->dup_group->gobject.first; go; go = go->next) { - if (go->ob) { - node2 = dag_get_node(dag, go->ob); - /* node2 changes node1, this keeps animations updated in groups?? not logical? */ - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Dupligroup"); - } - } - } - } - - /* rigidbody force fields */ - if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) { - if (ob->rigidbody_object && scene->rigidbody_world) { - dag_add_forcefield_relations(dag, scene, ob, node, scene->rigidbody_world->effector_weights, true, 0, "Force Field"); - } - } - - /* object data drivers */ - if (ob->data) { - AnimData *adt = BKE_animdata_from_id((ID *)ob->data); - if (adt) - dag_add_driver_relation(adt, dag, node, 1); - } - - /* object type/data relationships */ - switch (ob->type) { - case OB_CAMERA: - { - Camera *cam = (Camera *)ob->data; - - if (cam->dof_ob) { - node2 = dag_get_node(dag, cam->dof_ob); - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Camera DoF"); - } - break; - } - case OB_MBALL: - { - Object *mom = BKE_mball_basis_find(G.main, G.main->eval_ctx, scene, ob); - - if (mom != ob) { - node2 = dag_get_node(dag, mom); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Metaball"); /* mom depends on children! */ - } - break; - } - case OB_CURVE: - case OB_FONT: - { - Curve *cu = ob->data; - - if (cu->bevobj) { - node2 = dag_get_node(dag, cu->bevobj); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Bevel"); - } - if (cu->taperobj) { - node2 = dag_get_node(dag, cu->taperobj); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper"); - } - if (ob->type == OB_FONT) { - /* Really rather dirty hack. needs to support font family to work - * reliably on render export. - * - * This totally mimics behavior of regular verts duplication with - * parenting. The only tricky thing here is to get list of objects - * used for the custom "font". - * - * This shouldn't harm so much because this code only runs on DAG - * rebuild and this feature is not that commonly used. - * - * - sergey - - */ - if (cu->family[0] != '\n') { - ListBase *duplilist; - DupliObject *dob; - duplilist = object_duplilist(G.main, G.main->eval_ctx, scene, ob); - for (dob = duplilist->first; dob; dob = dob->next) { - node2 = dag_get_node(dag, dob->ob); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font"); - } - free_object_duplilist(duplilist); - } - - if (cu->textoncurve) { - node2 = dag_get_node(dag, cu->textoncurve); - /* Text on curve requires path to be evaluated for the target curve. */ - node2->eval_flags |= DAG_EVAL_NEED_CURVE_PATH; - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Texture On Curve"); - } - } - break; - } - } - - /* material drivers */ - if (ob->totcol) { - int a; - - for (a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - - if (ma) { - /* recursively figure out if there are drivers, and hook these up to this object */ - dag_add_material_driver_relations(dag, node, ma); - } - } - } - else if (ob->type == OB_LAMP) { - dag_add_lamp_driver_relations(dag, node, ob->data); - } - - /* particles */ - psys = ob->particlesystem.first; - if (psys) { - GroupObject *go; - - for (; psys; psys = psys->next) { - BoidRule *rule = NULL; - BoidState *state = NULL; - ParticleSettings *part = psys->part; - - if (part->adt) { - dag_add_driver_relation(part->adt, dag, node, 1); - } - - dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); - - if (!psys_check_enabled(ob, psys, G.is_rendering)) - continue; - - if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) { - ParticleTarget *pt = psys->targets.first; - - for (; pt; pt = pt->next) { - if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) { - node2 = dag_get_node(dag, pt->ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets"); - } - } - } - - if (part->ren_as == PART_DRAW_OB && part->dup_ob) { - node2 = dag_get_node(dag, part->dup_ob); - /* note that this relation actually runs in the wrong direction, the problem - * is that dupli system all have this (due to parenting), and the render - * engine instancing assumes particular ordering of objects in list */ - dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization"); - if (part->dup_ob->type == OB_MBALL) - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization"); - } - - if (part->ren_as == PART_DRAW_GR && part->dup_group) { - for (go = part->dup_group->gobject.first; go; go = go->next) { - node2 = dag_get_node(dag, go->ob); - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization"); - } - } - - if (part->type != PART_HAIR) { - /* Actual code uses get_collider_cache */ - dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision"); - } - else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) { - /* Hair uses cloth simulation, i.e. get_collision_objects */ - dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision"); - } - - dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field"); - - if (part->boids) { - for (state = part->boids->states.first; state; state = state->next) { - for (rule = state->rules.first; rule; rule = rule->next) { - Object *ruleob = NULL; - if (rule->type == eBoidRuleType_Avoid) - ruleob = ((BoidRuleGoalAvoid *)rule)->ob; - else if (rule->type == eBoidRuleType_FollowLeader) - ruleob = ((BoidRuleFollowLeader *)rule)->ob; - - if (ruleob) { - node2 = dag_get_node(dag, ruleob); - dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule"); - } - } - } - } - } - } - - /* object constraints */ - for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (!cti) - continue; - - /* special case for camera tracking -- it doesn't use targets to define relations */ - if (build_deg_tracking_constraints(dag, scene, scenenode, con, cti, node, false)) { - addtoroot = 0; - } - else if (cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - Object *obt; - - if (ct->tar) - obt = ct->tar; - else - continue; - - node2 = dag_get_node(dag, obt); - if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - else { - if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); - if (obt->type == OB_MESH) - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - else if (cti->type == CONSTRAINT_TYPE_SHRINKWRAP) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name); - } - else { - dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name); - } - } - addtoroot = 0; - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - } - - if (addtoroot == 1) - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); -} - -static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Scene *scene, Group *group, short mask) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - build_dag_object(dag, scenenode, scene, go->ob, mask); - if (go->ob->dup_group) - build_dag_group(dag, scenenode, bmain, scene, go->ob->dup_group, mask); - } -} - -DagForest *build_dag(Main *bmain, Scene *sce, short mask) -{ - Base *base; - Object *ob; - DagNode *node; - DagNode *scenenode; - DagForest *dag; - DagAdjList *itA; - - dag = sce->theDag; - if (dag) - free_forest(dag); - else { - dag = dag_init(); - sce->theDag = dag; - } - dag->need_update = false; - - BKE_main_id_tag_idcode(bmain, ID_OB, LIB_TAG_DOIT, false); - - /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */ - BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* add base node for scene. scene is always the first node in DAG */ - scenenode = dag_add_node(dag, sce); - - /* add current scene objects */ - for (base = sce->base.first; base; base = base->next) { - ob = base->object; - ob->id.tag |= LIB_TAG_DOIT; - build_dag_object(dag, scenenode, sce, ob, mask); - if (ob->proxy) - build_dag_object(dag, scenenode, sce, ob->proxy, mask); - if (ob->dup_group) - build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask); - } - - /* There might be situations when object from current scene depends on - * objects form other scene AND objects from other scene has own - * dependencies on objects from other scene. - * - * This is really important to include such indirect dependencies in order - * to keep threaded update safe but since we don't really know if object is - * coming from current scene or another scene we do rather stupid tag-based - * check here: all the objects for which build_dag_object() was called are - * getting tagged with LIB_TAG_DOIT. This way if some node has untagged - * object we know it's an object from other scene. - * - * It should be enough to to it once, because if there's longer chain of - * indirect dependencies, all the new nodes will be added to the end of the - * list, meaning we'll keep covering them in this for loop. - */ - for (node = sce->theDag->DagNode.first; node != NULL; node = node->next) { - if (node->type == ID_OB) { - ob = node->ob; - if ((ob->id.tag & LIB_TAG_DOIT) == 0) { - ob->id.tag |= LIB_TAG_DOIT; - build_dag_object(dag, scenenode, sce, ob, mask); - if (ob->proxy) - build_dag_object(dag, scenenode, sce, ob->proxy, mask); - if (ob->dup_group) - build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask); - } - } - } - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* Now all relations were built, but we need to solve 1 exceptional case; - * When objects have multiple "parents" (for example parent + constraint working on same object) - * the relation type has to be synced. One of the parents can change, and should give same event to child */ - - /* nodes were callocced, so we can use node->color for temporal storage */ - for (node = sce->theDag->DagNode.first; node; node = node->next) { - if (node->type == ID_OB) { - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - itA->node->color |= itA->type; - } - } - - /* also flush custom data mask */ - ((Object *)node->ob)->customdata_mask = node->customdata_mask; - - if (node->parent == NULL) { - dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); - } - } - } - /* now set relations equal, so that when only one parent changes, the correct recalcs are found */ - for (node = sce->theDag->DagNode.first; node; node = node->next) { - if (node->type == ID_OB) { - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - itA->type |= itA->node->color; - } - } - } - } - - /* cycle detection and solving */ - // solve_cycles(dag); - - return dag; -} - - -void free_forest(DagForest *Dag) -{ /* remove all nodes and deps */ - DagNode *tempN; - DagAdjList *tempA; - DagAdjList *itA; - DagNode *itN = Dag->DagNode.first; - - while (itN) { - itA = itN->child; - while (itA) { - tempA = itA; - itA = itA->next; - MEM_freeN(tempA); - } - - itA = itN->parent; - while (itA) { - tempA = itA; - itA = itA->next; - MEM_freeN(tempA); - } - - tempN = itN; - itN = itN->next; - MEM_freeN(tempN); - } - - BLI_ghash_free(Dag->nodeHash, NULL, NULL); - Dag->nodeHash = NULL; - Dag->DagNode.first = NULL; - Dag->DagNode.last = NULL; - Dag->numNodes = 0; - -} - -DagNode *dag_find_node(DagForest *forest, void *fob) -{ - if (forest->nodeHash) - return BLI_ghash_lookup(forest->nodeHash, fob); - - return NULL; -} - -static int dag_print_dependencies = 0; /* debugging */ - -/* no checking of existence, use dag_find_node first or dag_get_node */ -DagNode *dag_add_node(DagForest *forest, void *fob) -{ - DagNode *node; - - node = MEM_callocN(sizeof(DagNode), "DAG node"); - if (node) { - node->ob = fob; - node->color = DAG_WHITE; - - if (forest->ugly_hack_sorry) node->type = GS(((ID *) fob)->name); /* sorry, done for pose sorting */ - if (forest->numNodes) { - ((DagNode *) forest->DagNode.last)->next = node; - forest->DagNode.last = node; - forest->numNodes++; - } - else { - forest->DagNode.last = node; - forest->DagNode.first = node; - forest->numNodes = 1; - } - - if (!forest->nodeHash) - forest->nodeHash = BLI_ghash_ptr_new("dag_add_node gh"); - BLI_ghash_insert(forest->nodeHash, fob, node); - } - - return node; -} - -DagNode *dag_get_node(DagForest *forest, void *fob) -{ - DagNode *node; - - node = dag_find_node(forest, fob); - if (!node) - node = dag_add_node(forest, fob); - return node; -} - - - -DagNode *dag_get_sub_node(DagForest *forest, void *fob) -{ - DagNode *node; - DagAdjList *mainchild, *prev = NULL; - - mainchild = ((DagNode *) forest->DagNode.first)->child; - /* remove from first node (scene) adj list if present */ - while (mainchild) { - if (mainchild->node == fob) { - if (prev) { - prev->next = mainchild->next; - MEM_freeN(mainchild); - break; - } - else { - ((DagNode *) forest->DagNode.first)->child = mainchild->next; - MEM_freeN(mainchild); - break; - } - } - prev = mainchild; - mainchild = mainchild->next; - } - node = dag_find_node(forest, fob); - if (!node) - node = dag_add_node(forest, fob); - return node; -} - -static void dag_add_parent_relation(DagForest *UNUSED(forest), DagNode *fob1, DagNode *fob2, short rel, const char *name) -{ - DagAdjList *itA = fob2->parent; - - while (itA) { /* search if relation exist already */ - if (itA->node == fob1) { - itA->type |= rel; - itA->count += 1; - return; - } - itA = itA->next; - } - /* create new relation and insert at head. MALLOC alert! */ - itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list"); - itA->node = fob1; - itA->type = rel; - itA->count = 1; - itA->next = fob2->parent; - itA->name = name; - fob2->parent = itA; -} - -void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name) -{ - DagAdjList *itA = fob1->child; - - /* parent relation is for cycle checking */ - dag_add_parent_relation(forest, fob1, fob2, rel, name); - - /* TODO(sergey): Find a better place for this. */ -#ifdef WITH_OPENSUBDIV - if ((rel & (DAG_RL_DATA_DATA | DAG_RL_DATA_OB)) != 0) { - if (fob1->type == ID_OB) { - if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) { - Object *ob2 = fob2->ob; - if (ob2->recalc & OB_RECALC_ALL) { - /* Make sure object has all the data on CPU. */ - Object *ob1 = fob1->ob; - ob1->recalc |= OB_RECALC_DATA; - } - fob1->eval_flags |= DAG_EVAL_NEED_CPU; - } - } - } -#endif - - while (itA) { /* search if relation exist already */ - if (itA->node == fob2) { - itA->type |= rel; - itA->count += 1; - return; - } - itA = itA->next; - } - /* create new relation and insert at head. MALLOC alert! */ - itA = MEM_mallocN(sizeof(DagAdjList), "DAG adj list"); - itA->node = fob2; - itA->type = rel; - itA->count = 1; - itA->next = fob1->child; - itA->name = name; - fob1->child = itA; -} - -static const char *dag_node_name(DagForest *dag, DagNode *node) -{ - if (node->ob == NULL) - return "null"; - else if (dag->ugly_hack_sorry) - return ((ID *)(node->ob))->name + 2; - else - return ((bPoseChannel *)(node->ob))->name; -} - -static void dag_node_print_dependencies(DagForest *dag, DagNode *node) -{ - DagAdjList *itA; - - printf("%s depends on:\n", dag_node_name(dag, node)); - - for (itA = node->parent; itA; itA = itA->next) - printf(" %s through %s\n", dag_node_name(dag, itA->node), itA->name); - printf("\n"); -} - -static int dag_node_print_dependency_recurs(DagForest *dag, DagNode *node, DagNode *endnode) -{ - DagAdjList *itA; - - if (node->color == DAG_BLACK) - return 0; - - node->color = DAG_BLACK; - - if (node == endnode) - return 1; - - for (itA = node->parent; itA; itA = itA->next) { - if (dag_node_print_dependency_recurs(dag, itA->node, endnode)) { - printf(" %s depends on %s through %s.\n", dag_node_name(dag, node), dag_node_name(dag, itA->node), itA->name); - return 1; - } - } - - return 0; -} - -static void dag_node_print_dependency_cycle(DagForest *dag, DagNode *startnode, DagNode *endnode, const char *name) -{ - DagNode *node; - - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - printf(" %s depends on %s through %s.\n", dag_node_name(dag, endnode), dag_node_name(dag, startnode), name); - dag_node_print_dependency_recurs(dag, startnode, endnode); - printf("\n"); -} - -static int dag_node_recurs_level(DagNode *node, int level) -{ - DagAdjList *itA; - int newlevel; - - node->color = DAG_BLACK; /* done */ - newlevel = ++level; - - for (itA = node->parent; itA; itA = itA->next) { - if (itA->node->color == DAG_WHITE) { - itA->node->ancestor_count = dag_node_recurs_level(itA->node, level); - newlevel = MAX2(newlevel, level + itA->node->ancestor_count); - } - else - newlevel = MAX2(newlevel, level + itA->node->ancestor_count); - } - - return newlevel; -} - -static void dag_check_cycle(DagForest *dag) -{ - DagNode *node; - DagAdjList *itA; - - dag->is_acyclic = true; - - /* debugging print */ - if (dag_print_dependencies) - for (node = dag->DagNode.first; node; node = node->next) - dag_node_print_dependencies(dag, node); - - /* tag nodes unchecked */ - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - for (node = dag->DagNode.first; node; node = node->next) { - if (node->color == DAG_WHITE) { - node->ancestor_count = dag_node_recurs_level(node, 0); - } - } - - /* check relations, and print errors */ - for (node = dag->DagNode.first; node; node = node->next) { - for (itA = node->parent; itA; itA = itA->next) { - if (itA->node->ancestor_count > node->ancestor_count) { - if (node->ob && itA->node->ob) { - dag->is_acyclic = false; - printf("Dependency cycle detected:\n"); - dag_node_print_dependency_cycle(dag, itA->node, node, itA->name); - } - } - } - } - - /* parent relations are only needed for cycle checking, so free now */ - for (node = dag->DagNode.first; node; node = node->next) { - while (node->parent) { - itA = node->parent->next; - MEM_freeN(node->parent); - node->parent = itA; - } - } -} - -/* debug test functions */ - -void graph_print_queue(DagNodeQueue *nqueue) -{ - DagNodeQueueElem *queueElem; - - queueElem = nqueue->first; - while (queueElem) { - fprintf(stderr, "** %s %i %i-%i ", ((ID *) queueElem->node->ob)->name, queueElem->node->color, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm); - queueElem = queueElem->next; - } - fprintf(stderr, "\n"); -} - -void graph_print_queue_dist(DagNodeQueue *nqueue) -{ - DagNodeQueueElem *queueElem; - int count; - - queueElem = nqueue->first; - count = 0; - while (queueElem) { - fprintf(stderr, "** %25s %2.2i-%2.2i ", ((ID *) queueElem->node->ob)->name, queueElem->node->DFS_dvtm, queueElem->node->DFS_fntm); - while (count < queueElem->node->DFS_dvtm - 1) { fputc(' ', stderr); count++; } - fputc('|', stderr); - while (count < queueElem->node->DFS_fntm - 2) { fputc('-', stderr); count++; } - fputc('|', stderr); - fputc('\n', stderr); - count = 0; - queueElem = queueElem->next; - } - fprintf(stderr, "\n"); -} - -void graph_print_adj_list(DagForest *dag) -{ - DagNode *node; - DagAdjList *itA; - - node = dag->DagNode.first; - while (node) { - fprintf(stderr, "node : %s col: %i", ((ID *) node->ob)->name, node->color); - itA = node->child; - while (itA) { - fprintf(stderr, "-- %s ", ((ID *) itA->node->ob)->name); - - itA = itA->next; - } - fprintf(stderr, "\n"); - node = node->next; - } -} - -/* ************************ API *********************** */ - -/* mechanism to allow editors to be informed of depsgraph updates, - * to do their own updates based on changes... */ -static void (*EditorsUpdateIDCb)(Main *bmain, ID *id) = NULL; -static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NULL; -static void (*EditorsUpdateScenePreCb)(Main *bmain, Scene *scene, bool time) = NULL; - -void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), - void (*scene_func)(Main *bmain, Scene *scene, int updated), - void (*scene_pre_func)(Main *bmain, Scene *scene, bool time)) -{ - if (DEG_depsgraph_use_legacy()) { - EditorsUpdateIDCb = id_func; - EditorsUpdateSceneCb = scene_func; - EditorsUpdateScenePreCb = scene_pre_func; - } - else { - /* New dependency graph. */ - DEG_editors_set_update_cb(id_func, scene_func, scene_pre_func); - } -} - -void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time) -{ - if (DEG_depsgraph_use_legacy()) { - if (EditorsUpdateScenePreCb != NULL) { - EditorsUpdateScenePreCb(bmain, scene, time); - } - } - else { - DEG_editors_update_pre(bmain, scene, time); - } -} - -static void dag_editors_id_update(Main *bmain, ID *id) -{ - if (EditorsUpdateIDCb) - EditorsUpdateIDCb(bmain, id); -} - -static void dag_editors_scene_update(Main *bmain, Scene *scene, int updated) -{ - if (EditorsUpdateSceneCb) - EditorsUpdateSceneCb(bmain, scene, updated); -} - -/* groups with objects in this scene need to be put in the right order as well */ -static void scene_sort_groups(Main *bmain, Scene *sce) -{ - Base *base; - Group *group; - GroupObject *go; - Object *ob; - - /* test; are group objects all in this scene? */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - ob->id.tag &= ~LIB_TAG_DOIT; - } - for (base = sce->base.first; base; base = base->next) - base->object->id.tag |= LIB_TAG_DOIT; - - for (group = bmain->group.first; group; group = group->id.next) { - for (go = group->gobject.first; go; go = go->next) { - if ((go->ob->id.tag & LIB_TAG_DOIT) == 0) - break; - } - /* this group is entirely in this scene */ - if (go == NULL) { - ListBase listb = {NULL, NULL}; - - for (go = group->gobject.first; go; go = go->next) - go->ob->id.newid = (ID *)go; - - /* in order of sorted bases we reinsert group objects */ - for (base = sce->base.first; base; base = base->next) { - - if (base->object->id.newid) { - go = (GroupObject *)base->object->id.newid; - base->object->id.newid = NULL; - BLI_remlink(&group->gobject, go); - BLI_addtail(&listb, go); - } - } - /* copy the newly sorted listbase */ - group->gobject = listb; - } - } - - /* newid abused for GroupObject, cleanup. */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - ob->id.newid = NULL; - } -} - -static void dag_scene_tag_rebuild(Scene *sce) -{ - if (sce->theDag) { - sce->theDag->need_update = true; - } -} - -/* free the depency graph */ -static void dag_scene_free(Scene *sce) -{ - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; - } -} - -/* Check whether object data needs to be evaluated before it - * might be used by others. - * - * Means that mesh object needs to have proper derivedFinal, - * curves-typed objects are to have proper curve cache. - * - * Other objects or objects which are tagged for data update are - * not considered to be in need of evaluation. - */ -static bool check_object_needs_evaluation(Object *object) -{ - if (object->recalc & OB_RECALC_ALL) { - /* Object is tagged for update anyway, no need to re-tag it. */ - return false; - } - - if (object->type == OB_MESH) { - return object->derivedFinal == NULL; - } - else if (ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - return object->curve_cache == NULL; - } - - return false; -} - -/* Check whether object data is tagged for update. */ -static bool check_object_tagged_for_update(Object *object) -{ - if (object->recalc & OB_RECALC_ALL) { - return true; - } - - if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - ID *data_id = object->data; - return (data_id->recalc & ID_RECALC_ALL) != 0; - } - - return false; -} - -/* Flush changes from tagged objects in the scene to their - * dependencies which are not evaluated yet. - * - * This is needed to ensure all the dependencies are met - * before objects gets handled by object_handle_update(), - * - * This is needed when visible layers are changed or changing - * scene graph layout which involved usage of objects which - * aren't in the scene or weren't visible yet. - */ -static void dag_invisible_dependencies_flush(Scene *scene) -{ - DagNode *root_node = scene->theDag->DagNode.first, *node; - DagNodeQueue *queue; - - for (node = root_node; node != NULL; node = node->next) { - node->color = DAG_WHITE; - } - - queue = queue_create(DAGQUEUEALLOC); - - for (node = root_node; node != NULL; node = node->next) { - if (node->color == DAG_WHITE) { - push_stack(queue, node); - node->color = DAG_GRAY; - - while (queue->count) { - DagNode *current_node = get_top_node_queue(queue); - DagAdjList *itA; - bool skip = false; - - for (itA = current_node->child; itA; itA = itA->next) { - if (itA->node->color == DAG_WHITE) { - itA->node->color = DAG_GRAY; - push_stack(queue, itA->node); - skip = true; - break; - } - } - - if (!skip) { - current_node = pop_queue(queue); - - if (current_node->type == ID_OB) { - Object *current_object = current_node->ob; - if (check_object_needs_evaluation(current_object)) { - for (itA = current_node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - Object *object = itA->node->ob; - if (check_object_tagged_for_update(object)) { - current_object->recalc |= OB_RECALC_OB | OB_RECALC_DATA; - } - } - } - } - } - node->color = DAG_BLACK; - } - } - } - } - - queue_delete(queue); -} - -static void dag_invisible_dependencies_check_flush(Main *bmain, Scene *scene) -{ - if (DAG_id_type_tagged(bmain, ID_OB) || - DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */ - DAG_id_type_tagged(bmain, ID_CU) || /* Curve */ - DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */ - DAG_id_type_tagged(bmain, ID_LT)) /* Lattice */ - { - dag_invisible_dependencies_flush(scene); - } -} - -/* sort the base list on dependency order */ -static void dag_scene_build(Main *bmain, Scene *sce) -{ - DagNode *node, *rootnode; - DagNodeQueue *nqueue; - DagAdjList *itA; - int time; - int skip = 0; - ListBase tempbase; - Base *base; - - BLI_listbase_clear(&tempbase); - - build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA); - - dag_check_cycle(sce->theDag); - - nqueue = queue_create(DAGQUEUEALLOC); - - for (node = sce->theDag->DagNode.first; node; node = node->next) { - node->color = DAG_WHITE; - } - - time = 1; - - rootnode = sce->theDag->DagNode.first; - rootnode->color = DAG_GRAY; - time++; - push_stack(nqueue, rootnode); - - while (nqueue->count) { - - skip = 0; - node = get_top_node_queue(nqueue); - - itA = node->child; - while (itA != NULL) { - if (itA->node->color == DAG_WHITE) { - itA->node->DFS_dvtm = time; - itA->node->color = DAG_GRAY; - - time++; - push_stack(nqueue, itA->node); - skip = 1; - break; - } - itA = itA->next; - } - - if (!skip) { - if (node) { - node = pop_queue(nqueue); - if (node->ob == sce) /* we are done */ - break; - node->color = DAG_BLACK; - - time++; - base = sce->base.first; - while (base && base->object != node->ob) - base = base->next; - if (base) { - BLI_remlink(&sce->base, base); - BLI_addhead(&tempbase, base); - } - } - } - } - - /* temporal correction for circular dependencies */ - base = sce->base.first; - while (base) { - BLI_remlink(&sce->base, base); - BLI_addhead(&tempbase, base); - //if (G.debug & G_DEBUG) - printf("cyclic %s\n", base->object->id.name); - base = sce->base.first; - } - - sce->base = tempbase; - queue_delete(nqueue); - - /* all groups with objects in this scene gets resorted too */ - scene_sort_groups(bmain, sce); - - if (G.debug & G_DEBUG) { - printf("\nordered\n"); - for (base = sce->base.first; base; base = base->next) { - printf(" %s\n", base->object->id.name); - } - } - - /* Make sure that new dependencies which came from invisible layers - * are tagged for update (if they're needed for objects which were - * tagged for update). - */ - dag_invisible_dependencies_check_flush(bmain, sce); -} - -/* clear all dependency graphs */ -void DAG_relations_tag_update(Main *bmain) -{ - if (DEG_depsgraph_use_legacy()) { - Scene *sce; - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - dag_scene_tag_rebuild(sce); - } - } - else { - /* New dependency graph. */ - DEG_relations_tag_update(bmain); - } -} - -/* rebuild dependency graph only for a given scene */ -void DAG_scene_relations_rebuild(Main *bmain, Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - dag_scene_free(sce); - DAG_scene_relations_update(bmain, sce); - } - else { - /* New dependency graph. */ - DEG_scene_relations_rebuild(bmain, sce); - } -} - -/* create dependency graph if it was cleared or didn't exist yet */ -void DAG_scene_relations_update(Main *bmain, Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - if (!sce->theDag || sce->theDag->need_update) - dag_scene_build(bmain, sce); - } - else { - /* New dependency graph. */ - DEG_scene_relations_update(bmain, sce); - } -} - -void DAG_scene_relations_validate(Main *bmain, Scene *sce) -{ - if (!DEG_depsgraph_use_legacy()) { - DEG_debug_scene_relations_validate(bmain, sce); - } -} - -void DAG_scene_free(Scene *sce) -{ - if (DEG_depsgraph_use_legacy()) { - if (sce->theDag) { - free_forest(sce->theDag); - MEM_freeN(sce->theDag); - sce->theDag = NULL; - } - } - else { - if (sce->depsgraph) { - DEG_graph_free(sce->depsgraph); - sce->depsgraph = NULL; - } - } -} - -static void lib_id_recalc_tag(Main *bmain, ID *id) -{ - id->recalc |= ID_RECALC; - DAG_id_type_tag(bmain, GS(id->name)); -} - -static void lib_id_recalc_data_tag(Main *bmain, ID *id) -{ - id->recalc |= ID_RECALC_DATA; - DAG_id_type_tag(bmain, GS(id->name)); -} - -/* node was checked to have lasttime != curtime and is if type ID_OB */ -static void flush_update_node(Main *bmain, DagNode *node, unsigned int layer, int curtime) -{ - DagAdjList *itA; - Object *ob, *obc; - int oldflag; - bool changed = false; - unsigned int all_layer; - - node->lasttime = curtime; - - ob = node->ob; - if (ob && (ob->recalc & OB_RECALC_ALL)) { - all_layer = node->scelay; - - /* got an object node that changes, now check relations */ - for (itA = node->child; itA; itA = itA->next) { - all_layer |= itA->lay; - /* the relationship is visible */ - if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) - if (itA->node->type == ID_OB) { - obc = itA->node->ob; - oldflag = obc->recalc; - - /* got a ob->obc relation, now check if flag needs flush */ - if (ob->recalc & OB_RECALC_OB) { - if (itA->type & DAG_RL_OB_OB) { - //printf("ob %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obc->id); - } - if (itA->type & DAG_RL_OB_DATA) { - //printf("ob %s changes obdata %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - if (ob->recalc & OB_RECALC_DATA) { - if (itA->type & DAG_RL_DATA_OB) { - //printf("obdata %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obc->id); - } - if (itA->type & DAG_RL_DATA_DATA) { - //printf("obdata %s changes obdata %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - if (oldflag != obc->recalc) changed = 1; - } - } - } - /* even nicer, we can clear recalc flags... */ - if ((all_layer & layer) == 0) { // XXX && (ob != obedit)) { - /* but existing displaylists or derivedmesh should be freed */ - if (ob->recalc & OB_RECALC_DATA) - BKE_object_free_derived_caches(ob); - - ob->recalc &= ~OB_RECALC_ALL; - } - } - - /* check case where child changes and parent forcing obdata to change */ - /* should be done regardless if this ob has recalc set */ - /* could merge this in with loop above...? (ton) */ - for (itA = node->child; itA; itA = itA->next) { - /* the relationship is visible */ - if ((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) - if (itA->node->type == ID_OB) { - obc = itA->node->ob; - /* child moves */ - if ((obc->recalc & OB_RECALC_ALL) == OB_RECALC_OB) { - /* parent has deforming info */ - if (itA->type & (DAG_RL_OB_DATA | DAG_RL_DATA_DATA)) { - // printf("parent %s changes ob %s\n", ob->id.name, obc->id.name); - obc->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obc->id); - } - } - } - } - } - - /* we only go deeper if node not checked or something changed */ - for (itA = node->child; itA; itA = itA->next) { - if (changed || itA->node->lasttime != curtime) - flush_update_node(bmain, itA->node, layer, curtime); - } - -} - -/* node was checked to have lasttime != curtime, and is of type ID_OB */ -static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) -{ - DagAdjList *itA; - - node->lasttime = curtime; - node->lay = node->scelay; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - if (itA->node->lasttime != curtime) { - itA->lay = flush_layer_node(sce, itA->node, curtime); /* lay is only set once for each relation */ - } - else { - itA->lay = itA->node->lay; - } - - node->lay |= itA->lay; - } - } - - return node->lay; -} - -/* node was checked to have lasttime != curtime, and is of type ID_OB */ -static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, - int curtime, unsigned int lay, bool reset) -{ - DagAdjList *itA; - Object *ob; - - node->lasttime = curtime; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - if (itA->node->lasttime != curtime) { - ob = (Object *)(itA->node->ob); - - if (reset || (ob->recalc & OB_RECALC_ALL)) { - if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) { - /* Don't tag nodes which are on invisible layer. */ - if (itA->node->lay & lay) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &ob->id); - } - } - - flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, true); - } - else - flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, false); - } - } - } -} - -/* flush layer flags to dependencies */ -static void dag_scene_flush_layers(Scene *sce, int lay) -{ - DagNode *node, *firstnode; - DagAdjList *itA; - Base *base; - int lasttime; - - firstnode = sce->theDag->DagNode.first; /* always scene node */ - - for (itA = firstnode->child; itA; itA = itA->next) - itA->lay = 0; - - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - - /* update layer flags in nodes */ - for (base = sce->base.first; base; base = base->next) { - node = dag_get_node(sce->theDag, base->object); - node->scelay = base->object->lay; - } - - /* ensure cameras are set as if they are on a visible layer, because - * they ared still used for rendering or setting the camera view - * - * XXX, this wont work for local view / unlocked camera's */ - if (sce->camera) { - node = dag_get_node(sce->theDag, sce->camera); - node->scelay |= lay; - } - -#ifdef DURIAN_CAMERA_SWITCH - { - TimeMarker *m; - - for (m = sce->markers.first; m; m = m->next) { - if (m->camera) { - node = dag_get_node(sce->theDag, m->camera); - node->scelay |= lay; - } - } - } -#endif - - /* flush layer nodes to dependencies */ - for (itA = firstnode->child; itA; itA = itA->next) - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) - flush_layer_node(sce, itA->node, lasttime); -} - -static void dag_tag_renderlayers(Scene *sce, unsigned int lay) -{ - if (sce->nodetree) { - bNode *node; - Base *base; - unsigned int lay_changed = 0; - - for (base = sce->base.first; base; base = base->next) - if (base->lay & lay) - if (base->object->recalc) - lay_changed |= base->lay; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == (ID *)sce) { - SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1); - if (srl && (srl->lay & lay_changed)) - nodeUpdate(sce->nodetree, node); - } - } - } -} - -/* flushes all recalc flags in objects down the dependency tree */ -void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const short time) -{ - DagNode *firstnode; - DagAdjList *itA; - Object *ob; - int lasttime; - - if (!DEG_depsgraph_use_legacy()) { - DEG_scene_flush_update(bmain, sce); - return; - } - - if (sce->theDag == NULL || sce->theDag->need_update) { - printf("DAG zero... not allowed to happen!\n"); - DAG_scene_relations_update(bmain, sce); - } - - firstnode = sce->theDag->DagNode.first; /* always scene node */ - - /* first we flush the layer flags */ - dag_scene_flush_layers(sce, lay); - - /* then we use the relationships + layer info to flush update events */ - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - for (itA = firstnode->child; itA; itA = itA->next) - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) - flush_update_node(bmain, itA->node, lay, lasttime); - - /* if update is not due to time change, do pointcache clears */ - if (!time) { - sce->theDag->time++; /* so we know which nodes were accessed */ - lasttime = sce->theDag->time; - for (itA = firstnode->child; itA; itA = itA->next) { - if (itA->node->lasttime != lasttime && itA->node->type == ID_OB) { - ob = (Object *)(itA->node->ob); - - if (ob->recalc & OB_RECALC_ALL) { - if (BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH)) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &ob->id); - } - - flush_pointcache_reset(bmain, sce, itA->node, lasttime, - lay, true); - } - else - flush_pointcache_reset(bmain, sce, itA->node, lasttime, - lay, false); - } - } - } - - dag_tag_renderlayers(sce, lay); -} - -static bool modifier_nlastrips_use_time(ListBase *strips) -{ - NlaStrip *strip; - - if (strips) { - for (strip = strips->first; strip; strip = strip->next) { - if (modifier_nlastrips_use_time(&strip->strips)) { - return true; - } - else if (strip->act) { - FCurve *fcu; - - for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - } - } - } - - return false; -} - -static bool object_modifiers_use_time(Object *ob) -{ - ModifierData *md; - - /* check if a modifier in modifier stack needs time input */ - for (md = ob->modifiers.first; md; md = md->next) { - if (modifier_dependsOnTime(md)) - return true; - } - - /* check whether any modifiers are animated */ - if (ob->adt) { - AnimData *adt = ob->adt; - NlaTrack *nlt; - FCurve *fcu; - - /* action - check for F-Curves with paths containing 'modifiers[' */ - if (adt->action) { - for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - } - - /* This here allows modifier properties to get driven and still update properly - * - * Workaround to get [#26764] (e.g. subsurf levels not updating when animated/driven) - * working, without the updating problems ([#28525] [#28690] [#28774] [#28777]) caused - * by the RNA updates cache introduced in r.38649 - */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - if (fcu->rna_path && strstr(fcu->rna_path, "modifiers[")) - return true; - } - - /* Also check NLA Strips... [#T45938] */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - if (modifier_nlastrips_use_time(&nlt->strips)) - return true; - } - } - - return false; -} - -static short animdata_use_time(AnimData *adt) -{ - NlaTrack *nlt; - - if (adt == NULL) return 0; - - /* check action - only if assigned, and it has anim curves */ - if (adt->action && adt->action->curves.first) - return 1; - - /* check NLA tracks + strips */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - if (nlt->strips.first) - return 1; - } - - /* If we have drivers, more likely than not, on a frame change - * they'll need updating because their owner changed - * - * This is kindof a hack to get around a whole host of problems - * involving drivers using non-object datablock data (which the - * depsgraph currently has no way of representing let alone correctly - * dependency sort+tagging). By doing this, at least we ensure that - * some commonly attempted drivers (such as scene -> current frame; - * see "Driver updates fail" thread on Bf-committers dated July 2) - * will work correctly, and that other non-object datablocks will have - * their drivers update at least on frame change. - * - * -- Aligorith, July 4 2011 - */ - if (adt->drivers.first) - return 1; - - return 0; -} - -static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) -{ - if (ob->constraints.first) { - bConstraint *con; - for (con = ob->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti) { - /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM(cti->type, - CONSTRAINT_TYPE_FOLLOWTRACK, - CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER, - CONSTRAINT_TYPE_TRANSFORM_CACHE)) - { - ob->recalc |= OB_RECALC_OB; - } - else if (cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar) { - ob->recalc |= OB_RECALC_OB; - break; - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - - } - } - } - - if (ob->parent) { - /* motion path or bone child */ - if (ob->parent->type == OB_CURVE || ob->parent->type == OB_ARMATURE) ob->recalc |= OB_RECALC_OB; - } - -#if 0 // XXX old animation system - if (ob->nlastrips.first) { - if (ob->dup_group) { - bActionStrip *strip; - /* this case is for groups with nla, whilst nla target has no action or nla */ - for (strip = ob->nlastrips.first; strip; strip = strip->next) { - if (strip->object) - strip->object->recalc |= OB_RECALC_ALL; - } - } - } -#endif // XXX old animation system - - if (animdata_use_time(ob->adt)) { - ob->recalc |= OB_RECALC_OB; - ob->adt->recalc |= ADT_RECALC_ANIM; - } - - if ((ob->adt) && (ob->type == OB_ARMATURE)) ob->recalc |= OB_RECALC_DATA; - - 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; - - // XXX: scene here may not be the scene that contains the rigidbody world affecting this! - 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; - Curve *cu; - Lattice *lt; - - switch (ob->type) { - case OB_MESH: - me = ob->data; - if (me->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - if (ob->particlesystem.first) - ob->recalc |= OB_RECALC_DATA; - break; - case OB_CURVE: - case OB_SURF: - cu = ob->data; - if (cu->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - break; - case OB_FONT: - cu = ob->data; - if (cu->str && cu->vfont) { - /* Can be in the curve-cache or the curve. */ - if (ob->curve_cache && !BLI_listbase_is_empty(&ob->curve_cache->disp)) { - /* pass */ - } - else if (!BLI_listbase_is_empty(&cu->nurb)) { - /* pass */ - } - else { - ob->recalc |= OB_RECALC_DATA; - } - } - break; - case OB_LATTICE: - lt = ob->data; - if (lt->key) { - if (!(ob->shapeflag & OB_SHAPE_LOCK)) { - ob->recalc |= OB_RECALC_DATA; - } - } - break; - case OB_MBALL: - if (ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA; - break; - case OB_EMPTY: - /* update animated images */ - if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) - if (BKE_image_is_animated(ob->data)) - ob->recalc |= OB_RECALC_DATA; - break; - } - - if (animdata_use_time(adt)) { - ob->recalc |= OB_RECALC_DATA; - adt->recalc |= ADT_RECALC_ANIM; - } - - if (ob->particlesystem.first) { - ParticleSystem *psys = ob->particlesystem.first; - - for (; psys; psys = psys->next) { - if (psys_check_enabled(ob, psys, G.is_rendering)) { - ob->recalc |= OB_RECALC_DATA; - break; - } - } - } - } - - if (ob->recalc & OB_RECALC_OB) - lib_id_recalc_tag(bmain, &ob->id); - if (ob->recalc & OB_RECALC_DATA) - lib_id_recalc_data_tag(bmain, &ob->id); - -} - -/* recursively update objects in groups, each group is done at most once */ -static void dag_group_update_flags(Main *bmain, Scene *scene, Group *group, const bool do_time) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - if (do_time) - dag_object_time_update_flags(bmain, scene, go->ob); - if (go->ob->dup_group) - dag_group_update_flags(bmain, scene, go->ob->dup_group, do_time); - } -} - -/* flag all objects that need recalc, for changes in time for example */ -/* do_time: make this optional because undo resets objects to their animated locations without this */ -void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const bool do_time, const bool do_invisible_flush) -{ - Base *base; - Object *ob; - Group *group; - GroupObject *go; - Scene *sce_iter; - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* set ob flags where animated systems are */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - - 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 */ - - /* NOTE: "sce_iter" not "scene" so that rigidbodies in background scenes work - * (i.e. muting + rbw availability can be checked and tagged properly) [#33970] - */ - dag_object_time_update_flags(bmain, sce_iter, ob); - } - - /* recursively tag groups with LIB_TAG_DOIT, and update flags for objects */ - if (ob->dup_group) - dag_group_update_flags(bmain, scene, ob->dup_group, do_time); - } - - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) - DAG_scene_flush_update(bmain, sce_iter, lay, 1); - - if (do_time) { - /* test: set time flag, to disable baked systems to update */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - if (ob->recalc & OB_RECALC_ALL) - ob->recalc |= OB_RECALC_TIME; - } - - /* hrmf... an exception to look at once, for invisible camera object we do it over */ - if (scene->camera) - dag_object_time_update_flags(bmain, scene, scene->camera); - } - - /* and store the info in groupobject */ - for (group = bmain->group.first; group; group = group->id.next) { - if (group->id.tag & LIB_TAG_DOIT) { - for (go = group->gobject.first; go; go = go->next) { - go->recalc = go->ob->recalc; - // printf("ob %s recalc %d\n", go->ob->id.name, go->recalc); - } - group->id.tag &= ~LIB_TAG_DOIT; - } - } - - if (do_invisible_flush) { - dag_invisible_dependencies_check_flush(bmain, scene); - } -} - -/* struct returned by DagSceneLayer */ -typedef struct DagSceneLayer { - struct DagSceneLayer *next, *prev; - Scene *scene; - unsigned int layer; -} DagSceneLayer; - -/* returns visible scenes with valid DAG */ -static void dag_current_scene_layers(Main *bmain, ListBase *lb) -{ - wmWindowManager *wm; - wmWindow *win; - - BLI_listbase_clear(lb); - - /* if we have a windowmanager, look into windows */ - if ((wm = bmain->wm.first)) { - - BKE_main_id_flag_listbase(&bmain->scene, LIB_TAG_DOIT, 1); - - for (win = wm->windows.first; win; win = win->next) { - if (win->screen && win->screen->scene->theDag) { - Scene *scene = win->screen->scene; - DagSceneLayer *dsl; - - if (scene->id.tag & LIB_TAG_DOIT) { - dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); - - BLI_addtail(lb, dsl); - - dsl->scene = scene; - dsl->layer = BKE_screen_visible_layers(win->screen, scene); - - scene->id.tag &= ~LIB_TAG_DOIT; - } - else { - /* It is possible that multiple windows shares the same scene - * and have different layers visible. - * - * Here we deal with such cases by squashing layers bits from - * multiple windoew to the DagSceneLayer. - * - * TODO(sergey): Such a lookup could be optimized perhaps, - * however should be fine for now since we usually have only - * few open windows. - */ - for (dsl = lb->first; dsl; dsl = dsl->next) { - if (dsl->scene == scene) { - dsl->layer |= BKE_screen_visible_layers(win->screen, scene); - break; - } - } - } - } - } - } - else { - /* if not, use the first sce */ - DagSceneLayer *dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer"); - - BLI_addtail(lb, dsl); - - dsl->scene = bmain->scene.first; - dsl->layer = dsl->scene->lay; - - /* XXX for background mode, we should get the scene - * from somewhere, for the -S option, but it's in - * the context, how to get it here? */ - } -} - -static void dag_group_on_visible_update(Scene *scene, Group *group) -{ - GroupObject *go; - - if (group->id.tag & LIB_TAG_DOIT) - return; - - group->id.tag |= LIB_TAG_DOIT; - - for (go = group->gobject.first; go; go = go->next) { - if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { - go->ob->recalc |= OB_RECALC_DATA; - go->ob->id.tag |= LIB_TAG_DOIT; - lib_id_recalc_tag(G.main, &go->ob->id); - } - if (go->ob->proxy_from) { - go->ob->recalc |= OB_RECALC_OB; - go->ob->id.tag |= LIB_TAG_DOIT; - lib_id_recalc_tag(G.main, &go->ob->id); - } - - if (go->ob->dup_group) - dag_group_on_visible_update(scene, go->ob->dup_group); - } -} - -void DAG_on_visible_update(Main *bmain, const bool do_time) -{ - ListBase listbase; - DagSceneLayer *dsl; - - if (!DEG_depsgraph_use_legacy()) { - /* Inform new dependnecy graphs about visibility changes. */ - DEG_on_visible_update(bmain, do_time); - return; - } - - /* get list of visible scenes and layers */ - dag_current_scene_layers(bmain, &listbase); - - for (dsl = listbase.first; dsl; dsl = dsl->next) { - Scene *scene = dsl->scene; - Scene *sce_iter; - Base *base; - Object *ob; - DagNode *node; - unsigned int lay = dsl->layer, oblay; - - /* derivedmeshes and displists are not saved to file so need to be - * remade, tag them so they get remade in the scene update loop, - * note armature poses or object matrices are preserved and do not - * require updates, so we skip those */ - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) - dag_scene_flush_layers(sce_iter, lay); - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - node = (sce_iter->theDag) ? dag_get_node(sce_iter->theDag, ob) : NULL; - oblay = (node) ? node->lay : ob->lay; - - if ((oblay & lay) & ~scene->lay_updated) { - /* TODO(sergey): Why do we need armature here now but didn't need before? */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_tag(bmain, &ob->id); - } - /* This should not be needed here, but in some cases, like after a redo, we can end up with - * a wrong final matrix (see T42472). - * Quoting Sergey, this comes from BKE_object_handle_update_ex, which is calling - * BKE_object_where_is_calc_ex when it shouldn't, but that issue is not easily fixable. - */ - else { - ob->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &ob->id); - } - if (ob->proxy && (ob->proxy_group == NULL)) { - ob->proxy->recalc |= OB_RECALC_DATA; - lib_id_recalc_tag(bmain, &ob->id); - } - if (ob->dup_group) - dag_group_on_visible_update(scene, ob->dup_group); - } - } - - BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false); - - /* now tag update flags, to ensure deformers get calculated on redraw */ - DAG_scene_update_flags(bmain, scene, lay, do_time, true); - scene->lay_updated |= lay; - } - - BLI_freelistN(&listbase); - - /* hack to get objects updating on layer changes */ - DAG_id_type_tag(bmain, ID_OB); - - /* so masks update on load */ - if (bmain->mask.first) { - Mask *mask; - - for (mask = bmain->mask.first; mask; mask = mask->id.next) { - DAG_id_tag_update(&mask->id, 0); - } - } -} - -static void dag_id_flush_update__isDependentTexture( - void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cb_flag)) -{ - struct { ID *id; bool is_dependent; } *data = userData; - - if (*idpoin && GS((*idpoin)->name) == ID_TE) { - if (data->id == (*idpoin)) - data->is_dependent = 1; - } -} - -static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) -{ - Object *obt, *ob = NULL; - short idtype; - - /* here we flush a few things before actual scene wide flush, mostly - * due to only objects and not other datablocks being in the depsgraph */ - - /* set flags & pointcache for object */ - if (GS(id->name) == ID_OB) { - ob = (Object *)id; - BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH); - - /* So if someone tagged object recalc directly, - * id_tag_update bit-field stays relevant - */ - if (ob->recalc & OB_RECALC_ALL) { - DAG_id_type_tag(bmain, GS(id->name)); - } - - if (ob->recalc & OB_RECALC_DATA) { - /* all users of this ob->data should be checked */ - id = ob->data; - - /* no point in trying in this cases */ - if (id && id->us <= 1) { - dag_editors_id_update(bmain, id); - id = NULL; - } - } - } - - /* set flags & pointcache for object data */ - if (id) { - idtype = GS(id->name); - - - if (OB_DATA_SUPPORT_ID(idtype)) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - if (!(ob && obt == ob) && obt->data == id) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - else if (idtype == ID_VF) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - if (obt->type == OB_FONT) { - Curve *cu = obt->data; - if (ELEM((struct VFont *)id, CURVE_VFONT_ANY(cu))) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - } - } - } - } - - /* set flags based on textures - can influence depgraph via modifiers */ - if (idtype == ID_TE) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - struct { ID *id; bool is_dependent; } data; - data.id = id; - data.is_dependent = 0; - - modifiers_foreachIDLink(obt, dag_id_flush_update__isDependentTexture, &data); - if (data.is_dependent) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - } - - /* particle settings can use the texture as well */ - if (obt->particlesystem.first) { - ParticleSystem *psys = obt->particlesystem.first; - MTex **mtexp, *mtex; - int a; - for (; psys; psys = psys->next) { - mtexp = psys->part->mtex; - for (a = 0; a < MAX_MTEX; a++, mtexp++) { - mtex = *mtexp; - if (mtex && mtex->tex == (Tex *)id) { - obt->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &obt->id); - - if (mtex->mapto & PAMAP_INIT) - psys->recalc |= PSYS_RECALC_RESET; - if (mtex->mapto & PAMAP_CHILD) - psys->recalc |= PSYS_RECALC_CHILD; - - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - } - } - } - - /* set flags based on ShapeKey */ - if (idtype == ID_KE) { - for (obt = bmain->object.first; obt; obt = obt->id.next) { - Key *key = BKE_key_from_object(obt); - if (!(ob && obt == ob) && ((ID *)key == id)) { - obt->flag |= (OB_RECALC_OB | OB_RECALC_DATA); - lib_id_recalc_tag(bmain, &obt->id); - lib_id_recalc_data_tag(bmain, &obt->id); - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - } - } - - /* set flags based on particle settings */ - if (idtype == ID_PA) { - ParticleSystem *psys; - for (obt = bmain->object.first; obt; obt = obt->id.next) - for (psys = obt->particlesystem.first; psys; psys = psys->next) - if (&psys->part->id == id) - BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); - } - - if (ELEM(idtype, ID_MA, ID_TE)) { - obt = sce->basact ? sce->basact->object : NULL; - if (obt && obt->mode & OB_MODE_TEXTURE_PAINT) { - BKE_texpaint_slots_refresh_object(sce, obt); - BKE_paint_proj_mesh_data_check(sce, obt, NULL, NULL, NULL, NULL); - GPU_drawobject_free(obt->derivedFinal); - } - } - - if (idtype == ID_MC) { - MovieClip *clip = (MovieClip *) id; - - BKE_tracking_dopesheet_tag_update(&clip->tracking); - - for (obt = bmain->object.first; obt; obt = obt->id.next) { - bConstraint *con; - for (con = obt->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER)) - { - obt->recalc |= OB_RECALC_OB; - lib_id_recalc_tag(bmain, &obt->id); - break; - } - } - } - - if (sce->nodetree) { - bNode *node; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == id) { - nodeUpdate(sce->nodetree, node); - } - } - } - } - - /* Not pretty to iterate all the nodes here, but it's as good as it - * could be with the current depsgraph design/ - */ - if (idtype == ID_IM) { - FOREACH_NODETREE(bmain, ntree, parent_id) { - if (ntree->type == NTREE_SHADER) { - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == id) { - lib_id_recalc_tag(bmain, &ntree->id); - break; - } - } - } - } FOREACH_NODETREE_END - } - - if (idtype == ID_MSK) { - if (sce->nodetree) { - bNode *node; - - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == id) { - nodeUpdate(sce->nodetree, node); - } - } - } - } - - /* camera's matrix is used to orient reconstructed stuff, - * so it should happen tracking-related constraints recalculation - * when camera is changing (sergey) */ - if (sce->camera && &sce->camera->id == id) { - MovieClip *clip = BKE_object_movieclip_get(sce, sce->camera, true); - - if (clip) - dag_id_flush_update(bmain, sce, &clip->id); - } - - /* update editors */ - dag_editors_id_update(bmain, id); - } -} - -void DAG_ids_flush_tagged(Main *bmain) -{ - ListBase listbase; - DagSceneLayer *dsl; - ListBase *lbarray[MAX_LIBARRAY]; - int a; - bool do_flush = false; - - if (!DEG_depsgraph_use_legacy()) { - DEG_ids_flush_tagged(bmain); - return; - } - - /* get list of visible scenes and layers */ - dag_current_scene_layers(bmain, &listbase); - - if (BLI_listbase_is_empty(&listbase)) - return; - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - for (; id; id = id->next) { - if (id->recalc & ID_RECALC_ALL) { - for (dsl = listbase.first; dsl; dsl = dsl->next) - dag_id_flush_update(bmain, dsl->scene, id); - - do_flush = true; - } - } - } - } - - /* flush changes to other objects */ - if (do_flush) { - for (dsl = listbase.first; dsl; dsl = dsl->next) - DAG_scene_flush_update(bmain, dsl->scene, dsl->layer, 0); - } - - BLI_freelistN(&listbase); -} - -void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) -{ - ListBase *lbarray[MAX_LIBARRAY]; - int a; - bool updated = false; - - if (!DEG_depsgraph_use_legacy()) { - DEG_ids_check_recalc(bmain, scene, time); - return; - } - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - updated = true; - break; - } - } - - dag_editors_scene_update(bmain, scene, (updated || time)); -} - -/* It is possible that scene_update_post and frame_update_post handlers - * will modify objects. The issue is that DAG_ids_clear_recalc is called - * just after callbacks, which leaves objects with recalc flags but no - * corresponding bit in ID recalc bitfield. This leads to some kind of - * regression when using ID type tag fields to check whether there objects - * to be updated internally comparing threaded DAG with legacy one. - * - * For now let's have a workaround which will preserve tag for ID_OB - * if there're objects with OB_RECALC_ALL bits. This keeps behavior - * unchanged comparing with 2.69 release. - * - * TODO(sergey): Need to get rid of such a workaround. - * - * - sergey - - */ - -#define POST_UPDATE_HANDLER_WORKAROUND - -void DAG_ids_clear_recalc(Main *bmain) -{ - ListBase *lbarray[MAX_LIBARRAY]; - bNodeTree *ntree; - int a; - -#ifdef POST_UPDATE_HANDLER_WORKAROUND - bool have_updated_objects = false; - - if (DAG_id_type_tagged(bmain, ID_OB)) { - ListBase listbase; - DagSceneLayer *dsl; - - /* We need to check all visible scenes, otherwise resetting - * OB_ID changed flag will only work fine for first scene of - * multiple visible and all the rest will skip update. - * - * This could also lead to wrong behavior scene update handlers - * because of missing ID datablock changed flags. - * - * This is a bit of a bummer to allocate list here, but likely - * it wouldn't become too much bad because it only happens when - * objects were actually changed. - */ - dag_current_scene_layers(bmain, &listbase); - - for (dsl = listbase.first; dsl; dsl = dsl->next) { - Scene *scene = dsl->scene; - DagNode *node; - for (node = scene->theDag->DagNode.first; - node != NULL && have_updated_objects == false; - node = node->next) - { - if (node->type == ID_OB) { - Object *object = (Object *) node->ob; - if (object->recalc & OB_RECALC_ALL) { - have_updated_objects = true; - break; - } - } - } - } - - BLI_freelistN(&listbase); - } -#endif - - /* loop over all ID types */ - a = set_listbasepointers(bmain, lbarray); - - while (a--) { - ListBase *lb = lbarray[a]; - ID *id = lb->first; - - if (id && bmain->id_tag_update[BKE_idcode_to_index(GS(id->name))]) { - for (; id; id = id->next) { - id->recalc &= ~ID_RECALC_ALL; - - /* some ID's contain semi-datablock nodetree */ - ntree = ntreeFromID(id); - if (ntree) - ntree->id.recalc &= ~ID_RECALC_ALL; - } - } - } - - memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update)); - -#ifdef POST_UPDATE_HANDLER_WORKAROUND - if (have_updated_objects) { - DAG_id_type_tag(bmain, ID_OB); - } -#endif -} - -void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) -{ - if (!DEG_depsgraph_use_legacy()) { - DEG_id_tag_update_ex(bmain, id, flag); - return; - } - - if (id == NULL) return; - - if (G.debug & G_DEBUG_DEPSGRAPH_TAG) { - printf("%s: id=%s flag=%d\n", __func__, id->name, flag); - } - - /* tag ID for update */ - if (flag) { - if (flag & OB_RECALC_OB) - lib_id_recalc_tag(bmain, id); - if (flag & (OB_RECALC_DATA | PSYS_RECALC)) - lib_id_recalc_data_tag(bmain, id); - } - else - lib_id_recalc_tag(bmain, id); - - /* flag is for objects and particle systems */ - if (flag) { - Object *ob; - short idtype = GS(id->name); - - if (idtype == ID_OB) { - /* only quick tag */ - ob = (Object *)id; - ob->recalc |= (flag & OB_RECALC_ALL); - } - else if (idtype == ID_PA) { - ParticleSystem *psys; - /* this is weak still, should be done delayed as well */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (&psys->part->id == id) { - ob->recalc |= (flag & OB_RECALC_ALL); - psys->recalc |= (flag & PSYS_RECALC); - lib_id_recalc_tag(bmain, &ob->id); - lib_id_recalc_data_tag(bmain, &ob->id); - } - } - } - } - else { - /* disable because this is called on various ID types automatically. - * where printing warning is not useful. for now just ignore */ - /* BLI_assert(!"invalid flag for this 'idtype'"); */ - } - } - else if (GS(id->name) == ID_CF) { - for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { - ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); - - if (md) { - MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; - - if (mcmd->cache_file && (&mcmd->cache_file->id == id)) { - ob->recalc |= OB_RECALC_ALL; - continue; - } - } - - for (bConstraint *con = ob->constraints.first; con; con = con->next) { - if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { - continue; - } - - bTransformCacheConstraint *data = con->data; - - if (data->cache_file && (&data->cache_file->id == id)) { - ob->recalc |= OB_RECALC_ALL; - break; - } - } - } - } -} - -void DAG_id_tag_update(ID *id, short flag) -{ - DAG_id_tag_update_ex(G.main, id, flag); -} - -void DAG_id_type_tag(Main *bmain, short idtype) -{ - if (idtype == ID_NT) { - /* stupid workaround so parent datablocks of nested nodetree get looped - * over when we loop over tagged datablock types */ - DAG_id_type_tag(bmain, ID_MA); - DAG_id_type_tag(bmain, ID_TE); - DAG_id_type_tag(bmain, ID_LA); - DAG_id_type_tag(bmain, ID_WO); - DAG_id_type_tag(bmain, ID_SCE); - } - - atomic_fetch_and_or_uint8((uint8_t *)&bmain->id_tag_update[BKE_idcode_to_index(idtype)], 1); -} - -int DAG_id_type_tagged(Main *bmain, short idtype) -{ - return bmain->id_tag_update[BKE_idcode_to_index(idtype)]; -} - -#if 0 // UNUSED -/* recursively descends tree, each node only checked once */ -/* node is checked to be of type object */ -static int parent_check_node(DagNode *node, int curtime) -{ - DagAdjList *itA; - - node->lasttime = curtime; - - if (node->color == DAG_GRAY) - return DAG_GRAY; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node->type == ID_OB) { - - if (itA->node->color == DAG_GRAY) - return DAG_GRAY; - - /* descend if not done */ - if (itA->node->lasttime != curtime) { - itA->node->color = parent_check_node(itA->node, curtime); - - if (itA->node->color == DAG_GRAY) - return DAG_GRAY; - } - } - } - - return DAG_WHITE; -} -#endif - -/* ******************* DAG FOR ARMATURE POSE ***************** */ - -/* we assume its an armature with pose */ -void DAG_pose_sort(Object *ob) -{ - bPose *pose = ob->pose; - bPoseChannel *pchan; - bConstraint *con; - DagNode *node; - DagNode *node2, *node3; - DagNode *rootnode; - DagForest *dag; - DagNodeQueue *nqueue; - DagAdjList *itA; - ListBase tempbase; - int skip = 0; - - dag = dag_init(); - dag->ugly_hack_sorry = false; /* no ID structs */ - - rootnode = dag_add_node(dag, NULL); /* node->ob becomes NULL */ - - /* we add the hierarchy and the constraints */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - int addtoroot = 1; - - node = dag_get_node(dag, pchan); - - if (pchan->parent) { - node2 = dag_get_node(dag, pchan->parent); - dag_add_relation(dag, node2, node, 0, "Parent Relation"); - addtoroot = 0; - } - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob && ct->subtarget[0]) { - bPoseChannel *target = BKE_pose_channel_find_name(ob->pose, ct->subtarget); - if (target) { - node2 = dag_get_node(dag, target); - dag_add_relation(dag, node2, node, 0, "Pose Constraint"); - - if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - bPoseChannel *parchan; - int segcount = 0; - - /* exclude tip from chain? */ - if (!(data->flag & CONSTRAINT_IK_TIP)) - parchan = pchan->parent; - else - parchan = pchan; - - /* Walk to the chain's root */ - while (parchan) { - node3 = dag_get_node(dag, parchan); - dag_add_relation(dag, node2, node3, 0, "IK Constraint"); - - segcount++; - if (segcount == data->rootbone || segcount > 255) break; /* 255 is weak */ - parchan = parchan->parent; - } - } - } - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 1); - } - } - if (addtoroot == 1) { - dag_add_relation(dag, rootnode, node, 0, "Root Bone Relation"); - } - } - - dag_check_cycle(dag); - - /* now we try to sort... */ - BLI_listbase_clear(&tempbase); - - nqueue = queue_create(DAGQUEUEALLOC); - - /* tag nodes unchecked */ - for (node = dag->DagNode.first; node; node = node->next) - node->color = DAG_WHITE; - - rootnode->color = DAG_GRAY; - push_stack(nqueue, rootnode); - - while (nqueue->count) { - - skip = 0; - node = get_top_node_queue(nqueue); - - itA = node->child; - while (itA != NULL) { - if (itA->node->color == DAG_WHITE) { - itA->node->color = DAG_GRAY; - push_stack(nqueue, itA->node); - skip = 1; - break; - } - itA = itA->next; - } - - if (!skip) { - if (node) { - node = pop_queue(nqueue); - if (node->ob == NULL) /* we are done */ - break; - node->color = DAG_BLACK; - - /* put node in new list */ - BLI_remlink(&pose->chanbase, node->ob); - BLI_addhead(&tempbase, node->ob); - } - } - } - - /* temporal correction for circular dependencies */ - while (pose->chanbase.first) { - pchan = pose->chanbase.first; - BLI_remlink(&pose->chanbase, pchan); - BLI_addhead(&tempbase, pchan); - - printf("cyclic %s\n", pchan->name); - } - - pose->chanbase = tempbase; - queue_delete(nqueue); - -// printf("\nordered\n"); -// for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { -// printf(" %s\n", pchan->name); -// } - - free_forest(dag); - MEM_freeN(dag); -} - -/* ************************ DAG FOR THREADED UPDATE ********************* */ - -/* Initialize run-time data in the graph needed for traversing it - * from multiple threads and start threaded tree traversal by adding - * the root node to the queue. - * - * This will mark DAG nodes as object/non-object and will calculate - * num_pending_parents of nodes (which is how many non-updated parents node - * have, which helps a lot checking whether node could be scheduled - * already or not). - */ -void DAG_threaded_update_begin(Scene *scene, - void (*func)(void *node, void *user_data), - void *user_data) -{ - DagNode *node; - - /* We reset num_pending_parents to zero first and tag node as not scheduled yet... */ - for (node = scene->theDag->DagNode.first; node; node = node->next) { - node->num_pending_parents = 0; - node->scheduled = false; - } - - /* ... and then iterate over all the nodes and - * increase num_pending_parents for node childs. - */ - for (node = scene->theDag->DagNode.first; node; node = node->next) { - DagAdjList *itA; - - for (itA = node->child; itA; itA = itA->next) { - if (itA->node != node) { - itA->node->num_pending_parents++; - } - } - } - - /* Add root nodes to the queue. */ - BLI_spin_lock(&threaded_update_lock); - for (node = scene->theDag->DagNode.first; node; node = node->next) { - if (node->num_pending_parents == 0) { - node->scheduled = true; - func(node, user_data); - } - } - BLI_spin_unlock(&threaded_update_lock); -} - -/* This function is called when handling node is done. - * - * This function updates num_pending_parents for all childs and - * schedules them if they're ready. - */ -void DAG_threaded_update_handle_node_updated(void *node_v, - void (*func)(void *node, void *user_data), - void *user_data) -{ - DagNode *node = node_v; - DagAdjList *itA; - - for (itA = node->child; itA; itA = itA->next) { - DagNode *child_node = itA->node; - if (child_node != node) { - atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1); - - if (child_node->num_pending_parents == 0) { - bool need_schedule; - - BLI_spin_lock(&threaded_update_lock); - need_schedule = child_node->scheduled == false; - child_node->scheduled = true; - BLI_spin_unlock(&threaded_update_lock); - - if (need_schedule) { - func(child_node, user_data); - } - } - } - } -} - -/* ************************ DAG DEBUGGING ********************* */ - -void DAG_print_dependencies(Main *bmain, Scene *scene, Object *ob) -{ - /* utility for debugging dependencies */ - dag_print_dependencies = 1; - - if (ob && (ob->mode & OB_MODE_POSE)) { - printf("\nDEPENDENCY RELATIONS for %s\n\n", ob->id.name + 2); - DAG_pose_sort(ob); - } - else { - printf("\nDEPENDENCY RELATIONS for %s\n\n", scene->id.name + 2); - DAG_scene_relations_rebuild(bmain, scene); - } - - dag_print_dependencies = 0; -} - -/* ************************ DAG querying ********************* */ - -/* Will return Object ID if node represents Object, - * and will return NULL otherwise. - */ -Object *DAG_get_node_object(void *node_v) -{ - DagNode *node = node_v; - - if (node->type == ID_OB) { - return node->ob; - } - - return NULL; -} - -/* Returns node name, used for debug output only, atm. */ -const char *DAG_get_node_name(Scene *scene, void *node_v) -{ - DagNode *node = node_v; - - return dag_node_name(scene->theDag, node); -} - -short DAG_get_eval_flags_for_object(Scene *scene, void *object) -{ - DagNode *node; - - if (!DEG_depsgraph_use_legacy()) { - return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); - } - - if (scene->theDag == NULL) { - /* Happens when converting objects to mesh from a python script - * after modifying scene graph. - * - * Currently harmless because it's only called for temporary - * objects which are out of the DAG anyway. - */ - return 0; - } - - node = dag_find_node(scene->theDag, object); - - if (node) { - return node->eval_flags; - } - else { - /* Happens when external render engine exports temporary objects - * which are not in the DAG. - */ - - /* TODO(sergey): Doublecheck objects with Curve Deform exports all fine. */ - - /* TODO(sergey): Weak but currently we can't really access proper DAG from - * the modifiers stack. This is because in most cases modifier is to use - * the foreground scene, but to access evaluation flags we need to know - * active background scene, which we don't know. - */ - if (scene->set) { - return DAG_get_eval_flags_for_object(scene->set, object); - } - return 0; - } -} - -bool DAG_is_acyclic(Scene *scene) -{ - return scene->theDag->is_acyclic; -} - -#else - -/* ********************************************************************* - * Stubs to avoid linking issues and make sure legacy crap is not used * - * ********************************************************************* - */ - -DagNodeQueue *queue_create(int UNUSED(slots)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -void queue_raz(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void queue_delete(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -DagNode *pop_queue(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagForest *dag_init(void) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagForest *build_dag(Main *UNUSED(bmain), - Scene *UNUSED(sce), - short UNUSED(mask)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -void free_forest(DagForest *UNUSED(Dag)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -void dag_add_relation(DagForest *UNUSED(forest), - DagNode *UNUSED(fob1), - DagNode *UNUSED(fob2), - short UNUSED(rel), - const char *UNUSED(name)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -/* debug test functions */ - -void graph_print_queue(DagNodeQueue *UNUSED(nqueue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void graph_print_adj_list(DagForest *UNUSED(dag)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void DAG_scene_flush_update(Main *UNUSED(bmain), - Scene *UNUSED(sce), - unsigned int UNUSED(lay), - const short UNUSED(time)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -void DAG_scene_update_flags(Main *UNUSED(bmain), - Scene *UNUSED(scene), - unsigned int UNUSED(lay), - const bool UNUSED(do_time), - const bool UNUSED(do_invisible_flush)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -/* ******************* DAG FOR ARMATURE POSE ***************** */ - -void DAG_pose_sort(Object *UNUSED(ob)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); -} - -/* ************************ DAG FOR THREADED UPDATE ********************* */ - -void DAG_threaded_update_begin(Scene *UNUSED(scene), - void (*func)(void *node, void *user_data), - void *UNUSED(user_data)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - (void)func; -} - -void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v), - void (*func)(void *node, void *user_data), - void *UNUSED(user_data)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - (void)func; -} - -/* ************************ DAG querying ********************* */ - -Object *DAG_get_node_object(void *UNUSED(node_v)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return NULL; -} - -const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return "INVALID"; -} - -bool DAG_is_acyclic(Scene *UNUSED(scene)) -{ - BLI_assert(!"Should not be used with new dependnecy graph"); - return false; -} - -/* ************************************ - * This functions are to be supported * - * ************************************ - */ - -void DAG_init(void) -{ - DEG_register_node_types(); -} - -void DAG_exit(void) -{ - DEG_free_node_types(); -} - -/* ************************ API *********************** */ - -void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func, - DEG_EditorUpdateScenePreCb scene_func_pre) -{ - DEG_editors_set_update_cb(id_func, scene_func, scene_func_pre); -} - -void DAG_editors_update_pre(Main *bmain, Scene *scene, bool time) -{ - DEG_editors_update_pre(bmain, scene, time); -} - -/* Tag all relations for update. */ -void DAG_relations_tag_update(Main *bmain) -{ - DEG_relations_tag_update(bmain); -} - -/* Rebuild dependency graph only for a given scene. */ -void DAG_scene_relations_rebuild(Main *bmain, Scene *scene) -{ - DEG_scene_relations_rebuild(bmain, scene); -} - -/* Create dependency graph if it was cleared or didn't exist yet. */ -void DAG_scene_relations_update(Main *bmain, Scene *scene) -{ - DEG_scene_relations_update(bmain, scene); -} - -void DAG_scene_relations_validate(Main *bmain, Scene *scene) -{ - DEG_debug_scene_relations_validate(bmain, scene); -} - -void DAG_scene_free(Scene *scene) -{ - DEG_scene_graph_free(scene); -} - -void DAG_on_visible_update(Main *bmain, const bool do_time) -{ - DEG_on_visible_update(bmain, do_time); -} - -void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time) -{ - DEG_ids_check_recalc(bmain, scene, time); -} - -void DAG_id_tag_update(ID *id, short flag) -{ - DEG_id_tag_update_ex(G.main, id, flag); -} - -void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) -{ - DEG_id_tag_update_ex(bmain, id, flag); -} - -void DAG_id_type_tag(Main *bmain, short idtype) -{ - DEG_id_type_tag(bmain, idtype); -} - -int DAG_id_type_tagged(Main *bmain, short idtype) -{ - return DEG_id_type_tagged(bmain, idtype); -} - -void DAG_ids_clear_recalc(Main *bmain) -{ - DEG_ids_clear_recalc(bmain); -} - -short DAG_get_eval_flags_for_object(Scene *scene, void *object) -{ - return DEG_get_eval_flags_for_id(scene->depsgraph, (ID *)object); -} - -void DAG_ids_flush_tagged(Main *bmain) -{ - DEG_ids_flush_tagged(bmain); -} - -/* ************************ DAG DEBUGGING ********************* */ - -void DAG_print_dependencies(Main *UNUSED(bmain), - Scene *scene, - Object *UNUSED(ob)) -{ - DEG_debug_relations_graphviz(scene->depsgraph, stdout, "Depsgraph"); -} - -#endif diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index dea1a3718dd..8d49521831f 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -37,6 +37,7 @@ #include "MEM_guardedalloc.h" #include "DNA_curve_types.h" +#include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_vfont_types.h" @@ -48,13 +49,14 @@ #include "BLI_utildefines.h" #include "BKE_global.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_cdderivedmesh.h" #include "BKE_object.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_mball_tessellate.h" +#include "BKE_mesh.h" #include "BKE_curve.h" #include "BKE_key.h" #include "BKE_anim.h" @@ -64,6 +66,9 @@ #include "BLI_sys_types.h" // for intptr_t support +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + static void boundbox_displist_object(Object *ob); void BKE_displist_elem_free(DispList *dl) @@ -680,17 +685,17 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis * - first point left, last point right * - based on subdivided points in original curve, not on points in taper curve (still) */ -static float displist_calc_taper(Scene *scene, Object *taperobj, float fac) +static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, float fac) { DispList *dl; if (taperobj == NULL || taperobj->type != OB_CURVE) return 1.0; - dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL; + dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL; if (dl == NULL) { - BKE_displist_make_curveTypes(scene, taperobj, 0); - dl = taperobj->curve_cache->disp.first; + BKE_displist_make_curveTypes(depsgraph, scene, taperobj, 0); + dl = taperobj->runtime.curve_cache->disp.first; } if (dl) { float minx, dx, *fp; @@ -720,39 +725,39 @@ static float displist_calc_taper(Scene *scene, Object *taperobj, float fac) return 1.0; } -float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot) +float BKE_displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot) { float fac = ((float)cur) / (float)(tot - 1); - return displist_calc_taper(scene, taperobj, fac); + return displist_calc_taper(depsgraph, scene, taperobj, fac); } -void BKE_displist_make_mball(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob) +void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob) { if (!ob || ob->type != OB_MBALL) return; - if (ob == BKE_mball_basis_find(bmain, eval_ctx, scene, ob)) { - if (ob->curve_cache) { - BKE_displist_free(&(ob->curve_cache->disp)); + if (ob == BKE_mball_basis_find(scene, ob)) { + if (ob->runtime.curve_cache) { + BKE_displist_free(&(ob->runtime.curve_cache->disp)); } else { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); } - BKE_mball_polygonize(bmain, eval_ctx, scene, ob, &ob->curve_cache->disp); + BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp); BKE_mball_texspace_calc(ob); - object_deform_mball(ob, &ob->curve_cache->disp); + object_deform_mball(ob, &ob->runtime.curve_cache->disp); /* NOP for MBALLs anyway... */ boundbox_displist_object(ob); } } -void BKE_displist_make_mball_forRender(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase) +void BKE_displist_make_mball_forRender(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase) { - BKE_mball_polygonize(bmain, eval_ctx, scene, ob, dispbase); + BKE_mball_polygonize(depsgraph, scene, ob, dispbase); BKE_mball_texspace_calc(ob); object_deform_mball(ob, dispbase); @@ -800,14 +805,15 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, return pretessellatePoint; } -static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, - const bool for_render, const bool use_render_resolution) +static void curve_calc_modifiers_pre( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, + const bool for_render, const bool use_render_resolution) { VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); ModifierData *pretessellatePoint; Curve *cu = ob->data; - int numVerts = 0; + int numElems = 0, numVerts = 0; const bool editmode = (!for_render && (cu->editnurb || cu->editfont)); ModifierApplyFlag app_flag = 0; float (*deformedVerts)[3] = NULL; @@ -825,21 +831,25 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, else required_mode = eModifierMode_Realtime; + const ModifierEvalContext mectx = {depsgraph, ob, app_flag}; + pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode); if (editmode) required_mode |= eModifierMode_Editmode; if (!editmode) { - keyVerts = BKE_key_evaluate_object(ob, &numVerts); + keyVerts = BKE_key_evaluate_object(ob, &numElems); if (keyVerts) { + BLI_assert(BKE_keyblock_curve_element_count(nurb) == numElems); + /* split coords from key data, the latter also includes * tilts, which is passed through in the modifier stack. * this is also the reason curves do not use a virtual * shape key modifier yet. */ deformedVerts = BKE_curve_nurbs_keyVertexCos_get(nurb, keyVerts); - BLI_assert(BKE_nurbList_verts_count(nurb) == numVerts); + numVerts = BKE_nurbList_verts_count(nurb); } } @@ -847,8 +857,6 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, for (; md; md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - if (!modifier_isEnabled(scene, md, required_mode)) continue; if (mti->type != eModifierTypeType_OnlyDeform) @@ -858,7 +866,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts); } - mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, app_flag); + mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts); if (md == pretessellatePoint) break; @@ -910,9 +918,10 @@ static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3]) } } -static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, - ListBase *dispbase, DerivedMesh **r_dm_final, - const bool for_render, const bool use_render_resolution) +static void curve_calc_modifiers_post( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, + ListBase *dispbase, Mesh **r_final, + const bool for_render, const bool use_render_resolution) { VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -920,7 +929,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, Curve *cu = ob->data; int required_mode = 0, totvert = 0; const bool editmode = (!for_render && (cu->editnurb || cu->editfont)); - DerivedMesh *dm = NULL, *ndm; + Mesh *modified = NULL, *mesh_applied; float (*vertCos)[3] = NULL; int useCache = !for_render; ModifierApplyFlag app_flag = 0; @@ -932,6 +941,11 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, else required_mode = eModifierMode_Realtime; + const ModifierEvalContext mectx_deform = {depsgraph, ob, + editmode ? app_flag | MOD_APPLY_USECACHE : app_flag}; + const ModifierEvalContext mectx_apply = {depsgraph, ob, + useCache ? app_flag | MOD_APPLY_USECACHE : app_flag}; + pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode); if (editmode) @@ -941,43 +955,34 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, md = pretessellatePoint->next; } - if (r_dm_final && *r_dm_final) { - (*r_dm_final)->release(*r_dm_final); + if (r_final && *r_final) { + BKE_id_free(NULL, r_final); } for (; md; md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - ModifierApplyFlag appf = app_flag; - - md->scene = scene; if (!modifier_isEnabled(scene, md, required_mode)) continue; if (mti->type == eModifierTypeType_OnlyDeform || - (mti->type == eModifierTypeType_DeformOrConstruct && !dm)) + (mti->type == eModifierTypeType_DeformOrConstruct && !modified)) { - if (editmode) - appf |= MOD_APPLY_USECACHE; - if (dm) { + if (modified) { if (!vertCos) { - totvert = dm->getNumVerts(dm); - vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv"); - dm->getVertCos(dm, vertCos); + vertCos = BKE_mesh_vertexCos_get(modified, &totvert); } - - mti->deformVerts(md, ob, dm, vertCos, totvert, appf); + mti->deformVerts(md, &mectx_deform, modified, vertCos, totvert); } else { if (!vertCos) { vertCos = displist_get_allverts(dispbase, &totvert); } - - mti->deformVerts(md, ob, NULL, vertCos, totvert, appf); + mti->deformVerts(md, &mectx_deform, NULL, vertCos, totvert); } } else { - if (!r_dm_final) { + if (!r_final) { /* makeDisplistCurveTypes could be used for beveling, where derived mesh * is totally unnecessary, so we could stop modifiers applying * when we found constructive modifier but derived mesh is unwanted result @@ -985,13 +990,17 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, break; } - if (dm) { + if (modified) { if (vertCos) { - DerivedMesh *tdm = CDDM_copy(dm); - dm->release(dm); - dm = tdm; - - CDDM_apply_vert_coords(dm, vertCos); + Mesh *temp_mesh; + BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW, + false); + BKE_id_free(NULL, modified); + modified = temp_mesh; + + BKE_mesh_apply_vert_coords(modified, vertCos); } } else { @@ -1003,7 +1012,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, curve_to_filledpoly(cu, nurb, dispbase); } - dm = CDDM_from_curve_displist(ob, dispbase); + modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase); } if (vertCos) { @@ -1012,29 +1021,31 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, vertCos = NULL; } - if (useCache) - appf |= MOD_APPLY_USECACHE; + mesh_applied = mti->applyModifier(md, &mectx_apply, modified); - ndm = modwrap_applyModifier(md, ob, dm, appf); - - if (ndm) { + if (mesh_applied) { /* Modifier returned a new derived mesh */ - if (dm && dm != ndm) /* Modifier */ - dm->release(dm); - dm = ndm; + if (modified && modified != mesh_applied) /* Modifier */ + BKE_id_free(NULL, modified); + modified = mesh_applied; } } } if (vertCos) { - if (dm) { - DerivedMesh *tdm = CDDM_copy(dm); - dm->release(dm); - dm = tdm; + if (modified) { + Mesh *temp_mesh; + BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh, + LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW, + false); + BKE_id_free(NULL, modified); + modified = temp_mesh; + + BKE_mesh_apply_vert_coords(modified, vertCos); + BKE_mesh_calc_normals_mapping_simple(modified); - CDDM_apply_vert_coords(dm, vertCos); - CDDM_calc_normals_mapping(dm); MEM_freeN(vertCos); } else { @@ -1044,23 +1055,27 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, } } - if (r_dm_final) { - if (dm) { + if (r_final) { + if (modified) { /* see: mesh_calc_modifiers */ - if (dm->getNumTessFaces(dm) == 0) { - dm->recalcTessellation(dm); + if (modified->totface == 0) { + BKE_mesh_tessface_calc(modified); } /* Even if tessellation is not needed, some modifiers might have modified CD layers * (like mloopcol or mloopuv), hence we have to update those. */ - else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) { - DM_update_tessface_data(dm); + else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) { + BKE_mesh_tessface_calc(modified); } - if (dm->type == DM_TYPE_CDDM) { - CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true); - } + /* XXX2.8(Sybren): make sure the face normals are recalculated as well */ + BKE_mesh_ensure_normals(modified); + + (*r_final) = modified; + } + else { + (*r_final) = NULL; } - (*r_dm_final) = dm; + } } @@ -1092,13 +1107,15 @@ static void displist_surf_indices(DispList *dl) } } -static DerivedMesh *create_orco_dm(Scene *scene, Object *ob) +/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */ +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS +static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob) { DerivedMesh *dm; ListBase disp = {NULL, NULL}; /* OrcoDM should be created from underformed disp lists */ - BKE_displist_make_curveTypes_forOrco(scene, ob, &disp); + BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp); dm = CDDM_from_curve_displist(ob, &disp); BKE_displist_free(&disp); @@ -1135,9 +1152,13 @@ static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm) else DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco); } +#endif -static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final, - const bool for_render, const bool use_render_resolution) +/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */ +#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS +static void curve_calc_orcodm( + Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final, + const bool for_render, const bool use_render_resolution) { /* this function represents logic of mesh's orcodm calculation * for displist-based objects @@ -1158,6 +1179,8 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final, else required_mode = eModifierMode_Realtime; + const ModifierEvalContext mectx = {depsgraph, ob, app_flag}; + pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode); if (editmode) @@ -1174,7 +1197,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final, * This means we can create ORCO DM in advance and assume it's * never NULL. */ - orcodm = create_orco_dm(scene, ob); + orcodm = create_orco_dm(depsgraph, scene, ob); for (; md; md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -1186,7 +1209,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final, if (mti->type != eModifierTypeType_Constructive) continue; - ndm = modwrap_applyModifier(md, ob, orcodm, app_flag); + ndm = modwrap_applyModifier(md, &mectx, orcodm); if (ndm) { /* if the modifier returned a new dm, release the old one */ @@ -1202,10 +1225,12 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final, orcodm->release(orcodm); } +#endif -void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase, - DerivedMesh **r_dm_final, - const bool for_render, const bool for_orco, const bool use_render_resolution) +void BKE_displist_make_surf( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase, + Mesh **r_final, + const bool for_render, const bool for_orco, const bool use_render_resolution) { ListBase nubase = {NULL, NULL}; Nurb *nu; @@ -1222,7 +1247,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase, } if (!for_orco) - curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution); + curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution); for (nu = nubase.first; nu; nu = nu->next) { if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) { @@ -1288,8 +1313,8 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase, } if (!for_orco) { - BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final, + BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); + curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution); } @@ -1515,9 +1540,10 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu, } } -static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase, - DerivedMesh **r_dm_final, - const bool for_render, const bool for_orco, const bool use_render_resolution) +static void do_makeDispListCurveTypes( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase, + Mesh **r_final, + const bool for_render, const bool for_orco, const bool use_render_resolution) { Curve *cu = ob->data; @@ -1525,21 +1551,21 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; if (ob->type == OB_SURF) { - BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution); + BKE_displist_make_surf(depsgraph, scene, ob, dispbase, r_final, for_render, for_orco, use_render_resolution); } else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { ListBase dlbev; ListBase nubase = {NULL, NULL}; - BKE_curve_bevelList_free(&ob->curve_cache->bev); + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); /* We only re-evaluate path if evaluation is not happening for orco. * If the calculation happens for orco, we should never free data which * was needed before and only not needed for orco calculation. */ if (!for_orco) { - if (ob->curve_cache->path) free_path(ob->curve_cache->path); - ob->curve_cache->path = NULL; + if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path); + ob->runtime.curve_cache->path = NULL; } if (ob->type == OB_FONT) { @@ -1550,12 +1576,12 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } if (!for_orco) - curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution); + curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution); BKE_curve_bevelList_make(ob, &nubase, for_render != false); /* If curve has no bevel will return nothing */ - BKE_curve_bevel_make(scene, ob, &dlbev, for_render, use_render_resolution); + BKE_curve_bevel_make(depsgraph, scene, ob, &dlbev, for_render, use_render_resolution); /* no bevel or extrude, and no width correction? */ if (!dlbev.first && cu->width == 1.0f) { @@ -1563,7 +1589,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } else { float widfac = cu->width - 1.0f; - BevList *bl = ob->curve_cache->bev.first; + BevList *bl = ob->runtime.curve_cache->bev.first; Nurb *nu = nubase.first; for (; bl && nu; bl = bl->next, nu = nu->next) { @@ -1690,7 +1716,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba taper_fac -= (1.0f - lastblend) / len; } - fac = displist_calc_taper(scene, cu->taperobj, taper_fac); + fac = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_fac); } if (bevp->split_tag) { @@ -1743,18 +1769,18 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba if (!for_orco) { if ((cu->flag & CU_PATH) || - DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CURVE_PATH) + DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH) { calc_curvepath(ob, &nubase); } } if (!for_orco) { - BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase); - curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution); + BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); + curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution); } - if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) { + if (cu->flag & CU_DEFORM_FILL && !ob->runtime.mesh_eval) { curve_to_filledpoly(cu, &nubase, dispbase); } @@ -1762,7 +1788,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } } -void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco) +void BKE_displist_make_curveTypes(Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_orco) { ListBase *dispbase; @@ -1774,58 +1800,37 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco) BKE_object_free_derived_caches(ob); - if (!ob->curve_cache) { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); + if (!ob->runtime.curve_cache) { + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); } - dispbase = &(ob->curve_cache->disp); + dispbase = &(ob->runtime.curve_cache->disp); - do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0); + do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, &ob->runtime.mesh_eval, 0, for_orco, 0); boundbox_displist_object(ob); } -void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase, - DerivedMesh **r_dm_final, const bool for_orco, - const bool use_render_resolution) +void BKE_displist_make_curveTypes_forRender( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase, + Mesh **r_final, const bool for_orco, + const bool use_render_resolution) { - if (ob->curve_cache == NULL) { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); + if (ob->runtime.curve_cache == NULL) { + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); } - do_makeDispListCurveTypes(scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution); + do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, r_final, true, for_orco, use_render_resolution); } -void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase) +void BKE_displist_make_curveTypes_forOrco( + Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase) { - if (ob->curve_cache == NULL) { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); - } - - do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1); -} - -/* add Orco layer to the displist object which has got derived mesh and return orco */ -float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *dm_final, - const bool for_render, - const bool use_render_resolution) -{ - float *orco; - - if (dm_final == NULL) - dm_final = ob->derivedFinal; - - if (!dm_final->getVertDataArray(dm_final, CD_ORCO)) { - curve_calc_orcodm(scene, ob, dm_final, for_render, use_render_resolution); - } - - orco = dm_final->getVertDataArray(dm_final, CD_ORCO); - - if (orco) { - orco = MEM_dupallocN(orco); + if (ob->runtime.curve_cache == NULL) { + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); } - return orco; + do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, NULL, 1, 1, 1); } void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3]) @@ -1863,14 +1868,14 @@ static void boundbox_displist_object(Object *ob) if (ob->bb == NULL) ob->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); - if (ob->derivedFinal) { - DM_set_object_boundbox(ob, ob->derivedFinal); + if (ob->runtime.mesh_eval) { + BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval); } else { float min[3], max[3]; INIT_MINMAX(min, max); - BKE_displist_minmax(&ob->curve_cache->disp, min, max); + BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max); BKE_boundbox_init_from_minmax(ob->bb, min, max); ob->bb->flag &= ~BOUNDBOX_DIRTY; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index e129251157e..8afcc8ba41c 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -41,9 +41,9 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_dynamicpaint_types.h" -#include "DNA_group_types.h" /*GroupObject*/ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -55,27 +55,32 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_bvhutils.h" /* bvh tree */ +#include "BKE_collection.h" +#include "BKE_collision.h" #include "BKE_colorband.h" -#include "BKE_cdderivedmesh.h" #include "BKE_constraint.h" #include "BKE_customdata.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" #include "BKE_dynamicpaint.h" #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_scene.h" -/* for image output */ +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +/* for image output */ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -246,7 +251,7 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface) return 0; /* not supported atm */ } else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { - return (surface->canvas->dm) ? surface->canvas->dm->getNumVerts(surface->canvas->dm) : 0; + return (surface->canvas->mesh) ? surface->canvas->mesh->totvert : 0; } return 0; @@ -487,42 +492,17 @@ static void scene_setSubframe(Scene *scene, float subframe) scene->r.subframe = subframe; } -static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene) +static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgraph) { - Base *base = NULL; - GroupObject *go = NULL; - Object *brushObj = NULL; - ModifierData *md = NULL; + unsigned int numobjects; + Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint); int flags = 0; - if (surface->brush_group) - go = surface->brush_group->gobject.first; - else - base = scene->base.first; - - while (base || go) { - brushObj = NULL; - - /* select object */ - if (surface->brush_group) { - if (go->ob) - brushObj = go->ob; - } - else { - brushObj = base->object; - } - - if (surface->brush_group) - go = go->next; - else - base = base->next; - - if (!brushObj) { - continue; - } + for (int i = 0; i < numobjects; i++) { + Object *brushObj = objects[i]; - md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); + ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md; @@ -535,12 +515,9 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen } } - return flags; -} + BKE_collision_objects_free(objects); -static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene) -{ - return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(scene))); + return flags; } /* check whether two bounds intersect */ @@ -837,9 +814,10 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd) { if (pmd->brush) { - if (pmd->brush->dm) - pmd->brush->dm->release(pmd->brush->dm); - pmd->brush->dm = NULL; + if (pmd->brush->mesh) { + BKE_id_free(NULL, pmd->brush->mesh); + } + pmd->brush->mesh = NULL; if (pmd->brush->paint_ramp) MEM_freeN(pmd->brush->paint_ramp); @@ -966,10 +944,11 @@ void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd) surface = next_surface; } - /* free dm copy */ - if (pmd->canvas->dm) - pmd->canvas->dm->release(pmd->canvas->dm); - pmd->canvas->dm = NULL; + /* free mesh copy */ + if (pmd->canvas->mesh) { + BKE_id_free(NULL, pmd->canvas->mesh); + } + pmd->canvas->mesh = NULL; MEM_freeN(pmd->canvas); pmd->canvas = NULL; @@ -1081,7 +1060,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str if (!canvas) return false; canvas->pmd = pmd; - canvas->dm = NULL; + canvas->mesh = NULL; /* Create one surface */ if (!dynamicPaint_createNewSurface(canvas, scene)) @@ -1103,7 +1082,6 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA; brush->collision = MOD_DPAINT_COL_VOLUME; - brush->mat = NULL; brush->r = 0.15f; brush->g = 0.4f; brush->b = 0.8f; @@ -1122,7 +1100,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str brush->smudge_strength = 0.3f; brush->max_velocity = 1.0f; - brush->dm = NULL; + brush->mesh = NULL; /* Paint proximity falloff colorramp. */ { @@ -1243,7 +1221,6 @@ void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, stru t_brush->flags = brush->flags; t_brush->collision = brush->collision; - t_brush->mat = brush->mat; t_brush->r = brush->r; t_brush->g = brush->g; t_brush->b = brush->b; @@ -1311,7 +1288,7 @@ static bool surface_usesAdjData(DynamicPaintSurface *surface) static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init) { PaintSurfaceData *sData = surface->data; - DerivedMesh *dm = surface->canvas->dm; + Mesh *mesh = surface->canvas->mesh; PaintAdjData *ad; int *temp_data; int neigh_points = 0; @@ -1321,7 +1298,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { /* For vertex format, neighbors are connected by edges */ - neigh_points = 2 * dm->getNumEdges(dm); + neigh_points = 2 * mesh->totedge; } else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { neigh_points = sData->total_points * 8; @@ -1357,11 +1334,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b int n_pos; /* For vertex format, count every vertex that is connected by an edge */ - int numOfEdges = dm->getNumEdges(dm); - int numOfPolys = dm->getNumPolys(dm); - struct MEdge *edge = dm->getEdgeArray(dm); - struct MPoly *mpoly = dm->getPolyArray(dm); - struct MLoop *mloop = dm->getLoopArray(dm); + int numOfEdges = mesh->totedge; + int numOfPolys = mesh->totpoly; + struct MEdge *edge = mesh->medge; + struct MPoly *mpoly = mesh->mpoly; + struct MLoop *mloop = mesh->mloop; /* count number of edges per vertex */ for (i = 0; i < numOfEdges; i++) { @@ -1545,7 +1522,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface { PaintSurfaceData *sData = surface->data; PaintPoint *pPoint = (PaintPoint *)sData->type_data; - DerivedMesh *dm = surface->canvas->dm; + Mesh *mesh = surface->canvas->mesh; int i; const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene); @@ -1566,9 +1543,9 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) { Tex *tex = surface->init_texture; - const MLoop *mloop = dm->getLoopArray(dm); - const MLoopTri *mlooptri = dm->getLoopTriArray(dm); - const int tottri = dm->getNumLoopTri(dm); + const MLoop *mloop = mesh->mloop; + const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); + const int tottri = BKE_mesh_runtime_looptri_len(mesh); const MLoopUV *mloopuv = NULL; char uvname[MAX_CUSTOMDATA_LAYER_NAME]; @@ -1577,8 +1554,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface return; /* get uv map */ - CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->init_layername, uvname); - mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname); + CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname); + mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname); if (!mloopuv) return; @@ -1621,9 +1598,9 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface /* for vertex surface, just copy colors from mcol */ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) { - const MLoop *mloop = dm->getLoopArray(dm); - const int totloop = dm->getNumLoops(dm); - const MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername); + const MLoop *mloop = mesh->mloop; + const int totloop = mesh->totloop; + const MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername); if (!col) return; @@ -1632,8 +1609,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface } } else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) { - const MLoopTri *mlooptri = dm->getLoopTriArray(dm); - MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername); + const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); + MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername); if (!col) return; @@ -1755,7 +1732,7 @@ static void dynamic_paint_apply_surface_displace_cb( } /* apply displacing vertex surface to the derived mesh */ -static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result) +static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result) { PaintSurfaceData *sData = surface->data; @@ -1764,7 +1741,7 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri /* displace paint */ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { - MVert *mvert = result->getVertArray(result); + MVert *mvert = result->mvert; DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert}; ParallelRangeSettings settings; @@ -1882,10 +1859,10 @@ static void dynamic_paint_apply_surface_wave_cb( /* * Apply canvas data to the object derived mesh */ -static DerivedMesh *dynamicPaint_Modifier_apply( - DynamicPaintModifierData *pmd, Object *ob, DerivedMesh *dm) +static Mesh *dynamicPaint_Modifier_apply( + DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh) { - DerivedMesh *result = CDDM_copy(dm); + Mesh *result = BKE_mesh_copy_for_eval(mesh, false); if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) { @@ -1905,10 +1882,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply( /* vertex color paint */ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { - MLoop *mloop = CDDM_get_loops(result); - const int totloop = result->numLoopData; - MPoly *mpoly = CDDM_get_polys(result); - const int totpoly = result->numPolyData; + MLoop *mloop = result->mloop; + const int totloop = result->totloop; + MPoly *mpoly = result->mpoly; + const int totpoly = result->totpoly; /* paint is stored on dry and wet layers, so mix final color first */ float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color"); @@ -1926,28 +1903,28 @@ static DerivedMesh *dynamicPaint_Modifier_apply( } /* paint layer */ - MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name); + MLoopCol *mloopcol = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name); /* if output layer is lost from a constructive modifier, re-add it */ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) { mloopcol = CustomData_add_layer_named( - &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name); + &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name); } /* wet layer */ - MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2); + MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name2); /* if output layer is lost from a constructive modifier, re-add it */ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) { mloopcol_wet = CustomData_add_layer_named( - &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2); + &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2); } /* Save preview results to weight layer to be able to share same drawing methods */ MLoopCol *mloopcol_preview = NULL; if (surface->flags & MOD_DPAINT_PREVIEW) { - mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL); + mloopcol_preview = CustomData_get_layer(&result->ldata, CD_PREVIEW_MLOOPCOL); if (!mloopcol_preview) { mloopcol_preview = CustomData_add_layer( - &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop); + &result->ldata, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop); } } @@ -1972,12 +1949,12 @@ static DerivedMesh *dynamicPaint_Modifier_apply( MEM_freeN(fcolor); /* Mark tessellated CD layers as dirty. */ - result->dirty |= DM_DIRTY_TESS_CDLAYERS; + //result->dirty |= DM_DIRTY_TESS_CDLAYERS; } /* vertex group paint */ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) { int defgrp_index = defgroup_name_index(ob, surface->output_name); - MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT); + MDeformVert *dvert = CustomData_get_layer(&result->vdata, CD_MDEFORMVERT); float *weight = (float *)sData->type_data; /* viewport preview */ @@ -1985,12 +1962,13 @@ static DerivedMesh *dynamicPaint_Modifier_apply( /* Save preview results to weight layer to be * able to share same drawing methods. * Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */ - DM_update_weight_mcol(ob, result, 0, weight, 0, NULL); + //TODO port this function + //DM_update_weight_mcol(ob, result, 0, weight, 0, NULL); } /* apply weights into a vertex group, if doesn't exists add a new layer */ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) { - dvert = CustomData_add_layer(&result->vertData, CD_MDEFORMVERT, CD_CALLOC, + dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points); } if (defgrp_index != -1 && dvert) { @@ -2014,7 +1992,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply( } /* wave simulation */ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) { - MVert *mvert = result->getVertArray(result); + MVert *mvert = result->mvert; DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert}; ParallelRangeSettings settings; @@ -2038,14 +2016,15 @@ static DerivedMesh *dynamicPaint_Modifier_apply( } if (update_normals) { - result->dirty |= DM_DIRTY_NORMALS; + //result->dirty |= DM_DIRTY_NORMALS; } } - /* make a copy of dm to use as brush data */ + /* make a copy of mesh to use as brush data */ if (pmd->brush) { - if (pmd->brush->dm) - pmd->brush->dm->release(pmd->brush->dm); - pmd->brush->dm = CDDM_copy(result); + if (pmd->brush->mesh) { + BKE_id_free(NULL, pmd->brush->mesh); + } + pmd->brush->mesh = BKE_mesh_copy_for_eval(result, false); } return result; @@ -2060,27 +2039,28 @@ void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface) } } -static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMesh *dm) +static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh) { - if (canvas->dm) { - canvas->dm->release(canvas->dm); + if (canvas->mesh) { + BKE_id_free(NULL, canvas->mesh); } - canvas->dm = CDDM_copy(dm); + canvas->mesh = BKE_mesh_copy_for_eval(mesh, false); } /* * Updates derived mesh copy and processes dynamic paint step / caches. */ static void dynamicPaint_frameUpdate( - Main *bmain, EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm) + DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene, + Object *ob, Mesh *mesh) { if (pmd->canvas) { DynamicPaintCanvasSettings *canvas = pmd->canvas; DynamicPaintSurface *surface = canvas->surfaces.first; /* update derived mesh copy */ - canvas_copyDerivedMesh(canvas, dm); + canvas_copyMesh(canvas, mesh); /* in case image sequence baking, stop here */ if (canvas->flags & MOD_DPAINT_BAKING) @@ -2136,14 +2116,14 @@ static void dynamicPaint_frameUpdate( else if (can_simulate) { /* calculate surface frame */ canvas->flags |= MOD_DPAINT_BAKING; - dynamicPaint_calculateFrame(bmain, eval_ctx, surface, scene, ob, current_frame); + dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame); canvas->flags &= ~MOD_DPAINT_BAKING; - /* restore canvas derivedmesh if required */ + /* restore canvas mesh if required */ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE && surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next) { - canvas_copyDerivedMesh(canvas, dm); + canvas_copyMesh(canvas, mesh); } BKE_ptcache_validate(cache, surface->current_frame); @@ -2155,26 +2135,27 @@ static void dynamicPaint_frameUpdate( } /* Modifier call. Processes dynamic paint modifier step. */ -DerivedMesh *dynamicPaint_Modifier_do(Main *bmain, - EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm) +Mesh *dynamicPaint_Modifier_do( + DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene, + Object *ob, Mesh *mesh) { if (pmd->canvas) { - DerivedMesh *ret; + Mesh *ret; /* Update canvas data for a new frame */ - dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm); + dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh); /* Return output mesh */ - ret = dynamicPaint_Modifier_apply(pmd, ob, dm); + ret = dynamicPaint_Modifier_apply(pmd, ob, mesh); return ret; } else { /* Update canvas data for a new frame */ - dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm); + dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh); /* Return output mesh */ - return dynamicPaint_Modifier_apply(pmd, ob, dm); + return dynamicPaint_Modifier_apply(pmd, ob, mesh); } } @@ -2776,7 +2757,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo PaintSurfaceData *sData; DynamicPaintCanvasSettings *canvas = surface->canvas; - DerivedMesh *dm = canvas->dm; + Mesh *mesh = canvas->mesh; PaintUVPoint *tempPoints = NULL; Vec3f *tempWeights = NULL; @@ -2790,19 +2771,19 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo *progress = 0.0f; *do_update = true; - if (!dm) + if (!mesh) return setError(canvas, N_("Canvas mesh not updated")); if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) return setError(canvas, N_("Cannot bake non-'image sequence' formats")); - mloop = dm->getLoopArray(dm); - mlooptri = dm->getLoopTriArray(dm); - const int tottri = dm->getNumLoopTri(dm); + mloop = mesh->mloop; + mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);; + const int tottri = BKE_mesh_runtime_looptri_len(mesh); /* get uv map */ - if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { - CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->uvlayer_name, uvname); - mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname); + if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) { + CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname); + mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname); } /* Check for validity */ @@ -2928,7 +2909,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo BKE_mesh_vert_looptri_map_create( &vert_to_looptri_map, &vert_to_looptri_map_mem, - dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm)); + mesh->mvert, mesh->totvert, mlooptri, tottri, mloop, mesh->totloop); int total_border = 0; @@ -3341,91 +3322,6 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam } -/***************************** Material / Texture Sampling ******************************/ - -/* stores a copy of required materials to allow doing adjustments - * without interfering the render/preview */ -typedef struct BrushMaterials { - Material *mat; - Material **ob_mats; - int tot; -} BrushMaterials; - -/* Initialize materials for brush object: - * Calculates inverse matrices for linked objects, updates - * volume caches etc. */ -static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats) -{ - /* Calculate inverse transformation matrix - * for this object */ - invert_m4_m4(brushOb->imat, brushOb->obmat); - copy_m4_m4(brushOb->imat_ren, brushOb->imat); - - /* Now process every material linked to this brush object */ - if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) { - int i, tot = (*give_totcolp(brushOb)); - - /* allocate material pointer array */ - if (tot) { - bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials"); - for (i = 0; i < tot; i++) { - bMats->ob_mats[i] = RE_sample_material_init(give_current_material(brushOb, (i + 1)), scene); - } - } - bMats->tot = tot; - } - else { - bMats->mat = RE_sample_material_init(ui_mat, scene); - } -} - -/* free all data allocated by dynamicPaint_updateBrushMaterials() */ -static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats) -{ - /* Now process every material linked to this brush object */ - if (bMats->ob_mats) { - int i; - for (i = 0; i < bMats->tot; i++) { - RE_sample_material_free(bMats->ob_mats[i]); - } - MEM_freeN(bMats->ob_mats); - } - else if (bMats->mat) { - RE_sample_material_free(bMats->mat); - } -} - -/* - * Get material diffuse color and alpha (including linked textures) in given coordinates - */ -static void dynamicPaint_doMaterialTex( - const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, - const float volume_co[3], const float surface_co[3], - int triIndex, DerivedMesh *orcoDm) -{ - Material *mat = bMats->mat; - - const MLoopTri *mlooptri = orcoDm->getLoopTriArray(orcoDm); - const MPoly *mpoly = orcoDm->getPolyArray(orcoDm); - - /* If no material defined, use the one assigned to the mesh face */ - if (mat == NULL) { - if (bMats->ob_mats) { - int mat_nr = mpoly[mlooptri[triIndex].poly].mat_nr; - if (mat_nr >= (*give_totcolp(brushOb))) - return; - mat = bMats->ob_mats[mat_nr]; - if (mat == NULL) - return; /* No material assigned */ - } - else { - return; - } - } - RE_sample_material_color(mat, color, alpha, volume_co, surface_co, triIndex, orcoDm, brushOb); -} - - /***************************** Ray / Nearest Point Utils ******************************/ @@ -3746,11 +3642,11 @@ static void dynamic_paint_brush_velocity_compute_cb( } static void dynamicPaint_brushMeshCalculateVelocity( - Main *bmain, EvaluationContext *eval_ctx, Scene *scene, + Depsgraph *depsgraph, Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale) { float prev_obmat[4][4]; - DerivedMesh *dm_p, *dm_c; + Mesh *mesh_p, *mesh_c; MVert *mvert_p, *mvert_c; int numOfVerts_p, numOfVerts_c; @@ -3764,26 +3660,26 @@ static void dynamicPaint_brushMeshCalculateVelocity( prev_fra = cur_fra - 1; } - /* previous frame dm */ + /* previous frame mesh */ scene->r.cfra = prev_fra; scene->r.subframe = prev_sfra; BKE_object_modifier_update_subframe( - bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); - dm_p = CDDM_copy(brush->dm); - numOfVerts_p = dm_p->getNumVerts(dm_p); - mvert_p = dm_p->getVertArray(dm_p); + depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); + mesh_p = BKE_mesh_copy_for_eval(brush->mesh, false); + numOfVerts_p = mesh_p->totvert; + mvert_p = mesh_p->mvert; copy_m4_m4(prev_obmat, ob->obmat); - /* current frame dm */ + /* current frame mesh */ scene->r.cfra = cur_fra; scene->r.subframe = cur_sfra; BKE_object_modifier_update_subframe( - bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); - dm_c = brush->dm; - numOfVerts_c = dm_c->getNumVerts(dm_c); - mvert_c = dm_p->getVertArray(dm_c); + depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); + mesh_c = brush->mesh; + numOfVerts_c = mesh_c->totvert; + mvert_c = mesh_c->mvert; (*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity"); if (!(*brushVel)) @@ -3807,12 +3703,12 @@ static void dynamicPaint_brushMeshCalculateVelocity( dynamic_paint_brush_velocity_compute_cb, &settings); - dm_p->release(dm_p); + BKE_id_free(NULL, mesh_p); } /* calculate velocity for object center point */ static void dynamicPaint_brushObjectCalculateVelocity( - Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, Vec3f *brushVel, float timescale) + Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale) { float prev_obmat[4][4]; float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f}; @@ -3827,18 +3723,18 @@ static void dynamicPaint_brushObjectCalculateVelocity( prev_fra = cur_fra - 1; } - /* previous frame dm */ + /* previous frame mesh */ scene->r.cfra = prev_fra; scene->r.subframe = prev_sfra; BKE_object_modifier_update_subframe( - bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); + depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); copy_m4_m4(prev_obmat, ob->obmat); - /* current frame dm */ + /* current frame mesh */ scene->r.cfra = cur_fra; scene->r.subframe = cur_sfra; BKE_object_modifier_update_subframe( - bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); + depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); /* calculate speed */ mul_m4_v3(prev_obmat, prev_loc); @@ -3852,12 +3748,11 @@ typedef struct DynamicPaintPaintData { const DynamicPaintSurface *surface; const DynamicPaintBrushSettings *brush; Object *brushOb; - const BrushMaterials *bMats; const Scene *scene; const float timescale; const int c_index; - DerivedMesh *dm; + Mesh *mesh; const MVert *mvert; const MLoop *mloop; const MLoopTri *mlooptri; @@ -3889,14 +3784,10 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( VolumeGrid *grid = bData->grid; const DynamicPaintBrushSettings *brush = data->brush; - Object *brushOb = data->brushOb; - const BrushMaterials *bMats = data->bMats; - const Scene *scene = data->scene; const float timescale = data->timescale; const int c_index = data->c_index; - DerivedMesh *dm = data->dm; const MVert *mvert = data->mvert; const MLoop *mloop = data->mloop; const MLoopTri *mlooptri = data->mlooptri; @@ -4156,13 +4047,6 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( sampleColor[1] = brush->g; sampleColor[2] = brush->b; - /* Get material+textures color on hit point if required */ - if (brush_usesMaterial(brush, scene)) { - dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb, - bData->realCoord[bData->s_pos[index] + ss].v, - hitCoord, hitTri, dm); - } - /* Sample proximity colorband if required */ if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) @@ -4210,27 +4094,24 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( } } -static int dynamicPaint_paintMesh(Main *bmain, - EvaluationContext *eval_ctx, - DynamicPaintSurface *surface, +static int dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, Object *brushOb, - BrushMaterials *bMats, Scene *scene, float timescale) { PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; - DerivedMesh *dm = NULL; + Mesh *mesh = NULL; Vec3f *brushVelocity = NULL; MVert *mvert = NULL; const MLoopTri *mlooptri = NULL; const MLoop *mloop = NULL; if (brush->flags & MOD_DPAINT_USES_VELOCITY) - dynamicPaint_brushMeshCalculateVelocity(bmain, eval_ctx, scene, brushOb, brush, &brushVelocity, timescale); + dynamicPaint_brushMeshCalculateVelocity(depsgraph, scene, brushOb, brush, &brushVelocity, timescale); - if (!brush->dm) + if (!brush->mesh) return 0; { @@ -4242,11 +4123,11 @@ static int dynamicPaint_paintMesh(Main *bmain, Bounds3D mesh_bb = {{0}}; VolumeGrid *grid = bData->grid; - dm = CDDM_copy(brush->dm); - mvert = dm->getVertArray(dm); - mlooptri = dm->getLoopTriArray(dm); - mloop = dm->getLoopArray(dm); - numOfVerts = dm->getNumVerts(dm); + mesh = BKE_mesh_copy_for_eval(brush->mesh, false); + mvert = mesh->mvert; + mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); + mloop = mesh->mloop; + numOfVerts = mesh->totvert; /* Transform collider vertices to global space * (Faster than transforming per surface point @@ -4277,7 +4158,7 @@ static int dynamicPaint_paintMesh(Main *bmain, /* check bounding box collision */ if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) { /* Build a bvh tree from transformed vertices */ - if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) { + if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) { int c_index; int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2]; @@ -4293,9 +4174,9 @@ static int dynamicPaint_paintMesh(Main *bmain, /* loop through cell points and process brush */ DynamicPaintPaintData data = { .surface = surface, - .brush = brush, .brushOb = brushOb, .bMats = bMats, + .brush = brush, .brushOb = brushOb, .scene = scene, .timescale = timescale, .c_index = c_index, - .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, + .mesh = mesh, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity, .treeData = &treeData }; @@ -4311,7 +4192,7 @@ static int dynamicPaint_paintMesh(Main *bmain, } /* free bvh tree */ free_bvhtree_from_mesh(&treeData); - dm->release(dm); + BKE_id_free(NULL, mesh); } @@ -4618,13 +4499,9 @@ static void dynamic_paint_paint_single_point_cb_ex( const PaintBakeData *bData = sData->bData; const DynamicPaintBrushSettings *brush = data->brush; - Object *brushOb = data->brushOb; - const BrushMaterials *bMats = data->bMats; - const Scene *scene = data->scene; const float timescale = data->timescale; - const MVert *mvert = data->mvert; const float brush_radius = data->brush_radius; const Vec3f *brushVelocity = data->brushVelocity; @@ -4653,17 +4530,6 @@ static void dynamic_paint_paint_single_point_cb_ex( float depth = 0.0f; float velocity_val = 0.0f; - /* material */ - if (brush_usesMaterial(brush, scene)) { - float alpha_factor = 1.0f; - float hit_coord[3]; - /* use dummy coord of first vertex */ - mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co); - - dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb, - bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm); - } - /* color ramp */ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP && BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband)) @@ -4701,11 +4567,9 @@ static void dynamic_paint_paint_single_point_cb_ex( paintColor[2] = colorband[2]; } else { - if (!brush_usesMaterial(brush, scene)) { - paintColor[0] = brush->r; - paintColor[1] = brush->g; - paintColor[2] = brush->b; - } + paintColor[0] = brush->r; + paintColor[1] = brush->g; + paintColor[2] = brush->b; } } else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) { @@ -4718,24 +4582,24 @@ static void dynamic_paint_paint_single_point_cb_ex( } static int dynamicPaint_paintSinglePoint( - Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush, - Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale) + Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush, + Object *brushOb, Scene *scene, float timescale) { PaintSurfaceData *sData = surface->data; float brush_radius = brush->paint_distance * surface->radius_scale; Vec3f brushVel; if (brush->flags & MOD_DPAINT_USES_VELOCITY) - dynamicPaint_brushObjectCalculateVelocity(bmain, eval_ctx, scene, brushOb, &brushVel, timescale); + dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale); - const MVert *mvert = brush->dm->getVertArray(brush->dm); + const MVert *mvert = brush->mesh->mvert; /* * Loop through every surface point */ DynamicPaintPaintData data = { .surface = surface, - .brush = brush, .brushOb = brushOb, .bMats = bMats, + .brush = brush, .brushOb = brushOb, .scene = scene, .timescale = timescale, .mvert = mvert, .brush_radius = brush_radius, .brushVelocity = &brushVel, @@ -5019,7 +4883,7 @@ static void dynamic_paint_prepare_effect_cb( EffectedPoint epoint; pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint); epoint.vel_to_sec = 1.0f; - pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL); + BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL); } /* if global gravity is enabled, add it too */ @@ -5048,7 +4912,7 @@ static void dynamic_paint_prepare_effect_cb( } static int dynamicPaint_prepareEffectStep( - DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale) + struct Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale) { double average_force = 0.0f; float shrink_speed = 0.0f, spread_speed = 0.0f; @@ -5059,7 +4923,7 @@ static int dynamicPaint_prepareEffectStep( /* Init force data if required */ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { - ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true); + ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights); /* allocate memory for force data (dir vector + strength) */ *force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces"); @@ -5083,7 +4947,7 @@ static int dynamicPaint_prepareEffectStep( } average_force /= sData->total_points; } - pdEndEffectors(&effectors); + BKE_effectors_free(effectors); } /* Get number of required steps using average point distance @@ -5747,10 +5611,10 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o { PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; - DerivedMesh *dm = surface->canvas->dm; - MVert *mvert = dm->getVertArray(dm); + Mesh *mesh = surface->canvas->mesh; + MVert *mvert = mesh->mvert; - int numOfVerts = dm->getNumVerts(dm); + int numOfVerts = mesh->totvert; int i; if (!bData->prev_verts) @@ -5891,19 +5755,19 @@ static void dynamic_paint_generate_bake_data_cb( } } -static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob) +static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Depsgraph *depsgraph, Object *ob) { PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; - DerivedMesh *dm = surface->canvas->dm; + Mesh *mesh = surface->canvas->mesh; int index; bool new_bdata = false; const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) || - (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY)); + (surface_getBrushFlags(surface, depsgraph) & BRUSH_USES_VELOCITY)); const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0; - int canvasNumOfVerts = dm->getNumVerts(dm); - MVert *mvert = dm->getVertArray(dm); + int canvasNumOfVerts = mesh->totvert; + MVert *mvert = mesh->mvert; Vec3f *canvas_verts; if (bData) { @@ -6017,12 +5881,13 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce * Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface. */ static int dynamicPaint_doStep( - Main *bmain, EvaluationContext *eval_ctx, Scene *scene, + Depsgraph *depsgraph, Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe) { PaintSurfaceData *sData = surface->data; PaintBakeData *bData = sData->bData; DynamicPaintCanvasSettings *canvas = surface->canvas; + const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); int ret = 1; if (sData->total_points < 1) @@ -6043,50 +5908,23 @@ static int dynamicPaint_doStep( * Loop through surface's target paint objects and do painting */ { - Base *base = NULL; - GroupObject *go = NULL; - Object *brushObj = NULL; - ModifierData *md = NULL; + unsigned int numobjects; + Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint); /* backup current scene frame */ int scene_frame = scene->r.cfra; float scene_subframe = scene->r.subframe; - /* either from group or from all objects */ - if (surface->brush_group) - go = surface->brush_group->gobject.first; - else - base = scene->base.first; - - while (base || go) { - brushObj = NULL; - /* select object */ - if (surface->brush_group) { - if (go->ob) - brushObj = go->ob; - } - else - brushObj = base->object; - - /* next item */ - if (surface->brush_group) - go = go->next; - else - base = base->next; - - if (!brushObj) { - /* skip item */ - continue; - } + for (int i = 0; i < numobjects; i++) { + Object *brushObj = objects[i]; /* check if target has an active dp modifier */ - md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); + ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint); if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md; /* make sure we're dealing with a brush */ if (pmd2->brush) { DynamicPaintBrushSettings *brush = pmd2->brush; - BrushMaterials bMats = {NULL}; /* calculate brush speed vectors if required */ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) { @@ -6101,44 +5939,35 @@ static int dynamicPaint_doStep( /* update object data on this subframe */ if (subframe) { scene_setSubframe(scene, subframe); - BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION, + BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); } - /* Prepare materials if required */ - if (brush_usesMaterial(brush, scene)) - dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats); + /* Apply brush on the surface depending on it's collision type */ - /* Particle brush: */ - if (brush->collision == MOD_DPAINT_COL_PSYS) { - if (brush->psys && brush->psys->part && - ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && - psys_check_enabled(brushObj, brush->psys, G.is_rendering)) - { - /* Paint a particle system */ - BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt, - BKE_scene_frame_get(scene), ADT_RECALC_ANIM); - dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); - } + if (brush->psys && brush->psys->part && + ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && + psys_check_enabled(brushObj, brush->psys, for_render)) + { + /* Paint a particle system */ + BKE_animsys_evaluate_animdata(depsgraph, scene, &brush->psys->part->id, brush->psys->part->adt, + BKE_scene_frame_get(scene), ADT_RECALC_ANIM); + dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); } /* Object center distance: */ - else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { - dynamicPaint_paintSinglePoint( - bmain, eval_ctx, surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale); + if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) { + dynamicPaint_paintSinglePoint(depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale); } /* Mesh volume/proximity: */ else if (brushObj != ob) { - dynamicPaint_paintMesh(bmain, eval_ctx, surface, brush, brushObj, &bMats, scene, timescale); + dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale); } - /* free temp material data */ - if (brush_usesMaterial(brush, scene)) - dynamicPaint_freeBrushMaterials(&bMats); /* reset object to it's original state */ if (subframe) { scene->r.cfra = scene_frame; scene->r.subframe = scene_subframe; - BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION, + BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint); } @@ -6152,6 +5981,8 @@ static int dynamicPaint_doStep( } } } + + BKE_collision_objects_free(objects); } /* surfaces operations that use adjacency data */ @@ -6173,7 +6004,7 @@ static int dynamicPaint_doStep( return setError(canvas, N_("Not enough free memory")); /* Prepare effects and get number of required steps */ - steps = dynamicPaint_prepareEffectStep(surface, scene, ob, &force, timescale); + steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale); for (s = 0; s < steps; s++) { dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps); } @@ -6198,16 +6029,17 @@ static int dynamicPaint_doStep( * Calculate a single frame and included subframes for surface */ int dynamicPaint_calculateFrame( - Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame) + DynamicPaintSurface *surface, struct Depsgraph *depsgraph, + Scene *scene, Object *cObject, int frame) { float timescale = 1.0f; /* apply previous displace on derivedmesh if incremental surface */ if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) - dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm); + dynamicPaint_applySurfaceDisplace(surface, surface->canvas->mesh); /* update bake data */ - dynamicPaint_generateBakeData(surface, scene, cObject); + dynamicPaint_generateBakeData(surface, depsgraph, cObject); /* don't do substeps for first frame */ if (surface->substeps && (frame != surface->start_frame)) { @@ -6216,10 +6048,10 @@ int dynamicPaint_calculateFrame( for (st = 1; st <= surface->substeps; st++) { float subframe = ((float) st) / (surface->substeps + 1); - if (!dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, subframe)) + if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe)) return 0; } } - return dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, 0.0f); + return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f); } diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index db9ce6c9b7d..e6873e66c91 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -49,2290 +49,20 @@ #include "BLI_task.h" #include "BKE_cdderivedmesh.h" +#include "BKE_deform.h" #include "BKE_mesh.h" +#include "BKE_mesh_iterators.h" #include "BKE_editmesh.h" #include "BKE_editmesh_bvh.h" +#include "BKE_editmesh_cache.h" +#include "BKE_editmesh_tangent.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "DNA_mesh_types.h" #include "MEM_guardedalloc.h" -#include "GPU_glew.h" -#include "GPU_buffers.h" -#include "GPU_shader.h" -#include "GPU_basic_shader.h" - -static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4]); - -typedef struct EditDerivedBMesh { - DerivedMesh dm; - - BMEditMesh *em; - - /** when set, \a vertexNos, polyNos are lazy initialized */ - const float (*vertexCos)[3]; - - /** lazy initialize (when \a vertexCos is set) */ - float const (*vertexNos)[3]; - float const (*polyNos)[3]; - /** also lazy init but dont depend on \a vertexCos */ - const float (*polyCos)[3]; -} EditDerivedBMesh; - -/* -------------------------------------------------------------------- */ -/* Lazy initialize datastructures */ - -static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm); - -static void emDM_ensureVertNormals(EditDerivedBMesh *bmdm) -{ - if (bmdm->vertexCos && (bmdm->vertexNos == NULL)) { - - BMesh *bm = bmdm->em->bm; - const float (*vertexCos)[3], (*polyNos)[3]; - float (*vertexNos)[3]; - - /* calculate vertex normals from poly normals */ - emDM_ensurePolyNormals(bmdm); - - BM_mesh_elem_index_ensure(bm, BM_FACE); - - polyNos = bmdm->polyNos; - vertexCos = bmdm->vertexCos; - vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__); - - BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos); - - bmdm->vertexNos = (const float (*)[3])vertexNos; - } -} - -static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm) -{ - if (bmdm->vertexCos && (bmdm->polyNos == NULL)) { - BMesh *bm = bmdm->em->bm; - const float (*vertexCos)[3]; - float (*polyNos)[3]; - - BMFace *efa; - BMIter fiter; - int i; - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__); - - vertexCos = bmdm->vertexCos; - - BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { - BM_elem_index_set(efa, i); /* set_inline */ - BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos); - } - bm->elem_index_dirty &= ~BM_FACE; - - bmdm->polyNos = (const float (*)[3])polyNos; - } -} - -static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm) -{ - if (bmdm->polyCos == NULL) { - BMesh *bm = bmdm->em->bm; - float (*polyCos)[3]; - - BMFace *efa; - BMIter fiter; - int i; - - polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__); - - if (bmdm->vertexCos) { - const float (*vertexCos)[3]; - vertexCos = bmdm->vertexCos; - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { - BM_face_calc_center_mean_vcos(bm, efa, polyCos[i], vertexCos); - } - } - else { - BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { - BM_face_calc_center_mean(efa, polyCos[i]); - } - } - - bmdm->polyCos = (const float (*)[3])polyCos; - } -} - -static void emDM_calcNormals(DerivedMesh *dm) -{ - /* Nothing to do: normals are already calculated and stored on the - * BMVerts and BMFaces */ - dm->dirty &= ~DM_DIRTY_NORMALS; -} - -static void emDM_calcLoopNormalsSpaceArray( - DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr); - -static void emDM_calcLoopNormals(DerivedMesh *dm, const bool use_split_normals, const float split_angle) -{ - emDM_calcLoopNormalsSpaceArray(dm, use_split_normals, split_angle, NULL); -} - -/* #define DEBUG_CLNORS */ - -static void emDM_calcLoopNormalsSpaceArray( - DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - const float (*vertexCos)[3], (*vertexNos)[3], (*polyNos)[3]; - float (*loopNos)[3]; - short (*clnors_data)[2]; - int cd_loop_clnors_offset; - - /* calculate loop normals from poly and vertex normals */ - emDM_ensureVertNormals(bmdm); - emDM_ensurePolyNormals(bmdm); - dm->dirty &= ~DM_DIRTY_NORMALS; - - vertexCos = bmdm->vertexCos; - vertexNos = bmdm->vertexNos; - polyNos = bmdm->polyNos; - - loopNos = dm->getLoopDataArray(dm, CD_NORMAL); - if (!loopNos) { - DM_add_loop_layer(dm, CD_NORMAL, CD_CALLOC, NULL); - loopNos = dm->getLoopDataArray(dm, CD_NORMAL); - } - - /* We can have both, give priority to dm's data, and fallback to bm's ones. */ - clnors_data = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL); - cd_loop_clnors_offset = clnors_data ? -1 : CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); - - BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos, - r_lnors_spacearr, clnors_data, cd_loop_clnors_offset); -#ifdef DEBUG_CLNORS - if (r_lnors_spacearr) { - int i; - for (i = 0; i < numLoops; i++) { - if (r_lnors_spacearr->lspacearr[i]->ref_alpha != 0.0f) { - LinkNode *loops = r_lnors_spacearr->lspacearr[i]->loops; - printf("Loop %d uses lnor space %p:\n", i, r_lnors_spacearr->lspacearr[i]); - print_v3("\tfinal lnor:", loopNos[i]); - print_v3("\tauto lnor:", r_lnors_spacearr->lspacearr[i]->vec_lnor); - print_v3("\tref_vec:", r_lnors_spacearr->lspacearr[i]->vec_ref); - printf("\talpha: %f\n\tbeta: %f\n\tloops: %p\n", r_lnors_spacearr->lspacearr[i]->ref_alpha, - r_lnors_spacearr->lspacearr[i]->ref_beta, r_lnors_spacearr->lspacearr[i]->loops); - printf("\t\t(shared with loops"); - while (loops) { - printf(" %d", POINTER_AS_INT(loops->link)); - loops = loops->next; - } - printf(")\n"); - } - else { - printf("Loop %d has no lnor space\n", i); - } - } - } -#endif -} - - -/** \name Tangent Space Calculation - * \{ */ - -/* Necessary complexity to handle looptri's as quads for correct tangents */ -#define USE_LOOPTRI_DETECT_QUADS - -typedef struct { - const float (*precomputedFaceNormals)[3]; - const float (*precomputedLoopNormals)[3]; - const BMLoop *(*looptris)[3]; - int cd_loop_uv_offset; /* texture coordinates */ - const float (*orco)[3]; - float (*tangent)[4]; /* destination */ - int numTessFaces; - -#ifdef USE_LOOPTRI_DETECT_QUADS - /* map from 'fake' face index to looptri, - * quads will point to the first looptri of the quad */ - const int *face_as_quad_map; - int num_face_as_quad_map; -#endif - -} SGLSLEditMeshToTangent; - -#ifdef USE_LOOPTRI_DETECT_QUADS -/* seems weak but only used on quads */ -static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index) -{ - const BMLoop *l = BM_FACE_FIRST_LOOP(f); - while (vert_index--) { - l = l->next; - } - return l; -} -#endif - -/* interface */ -#include "mikktspace.h" - -static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) -{ - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - -#ifdef USE_LOOPTRI_DETECT_QUADS - return pMesh->num_face_as_quad_map; -#else - return pMesh->numTessFaces; -#endif -} - -static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) -{ -#ifdef USE_LOOPTRI_DETECT_QUADS - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - if (pMesh->face_as_quad_map) { - const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - return 4; - } - } - return 3; -#else - UNUSED_VARS(pContext, face_num); - return 3; -#endif -} - -static void emdm_ts_GetPosition( - const SMikkTSpaceContext *pContext, float r_co[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - - const float *co; - -finally: - co = l->v->co; - copy_v3_v3(r_co, co); -} - -static void emdm_ts_GetTextureCoordinate( - const SMikkTSpaceContext *pContext, float r_uv[2], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - -finally: - if (pMesh->cd_loop_uv_offset != -1) { - const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset); - copy_v2_v2(r_uv, uv); - } - else { - const float *orco = pMesh->orco[BM_elem_index_get(l->v)]; - map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); - } -} - -static void emdm_ts_GetNormal( - const SMikkTSpaceContext *pContext, float r_no[3], - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - -finally: - if (pMesh->precomputedLoopNormals) { - copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]); - } - else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */ - if (pMesh->precomputedFaceNormals) { - copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]); - } - else { - copy_v3_v3(r_no, l->f->no); - } - } - else { - copy_v3_v3(r_no, l->v->no); - } -} - -static void emdm_ts_SetTSpace( - const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, - const int face_num, const int vert_index) -{ - //assert(vert_index >= 0 && vert_index < 4); - SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; - const BMLoop **lt; - const BMLoop *l; - -#ifdef USE_LOOPTRI_DETECT_QUADS - if (pMesh->face_as_quad_map) { - lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; - if (lt[0]->f->len == 4) { - l = bm_loop_at_face_index(lt[0]->f, vert_index); - goto finally; - } - /* fall through to regular triangle */ - } - else { - lt = pMesh->looptris[face_num]; - } -#else - lt = pMesh->looptris[face_num]; -#endif - l = lt[vert_index]; - - float *pRes; - -finally: - pRes = pMesh->tangent[BM_elem_index_get(l)]; - copy_v3_v3(pRes, fvTangent); - pRes[3] = fSign; -} - -static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) -{ - struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; - /* new computation method */ - { - SMikkTSpaceContext sContext = {NULL}; - SMikkTSpaceInterface sInterface = {NULL}; - sContext.m_pUserData = mesh2tangent; - sContext.m_pInterface = &sInterface; - sInterface.m_getNumFaces = emdm_ts_GetNumFaces; - sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace; - sInterface.m_getPosition = emdm_ts_GetPosition; - sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate; - sInterface.m_getNormal = emdm_ts_GetNormal; - sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace; - /* 0 if failed */ - genTangSpaceDefault(&sContext); - } -} - -/** - * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data. - * - * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`. - * This is done because #CD_TANGENT is cache data used only for drawing. - */ - -static void emDM_calc_loop_tangents( - DerivedMesh *dm, bool calc_active_tangent, - const char (*tangent_names)[MAX_NAME], int tangent_names_count) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMEditMesh *em = bmdm->em; - BMesh *bm = bmdm->em->bm; - - int act_uv_n = -1; - int ren_uv_n = -1; - bool calc_act = false; - bool calc_ren = false; - char act_uv_name[MAX_NAME]; - char ren_uv_name[MAX_NAME]; - short tangent_mask = 0; - - DM_calc_loop_tangents_step_0( - &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count, - &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); - - if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) { - for (int i = 0; i < tangent_names_count; i++) - if (tangent_names[i][0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]); - if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1) - CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, ""); - if (calc_act && act_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name); - if (calc_ren && ren_uv_name[0]) - DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name); - int totface = em->tottri; -#ifdef USE_LOOPTRI_DETECT_QUADS - int num_face_as_quad_map; - int *face_as_quad_map = NULL; - - /* map faces to quads */ - if (bmdm->em->tottri != bm->totface) { - /* over alloc, since we dont know how many ngon or quads we have */ - - /* map fake face index to looptri */ - face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__); - int i, j; - for (i = 0, j = 0; j < totface; i++, j++) { - face_as_quad_map[i] = j; - /* step over all quads */ - if (em->looptris[j][0]->f->len == 4) { - j++; /* skips the nest looptri */ - } - } - num_face_as_quad_map = i; - } - else { - num_face_as_quad_map = totface; - } -#endif - /* Calculation */ - { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool; - task_pool = BLI_task_pool_create(scheduler, NULL); - - dm->tangent_mask = 0; - /* Calculate tangent layers */ - SGLSLEditMeshToTangent data_array[MAX_MTFACE]; - int index = 0; - int n = 0; - CustomData_update_typemap(&dm->loopData); - const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT); - for (n = 0; n < tangent_layer_num; n++) { - index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n); - BLI_assert(n < MAX_MTFACE); - SGLSLEditMeshToTangent *mesh2tangent = &data_array[n]; - mesh2tangent->numTessFaces = em->tottri; -#ifdef USE_LOOPTRI_DETECT_QUADS - mesh2tangent->face_as_quad_map = face_as_quad_map; - mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; -#endif - mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */ - /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), - * have to check this is valid... - */ - mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL); - mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n); - - /* needed for indexing loop-tangents */ - int htype_index = BM_LOOP; - if (mesh2tangent->cd_loop_uv_offset == -1) { - mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO); - if (!mesh2tangent->orco) - continue; - /* needed for orco lookups */ - htype_index |= BM_VERT; - dm->tangent_mask |= DM_TANGENT_MASK_ORCO; - } - else { - /* Fill the resulting tangent_mask */ - int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name); - int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV); - BLI_assert(uv_ind != -1 && uv_start != -1); - BLI_assert(uv_ind - uv_start < MAX_MTFACE); - dm->tangent_mask |= 1 << (uv_ind - uv_start); - } - - if (mesh2tangent->precomputedFaceNormals) { - /* needed for face normal lookups */ - htype_index |= BM_FACE; - } - BM_mesh_elem_index_ensure(bm, htype_index); - - mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris; - mesh2tangent->tangent = dm->loopData.layers[index].data; - - BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); - } - - BLI_assert(dm->tangent_mask == tangent_mask); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - } -#ifdef USE_LOOPTRI_DETECT_QUADS - if (face_as_quad_map) { - MEM_freeN(face_as_quad_map); - } -#undef USE_LOOPTRI_DETECT_QUADS -#endif - } - - /* Update active layer index */ - int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n); - if (act_uv_index >= 0) { - int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[act_uv_index].name); - CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index); - } /* else tangent has been built from orco */ - - /* Update render layer index */ - int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n); - if (ren_uv_index >= 0) { - int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[ren_uv_index].name); - CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index); - } /* else tangent has been built from orco */ -} - -/** \} */ - - -static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm)) -{ - /* do nothing */ -} - -static void emDM_recalcLoopTri(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMLoop *(*looptris)[3] = bmdm->em->looptris; - MLoopTri *mlooptri; - const int tottri = bmdm->em->tottri; - int i; - - DM_ensure_looptri_data(dm); - mlooptri = dm->looptris.array_wip; - - BLI_assert(tottri == 0 || mlooptri != NULL); - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - BLI_assert(tottri == dm->looptris.num); - - BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP); - - for (i = 0; i < tottri; i++) { - BMLoop **ltri = looptris[i]; - MLoopTri *lt = &mlooptri[i]; - - ARRAY_SET_ITEMS( - lt->tri, - BM_elem_index_get(ltri[0]), - BM_elem_index_get(ltri[1]), - BM_elem_index_get(ltri[2])); - lt->poly = BM_elem_index_get(ltri[0]->f); - } - - BLI_assert(dm->looptris.array == NULL); - atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip); - dm->looptris.array_wip = NULL; -} - -static void emDM_foreachMappedVert( - DerivedMesh *dm, - void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]), - void *userData, - DMForeachFlag flag) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMVert *eve; - BMIter iter; - int i; - - if (bmdm->vertexCos) { - const float (*vertexCos)[3] = bmdm->vertexCos; - const float (*vertexNos)[3]; - - if (flag & DM_FOREACH_USE_NORMAL) { - emDM_ensureVertNormals(bmdm); - vertexNos = bmdm->vertexNos; - } - else { - vertexNos = NULL; - } - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - const float *no = (flag & DM_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL; - func(userData, i, vertexCos[i], no, NULL); - } - } - else { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - const float *no = (flag & DM_FOREACH_USE_NORMAL) ? eve->no : NULL; - func(userData, i, eve->co, no, NULL); - } - } -} -static void emDM_foreachMappedEdge( - DerivedMesh *dm, - void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), - void *userData) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMEdge *eed; - BMIter iter; - int i; - - if (bmdm->vertexCos) { - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { - func(userData, i, - bmdm->vertexCos[BM_elem_index_get(eed->v1)], - bmdm->vertexCos[BM_elem_index_get(eed->v2)]); - } - } - else { - BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { - func(userData, i, eed->v1->co, eed->v2->co); - } - } -} - -static void emDM_drawMappedEdges( - DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - void *userData) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMEdge *eed; - BMIter iter; - int i; - - if (bmdm->vertexCos) { - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - glBegin(GL_LINES); - BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { - if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) { - glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]); - glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]); - } - } - glEnd(); - } - else { - glBegin(GL_LINES); - BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { - if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) { - glVertex3fv(eed->v1->co); - glVertex3fv(eed->v2->co); - } - } - glEnd(); - } -} -static void emDM_drawEdges( - DerivedMesh *dm, - bool UNUSED(drawLooseEdges), - bool UNUSED(drawAllEdges)) -{ - emDM_drawMappedEdges(dm, NULL, NULL); -} - -static void emDM_drawMappedEdgesInterp( - DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - DMSetDrawInterpOptions setDrawInterpOptions, - void *userData) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMEdge *eed; - BMIter iter; - int i; - - if (bmdm->vertexCos) { - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - glBegin(GL_LINES); - BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { - if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) { - setDrawInterpOptions(userData, i, 0.0); - glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]); - setDrawInterpOptions(userData, i, 1.0); - glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]); - } - } - glEnd(); - } - else { - glBegin(GL_LINES); - BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { - if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) { - setDrawInterpOptions(userData, i, 0.0); - glVertex3fv(eed->v1->co); - setDrawInterpOptions(userData, i, 1.0); - glVertex3fv(eed->v2->co); - } - } - glEnd(); - } -} - -static void emDM_drawUVEdges(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMFace *efa; - BMIter iter; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - if (UNLIKELY(cd_loop_uv_offset == -1)) { - return; - } - - glBegin(GL_LINES); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - const float *uv, *uv_prev; - - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) - continue; - - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter->prev, cd_loop_uv_offset))->uv; - do { - uv = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; - glVertex2fv(uv); - glVertex2fv(uv_prev); - uv_prev = uv; - } while ((l_iter = l_iter->next) != l_first); - } - glEnd(); -} - -static void emDM_foreachMappedLoop( - DerivedMesh *dm, - void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]), - void *userData, - DMForeachFlag flag) -{ - /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would - * return loop data from bmesh itself. */ - const float (*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) : NULL; - - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMFace *efa; - BMIter iter; - - const float (*vertexCos)[3] = bmdm->vertexCos; - int f_idx; - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) { - BMLoop *l_iter, *l_first; - - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - const BMVert *eve = l_iter->v; - const int v_idx = BM_elem_index_get(eve); - const float *no = lnors ? *lnors++ : NULL; - func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no); - } while ((l_iter = l_iter->next) != l_first); - } -} - -static void emDM_foreachMappedFaceCenter( - DerivedMesh *dm, - void (*func)(void *userData, int index, const float co[3], const float no[3]), - void *userData, - DMForeachFlag flag) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - const float (*polyNos)[3]; - const float (*polyCos)[3]; - BMFace *efa; - BMIter iter; - int i; - - emDM_ensurePolyCenters(bmdm); - polyCos = bmdm->polyCos; /* always set */ - - if (flag & DM_FOREACH_USE_NORMAL) { - emDM_ensurePolyNormals(bmdm); - polyNos = bmdm->polyNos; /* maybe NULL */ - } - else { - polyNos = NULL; - } - - if (polyNos) { - BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - const float *no = polyNos[i]; - func(userData, i, polyCos[i], no); - } - } - else { - BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - const float *no = (flag & DM_FOREACH_USE_NORMAL) ? efa->no : NULL; - func(userData, i, polyCos[i], no); - } - } -} - -static void emDM_drawMappedFaces( - DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - DMSetMaterial setMaterial, - /* currently unused -- each original face is handled separately */ - DMCompareDrawOptions UNUSED(compareDrawOptions), - void *userData, - DMDrawFlag flag) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMEditMesh *em = bmdm->em; - BMesh *bm = em->bm; - BMFace *efa; - struct BMLoop *(*looptris)[3] = bmdm->em->looptris; - const int tottri = bmdm->em->tottri; - DMDrawOption draw_option; - int i; - const int skip_normals = !(flag & DM_DRAW_NEED_NORMALS); - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */; - unsigned char(*color_vert_array)[4] = em->derivedVertColor; - unsigned char(*color_face_array)[4] = em->derivedFaceColor; - bool has_vcol_preview = (color_vert_array != NULL) && !skip_normals; - bool has_fcol_preview = (color_face_array != NULL) && !skip_normals; - bool has_vcol_any = has_vcol_preview; - - /* GL_ZERO is used to detect if drawing has started or not */ - GLenum poly_prev = GL_ZERO; - GLenum shade_prev = GL_ZERO; - DMDrawOption draw_option_prev = DM_DRAW_OPTION_SKIP; - - /* call again below is ok */ - if (has_vcol_preview) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - if (has_fcol_preview) { - BM_mesh_elem_index_ensure(bm, BM_FACE); - } - if (has_vcol_preview || has_fcol_preview) { - flag |= DM_DRAW_ALWAYS_SMOOTH; - /* weak, this logic should really be moved higher up */ - setMaterial = NULL; - } - - if (bmdm->vertexCos) { - short prev_mat_nr = -1; - - /* add direct access */ - const float (*vertexCos)[3] = bmdm->vertexCos; - const float (*vertexNos)[3]; - const float (*polyNos)[3]; - - if (skip_normals) { - vertexNos = NULL; - polyNos = NULL; - } - else { - emDM_ensureVertNormals(bmdm); - emDM_ensurePolyNormals(bmdm); - vertexNos = bmdm->vertexNos; - polyNos = bmdm->polyNos; - } - - BM_mesh_elem_index_ensure(bm, lnors ? BM_VERT | BM_FACE | BM_LOOP : BM_VERT | BM_FACE); - - for (i = 0; i < tottri; i++) { - BMLoop **ltri = looptris[i]; - int drawSmooth; - - efa = ltri[0]->f; - drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH)); - - draw_option = (!setDrawOptions ? - DM_DRAW_OPTION_NORMAL : - setDrawOptions(userData, BM_elem_index_get(efa))); - if (draw_option != DM_DRAW_OPTION_SKIP) { - const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ - - if (draw_option_prev != draw_option) { - if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) { - if (poly_prev != GL_ZERO) glEnd(); - poly_prev = GL_ZERO; /* force glBegin */ - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - draw_option_prev = draw_option; - } - - - if (efa->mat_nr != prev_mat_nr) { - if (setMaterial) { - if (poly_prev != GL_ZERO) glEnd(); - poly_prev = GL_ZERO; /* force glBegin */ - - setMaterial(efa->mat_nr + 1, NULL); - } - prev_mat_nr = efa->mat_nr; - } - - if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ - - if (poly_prev != GL_ZERO) glEnd(); - poly_prev = GL_ZERO; /* force glBegin */ - - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); - } - - if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array); - else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)])); - if (skip_normals) { - if (poly_type != poly_prev) { - if (poly_prev != GL_ZERO) glEnd(); - glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */ - } - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]); - } - else { - const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT; - if (shade_type != shade_prev) { - if (poly_prev != GL_ZERO) glEnd(); - glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */ - glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */ - } - if (poly_type != poly_prev) { - if (poly_prev != GL_ZERO) glEnd(); - glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */ - } - - if (!drawSmooth) { - glNormal3fv(polyNos[BM_elem_index_get(efa)]); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]); - } - else { - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]); - } - } - } - } - } - else { - short prev_mat_nr = -1; - - BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE); - - for (i = 0; i < tottri; i++) { - BMLoop **ltri = looptris[i]; - int drawSmooth; - - efa = ltri[0]->f; - drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH)); - - draw_option = (setDrawOptions ? - setDrawOptions(userData, BM_elem_index_get(efa)) : - DM_DRAW_OPTION_NORMAL); - - if (draw_option != DM_DRAW_OPTION_SKIP) { - const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */ - - if (draw_option_prev != draw_option) { - if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) { - if (poly_prev != GL_ZERO) glEnd(); - poly_prev = GL_ZERO; /* force glBegin */ - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - draw_option_prev = draw_option; - } - - if (efa->mat_nr != prev_mat_nr) { - if (setMaterial) { - if (poly_prev != GL_ZERO) glEnd(); - poly_prev = GL_ZERO; /* force glBegin */ - - setMaterial(efa->mat_nr + 1, NULL); - } - prev_mat_nr = efa->mat_nr; - } - - if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */ - - if (poly_prev != GL_ZERO) glEnd(); - poly_prev = GL_ZERO; /* force glBegin */ - - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); - } - - if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array); - else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)])); - - if (skip_normals) { - if (poly_type != poly_prev) { - if (poly_prev != GL_ZERO) glEnd(); - glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */ - } - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(ltri[0]->v->co); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(ltri[1]->v->co); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(ltri[2]->v->co); - } - else { - const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT; - if (shade_type != shade_prev) { - if (poly_prev != GL_ZERO) glEnd(); - glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */ - glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */ - } - if (poly_type != poly_prev) { - if (poly_prev != GL_ZERO) glEnd(); - glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */ - } - - if (!drawSmooth) { - glNormal3fv(efa->no); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(ltri[0]->v->co); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(ltri[1]->v->co); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(ltri[2]->v->co); - } - else { - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]); - else glNormal3fv(ltri[0]->v->no); - glVertex3fv(ltri[0]->v->co); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]); - else glNormal3fv(ltri[1]->v->no); - glVertex3fv(ltri[1]->v->co); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]); - else glNormal3fv(ltri[2]->v->no); - glVertex3fv(ltri[2]->v->co); - } - } - } - } - } - - /* if non zero we know a face was rendered */ - if (poly_prev != GL_ZERO) glEnd(); - - if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - - if (shade_prev == GL_FLAT) { - glShadeModel(GL_SMOOTH); - } -} - -static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset) -{ - luv[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_uv_offset); - luv[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_uv_offset); - luv[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_uv_offset); -} - -static void bmdm_get_tri_col(BMLoop *ltri[3], MLoopCol *lcol[3], const int cd_loop_color_offset) -{ - lcol[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_color_offset); - lcol[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_color_offset); - lcol[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_color_offset); -} - -static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4]) -{ - lcol[0] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[0]->v)]; - lcol[1] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[1]->v)]; - lcol[2] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[2]->v)]; -} - -static void emDM_drawFacesTex_common( - DerivedMesh *dm, - DMSetDrawOptionsTex drawParams, - DMSetDrawOptionsMappedTex drawParamsMapped, - DMCompareDrawOptions compareDrawOptions, - void *userData) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMEditMesh *em = bmdm->em; - BMesh *bm = em->bm; - struct BMLoop *(*looptris)[3] = em->looptris; - BMFace *efa; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - MLoopUV *luv[3], dummyluv = {{0}}; - MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); - unsigned char(*color_vert_array)[4] = em->derivedVertColor; - bool has_uv = (cd_loop_uv_offset != -1); - bool has_vcol_preview = (color_vert_array != NULL); - bool has_vcol = (cd_loop_color_offset != -1) && (has_vcol_preview == false); - bool has_vcol_any = (has_vcol_preview || has_vcol); - int i; - - (void) compareDrawOptions; - - luv[0] = luv[1] = luv[2] = &dummyluv; - - // dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */ - - /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ - BM_mesh_elem_index_ensure(bm, BM_FACE); - - /* call again below is ok */ - if (has_vcol_preview) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - } - - if (bmdm->vertexCos) { - /* add direct access */ - const float (*vertexCos)[3] = bmdm->vertexCos; - const float (*vertexNos)[3]; - const float (*polyNos)[3]; - - emDM_ensureVertNormals(bmdm); - emDM_ensurePolyNormals(bmdm); - vertexNos = bmdm->vertexNos; - polyNos = bmdm->polyNos; - - BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT); - - for (i = 0; i < em->tottri; i++) { - BMLoop **ltri = looptris[i]; - MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL; - /*unsigned char *cp = NULL;*/ /*UNUSED*/ - int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH); - DMDrawOption draw_option; - - efa = ltri[0]->f; - - if (drawParams) { - draw_option = drawParams(tp, has_vcol, efa->mat_nr); - } - else if (drawParamsMapped) - draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr); - else - draw_option = DM_DRAW_OPTION_NORMAL; - - if (draw_option != DM_DRAW_OPTION_SKIP) { - - if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset); - if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset); - else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array); - - glBegin(GL_TRIANGLES); - if (!drawSmooth) { - glNormal3fv(polyNos[BM_elem_index_get(efa)]); - - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]); - } - else { - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]); - else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]); - } - glEnd(); - } - } - } - else { - BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT); - - for (i = 0; i < em->tottri; i++) { - BMLoop **ltri = looptris[i]; - MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL; - /*unsigned char *cp = NULL;*/ /*UNUSED*/ - int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH); - DMDrawOption draw_option; - - efa = ltri[0]->f; - - if (drawParams) - draw_option = drawParams(tp, has_vcol, efa->mat_nr); - else if (drawParamsMapped) - draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr); - else - draw_option = DM_DRAW_OPTION_NORMAL; - - if (draw_option != DM_DRAW_OPTION_SKIP) { - - if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset); - if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset); - else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array); - - glBegin(GL_TRIANGLES); - if (!drawSmooth) { - glNormal3fv(efa->no); - - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - glVertex3fv(ltri[0]->v->co); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - glVertex3fv(ltri[1]->v->co); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - glVertex3fv(ltri[2]->v->co); - } - else { - glTexCoord2fv(luv[0]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]); - else glNormal3fv(ltri[0]->v->no); - glVertex3fv(ltri[0]->v->co); - - glTexCoord2fv(luv[1]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]); - else glNormal3fv(ltri[1]->v->no); - glVertex3fv(ltri[1]->v->co); - - glTexCoord2fv(luv[2]->uv); - if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r)); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]); - else glNormal3fv(ltri[2]->v->no); - glVertex3fv(ltri[2]->v->co); - } - glEnd(); - } - } - } -} - -static void emDM_drawFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag UNUSED(flag)) -{ - emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); -} - -static void emDM_drawMappedFacesTex( - DerivedMesh *dm, - DMSetDrawOptionsMappedTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag UNUSED(flag)) -{ - emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); -} - -/** - * \note - * - * For UV's: - * const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset); - * - * This is intentionally different to calling: - * CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, i); - * - * ... because the material may use layer names to select different UV's - * see: [#34378] - */ -static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop) -{ - BMVert *eve = loop->v; - int i; - const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - if (attribs->totorco) { - int index = BM_elem_index_get(eve); - const float *orco = (attribs->orco.array) ? attribs->orco.array[index] : zero; - - if (attribs->orco.gl_texco) - glTexCoord3fv(orco); - else - glVertexAttrib3fv(attribs->orco.gl_index, orco); - } - for (i = 0; i < attribs->tottface; i++) { - const float *uv; - - if (attribs->tface[i].em_offset != -1) { - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset); - uv = luv->uv; - } - else { - uv = zero; - } - - if (attribs->tface[i].gl_texco) - glTexCoord2fv(uv); - else - glVertexAttrib2fv(attribs->tface[i].gl_index, uv); - } - for (i = 0; i < attribs->totmcol; i++) { - float col[4]; - if (attribs->mcol[i].em_offset != -1) { - const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset); - rgba_uchar_to_float(col, &cp->r); - } - else { - col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f; - } - glVertexAttrib4fv(attribs->mcol[i].gl_index, col); - } - - for (i = 0; i < attribs->tottang; i++) { - const float *tang; - if (attribs->tang[i].em_offset != -1) { - tang = attribs->tang[i].array[BM_elem_index_get(loop)]; - } - else { - tang = zero; - } - glVertexAttrib4fv(attribs->tang[i].gl_index, tang); - } -} - -static void emDM_drawMappedFacesGLSL( - DerivedMesh *dm, - DMSetMaterial setMaterial, - DMSetDrawOptions setDrawOptions, - void *userData) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMEditMesh *em = bmdm->em; - BMesh *bm = em->bm; - struct BMLoop *(*looptris)[3] = em->looptris; - /* add direct access */ - const float (*vertexCos)[3] = bmdm->vertexCos; - const float (*vertexNos)[3]; - const float (*polyNos)[3]; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - - BMFace *efa; - DMVertexAttribs attribs; - GPUVertexAttribs gattribs; - - int i, matnr, new_matnr, fi; - bool do_draw; - - do_draw = false; - matnr = -1; - - memset(&attribs, 0, sizeof(attribs)); - - emDM_ensureVertNormals(bmdm); - emDM_ensurePolyNormals(bmdm); - vertexNos = bmdm->vertexNos; - polyNos = bmdm->polyNos; - - BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0)); - - for (i = 0; i < em->tottri; i++) { - BMLoop **ltri = looptris[i]; - int drawSmooth; - - efa = ltri[0]->f; - - if (setDrawOptions && (setDrawOptions(userData, BM_elem_index_get(efa)) == DM_DRAW_OPTION_SKIP)) - continue; - - /* material */ - new_matnr = efa->mat_nr + 1; - if (new_matnr != matnr) { - if (matnr != -1) - glEnd(); - - do_draw = setMaterial(matnr = new_matnr, &gattribs); - if (do_draw) { - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - DM_draw_attrib_vertex_uniforms(&attribs); - if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) { - BM_mesh_elem_index_ensure(bm, BM_LOOP); - } - } - - glBegin(GL_TRIANGLES); - } - - if (do_draw) { - - /* draw face */ - drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH); - - if (!drawSmooth) { - if (vertexCos) { - glNormal3fv(polyNos[BM_elem_index_get(efa)]); - for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); - } - } - else { - glNormal3fv(efa->no); - for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - glVertex3fv(ltri[fi]->v->co); - } - } - } - else { - if (vertexCos) { - for (fi = 0; fi < 3; fi++) { - const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); - else glNormal3fv(vertexNos[j]); - glVertex3fv(vertexCos[j]); - } - } - else { - for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); - else glNormal3fv(ltri[fi]->v->no); - glVertex3fv(ltri[fi]->v->co); - } - } - } - } - } - - if (matnr != -1) { - glEnd(); - } -} - -static void emDM_drawFacesGLSL( - DerivedMesh *dm, - int (*setMaterial)(int matnr, void *attribs)) -{ - dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL); -} - -static void emDM_drawMappedFacesMat( - DerivedMesh *dm, - void (*setMaterial)(void *userData, int matnr, void *attribs), - bool (*setFace)(void *userData, int index), void *userData) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMEditMesh *em = bmdm->em; - BMesh *bm = em->bm; - struct BMLoop *(*looptris)[3] = em->looptris; - const float (*vertexCos)[3] = bmdm->vertexCos; - const float (*vertexNos)[3]; - const float (*polyNos)[3]; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - BMFace *efa; - DMVertexAttribs attribs = {{{NULL}}}; - GPUVertexAttribs gattribs; - int i, matnr, new_matnr, fi; - - matnr = -1; - - emDM_ensureVertNormals(bmdm); - emDM_ensurePolyNormals(bmdm); - - vertexNos = bmdm->vertexNos; - polyNos = bmdm->polyNos; - - BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0)); - - for (i = 0; i < em->tottri; i++) { - BMLoop **ltri = looptris[i]; - int drawSmooth; - - efa = ltri[0]->f; - - /* face hiding */ - if (setFace && !setFace(userData, BM_elem_index_get(efa))) - continue; - - /* material */ - new_matnr = efa->mat_nr + 1; - if (new_matnr != matnr) { - if (matnr != -1) - glEnd(); - - setMaterial(userData, matnr = new_matnr, &gattribs); - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) { - BM_mesh_elem_index_ensure(bm, BM_LOOP); - } - - glBegin(GL_TRIANGLES); - } - - /* draw face */ - drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH); - - if (!drawSmooth) { - if (vertexCos) { - glNormal3fv(polyNos[BM_elem_index_get(efa)]); - for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]); - } - } - else { - glNormal3fv(efa->no); - for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - glVertex3fv(ltri[fi]->v->co); - } - } - } - else { - if (vertexCos) { - for (fi = 0; fi < 3; fi++) { - const int j = BM_elem_index_get(ltri[fi]->v); - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); - else glNormal3fv(vertexNos[j]); - glVertex3fv(vertexCos[j]); - } - } - else { - for (fi = 0; fi < 3; fi++) { - emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]); - if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]); - else glNormal3fv(ltri[fi]->v->no); - glVertex3fv(ltri[fi]->v->co); - } - } - } - } - - if (matnr != -1) { - glEnd(); - } -} - -static void emDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3]) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMVert *eve; - BMIter iter; - int i; - - if (bm->totvert) { - if (bmdm->vertexCos) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - minmax_v3v3_v3(r_min, r_max, bmdm->vertexCos[i]); - } - } - else { - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - minmax_v3v3_v3(r_min, r_max, eve->co); - } - } - } - else { - zero_v3(r_min); - zero_v3(r_max); - } -} -static int emDM_getNumVerts(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return bmdm->em->bm->totvert; -} - -static int emDM_getNumEdges(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return bmdm->em->bm->totedge; -} - -static int emDM_getNumTessFaces(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return bmdm->em->tottri; -} - -static int emDM_getNumLoops(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return bmdm->em->bm->totloop; -} - -static int emDM_getNumPolys(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return bmdm->em->bm->totface; -} - -static void bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *r_vert) -{ - const float *f; - - copy_v3_v3(r_vert->co, ev->co); - - normal_float_to_short_v3(r_vert->no, ev->no); - - r_vert->flag = BM_vert_flag_to_mflag(ev); - - if ((f = CustomData_bmesh_get(&bm->vdata, ev->head.data, CD_BWEIGHT))) { - r_vert->bweight = (unsigned char)((*f) * 255.0f); - } -} - -static void emDM_getVert(DerivedMesh *dm, int index, MVert *r_vert) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMVert *ev; - - if (UNLIKELY(index < 0 || index >= bm->totvert)) { - BLI_assert(!"error in emDM_getVert"); - return; - } - - BLI_assert((bm->elem_table_dirty & BM_VERT) == 0); - ev = bm->vtable[index]; /* should be BM_vert_at_index() */ - // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */ - - bmvert_to_mvert(bm, ev, r_vert); - if (bmdm->vertexCos) - copy_v3_v3(r_vert->co, bmdm->vertexCos[index]); -} - -static void emDM_getVertCo(DerivedMesh *dm, int index, float r_co[3]) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - - if (UNLIKELY(index < 0 || index >= bm->totvert)) { - BLI_assert(!"error in emDM_getVertCo"); - return; - } - - if (bmdm->vertexCos) { - copy_v3_v3(r_co, bmdm->vertexCos[index]); - } - else { - BMVert *ev; - - BLI_assert((bm->elem_table_dirty & BM_VERT) == 0); - ev = bm->vtable[index]; /* should be BM_vert_at_index() */ - // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */ - copy_v3_v3(r_co, ev->co); - } -} - -static void emDM_getVertNo(DerivedMesh *dm, int index, float r_no[3]) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - - if (UNLIKELY(index < 0 || index >= bm->totvert)) { - BLI_assert(!"error in emDM_getVertNo"); - return; - } - - - if (bmdm->vertexCos) { - emDM_ensureVertNormals(bmdm); - copy_v3_v3(r_no, bmdm->vertexNos[index]); - } - else { - BMVert *ev; - - BLI_assert((bm->elem_table_dirty & BM_VERT) == 0); - ev = bm->vtable[index]; /* should be BM_vert_at_index() */ - // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */ - copy_v3_v3(r_no, ev->no); - } -} - -static void emDM_getPolyNo(DerivedMesh *dm, int index, float r_no[3]) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - - if (UNLIKELY(index < 0 || index >= bm->totface)) { - BLI_assert(!"error in emDM_getPolyNo"); - return; - } - - if (bmdm->vertexCos) { - emDM_ensurePolyNormals(bmdm); - copy_v3_v3(r_no, bmdm->polyNos[index]); - } - else { - BMFace *efa; - - BLI_assert((bm->elem_table_dirty & BM_FACE) == 0); - efa = bm->ftable[index]; /* should be BM_vert_at_index() */ - // efa = BM_face_at_index(bm, index); /* warning, does list loop, _not_ ideal */ - copy_v3_v3(r_no, efa->no); - } -} - -static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *r_edge) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMEdge *e; - const float *f; - - if (UNLIKELY(index < 0 || index >= bm->totedge)) { - BLI_assert(!"error in emDM_getEdge"); - return; - } - - BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0); - e = bm->etable[index]; /* should be BM_edge_at_index() */ - // e = BM_edge_at_index(bm, index); /* warning, does list loop, _not_ ideal */ - - r_edge->flag = BM_edge_flag_to_mflag(e); - - r_edge->v1 = BM_elem_index_get(e->v1); - r_edge->v2 = BM_elem_index_get(e->v2); - - if ((f = CustomData_bmesh_get(&bm->edata, e->head.data, CD_BWEIGHT))) { - r_edge->bweight = (unsigned char)((*f) * 255.0f); - } - if ((f = CustomData_bmesh_get(&bm->edata, e->head.data, CD_CREASE))) { - r_edge->crease = (unsigned char)((*f) * 255.0f); - } -} - -static void emDM_getTessFace(DerivedMesh *dm, int index, MFace *r_face) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMFace *ef; - BMLoop **ltri; - - if (UNLIKELY(index < 0 || index >= bmdm->em->tottri)) { - BLI_assert(!"error in emDM_getTessFace"); - return; - } - - ltri = bmdm->em->looptris[index]; - - ef = ltri[0]->f; - - r_face->mat_nr = (unsigned char) ef->mat_nr; - r_face->flag = BM_face_flag_to_mflag(ef); - - r_face->v1 = BM_elem_index_get(ltri[0]->v); - r_face->v2 = BM_elem_index_get(ltri[1]->v); - r_face->v3 = BM_elem_index_get(ltri[2]->v); - r_face->v4 = 0; - - test_index_face(r_face, NULL, 0, 3); -} - -static void emDM_copyVertArray(DerivedMesh *dm, MVert *r_vert) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMVert *eve; - BMIter iter; - const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - - if (bmdm->vertexCos) { - int i; - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - copy_v3_v3(r_vert->co, bmdm->vertexCos[i]); - normal_float_to_short_v3(r_vert->no, eve->no); - r_vert->flag = BM_vert_flag_to_mflag(eve); - - r_vert->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0; - - r_vert++; - } - } - else { - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - copy_v3_v3(r_vert->co, eve->co); - normal_float_to_short_v3(r_vert->no, eve->no); - r_vert->flag = BM_vert_flag_to_mflag(eve); - - r_vert->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0; - - r_vert++; - } - } -} - -static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *r_edge) -{ - BMesh *bm = ((EditDerivedBMesh *)dm)->em->bm; - BMEdge *eed; - BMIter iter; - - const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); - const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - r_edge->v1 = BM_elem_index_get(eed->v1); - r_edge->v2 = BM_elem_index_get(eed->v2); - - r_edge->flag = BM_edge_flag_to_mflag(eed); - - r_edge->crease = (cd_edge_crease_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset) : 0; - r_edge->bweight = (cd_edge_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset) : 0; - - r_edge++; - } -} - -static void emDM_copyTessFaceArray(DerivedMesh *dm, MFace *r_face) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - struct BMLoop *(*looptris)[3] = bmdm->em->looptris; - BMFace *ef; - int i; - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - for (i = 0; i < bmdm->em->tottri; i++, r_face++) { - BMLoop **ltri = looptris[i]; - ef = ltri[0]->f; - - r_face->mat_nr = (unsigned char) ef->mat_nr; - - r_face->flag = BM_face_flag_to_mflag(ef); - r_face->edcode = 0; - - r_face->v1 = BM_elem_index_get(ltri[0]->v); - r_face->v2 = BM_elem_index_get(ltri[1]->v); - r_face->v3 = BM_elem_index_get(ltri[2]->v); - r_face->v4 = 0; - - test_index_face(r_face, NULL, 0, 3); - } -} - -static void emDM_copyLoopArray(DerivedMesh *dm, MLoop *r_loop) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMIter iter; - BMFace *efa; - - BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - r_loop->v = BM_elem_index_get(l_iter->v); - r_loop->e = BM_elem_index_get(l_iter->e); - r_loop++; - } while ((l_iter = l_iter->next) != l_first); - } -} - -static void emDM_copyPolyArray(DerivedMesh *dm, MPoly *r_poly) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMIter iter; - BMFace *efa; - int i; - - i = 0; - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - r_poly->flag = BM_face_flag_to_mflag(efa); - r_poly->loopstart = i; - r_poly->totloop = efa->len; - r_poly->mat_nr = efa->mat_nr; - - r_poly++; - i += efa->len; - } -} - -static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - void *datalayer; - - datalayer = DM_get_tessface_data_layer(dm, type); - if (datalayer) - return datalayer; - - /* layers are store per face for editmesh, we convert to a temporary - * data layer array in the derivedmesh when these are requested */ - if (type == CD_MTFACE || type == CD_MCOL) { - const char *bmdata; - char *data; - bool has_type_source = false; - - if (type == CD_MTFACE) { - has_type_source = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY); - } - else { - has_type_source = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL); - } - - if (has_type_source) { - /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */ - BMLoop *(*looptris)[3] = bmdm->em->looptris; - const int size = CustomData_sizeof(type); - int i, j; - - DM_add_tessface_layer(dm, type, CD_CALLOC, NULL); - const int index = CustomData_get_layer_index(&dm->faceData, type); - dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY; - - data = datalayer = DM_get_tessface_data_layer(dm, type); - - if (type == CD_MTFACE) { - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY); - - for (i = 0; i < bmdm->em->tottri; i++, data += size) { - BMFace *efa = looptris[i][0]->f; - - // bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY); - bmdata = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); - - ME_MTEXFACE_CPY(((MTFace *)data), ((const MTexPoly *)bmdata)); - for (j = 0; j < 3; j++) { - // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPUV); - bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_uv_offset); - copy_v2_v2(((MTFace *)data)->uv[j], ((const MLoopUV *)bmdata)->uv); - } - } - } - else { - const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL); - for (i = 0; i < bmdm->em->tottri; i++, data += size) { - for (j = 0; j < 3; j++) { - // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPCOL); - bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_color_offset); - MESH_MLOOPCOL_TO_MCOL(((const MLoopCol *)bmdata), (((MCol *)data) + j)); - } - } - } - } - } - - /* Special handling for CD_TESSLOOPNORMAL, we generate it on demand as well. */ - if (type == CD_TESSLOOPNORMAL) { - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - - if (lnors) { - BMLoop *(*looptris)[3] = bmdm->em->looptris; - short (*tlnors)[4][3], (*tlnor)[4][3]; - int index, i, j; - - DM_add_tessface_layer(dm, type, CD_CALLOC, NULL); - index = CustomData_get_layer_index(&dm->faceData, type); - dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY; - - tlnor = tlnors = DM_get_tessface_data_layer(dm, type); - - BM_mesh_elem_index_ensure(bm, BM_LOOP); - - for (i = 0; i < bmdm->em->tottri; i++, tlnor++, looptris++) { - for (j = 0; j < 3; j++) { - normal_float_to_short_v3((*tlnor)[j], lnors[BM_elem_index_get((*looptris)[j])]); - } - } - } - } - - return datalayer; -} - -static void emDM_getVertCos(DerivedMesh *dm, float (*r_cos)[3]) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMesh *bm = bmdm->em->bm; - BMVert *eve; - BMIter iter; - int i; - - if (bmdm->vertexCos) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - copy_v3_v3(r_cos[i], bmdm->vertexCos[i]); - } - } - else { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - copy_v3_v3(r_cos[i], eve->co); - } - } -} - -static void emDM_release(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - if (DM_release(dm)) { - if (bmdm->vertexCos) { - MEM_freeN((void *)bmdm->vertexCos); - if (bmdm->vertexNos) { - MEM_freeN((void *)bmdm->vertexNos); - } - if (bmdm->polyNos) { - MEM_freeN((void *)bmdm->polyNos); - } - } - - if (bmdm->polyCos) { - MEM_freeN((void *)bmdm->polyCos); - } - - MEM_freeN(bmdm); - } -} - -static CustomData *bmDm_getVertDataLayout(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return &bmdm->em->bm->vdata; -} - -static CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return &bmdm->em->bm->edata; -} - -static CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return &bmdm->dm.faceData; -} - -static CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return &bmdm->em->bm->ldata; -} - -static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm) -{ - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - - return &bmdm->em->bm->pdata; -} - -/** - * \note This may be called per-draw, - * avoid allocating large arrays where possible and keep this a thin wrapper for #BMesh. - */ -DerivedMesh *getEditDerivedBMesh( - BMEditMesh *em, struct Object *UNUSED(ob), - CustomDataMask data_mask, - float (*vertexCos)[3]) -{ - EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__); - BMesh *bm = em->bm; - - bmdm->em = em; - - DM_init((DerivedMesh *)bmdm, DM_TYPE_EDITBMESH, bm->totvert, - bm->totedge, em->tottri, bm->totloop, bm->totface); - - /* could also get from the objects mesh directly */ - bmdm->dm.cd_flag = BM_mesh_cd_flag_from_bmesh(bm); - - bmdm->dm.getVertCos = emDM_getVertCos; - bmdm->dm.getMinMax = emDM_getMinMax; - - bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout; - bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout; - bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout; - bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout; - bmdm->dm.getPolyDataLayout = bmDm_getPolyDataLayout; - - bmdm->dm.getNumVerts = emDM_getNumVerts; - bmdm->dm.getNumEdges = emDM_getNumEdges; - bmdm->dm.getNumTessFaces = emDM_getNumTessFaces; - bmdm->dm.getNumLoops = emDM_getNumLoops; - bmdm->dm.getNumPolys = emDM_getNumPolys; - - bmdm->dm.getVert = emDM_getVert; - bmdm->dm.getVertCo = emDM_getVertCo; - bmdm->dm.getVertNo = emDM_getVertNo; - bmdm->dm.getPolyNo = emDM_getPolyNo; - bmdm->dm.getEdge = emDM_getEdge; - bmdm->dm.getTessFace = emDM_getTessFace; - bmdm->dm.copyVertArray = emDM_copyVertArray; - bmdm->dm.copyEdgeArray = emDM_copyEdgeArray; - bmdm->dm.copyTessFaceArray = emDM_copyTessFaceArray; - bmdm->dm.copyLoopArray = emDM_copyLoopArray; - bmdm->dm.copyPolyArray = emDM_copyPolyArray; - - bmdm->dm.getTessFaceDataArray = emDM_getTessFaceDataArray; - - bmdm->dm.calcNormals = emDM_calcNormals; - bmdm->dm.calcLoopNormals = emDM_calcLoopNormals; - bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray; - bmdm->dm.calcLoopTangents = emDM_calc_loop_tangents; - bmdm->dm.recalcTessellation = emDM_recalcTessellation; - bmdm->dm.recalcLoopTri = emDM_recalcLoopTri; - - bmdm->dm.foreachMappedVert = emDM_foreachMappedVert; - bmdm->dm.foreachMappedLoop = emDM_foreachMappedLoop; - bmdm->dm.foreachMappedEdge = emDM_foreachMappedEdge; - bmdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter; - - bmdm->dm.drawEdges = emDM_drawEdges; - bmdm->dm.drawMappedEdges = emDM_drawMappedEdges; - bmdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp; - bmdm->dm.drawMappedFaces = emDM_drawMappedFaces; - bmdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex; - bmdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL; - bmdm->dm.drawMappedFacesMat = emDM_drawMappedFacesMat; - bmdm->dm.drawFacesTex = emDM_drawFacesTex; - bmdm->dm.drawFacesGLSL = emDM_drawFacesGLSL; - bmdm->dm.drawUVEdges = emDM_drawUVEdges; - - bmdm->dm.release = emDM_release; - - bmdm->vertexCos = (const float (*)[3])vertexCos; - bmdm->dm.deformedOnly = (vertexCos != NULL); - - const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ? - CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1; - - if (cd_dvert_offset != -1) { - BMIter iter; - BMVert *eve; - int i; - - DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL); - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT, - BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); - } - } - - const int cd_skin_offset = (data_mask & CD_MASK_MVERT_SKIN) ? - CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN) : -1; - - if (cd_skin_offset != -1) { - BMIter iter; - BMVert *eve; - int i; - - DM_add_vert_layer(&bmdm->dm, CD_MVERT_SKIN, CD_CALLOC, NULL); - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - DM_set_vert_data(&bmdm->dm, i, CD_MVERT_SKIN, - BM_ELEM_CD_GET_VOID_P(eve, cd_skin_offset)); - } - } - - return (DerivedMesh *)bmdm; -} - - - /* -------------------------------------------------------------------- */ /* StatVis Functions */ @@ -2375,7 +105,7 @@ static void statvis_calc_overhang( /* fallback max */ { float fcol[3]; - weight_to_rgb(fcol, 1.0f); + BKE_defvert_weight_to_rgb(fcol, 1.0f); rgb_float_to_uchar(col_fallback_max, fcol); } @@ -2389,7 +119,7 @@ static void statvis_calc_overhang( fac = (fac - min) * minmax_irange; fac = 1.0f - fac; CLAMP(fac, 0.0f, 1.0f); - weight_to_rgb(fcol, fac); + BKE_defvert_weight_to_rgb(fcol, fac); rgb_float_to_uchar(r_face_colors[index], fcol); } else { @@ -2524,7 +254,7 @@ static void statvis_calc_thickness( fac = (fac - min) * minmax_irange; fac = 1.0f - fac; CLAMP(fac, 0.0f, 1.0f); - weight_to_rgb(fcol, fac); + BKE_defvert_weight_to_rgb(fcol, fac); rgb_float_to_uchar(r_face_colors[i], fcol); } else { @@ -2563,7 +293,7 @@ static void statvis_calc_intersect( overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len); /* same for all faces */ - weight_to_rgb(fcol, 1.0f); + BKE_defvert_weight_to_rgb(fcol, 1.0f); rgb_float_to_uchar(col, fcol); if (overlap) { @@ -2650,7 +380,7 @@ static void statvis_calc_distort( float fcol[3]; fac = (fac - min) * minmax_irange; CLAMP(fac, 0.0f, 1.0f); - weight_to_rgb(fcol, fac); + BKE_defvert_weight_to_rgb(fcol, fac); rgb_float_to_uchar(r_face_colors[index], fcol); } else { @@ -2700,7 +430,7 @@ static void statvis_calc_sharp( float fcol[3]; fac = (fac - min) * minmax_irange; CLAMP(fac, 0.0f, 1.0f); - weight_to_rgb(fcol, fac); + BKE_defvert_weight_to_rgb(fcol, fac); rgb_float_to_uchar(r_vert_colors[i], fcol); } else { @@ -2710,18 +440,15 @@ static void statvis_calc_sharp( } void BKE_editmesh_statvis_calc( - BMEditMesh *em, DerivedMesh *dm, + BMEditMesh *em, EditMeshData *emd, const MeshStatVis *statvis) { - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BLI_assert(dm == NULL || dm->type == DM_TYPE_EDITBMESH); - switch (statvis->type) { case SCE_STATVIS_OVERHANG: { BKE_editmesh_color_ensure(em, BM_FACE); statvis_calc_overhang( - em, bmdm ? bmdm->polyNos : NULL, + em, emd ? emd->polyNos : NULL, statvis->overhang_min / (float)M_PI, statvis->overhang_max / (float)M_PI, statvis->overhang_axis, @@ -2733,7 +460,7 @@ void BKE_editmesh_statvis_calc( const float scale = 1.0f / mat4_to_scale(em->ob->obmat); BKE_editmesh_color_ensure(em, BM_FACE); statvis_calc_thickness( - em, bmdm ? bmdm->vertexCos : NULL, + em, emd ? emd->vertexCos : NULL, statvis->thickness_min * scale, statvis->thickness_max * scale, statvis->thickness_samples, @@ -2744,7 +471,7 @@ void BKE_editmesh_statvis_calc( { BKE_editmesh_color_ensure(em, BM_FACE); statvis_calc_intersect( - em, bmdm ? bmdm->vertexCos : NULL, + em, emd ? emd->vertexCos : NULL, em->derivedFaceColor); break; } @@ -2752,11 +479,12 @@ void BKE_editmesh_statvis_calc( { BKE_editmesh_color_ensure(em, BM_FACE); - if (bmdm) - emDM_ensurePolyNormals(bmdm); + if (emd) { + BKE_editmesh_cache_ensure_poly_normals(em, emd); + } statvis_calc_distort( - em, bmdm ? bmdm->vertexCos : NULL, bmdm ? bmdm->polyNos : NULL, + em, emd ? emd->vertexCos : NULL, emd ? emd->polyNos : NULL, statvis->distort_min, statvis->distort_max, em->derivedFaceColor); @@ -2766,7 +494,7 @@ void BKE_editmesh_statvis_calc( { BKE_editmesh_color_ensure(em, BM_VERT); statvis_calc_sharp( - em, bmdm ? bmdm->vertexCos : NULL, + em, emd ? emd->vertexCos : NULL, statvis->sharp_min, statvis->sharp_max, /* in this case they are vertex colors */ @@ -2799,14 +527,14 @@ static void cage_mapped_verts_callback( } } -float (*BKE_editmesh_vertexCos_get(BMEditMesh *em, Scene *scene, int *r_numVerts))[3] +float (*BKE_editmesh_vertexCos_get(struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_numVerts))[3] { - DerivedMesh *cage, *final; + Mesh *cage, *final; BLI_bitmap *visit_bitmap; struct CageUserData data; float (*cos_cage)[3]; - cage = editbmesh_get_derived_cage_and_final(scene, em->ob, em, CD_MASK_BAREMESH, &final); + cage = editbmesh_get_eval_cage_and_final(depsgraph, scene, em->ob, em, CD_MASK_BAREMESH, &final); cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage"); /* when initializing cage verts, we only want the first cage coordinate for each vertex, @@ -2817,7 +545,7 @@ float (*BKE_editmesh_vertexCos_get(BMEditMesh *em, Scene *scene, int *r_numVerts data.cos_cage = cos_cage; data.visit_bitmap = visit_bitmap; - cage->foreachMappedVert(cage, cage_mapped_verts_callback, &data, DM_FOREACH_NOP); + BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP); MEM_freeN(visit_bitmap); diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index fea3c24d322..11f3594da04 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -39,6 +39,7 @@ #include "BKE_editmesh.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library.h" BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate) @@ -58,7 +59,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em) BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__); *em_copy = *em; - em_copy->derivedCage = em_copy->derivedFinal = NULL; + em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL; em_copy->derivedVertColor = NULL; em_copy->derivedVertColorLen = 0; @@ -89,11 +90,13 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob) { BLI_assert(ob->type == OB_MESH); /* sanity check */ +#if 0 /* disable in mutlti-object edit. */ #ifndef NDEBUG if (((Mesh *)ob->data)->edit_btmesh) { BLI_assert(((Mesh *)ob->data)->edit_btmesh->ob == ob); } #endif +#endif return ((Mesh *)ob->data)->edit_btmesh; } @@ -112,18 +115,6 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em) BMLoop *(*looptris)[3]; -#if 0 - /* note, we could be clever and re-use this array but would need to ensure - * its realloced at some point, for now just free it */ - if (em->looptris) MEM_freeN(em->looptris); - - /* Use em->tottri when set, this means no reallocs while transforming, - * (unless scanfill fails), otherwise... */ - /* allocate the length of totfaces, avoid many small reallocs, - * if all faces are tri's it will be correct, quads == 2x allocs */ - BLI_array_reserve(looptris, (em->tottri && em->tottri < bm->totface * 3) ? em->tottri : bm->totface); -#else - /* this means no reallocs for quad dominant models, for */ if ((em->looptris != NULL) && /* (*em->tottri >= looptris_tot)) */ @@ -137,8 +128,6 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em) looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); } -#endif - em->looptris = looptris; /* after allocating the em->looptris, we're ready to tessellate */ @@ -152,51 +141,25 @@ void BKE_editmesh_tessface_calc(BMEditMesh *em) /* commented because editbmesh_build_data() ensures we get tessfaces */ #if 0 - if (em->derivedFinal && em->derivedFinal == em->derivedCage) { - if (em->derivedFinal->recalcTessellation) - em->derivedFinal->recalcTessellation(em->derivedFinal); + if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) { + BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final); } - else if (em->derivedFinal) { - if (em->derivedCage->recalcTessellation) - em->derivedCage->recalcTessellation(em->derivedCage); - if (em->derivedFinal->recalcTessellation) - em->derivedFinal->recalcTessellation(em->derivedFinal); + else if (em->mesh_eval_final) { + BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final); + BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage); } #endif } -void BKE_editmesh_update_linked_customdata(BMEditMesh *em) -{ - BMesh *bm = em->bm; - int act; - - if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) { - act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act); - - act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act); - - act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act); - - act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY); - CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act); - } -} - void BKE_editmesh_free_derivedmesh(BMEditMesh *em) { - if (em->derivedCage) { - em->derivedCage->needsFree = 1; - em->derivedCage->release(em->derivedCage); + if (em->mesh_eval_cage) { + BKE_id_free(NULL, em->mesh_eval_cage); } - if (em->derivedFinal && em->derivedFinal != em->derivedCage) { - em->derivedFinal->needsFree = 1; - em->derivedFinal->release(em->derivedFinal); + if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) { + BKE_id_free(NULL, em->mesh_eval_final); } - - em->derivedCage = em->derivedFinal = NULL; + em->mesh_eval_cage = em->mesh_eval_final = NULL; } /*does not free the BMEditMesh struct itself*/ @@ -264,3 +227,24 @@ float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3] return orco; } + +void BKE_editmesh_lnorspace_update(BMEditMesh *em) +{ + BMesh *bm = em->bm; + + /* We need to create clnors data if none exist yet, otherwise there is no way to edit them. + * Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading + * in case we were using autosmooth so far... + * Note: there is a problem here, which is that if someone starts a normal editing operation on previously + * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges + * (and hence autosmooth is 'lost'). + * Not sure how critical this is, and how to fix that issue? */ + if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { + Mesh *me = em->ob->data; + if (me->flag & ME_AUTOSMOOTH) { + BM_edges_sharp_from_angle_set(bm, me->smoothresh); + } + } + + BM_lnorspace_update(bm); +} diff --git a/source/blender/blenkernel/intern/editmesh_cache.c b/source/blender/blenkernel/intern/editmesh_cache.c new file mode 100644 index 00000000000..f0af0ede9b1 --- /dev/null +++ b/source/blender/blenkernel/intern/editmesh_cache.c @@ -0,0 +1,120 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/editmesh_cache.c + * \ingroup bke + * + * Manage edit mesh cache: #EditMeshData + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" + +#include "BLI_math.h" + +#include "BKE_editmesh.h" +#include "BKE_editmesh_cache.h" /* own include */ + +void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd) +{ + if (!(emd->vertexCos && (emd->polyNos == NULL))) { + return; + } + + BMesh *bm = em->bm; + const float (*vertexCos)[3]; + float (*polyNos)[3]; + + BMFace *efa; + BMIter fiter; + int i; + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__); + + vertexCos = emd->vertexCos; + + BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { + BM_elem_index_set(efa, i); /* set_inline */ + BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos); + } + bm->elem_index_dirty &= ~BM_FACE; + + emd->polyNos = (const float (*)[3])polyNos; +} + +void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, EditMeshData *emd) +{ + if (!(emd->vertexCos && (emd->vertexNos == NULL))) { + return; + } + + BMesh *bm = em->bm; + const float (*vertexCos)[3], (*polyNos)[3]; + float (*vertexNos)[3]; + + /* calculate vertex normals from poly normals */ + BKE_editmesh_cache_ensure_poly_normals(em, emd); + + BM_mesh_elem_index_ensure(bm, BM_FACE); + + polyNos = emd->polyNos; + vertexCos = emd->vertexCos; + vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__); + + BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos); + + emd->vertexNos = (const float (*)[3])vertexNos; +} + +void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd) +{ + if (emd->polyCos != NULL) { + return; + } + BMesh *bm = em->bm; + float (*polyCos)[3]; + + BMFace *efa; + BMIter fiter; + int i; + + polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__); + + if (emd->vertexCos) { + const float (*vertexCos)[3]; + vertexCos = emd->vertexCos; + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { + BM_face_calc_center_mean_vcos(bm, efa, polyCos[i], vertexCos); + } + } + else { + BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { + BM_face_calc_center_mean(efa, polyCos[i]); + } + } + + emd->polyCos = (const float (*)[3])polyCos; +} diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c new file mode 100644 index 00000000000..4231ad54ea8 --- /dev/null +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -0,0 +1,433 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/editmesh_tangent.c + * \ingroup bke + */ + +#include "BLI_math.h" +#include "BLI_task.h" + +#include "DNA_defs.h" +#include "DNA_customdata_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" +#include "BKE_mesh_tangent.h" /* for utility functions */ +#include "BKE_editmesh.h" +#include "BKE_editmesh_tangent.h" + +#include "MEM_guardedalloc.h" + +/* interface */ +#include "mikktspace.h" + +/** \name Tangent Space Calculation + * \{ */ + +/* Necessary complexity to handle looptri's as quads for correct tangents */ +#define USE_LOOPTRI_DETECT_QUADS + +typedef struct { + const float (*precomputedFaceNormals)[3]; + const float (*precomputedLoopNormals)[3]; + const BMLoop *(*looptris)[3]; + int cd_loop_uv_offset; /* texture coordinates */ + const float (*orco)[3]; + float (*tangent)[4]; /* destination */ + int numTessFaces; + +#ifdef USE_LOOPTRI_DETECT_QUADS + /* map from 'fake' face index to looptri, + * quads will point to the first looptri of the quad */ + const int *face_as_quad_map; + int num_face_as_quad_map; +#endif + +} SGLSLEditMeshToTangent; + +#ifdef USE_LOOPTRI_DETECT_QUADS +/* seems weak but only used on quads */ +static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index) +{ + const BMLoop *l = BM_FACE_FIRST_LOOP(f); + while (vert_index--) { + l = l->next; + } + return l; +} +#endif + +static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + +#ifdef USE_LOOPTRI_DETECT_QUADS + return pMesh->num_face_as_quad_map; +#else + return pMesh->numTessFaces; +#endif +} + +static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ +#ifdef USE_LOOPTRI_DETECT_QUADS + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + if (pMesh->face_as_quad_map) { + const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + return 4; + } + } + return 3; +#else + UNUSED_VARS(pContext, face_num); + return 3; +#endif +} + +static void emdm_ts_GetPosition( + const SMikkTSpaceContext *pContext, float r_co[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + + const float *co; + +finally: + co = l->v->co; + copy_v3_v3(r_co, co); +} + +static void emdm_ts_GetTextureCoordinate( + const SMikkTSpaceContext *pContext, float r_uv[2], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + +finally: + if (pMesh->cd_loop_uv_offset != -1) { + const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset); + copy_v2_v2(r_uv, uv); + } + else { + const float *orco = pMesh->orco[BM_elem_index_get(l->v)]; + map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); + } +} + +static void emdm_ts_GetNormal( + const SMikkTSpaceContext *pContext, float r_no[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + +finally: + if (pMesh->precomputedLoopNormals) { + copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]); + } + else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */ + if (pMesh->precomputedFaceNormals) { + copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]); + } + else { + copy_v3_v3(r_no, l->f->no); + } + } + else { + copy_v3_v3(r_no, l->v->no); + } +} + +static void emdm_ts_SetTSpace( + const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData; + const BMLoop **lt; + const BMLoop *l; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]]; + if (lt[0]->f->len == 4) { + l = bm_loop_at_face_index(lt[0]->f, vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = pMesh->looptris[face_num]; + } +#else + lt = pMesh->looptris[face_num]; +#endif + l = lt[vert_index]; + + float *pRes; + +finally: + pRes = pMesh->tangent[BM_elem_index_get(l)]; + copy_v3_v3(pRes, fvTangent); + pRes[3] = fSign; +} + +static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +{ + struct SGLSLEditMeshToTangent *mesh2tangent = taskdata; + /* new computation method */ + { + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + sContext.m_pUserData = mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = emdm_ts_GetNumFaces; + sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace; + sInterface.m_getPosition = emdm_ts_GetPosition; + sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate; + sInterface.m_getNormal = emdm_ts_GetNormal; + sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace; + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } +} + +/** + * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data. + * + * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`. + * This is done because #CD_TANGENT is cache data used only for drawing. + */ +void BKE_editmesh_loop_tangent_calc( + BMEditMesh *em, bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_len, + const float (*poly_normals)[3], + const float (*loop_normals)[3], + const float (*vert_orco)[3], + /* result */ + CustomData *loopdata_out, + const uint loopdata_out_len, + short *tangent_mask_curr_p) +{ + BMesh *bm = em->bm; + + int act_uv_n = -1; + int ren_uv_n = -1; + bool calc_act = false; + bool calc_ren = false; + char act_uv_name[MAX_NAME]; + char ren_uv_name[MAX_NAME]; + short tangent_mask = 0; + short tangent_mask_curr = *tangent_mask_curr_p; + + BKE_mesh_calc_loop_tangent_step_0( + &bm->ldata, calc_active_tangent, tangent_names, tangent_names_len, + &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); + + if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) { + for (int i = 0; i < tangent_names_len; i++) { + if (tangent_names[i][0]) { + BKE_mesh_add_loop_tangent_named_layer_for_uv( + &bm->ldata, loopdata_out, (int)loopdata_out_len, tangent_names[i]); + } + } + if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1) + CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + if (calc_act && act_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, act_uv_name); + if (calc_ren && ren_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, ren_uv_name); + int totface = em->tottri; +#ifdef USE_LOOPTRI_DETECT_QUADS + int num_face_as_quad_map; + int *face_as_quad_map = NULL; + + /* map faces to quads */ + if (em->tottri != bm->totface) { + /* over alloc, since we dont know how many ngon or quads we have */ + + /* map fake face index to looptri */ + face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__); + int i, j; + for (i = 0, j = 0; j < totface; i++, j++) { + face_as_quad_map[i] = j; + /* step over all quads */ + if (em->looptris[j][0]->f->len == 4) { + j++; /* skips the nest looptri */ + } + } + num_face_as_quad_map = i; + } + else { + num_face_as_quad_map = totface; + } +#endif + /* Calculation */ + if (em->tottri != 0) { + TaskScheduler *scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + task_pool = BLI_task_pool_create(scheduler, NULL); + + tangent_mask_curr = 0; + /* Calculate tangent layers */ + SGLSLEditMeshToTangent data_array[MAX_MTFACE]; + int index = 0; + int n = 0; + CustomData_update_typemap(loopdata_out); + const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT); + for (n = 0; n < tangent_layer_num; n++) { + index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n); + BLI_assert(n < MAX_MTFACE); + SGLSLEditMeshToTangent *mesh2tangent = &data_array[n]; + mesh2tangent->numTessFaces = em->tottri; +#ifdef USE_LOOPTRI_DETECT_QUADS + mesh2tangent->face_as_quad_map = face_as_quad_map; + mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; +#endif + mesh2tangent->precomputedFaceNormals = poly_normals; + /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), + * have to check this is valid... + */ + mesh2tangent->precomputedLoopNormals = loop_normals; + mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n); + + /* needed for indexing loop-tangents */ + int htype_index = BM_LOOP; + if (mesh2tangent->cd_loop_uv_offset == -1) { + mesh2tangent->orco = vert_orco; + if (!mesh2tangent->orco) + continue; + /* needed for orco lookups */ + htype_index |= BM_VERT; + tangent_mask_curr |= DM_TANGENT_MASK_ORCO; + } + else { + /* Fill the resulting tangent_mask */ + int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name); + int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV); + BLI_assert(uv_ind != -1 && uv_start != -1); + BLI_assert(uv_ind - uv_start < MAX_MTFACE); + tangent_mask_curr |= 1 << (uv_ind - uv_start); + } + if (mesh2tangent->precomputedFaceNormals) { + /* needed for face normal lookups */ + htype_index |= BM_FACE; + } + BM_mesh_elem_index_ensure(bm, htype_index); + + mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris; + mesh2tangent->tangent = loopdata_out->layers[index].data; + + BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); + } + + BLI_assert(tangent_mask_curr == tangent_mask); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + } + else { + tangent_mask_curr = tangent_mask; + } +#ifdef USE_LOOPTRI_DETECT_QUADS + if (face_as_quad_map) { + MEM_freeN(face_as_quad_map); + } +#undef USE_LOOPTRI_DETECT_QUADS +#endif + } + + *tangent_mask_curr_p = tangent_mask_curr; + + int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n); + if (act_uv_index >= 0) { + int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name); + CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index); + } /* else tangent has been built from orco */ + + /* Update render layer index */ + int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n); + if (ren_uv_index >= 0) { + int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name); + CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index); + } /* else tangent has been built from orco */ +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 82bf65993a8..7c86c0722dc 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -37,9 +37,10 @@ #include "MEM_guardedalloc.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_group_types.h" #include "DNA_listBase.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_object_force_types.h" @@ -57,13 +58,14 @@ #include "PIL_time.h" #include "BKE_anim.h" /* needed for where_on_path */ +#include "BKE_bvhutils.h" +#include "BKE_collection.h" #include "BKE_collision.h" #include "BKE_curve.h" #include "BKE_displist.h" -#include "BKE_DerivedMesh.h" -#include "BKE_cdderivedmesh.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -71,6 +73,9 @@ #include "BKE_scene.h" #include "BKE_smoke.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_physics.h" +#include "DEG_depsgraph_query.h" #include "RE_render_ext.h" #include "RE_shader_ext.h" @@ -82,7 +87,7 @@ #include <string.h> #endif // WITH_MOD_FLUID -EffectorWeights *BKE_add_effector_weights(Group *group) +EffectorWeights *BKE_add_effector_weights(Collection *collection) { EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights"); int i; @@ -93,7 +98,7 @@ EffectorWeights *BKE_add_effector_weights(Group *group) weights->global_gravity = 1.0f; - weights->group = group; + weights->group = collection; return weights; } @@ -107,6 +112,7 @@ PartDeflect *object_add_collision_fields(int type) pd->pdef_sbdamp = 0.1f; pd->pdef_sbift = 0.2f; pd->pdef_sboft = 0.02f; + pd->pdef_cfrict = 5.0f; pd->seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128; pd->f_strength = 1.0f; pd->f_damp = 1.0f; @@ -127,14 +133,13 @@ PartDeflect *object_add_collision_fields(int type) pd->f_flow = 1.0f; break; } - pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION; + pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION | PFIELD_CLOTH_USE_CULLING; return pd; } -/* ***************** PARTICLES ***************** */ +/************************ PARTICLES ***************************/ -/* -------------------------- Effectors ------------------ */ void free_partdeflect(PartDeflect *pd) { if (!pd) { @@ -146,183 +151,195 @@ void free_partdeflect(PartDeflect *pd) MEM_freeN(pd); } -static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd) -{ - EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache"); - eff->scene = scene; - eff->ob = ob; - eff->psys = psys; - eff->pd = pd; - eff->frame = -1; - return eff; -} -static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src, bool for_simulation) -{ - EffectorCache *eff = NULL; +/******************** EFFECTOR RELATIONS ***********************/ - if (ob == ob_src) { - return; +static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *eff) +{ + float ctime = DEG_get_ctime(depsgraph); + uint cfra = (uint)(ctime >= 0 ? ctime : -ctime); + if (!eff->pd->rng) { + eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra); + } + else { + BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra); } - if (for_simulation) { - if (weights->weight[ob->pd->forcefield] == 0.0f) { - return; - } + if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) { + Curve *cu = eff->ob->data; + if (cu->flag & CU_PATH) { + if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path == NULL || eff->ob->runtime.curve_cache->path->data == NULL) + BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, 0); - if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal) { - return; + if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) { + where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL); + mul_m4_v3(eff->ob->obmat, eff->guide_loc); + mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir); + } } } + else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) { + eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface); + if (eff->ob->type == OB_CURVE) + eff->flag |= PE_USE_NORMAL_DATA; + } + else if (eff->psys) + psys_update_particle_tree(eff->psys, ctime); - if (*effectors == NULL) - *effectors = MEM_callocN(sizeof(ListBase), "effectors list"); + /* Store object velocity */ + if (eff->ob) { + float old_vel[3]; - eff = new_effector_cache(scene, ob, NULL, ob->pd); + BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra - 1.0f); + copy_v3_v3(old_vel, eff->ob->obmat[3]); + BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra); + sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel); + } +} - /* make sure imat is up to date */ - invert_m4_m4(ob->imat, ob->obmat); +static void add_effector_relation(ListBase *relations, Object *ob, ParticleSystem *psys, PartDeflect *pd) +{ + EffectorRelation *relation = MEM_callocN(sizeof(EffectorRelation), "EffectorRelation"); + relation->ob = ob; + relation->psys = psys; + relation->pd = pd; - BLI_addtail(*effectors, eff); + BLI_addtail(relations, relation); } -static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src, bool for_simulation) -{ - ParticleSettings *part = psys->part; - if (!psys_check_enabled(ob, psys, G.is_rendering)) { - return; - } - if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) { - return; - } - if (part->pd && part->pd->forcefield && (!for_simulation || weights->weight[part->pd->forcefield] != 0.0f)) { - if (*effectors == NULL) { - *effectors = MEM_callocN(sizeof(ListBase), "effectors list"); - } - BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd)); +static void add_effector_evaluation(ListBase **effectors, Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd) +{ + if (*effectors == NULL) { + *effectors = MEM_callocN(sizeof(ListBase), "effector effectors"); } - if (part->pd2 && part->pd2->forcefield && (!for_simulation || weights->weight[part->pd2->forcefield] != 0.0f)) { - if (*effectors == NULL) { - *effectors = MEM_callocN(sizeof(ListBase), "effectors list"); - } - BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd2)); - } + EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache"); + eff->depsgraph = depsgraph; + eff->scene = scene; + eff->ob = ob; + eff->psys = psys; + eff->pd = pd; + eff->frame = -1; + BLI_addtail(*effectors, eff); + + precalculate_effector(depsgraph, eff); } -/* returns ListBase handle with objects taking part in the effecting */ -ListBase *pdInitEffectors( - Scene *scene, Object *ob_src, ParticleSystem *psys_src, - EffectorWeights *weights, bool for_simulation) +/* Create list of effector relations in the collection or entire scene. + * This is used by the depsgraph to build relations, as well as faster + * lookup of effectors during evaluation. */ +ListBase *BKE_effector_relations_create( + Depsgraph *depsgraph, + ViewLayer *view_layer, + Collection *collection) { - const uint layer = ob_src->lay; - ListBase *effectors = NULL; + Base *base = BKE_collection_or_layer_objects(view_layer, collection); + const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT; - if (weights->group) { - for (GroupObject *go = weights->group->gobject.first; go; go = go->next) { - if ((go->ob->lay & layer)) { - if (go->ob->pd && go->ob->pd->forcefield) { - add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src, for_simulation); - } + ListBase *relations = MEM_callocN(sizeof(ListBase), "effector relations"); - if (go->ob->particlesystem.first) { - for (ParticleSystem *psys = go->ob->particlesystem.first; psys; psys = psys->next) { - add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src, for_simulation); - } - } - } + for (; base; base = base->next) { + if (!(base->flag & base_flag)) { + continue; } - } - else { - for (Base *base = scene->base.first; base; base = base->next) { - if ((base->lay & layer)) { - if (base->object->pd && base->object->pd->forcefield) { - add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation); + + Object *ob = base->object; + + if (ob->pd && ob->pd->forcefield) { + add_effector_relation(relations, ob, NULL, ob->pd); + } + + for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) { + ParticleSettings *part = psys->part; + + if (psys_check_enabled(ob, psys, for_render)) { + if (part->pd && part->pd->forcefield) { + add_effector_relation(relations, ob, psys, part->pd); } - if (base->object->particlesystem.first) { - for (ParticleSystem *psys = base->object->particlesystem.first; psys; psys = psys->next) { - add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation); - } + if (part->pd2 && part->pd2->forcefield) { + add_effector_relation(relations, ob, psys, part->pd2); } } } } - if (for_simulation) { - pdPrecalculateEffectors(effectors); - } - - return effectors; + return relations; } -void pdEndEffectors(ListBase **effectors) +void BKE_effector_relations_free(ListBase *lb) { - if (*effectors) { - for (EffectorCache *eff = (*effectors)->first; eff; eff = eff->next) { - if (eff->guide_data) { - MEM_freeN(eff->guide_data); - } - } - - BLI_freelistN(*effectors); - MEM_freeN(*effectors); - *effectors = NULL; + if (lb) { + BLI_freelistN(lb); + MEM_freeN(lb); } } -static void precalculate_effector(EffectorCache *eff) +/* Create effective list of effectors from relations built beforehand. */ +ListBase *BKE_effectors_create( + Depsgraph *depsgraph, + Object *ob_src, + ParticleSystem *psys_src, + EffectorWeights *weights) { - uint cfra = (uint)(eff->scene->r.cfra >= 0 ? eff->scene->r.cfra : -eff->scene->r.cfra); - if (!eff->pd->rng) { - eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra); - } - else { - BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra); + Scene *scene = DEG_get_evaluated_scene(depsgraph); + ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group); + ListBase *effectors = NULL; + + if (!relations) { + return NULL; } - if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) { - Curve *cu = eff->ob->data; - if (cu->flag & CU_PATH) { - if ((eff->ob->curve_cache == NULL) || - (eff->ob->curve_cache->path == NULL) || - (eff->ob->curve_cache->path->data == NULL)) - { - BKE_displist_make_curveTypes(eff->scene, eff->ob, 0); + for (EffectorRelation *relation = relations->first; relation; relation = relation->next) { + /* Get evaluated object. */ + Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id); + + if (relation->psys) { + /* Get evaluated particle system. */ + ParticleSystem *psys = BLI_findstring(&ob->particlesystem, + relation->psys->name, offsetof(ParticleSystem, name)); + ParticleSettings *part = psys->part; + + if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) { + continue; } - if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) { - where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL); - mul_m4_v3(eff->ob->obmat, eff->guide_loc); - mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir); + PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2; + if (weights->weight[pd->forcefield] == 0.0f) { + continue; } + + add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd); } - } - else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) { - eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface); - if (eff->ob->type == OB_CURVE) { - eff->flag |= PE_USE_NORMAL_DATA; + else { + /* Object effector. */ + if (ob == ob_src) { + continue; + } + else if (weights->weight[ob->pd->forcefield] == 0.0f) { + continue; + } + else if (ob->pd->shape == PFIELD_SHAPE_POINTS && ob->runtime.mesh_eval == NULL) { + continue; + } + + add_effector_evaluation(&effectors, depsgraph, scene, ob, NULL, ob->pd); } } - else if (eff->psys) { - psys_update_particle_tree(eff->psys, eff->scene->r.cfra); - } - /* Store object velocity */ - if (eff->ob) { - float old_vel[3]; - - BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra - 1.0f); - copy_v3_v3(old_vel, eff->ob->obmat[3]); - BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra); - sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel); - } + return effectors; } -void pdPrecalculateEffectors(ListBase *effectors) +void BKE_effectors_free(ListBase *lb) { - if (effectors) { - for (EffectorCache *eff = effectors->first; eff; eff = eff->next) { - precalculate_effector(eff); + if (lb) { + for (EffectorCache *eff = lb->first; eff; eff = eff->next) { + if (eff->guide_data) { + MEM_freeN(eff->guide_data); + } } + + BLI_freelistN(lb); + MEM_freeN(lb); } } @@ -413,7 +430,7 @@ static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, Effect return visibility; } if (!colls) { - colls = get_collider_cache(eff->scene, eff->ob, NULL); + colls = BKE_collider_cache_create(eff->depsgraph, eff->ob, NULL); } if (!colls) { return visibility; @@ -453,7 +470,7 @@ static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, Effect } if (!colliders) - free_collider_cache(&colls); + BKE_collider_cache_free(&colls); return visibility; } @@ -534,7 +551,7 @@ float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *UNU if (falloff == 0.0f) break; - r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point))); + r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point2))); falloff *= falloff_func_rad(eff->pd, r_fac); break; @@ -577,7 +594,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], floa } int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity) { - float cfra = eff->scene->r.cfra; + float cfra = DEG_get_ctime(eff->depsgraph); int ret = 0; /* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed @@ -596,12 +613,10 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin efd->size = 0.0f; } else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) { - - if (eff->ob->derivedFinal) { - DerivedMesh *dm = eff->ob->derivedFinal; - - dm->getVertCo(dm, *efd->index, efd->loc); - dm->getVertNo(dm, *efd->index, efd->nor); + Mesh *me_eval = eff->ob->runtime.mesh_eval; + if (me_eval != NULL) { + copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co); + normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no); mul_m4_v3(eff->ob->obmat, efd->loc); mul_mat3_m4_v3(eff->ob->obmat, efd->nor); @@ -624,6 +639,7 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin } else { ParticleSimulationData sim = {NULL}; + sim.depsgraph = eff->depsgraph; sim.scene = eff->scene; sim.ob = eff->ob; sim.psys = eff->psys; @@ -658,13 +674,13 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin /* use z-axis as normal*/ normalize_v3_v3(efd->nor, ob->obmat[2]); - if (eff->pd && eff->pd->shape == PFIELD_SHAPE_PLANE) { + if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) { float temp[3], translate[3]; sub_v3_v3v3(temp, point->loc, ob->obmat[3]); project_v3_v3v3(translate, temp, efd->nor); /* for vortex the shape chooses between old / new force */ - if (eff->pd->forcefield == PFIELD_VORTEX) { + if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) { add_v3_v3v3(efd->loc, ob->obmat[3], translate); } else { /* normally efd->loc is closest point on effector xy-plane */ @@ -710,7 +726,8 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin efd->index = p; if (eff->pd->shape == PFIELD_SHAPE_POINTS) { - *tot = eff->ob->derivedFinal ? eff->ob->derivedFinal->numVertData : 1; + Mesh *me_eval = eff->ob->runtime.mesh_eval; + *tot = me_eval != NULL ? me_eval->totvert : 1; if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) { *p = point->index % *tot; @@ -893,7 +910,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected } break; case PFIELD_MAGNET: - if (eff->pd->shape == PFIELD_SHAPE_POINT) + if (ELEM(eff->pd->shape, PFIELD_SHAPE_POINT, PFIELD_SHAPE_LINE)) /* magnetic field of a moving charge */ cross_v3_v3v3(temp, efd->nor, efd->vec_to_point); else @@ -988,7 +1005,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected } } -/* -------- pdDoEffectors() -------- +/* -------- BKE_effectors_apply() -------- * generic force/speed system, now used for particles and softbodies * scene = scene where it runs in, for time and stuff * lb = listbase with objects that take part in effecting @@ -1001,7 +1018,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected * flags = only used for softbody wind now * guide = old speed of particle */ -void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse) +void BKE_effectors_apply(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse) { /* * Modifies the force on a particle according to its diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index d4e69ad06ac..ed3874ae1c2 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -49,6 +49,8 @@ #include "BLI_threads.h" #include "BLI_string_utils.h" #include "BLI_utildefines.h" +#include "BLI_expr_pylike_eval.h" +#include "BLI_alloca.h" #include "BLT_translation.h" @@ -65,6 +67,8 @@ #include "RNA_access.h" +#include "atomic_ops.h" + #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -882,25 +886,44 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample * that the handles are correctly */ -/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */ -bool BKE_fcurve_is_cyclic(FCurve *fcu) +/* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */ +eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu) { FModifier *fcm = fcu->modifiers.first; - if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) - return false; + if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) { + return FCU_CYCLE_NONE; + } - if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) - return false; + if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) { + return FCU_CYCLE_NONE; + } - if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE)) - return false; + if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE)) { + return FCU_CYCLE_NONE; + } FMod_Cycles *data = (FMod_Cycles *)fcm->data; - return data && data->after_cycles == 0 && data->before_cycles == 0 && - ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) && - ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET); + if (data && data->after_cycles == 0 && data->before_cycles == 0) { + if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC && data->after_mode == FCM_EXTRAPOLATE_CYCLIC) { + return FCU_CYCLE_PERFECT; + } + + if (ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) && + ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET)) + { + return FCU_CYCLE_OFFSET; + } + } + + return FCU_CYCLE_NONE; +} + +/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */ +bool BKE_fcurve_is_cyclic(FCurve *fcu) +{ + return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE; } /* Shifts 'in' by the difference in coordinates between 'to' and 'from', using 'out' as the output buffer. @@ -1288,31 +1311,6 @@ bool driver_get_variable_property( return true; } -#if 0 -/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */ -static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar) -{ - ID *id; - /* sanity check */ - if (ELEM(NULL, driver, dtar)) - return NULL; - - id = dtar_id_ensure_proxy_from(dtar->id); - - /* check if the ID here is a valid object */ - if (id && GS(id->name)) { - Object *ob = (Object *)id; - - /* get pose, and subsequently, posechannel */ - return BKE_pose_channel_find_name(ob->pose, dtar->pchan_name); - } - else { - /* cannot find a posechannel this way */ - return NULL; - } -} -#endif - static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar) { short valid_targets = 0; @@ -1694,11 +1692,8 @@ void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar) /* remove and free the driver variable */ driver_free_variable(&driver->variables, dvar); -#ifdef WITH_PYTHON /* since driver variables are cached, the expression needs re-compiling too */ - if (driver->type == DRIVER_TYPE_PYTHON) - driver->flag |= DRIVER_FLAG_RENAMEVAR; -#endif + BKE_driver_invalidate_expression(driver, false, true); } /* Copy driver variables from src_vars list to dst_vars list */ @@ -1835,11 +1830,8 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver) /* set the default type to 'single prop' */ driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP); -#ifdef WITH_PYTHON /* since driver variables are cached, the expression needs re-compiling too */ - if (driver->type == DRIVER_TYPE_PYTHON) - driver->flag |= DRIVER_FLAG_RENAMEVAR; -#endif + BKE_driver_invalidate_expression(driver, false, true); /* return the target */ return dvar; @@ -1868,6 +1860,8 @@ void fcurve_free_driver(FCurve *fcu) BPY_DECREF(driver->expr_comp); #endif + BLI_expr_pylike_free(driver->expr_simple); + /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */ MEM_freeN(driver); fcu->driver = NULL; @@ -1885,6 +1879,7 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver) /* copy all data */ ndriver = MEM_dupallocN(driver); ndriver->expr_comp = NULL; + ndriver->expr_simple = NULL; /* copy variables */ BLI_listbase_clear(&ndriver->variables); /* to get rid of refs to non-copied data (that's still used on original) */ @@ -1894,6 +1889,124 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver) return ndriver; } +/* Driver Expression Evaluation --------------- */ + +static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver) +{ + /* Prepare parameter names. */ + int names_len = BLI_listbase_count(&driver->variables); + const char **names = BLI_array_alloca(names, names_len + 1); + int i = 0; + + names[i++] = "frame"; + + for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) { + names[i++] = dvar->name; + } + + return BLI_expr_pylike_parse(driver->expression, names, names_len + 1); +} + +static bool driver_evaluate_simple_expr(ChannelDriver *driver, ExprPyLike_Parsed *expr, float *result, float time) +{ + /* Prepare parameter values. */ + int vars_len = BLI_listbase_count(&driver->variables); + double *vars = BLI_array_alloca(vars, vars_len + 1); + int i = 0; + + vars[i++] = time; + + for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) { + vars[i++] = driver_get_variable_value(driver, dvar); + } + + /* Evaluate expression. */ + double result_val; + eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, vars, vars_len + 1, &result_val); + const char *message; + + switch (status) { + case EXPR_PYLIKE_SUCCESS: + if (isfinite(result_val)) { + *result = (float)result_val; + } + return true; + + case EXPR_PYLIKE_DIV_BY_ZERO: + case EXPR_PYLIKE_MATH_ERROR: + message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error"; + fprintf(stderr, "\n%s in Driver: '%s'\n", message, driver->expression); + + driver->flag |= DRIVER_FLAG_INVALID; + return true; + + default: + /* arriving here means a bug, not user error */ + printf("Error: simple driver expression evaluation failed: '%s'\n", driver->expression); + return false; + } +} + +/* Compile and cache the driver expression if necessary, with thread safety. */ +static bool driver_compile_simple_expr(ChannelDriver *driver) +{ + if (driver->expr_simple != NULL) { + return true; + } + + if (driver->type != DRIVER_TYPE_PYTHON) { + return false; + } + + /* It's safe to parse in multiple threads; at worst it'll + * waste some effort, but in return avoids mutex contention. */ + ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver); + + /* Store the result if the field is still NULL, or discard + * it if another thread got here first. */ + if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) { + BLI_expr_pylike_free(expr); + } + + return true; +} + +/* Try using the simple expression evaluator to compute the result of the driver. + * On success, stores the result and returns true; on failure result is set to 0. */ +static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, ChannelDriver *driver_orig, float *result, float time) +{ + *result = 0.0f; + + return driver_compile_simple_expr(driver_orig) && + BLI_expr_pylike_is_valid(driver_orig->expr_simple) && + driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time); +} + +/* Check if the expression in the driver conforms to the simple subset. */ +bool BKE_driver_has_simple_expression(ChannelDriver *driver) +{ + return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple); +} + +/* Reset cached compiled expression data */ +void BKE_driver_invalidate_expression(ChannelDriver *driver, bool expr_changed, bool varname_changed) +{ + if (expr_changed || varname_changed) { + BLI_expr_pylike_free(driver->expr_simple); + driver->expr_simple = NULL; + } + +#ifdef WITH_PYTHON + if (expr_changed) { + driver->flag |= DRIVER_FLAG_RECOMPILE; + } + + if (varname_changed) { + driver->flag |= DRIVER_FLAG_RENAMEVAR; + } +#endif +} + /* Driver Evaluation -------------------------- */ /* Evaluate a Driver Variable to get a value that contributes to the final */ @@ -1922,13 +2035,14 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar) /* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime" * - "evaltime" is the frame at which F-Curve is being evaluated * - has to return a float value + * - driver_orig is where we cache Python expressions, in case of COW */ -float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime) +float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime) { DriverVar *dvar; /* check if driver can be evaluated */ - if (driver->flag & DRIVER_FLAG_INVALID) + if (driver_orig->flag & DRIVER_FLAG_INVALID) return 0.0f; switch (driver->type) { @@ -1996,26 +2110,26 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl } case DRIVER_TYPE_PYTHON: /* expression */ { -#ifdef WITH_PYTHON /* check for empty or invalid expression */ - if ( (driver->expression[0] == '\0') || - (driver->flag & DRIVER_FLAG_INVALID) ) + if ( (driver_orig->expression[0] == '\0') || + (driver_orig->flag & DRIVER_FLAG_INVALID) ) { driver->curval = 0.0f; } - else { + else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) { +#ifdef WITH_PYTHON /* this evaluates the expression using Python, and returns its result: * - on errors it reports, then returns 0.0f */ BLI_mutex_lock(&python_driver_lock); - driver->curval = BPY_driver_exec(anim_rna, driver, evaltime); + driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime); BLI_mutex_unlock(&python_driver_lock); - } #else /* WITH_PYTHON*/ - UNUSED_VARS(anim_rna, evaltime); + UNUSED_VARS(anim_rna, evaltime); #endif /* WITH_PYTHON*/ + } break; } default: @@ -2187,24 +2301,6 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b) } } -#if 0 -static void berekenx(float *f, float *o, int b) -{ - float t, c0, c1, c2, c3; - int a; - - c0 = f[0]; - c1 = 3.0f * (f[3] - f[0]); - c2 = 3.0f * (f[0] - 2.0f * f[3] + f[6]); - c3 = f[9] - f[0] + 3.0f * (f[3] - f[6]); - - for (a = 0; a < b; a++) { - t = o[a]; - o[a] = c0 + t * c1 + t * t * c2 + t * t * t * c3; - } -} -#endif - /* -------------------------- */ @@ -2705,7 +2801,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime) return evaluate_fcurve_ex(fcu, evaltime, 0.0); } -float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) +float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, ChannelDriver *driver_orig, float evaltime) { BLI_assert(fcu->driver != NULL); float cvalue = 0.0f; @@ -2715,7 +2811,7 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evalt */ if (fcu->driver) { /* evaltime now serves as input for the curve */ - evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime); + evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, evaltime); /* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */ if (fcu->totvert == 0) { @@ -2762,7 +2858,7 @@ float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime) /* calculate and set curval (evaluates driver too if necessary) */ float curval; if (fcu->driver) { - curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime); + curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, evaltime); } else { curval = evaluate_fcurve(fcu, evaltime); diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index 0487302d9b6..bf1532bab42 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -30,46 +30,31 @@ */ -// headers for fluidsim bobj meshes -#include <stdlib.h> -#include <zlib.h> -#include <string.h> -#include <stdio.h> - #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_object_fluidsim_types.h" -#include "DNA_object_force_types.h" // for pointcache #include "DNA_object_types.h" -#include "DNA_particle_types.h" -#include "DNA_scene_types.h" #include "BLI_math.h" -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" -#include "BKE_cdderivedmesh.h" #include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" #include "BKE_fluidsim.h" -#include "BKE_modifier.h" -#include "BKE_mesh.h" +#include "BKE_library.h" +#include "BKE_mesh_runtime.h" /* ************************* fluidsim bobj file handling **************************** */ - //------------------------------------------------------------------------------- // file handling //------------------------------------------------------------------------------- -void initElbeemMesh(struct Scene *scene, struct Object *ob, +void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords, int modifierIndex) { - DerivedMesh *dm; + Mesh *mesh; const MVert *mvert; const MLoop *mloop; const MLoopTri *looptri, *lt; @@ -77,13 +62,13 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob, float *verts; int *tris; - dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex); + mesh = mesh_create_eval_final_index_render(depsgraph, scene, ob, CD_MASK_BAREMESH, modifierIndex); - mvert = dm->getVertArray(dm); - mloop = dm->getLoopArray(dm); - looptri = dm->getLoopTriArray(dm); - mvert_num = dm->getNumVerts(dm); - looptri_num = dm->getNumLoopTri(dm); + mvert = mesh->mvert; + mloop = mesh->mloop; + looptri = BKE_mesh_runtime_looptri_ensure(mesh); + mvert_num = mesh->totvert; + looptri_num = mesh->runtime.looptris.len; *numVertices = mvert_num; verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices"); @@ -102,5 +87,5 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob, } *triangles = tris; - dm->release(dm); + BKE_id_free(NULL, mesh); } diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c index f5915e1ddb9..8fce320800e 100644 --- a/source/blender/blenkernel/intern/fmodifier.c +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -835,27 +835,6 @@ static FModifierTypeInfo FMI_NOISE = { NULL /* evaluate with storage */ }; -/* Filter F-Curve Modifier --------------------------- */ - -#if 0 // XXX not yet implemented -static FModifierTypeInfo FMI_FILTER = { - FMODIFIER_TYPE_FILTER, /* type */ - sizeof(FMod_Filter), /* size */ - FMI_TYPE_REPLACE_VALUES, /* action type */ - 0, /* requirements */ - N_("Filter"), /* name */ - "FMod_Filter", /* struct name */ - NULL, /* free data */ - NULL, /* copy data */ - NULL, /* new data */ - NULL /*fcm_filter_verify*/, /* verify */ - NULL, /* evaluate time */ - fcm_filter_evaluate, /* evaluate */ - NULL, /* evaluate time with storage */ - NULL /* evaluate with storage */ -}; -#endif // XXX not yet implemented - /* Python F-Curve Modifier --------------------------- */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index e51b10a97a4..f6e1fabc6c0 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -635,6 +635,22 @@ struct TempLineInfo { int wspace_nr; /* number of whitespaces of line */ }; +/** + * Font metric values explained: + * + * Baseline: Line where the text "rests", used as the origin vertical position for the glyphs. + * Em height: Space most glyphs should fit within. + * Ascent: the recommended distance above the baseline to fit most characters. + * Descent: the recommended distance below the baseline to fit most characters. + * + * We obtain ascent and descent from the font itself (FT_Face->ascender / face->height). + * And in some cases it is even the same value as FT_Face->bbox.yMax/yMin (font top and bottom respectively). + * + * The em_height here is relative to FT_Face->bbox. +*/ +#define ASCENT(vfd) ((vfd)->ascender * (vfd)->em_height) +#define DESCENT(vfd) ((vfd)->em_height - ASCENT(vfd)) + bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase, const wchar_t **r_text, int *r_text_len, bool *r_text_free, struct CharTrans **r_chartransdata) @@ -648,8 +664,6 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase, bool use_textbox; VChar *che; struct CharTrans *chartransdata = NULL, *ct; - /* Text at the beginning of the last used text-box (use for y-axis alignment). */ - int i_textbox = 0; struct TempLineInfo *lineinfo; float *f, xof, yof, xtrax, linedist; float twidth, maxlen = 0; @@ -663,6 +677,10 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase, const float xof_scale = cu->xof / cu->fsize; const float yof_scale = cu->yof / cu->fsize; + /* Text at the beginning of the last used text-box (use for y-axis alignment). + * We overallocate by one to simplify logic of getting last char. */ + int *i_textbox_array = MEM_callocN(sizeof(*i_textbox_array) * (cu->totbox + 1), "TextBox initial char index"); + #define MARGIN_X_MIN (xof_scale + tb_scale.x) #define MARGIN_Y_MIN (yof_scale + tb_scale.y) @@ -862,9 +880,9 @@ makebreak: (cu->totbox > (curbox + 1)) && ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale)) { - i_textbox = i + 1; maxlen = 0; curbox++; + i_textbox_array[curbox] = i + 1; textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize); @@ -1019,50 +1037,73 @@ makebreak: /* top-baseline is default, in this case, do nothing */ if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) { if (tb_scale.h != 0.0f) { - /* top and top-baseline are the same when text-boxes are used */ - if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) { - /* all previous textboxes are 'full', only align the last used text-box */ - float yoff; + /* We need to loop all the text-boxes even the "full" ones. + * This way they all get the same vertical padding. */ + for (int tb_index = 0; tb_index < cu->totbox; tb_index++) { + struct CharTrans *ct_first, *ct_last; + const int i_textbox = i_textbox_array[tb_index]; + const int i_textbox_next = i_textbox_array[tb_index + 1]; + const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1); int lines; - struct CharTrans *ct_last, *ct_textbox; - ct_last = chartransdata + slen - 1; - ct_textbox = chartransdata + i_textbox; + ct_first = chartransdata + i_textbox; + ct_last = chartransdata + (is_last_filled_textbox ? slen: i_textbox_next - 1); + lines = ct_last->linenr - ct_first->linenr + 1; - lines = ct_last->linenr - ct_textbox->linenr + 1; - if (mem[slen - 1] == '\n') { - lines++; - } + textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / cu->fsize); + /* The initial Y origin of the textbox is hardcoded to 1.0f * text scale. */ + const float textbox_y_origin = 1.0f; + float yoff = 0.0f; - if (cu->align_y == CU_ALIGN_Y_BOTTOM) { - yoff = (lines * linedist) - tb_scale.h; - } - else if (cu->align_y == CU_ALIGN_Y_CENTER) { - yoff = 0.5f * ((lines * linedist) - tb_scale.h); + switch (cu->align_y) { + case CU_ALIGN_Y_TOP_BASELINE: + break; + case CU_ALIGN_Y_TOP: + yoff = textbox_y_origin - ASCENT(vfd); + break; + case CU_ALIGN_Y_CENTER: + yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - ASCENT(vfd)) - + (tb_scale.h * 0.5f) + textbox_y_origin); + break; + case CU_ALIGN_Y_BOTTOM_BASELINE: + yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h; + break; + case CU_ALIGN_Y_BOTTOM: + yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + DESCENT(vfd); + break; } - ct = ct_textbox; - for (i = i_textbox - 1; i < slen; i++) { + for (ct = ct_first; ct <= ct_last; ct++) { ct->yof += yoff; - ct++; + } + + if (is_last_filled_textbox) { + break; } } } else { - /* non text-box case handled separately */ - ct = chartransdata; - float yoff; + /* Non text-box case handled separately. */ + float yoff = 0.0f; - if (cu->align_y == CU_ALIGN_Y_TOP) { - yoff = -linedist; - } - else if (cu->align_y == CU_ALIGN_Y_BOTTOM) { - yoff = (lnr - 1.0f) * linedist; - } - else if (cu->align_y == CU_ALIGN_Y_CENTER) { - yoff = (lnr - 2.0f) * linedist * 0.5f; + switch (cu->align_y) { + case CU_ALIGN_Y_TOP_BASELINE: + break; + case CU_ALIGN_Y_TOP: + yoff = -ASCENT(vfd); + break; + case CU_ALIGN_Y_CENTER: + yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd); + break; + case CU_ALIGN_Y_BOTTOM_BASELINE: + yoff = (lnr - 1) * linedist; + break; + case CU_ALIGN_Y_BOTTOM: + yoff = (lnr - 1) * linedist + DESCENT(vfd); + break; } + ct = chartransdata; for (i = 0; i <= slen; i++) { ct->yof += yoff; ct++; @@ -1071,12 +1112,13 @@ makebreak: } MEM_freeN(lineinfo); + MEM_freeN(i_textbox_array); /* TEXT ON CURVE */ /* Note: Only OB_CURVE objects could have a path */ if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) { - BLI_assert(cu->textoncurve->curve_cache != NULL); - if (cu->textoncurve->curve_cache->path) { + BLI_assert(cu->textoncurve->runtime.curve_cache != NULL); + if (cu->textoncurve->runtime.curve_cache != NULL && cu->textoncurve->runtime.curve_cache->path != NULL) { float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; @@ -1106,7 +1148,7 @@ makebreak: /* we put the x-coordinaat exact at the curve, the y is rotated */ /* length correction */ - distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx); + distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx); timeofs = 0.0f; if (distfac > 1.0f) { @@ -1190,13 +1232,13 @@ makebreak: } } - if (mode == FO_CURSUP || mode == FO_CURSDOWN || mode == FO_PAGEUP || mode == FO_PAGEDOWN) { + if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN)) { ct = &chartransdata[ef->pos]; - if ((mode == FO_CURSUP || mode == FO_PAGEUP) && ct->linenr == 0) { + if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) { /* pass */ } - else if ((mode == FO_CURSDOWN || mode == FO_PAGEDOWN) && ct->linenr == lnr) { + else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) { /* pass */ } else { @@ -1339,6 +1381,8 @@ finally: #undef MARGIN_Y_MIN } +#undef DESCENT +#undef ASCENT bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase) { @@ -1348,6 +1392,7 @@ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase) NULL, NULL, NULL, NULL); } +/** Warning: expects to have access to evaluated data (i.e. passed object should be evaluated one...). */ bool BKE_vfont_to_curve(Object *ob, int mode) { Curve *cu = ob->data; diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 686fe3bda93..57a2d2d4134 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -31,8 +31,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_collection_types.h" #include "DNA_freestyle_types.h" -#include "DNA_group_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" @@ -61,17 +61,21 @@ void BKE_freestyle_config_init(FreestyleConfig *config) BLI_listbase_clear(&config->linesets); } -void BKE_freestyle_config_free(FreestyleConfig *config) +void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user) { FreestyleLineSet *lineset; for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) { if (lineset->group) { - id_us_min(&lineset->group->id); + if (do_id_user) { + id_us_min(&lineset->group->id); + } lineset->group = NULL; } if (lineset->linestyle) { - id_us_min(&lineset->linestyle->id); + if (do_id_user) { + id_us_min(&lineset->linestyle->id); + } lineset->linestyle = NULL; } } @@ -79,7 +83,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config) BLI_freelistN(&config->modules); } -void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag) +void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag) { FreestyleLineSet *lineset, *new_lineset; FreestyleModuleConfig *module, *new_module; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index a0d759118ec..f2225bca3f5 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -39,26 +39,84 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_math_color.h" #include "BLI_string_utils.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" #include "BLT_translation.h" +#include "DNA_anim_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" #include "DNA_gpencil_types.h" #include "DNA_userdef_types.h" #include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "BKE_context.h" +#include "BKE_action.h" #include "BKE_animsys.h" +#include "BKE_deform.h" #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_colortools.h" +#include "BKE_icons.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_material.h" +#include "DEG_depsgraph.h" /* ************************************************** */ -/* GENERAL STUFF */ +/* Draw Engine */ -/* --------- Memory Management ------------ */ +void(*BKE_gpencil_batch_cache_dirty_tag_cb)(bGPdata *gpd) = NULL; +void(*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL; + +void BKE_gpencil_batch_cache_dirty_tag(bGPdata *gpd) +{ + if (gpd) { + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + BKE_gpencil_batch_cache_dirty_tag_cb(gpd); + } +} + +void BKE_gpencil_batch_cache_free(bGPdata *gpd) +{ + if (gpd) { + BKE_gpencil_batch_cache_free_cb(gpd); + } +} + +/* ************************************************** */ +/* Memory Management */ + +/* clean vertex groups weights */ +void BKE_gpencil_free_point_weights(MDeformVert *dvert) +{ + if (dvert == NULL) { + return; + } + MEM_SAFE_FREE(dvert->dw); +} + +void BKE_gpencil_free_stroke_weights(bGPDstroke *gps) +{ + if (gps == NULL) { + return; + } + + if (gps->dvert == NULL) { + return; + } + + for (int i = 0; i < gps->totpoints; i++) { + MDeformVert *dvert = &gps->dvert[i]; + BKE_gpencil_free_point_weights(dvert); + } +} /* free stroke, doesn't unlink from any listbase */ void BKE_gpencil_free_stroke(bGPDstroke *gps) @@ -66,10 +124,14 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps) if (gps == NULL) { return; } - /* free stroke memory arrays, then stroke itself */ - if (gps->points) + if (gps->points) { MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } if (gps->triangles) MEM_freeN(gps->triangles); @@ -92,6 +154,24 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf) return changed; } +/* Free strokes and colors belonging to a gp-frame */ +bool BKE_gpencil_free_frame_runtime_data(bGPDframe *derived_gpf) +{ + bGPDstroke *gps_next; + if (!derived_gpf) { + return false; + } + + /* free strokes */ + for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) { + gps_next = gps->next; + BKE_gpencil_free_stroke(gps); + } + BLI_listbase_clear(&derived_gpf->strokes); + + return true; +} + /* Free all of a gp-layer's frames */ void BKE_gpencil_free_frames(bGPDlayer *gpl) { @@ -111,101 +191,90 @@ void BKE_gpencil_free_frames(bGPDlayer *gpl) gpl->actframe = NULL; } -/* Free all of a gp-colors */ -static void free_gpencil_colors(bGPDpalette *palette) -{ - /* error checking */ - if (palette == NULL) { - return; - } - /* free colors */ - BLI_freelistN(&palette->colors); -} -/* Free all of the gp-palettes and colors */ -void BKE_gpencil_free_palettes(ListBase *list) +/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ +void BKE_gpencil_free_layers(ListBase *list) { - bGPDpalette *palette_next; + bGPDlayer *gpl_next; /* error checking */ - if (list == NULL) { - return; - } + if (list == NULL) return; - /* delete palettes */ - for (bGPDpalette *palette = list->first; palette; palette = palette_next) { - palette_next = palette->next; - /* free palette colors */ - free_gpencil_colors(palette); + /* delete layers */ + for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) { + gpl_next = gpl->next; - MEM_freeN(palette); + /* free layers and their data */ + BKE_gpencil_free_frames(gpl); + BLI_freelinkN(list, gpl); } - BLI_listbase_clear(list); } -/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */ -void BKE_gpencil_free_brushes(ListBase *list) +/* clear all runtime derived data */ +static void BKE_gpencil_clear_derived(bGPDlayer *gpl) { - bGPDbrush *brush_next; - - /* error checking */ - if (list == NULL) { + if (gpl->runtime.derived_array == NULL) { return; } - /* delete brushes */ - for (bGPDbrush *brush = list->first; brush; brush = brush_next) { - brush_next = brush->next; - /* free curves */ - if (brush->cur_sensitivity) { - curvemapping_free(brush->cur_sensitivity); - } - if (brush->cur_strength) { - curvemapping_free(brush->cur_strength); - } - if (brush->cur_jitter) { - curvemapping_free(brush->cur_jitter); - } - - MEM_freeN(brush); + for (int i = 0; i < gpl->runtime.len_derived; i++) { + bGPDframe *derived_gpf = &gpl->runtime.derived_array[i]; + BKE_gpencil_free_frame_runtime_data(derived_gpf); + derived_gpf = NULL; } - BLI_listbase_clear(list); + gpl->runtime.len_derived = 0; + MEM_SAFE_FREE(gpl->runtime.derived_array); } -/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ -void BKE_gpencil_free_layers(ListBase *list) +/* Free all of the gp-layers temp data*/ +static void BKE_gpencil_free_layers_temp_data(ListBase *list) { bGPDlayer *gpl_next; /* error checking */ if (list == NULL) return; - /* delete layers */ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) { gpl_next = gpl->next; + BKE_gpencil_clear_derived(gpl); + } +} - /* free layers and their data */ - BKE_gpencil_free_frames(gpl); - BLI_freelinkN(list, gpl); +/* Free temp gpf derived frames */ +void BKE_gpencil_free_derived_frames(bGPdata *gpd) +{ + /* error checking */ + if (gpd == NULL) return; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + BKE_gpencil_clear_derived(gpl); } } /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ -void BKE_gpencil_free(bGPdata *gpd, bool free_palettes) +void BKE_gpencil_free(bGPdata *gpd, bool free_all) { + /* clear animation data */ BKE_animdata_free(&gpd->id, false); /* free layers */ + if (free_all) { + BKE_gpencil_free_layers_temp_data(&gpd->layers); + } BKE_gpencil_free_layers(&gpd->layers); - /* free palettes */ - if (free_palettes) { - BKE_gpencil_free_palettes(&gpd->palettes); + /* materials */ + MEM_SAFE_FREE(gpd->mat); + + /* free all data */ + if (free_all) { + /* clear cache */ + BKE_gpencil_batch_cache_free(gpd); } } -/* -------- Container Creation ---------- */ +/* ************************************************** */ +/* Container Creation */ /* add a new gp-frame to the given layer */ bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe) @@ -317,7 +386,8 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) /* add a new gp-layer and make it the active layer */ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive) { - bGPDlayer *gpl; + bGPDlayer *gpl = NULL; + bGPDlayer *gpl_active = NULL; /* check that list is ok */ if (gpd == NULL) @@ -326,31 +396,42 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti /* allocate memory for frame and add to end of list */ gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer"); - /* add to datablock */ - BLI_addtail(&gpd->layers, gpl); - - /* set basic settings */ - copy_v4_v4(gpl->color, U.gpencil_new_layer_col); - /* Since GPv2 thickness must be 0 */ - gpl->thickness = 0; + gpl_active = BKE_gpencil_layer_getactive(gpd); - gpl->opacity = 1.0f; - - /* onion-skinning settings */ - if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) - gpl->flag |= GP_LAYER_ONIONSKIN; + /* add to datablock */ + if (gpl_active == NULL) { + BLI_addtail(&gpd->layers, gpl); + } + else { + /* if active layer, add after that layer */ + BLI_insertlinkafter(&gpd->layers, gpl_active, gpl); + } - gpl->flag |= (GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL); + /* annotation vs GP Object behaviour is slightly different */ + if (gpd->flag & GP_DATA_ANNOTATIONS) { + /* set default color of new strokes for this layer */ + copy_v4_v4(gpl->color, U.gpencil_new_layer_col); + gpl->opacity = 1.0f; - ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */ - ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */ + /* set default thickness of new strokes for this layer */ + gpl->thickness = 3; - /* high quality fill by default */ - gpl->flag |= GP_LAYER_HQ_FILL; + } + else { + /* thickness parameter represents "thickness change", not absolute thickness */ + gpl->thickness = 0; + gpl->opacity = 1.0f; + /* onion-skinning settings */ + gpl->onion_flag |= GP_LAYER_ONIONSKIN; + } /* auto-name */ BLI_strncpy(gpl->info, name, sizeof(gpl->info)); - BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); + BLI_uniquename(&gpd->layers, gpl, + (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"), + '.', + offsetof(bGPDlayer, info), + sizeof(gpl->info)); /* make this one the active one */ if (setactive) @@ -360,292 +441,148 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti return gpl; } -/* add a new gp-palette and make it the active */ -bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive) -{ - bGPDpalette *palette; - - /* check that list is ok */ - if (gpd == NULL) { - return NULL; - } - - /* allocate memory and add to end of list */ - palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette"); - - /* add to datablock */ - BLI_addtail(&gpd->palettes, palette); - - /* set basic settings */ - /* auto-name */ - BLI_strncpy(palette->info, name, sizeof(palette->info)); - BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info), - sizeof(palette->info)); - - /* make this one the active one */ - /* NOTE: Always make this active if there's nothing else yet (T50123) */ - if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) { - BKE_gpencil_palette_setactive(gpd, palette); - } - - /* return palette */ - return palette; -} - -/* create a set of default drawing brushes with predefined presets */ -void BKE_gpencil_brush_init_presets(ToolSettings *ts) +/* add a new gp-datablock */ +bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) { - bGPDbrush *brush; - /* Basic brush */ - brush = BKE_gpencil_brush_addnew(ts, "Basic", true); - brush->thickness = 3.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.0f; - brush->flag |= GP_BRUSH_USE_PRESSURE; - - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->draw_random_press = 0.0f; - - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; - - brush->draw_smoothfac = 0.0f; - brush->draw_smoothlvl = 1; - brush->sublevel = 0; - brush->draw_random_sub = 0.0f; - - /* Pencil brush */ - brush = BKE_gpencil_brush_addnew(ts, "Pencil", false); - brush->thickness = 7.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.0f; - brush->flag |= GP_BRUSH_USE_PRESSURE; - - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 0.7f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->draw_random_press = 0.0f; - - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; - - brush->draw_smoothfac = 1.0f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; - - /* Ink brush */ - brush = BKE_gpencil_brush_addnew(ts, "Ink", false); - brush->thickness = 7.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.6f; - brush->flag |= GP_BRUSH_USE_PRESSURE; - - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->draw_random_press = 0.0f; - - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + bGPdata *gpd; - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; + /* allocate memory for a new block */ + gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0); - brush->draw_smoothfac = 1.1f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; + /* initial settings */ + gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND); - /* Ink Noise brush */ - brush = BKE_gpencil_brush_addnew(ts, "Ink noise", false); - brush->thickness = 6.0f; - brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.611f; - brush->flag |= GP_BRUSH_USE_PRESSURE; + /* general flags */ + gpd->flag |= GP_DATA_VIEWALIGN; + gpd->flag |= GP_DATA_STROKE_FORCE_RECALC; - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + /* GP object specific settings */ + ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f); - brush->draw_random_press = 1.0f; + gpd->xray_mode = GP_XRAY_3DSPACE; + gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + /* grid settings */ + ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color + ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale + gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; + /* onion-skinning settings (datablock level) */ + gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL); + gpd->onion_flag |= GP_ONION_FADE; + gpd->onion_mode = GP_ONION_MODE_RELATIVE; + gpd->onion_factor = 0.5f; + ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */ + ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */ + gpd->gstep = 1; + gpd->gstep_next = 1; - brush->draw_smoothfac = 1.1f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; + return gpd; +} - /* Marker brush */ - brush = BKE_gpencil_brush_addnew(ts, "Marker", false); - brush->thickness = 10.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 2.0f; - brush->flag &= ~GP_BRUSH_USE_PRESSURE; - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE; +/* ************************************************** */ +/* Primitive Creation */ +/* Utilities for easier bulk-creation of geometry */ - brush->draw_random_press = 0.0f; +/** + * Populate stroke with point data from data buffers + * + * \param array Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values + * \param mat 4x4 transform matrix to transform points into the right coordinate space + */ +void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, const int totpoints, const float mat[4][4]) +{ + for (int i = 0; i < totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + const int x = GP_PRIM_DATABUF_SIZE * i; - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + pt->x = array[x]; + pt->y = array[x + 1]; + pt->z = array[x + 2]; + mul_m4_v3(mat, &pt->x); - brush->draw_angle = M_PI_4; /* 45 degrees */ - brush->draw_angle_factor = 1.0f; + pt->pressure = array[x + 3]; + pt->strength = array[x + 4]; + } +} - brush->draw_smoothfac = 1.0f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; +/* Create a new stroke, with pre-allocated data buffers */ +bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness) +{ + /* allocate memory for a new stroke */ + bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); - /* Crayon brush */ - brush = BKE_gpencil_brush_addnew(ts, "Crayon", false); - brush->thickness = 10.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 3.0f; - brush->flag &= ~GP_BRUSH_USE_PRESSURE; + gps->thickness = thickness * 25; + gps->inittime = 0; - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 0.140f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + /* enable recalculation flag by default */ + gps->flag = GP_STROKE_RECALC_CACHES | GP_STROKE_3DSPACE; - brush->draw_random_press = 0.0f; + gps->totpoints = totpoints; + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + /* initialize triangle memory to dummy data */ + gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation"); + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; + gps->mat_nr = mat_idx; - brush->draw_smoothfac = 0.0f; - brush->draw_smoothlvl = 1; - brush->sublevel = 2; - brush->draw_random_sub = 0.5f; + /* add to frame */ + BLI_addtail(&gpf->strokes, gps); + return gps; } -/* add a new gp-brush and make it the active */ -bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive) -{ - bGPDbrush *brush; - /* check that list is ok */ - if (ts == NULL) { - return NULL; - } - - /* allocate memory and add to end of list */ - brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush"); - - /* add to datablock */ - BLI_addtail(&ts->gp_brushes, brush); - - /* set basic settings */ - brush->thickness = 3; - brush->draw_smoothlvl = 1; - brush->flag |= GP_BRUSH_USE_PRESSURE; - brush->draw_sensitivity = 1.0f; - brush->draw_strength = 1.0f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - /* curves */ - brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - - /* auto-name */ - BLI_strncpy(brush->info, name, sizeof(brush->info)); - BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info)); +/* ************************************************** */ +/* Data Duplication */ - /* make this one the active one */ - if (setactive) { - BKE_gpencil_brush_setactive(ts, brush); +/* make a copy of a given gpencil weights */ +void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst) +{ + if (gps_src == NULL) { + return; } + BLI_assert(gps_src->totpoints == gps_dst->totpoints); - /* return brush */ - return brush; + BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints); } -/* add a new gp-palettecolor and make it the active */ -bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive) +/* make a copy of a given gpencil stroke */ +bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src) { - bGPDpalettecolor *palcolor; + bGPDstroke *gps_dst = NULL; - /* check that list is ok */ - if (palette == NULL) { - return NULL; - } + gps_dst = MEM_dupallocN(gps_src); + gps_dst->prev = gps_dst->next = NULL; - /* allocate memory and add to end of list */ - palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor"); + gps_dst->points = MEM_dupallocN(gps_src->points); - /* add to datablock */ - BLI_addtail(&palette->colors, palcolor); - - /* set basic settings */ - palcolor->flag |= PC_COLOR_HQ_FILL; - copy_v4_v4(palcolor->color, U.gpencil_new_layer_col); - ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f); - - /* auto-name */ - BLI_strncpy(palcolor->info, name, sizeof(palcolor->info)); - BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info), - sizeof(palcolor->info)); - - /* make this one the active one */ - if (setactive) { - BKE_gpencil_palettecolor_setactive(palette, palcolor); + if (gps_src->dvert != NULL) { + gps_dst->dvert = MEM_dupallocN(gps_src->dvert); + BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); + } + else { + gps_dst->dvert = NULL; } - /* return palette color */ - return palcolor; -} - -/* add a new gp-datablock */ -bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) -{ - bGPdata *gpd; - - /* allocate memory for a new block */ - gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0); - - /* initial settings */ - gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND); - - /* for now, stick to view is also enabled by default - * since this is more useful... + /* Don't clear triangles, so that modifier evaluation can just use + * this without extra work first. Most places that need to force + * this data to get recalculated will destroy the data anyway though. */ - gpd->flag |= GP_DATA_VIEWALIGN; + gps_dst->triangles = MEM_dupallocN(gps_dst->triangles); + /* gps_dst->flag |= GP_STROKE_RECALC_CACHES; */ - return gpd; + /* return new stroke */ + return gps_dst; } -/* -------- Data Duplication ---------- */ - /* make a copy of a given gpencil frame */ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) { - bGPDstroke *gps_dst; + bGPDstroke *gps_dst = NULL; bGPDframe *gpf_dst; /* error checking */ @@ -660,11 +597,8 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) /* copy strokes */ BLI_listbase_clear(&gpf_dst->strokes); for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { - /* make copy of source stroke, then adjust pointer to points too */ - gps_dst = MEM_dupallocN(gps_src); - gps_dst->points = MEM_dupallocN(gps_src->points); - gps_dst->triangles = MEM_dupallocN(gps_src->triangles); - gps_dst->flag |= GP_STROKE_RECALC_CACHES; + /* make copy of source stroke */ + gps_dst = BKE_gpencil_stroke_duplicate(gps_src); BLI_addtail(&gpf_dst->strokes, gps_dst); } @@ -672,55 +606,24 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) return gpf_dst; } -/* make a copy of a given gpencil brush */ -bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src) +/* make a copy of strokes between gpencil frames */ +void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst) { - bGPDbrush *brush_dst; - + bGPDstroke *gps_dst = NULL; /* error checking */ - if (brush_src == NULL) { - return NULL; - } - - /* make a copy of source brush */ - brush_dst = MEM_dupallocN(brush_src); - brush_dst->prev = brush_dst->next = NULL; - /* make a copy of curves */ - brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity); - brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength); - brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter); - - /* return new brush */ - return brush_dst; -} - -/* make a copy of a given gpencil palette */ -bGPDpalette *BKE_gpencil_palette_duplicate(const bGPDpalette *palette_src) -{ - bGPDpalette *palette_dst; - const bGPDpalettecolor *palcolor_src; - bGPDpalettecolor *palcolord_dst; - - /* error checking */ - if (palette_src == NULL) { - return NULL; + if ((gpf_src == NULL) || (gpf_dst == NULL)) { + return; } - /* make a copy of source palette */ - palette_dst = MEM_dupallocN(palette_src); - palette_dst->prev = palette_dst->next = NULL; - - /* copy colors */ - BLI_listbase_clear(&palette_dst->colors); - for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) { - /* make a copy of source */ - palcolord_dst = MEM_dupallocN(palcolor_src); - BLI_addtail(&palette_dst->colors, palcolord_dst); + /* copy strokes */ + BLI_listbase_clear(&gpf_dst->strokes); + for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { + /* make copy of source stroke */ + gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + BLI_addtail(&gpf_dst->strokes, gps_dst); } - - /* return new palette */ - return palette_dst; } + /* make a copy of a given gpencil layer */ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) { @@ -736,6 +639,8 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) /* make a copy of source layer */ gpl_dst = MEM_dupallocN(gpl_src); gpl_dst->prev = gpl_dst->next = NULL; + gpl_dst->runtime.derived_array = NULL; + gpl_dst->runtime.len_derived = 0; /* copy frames */ BLI_listbase_clear(&gpl_dst->frames); @@ -755,14 +660,19 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) /** * Only copy internal data of GreasePencil ID from source to already allocated/initialized destination. - * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * You probably never want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. * * WARNING! This function will not handle ID user count! * * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag)) +void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag)) { + /* duplicate material array */ + if (gpd_src->mat) { + gpd_dst->mat = MEM_dupallocN(gpd_src->mat); + } + /* copy layers */ BLI_listbase_clear(&gpd_dst->layers); for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { @@ -771,45 +681,45 @@ void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata BLI_addtail(&gpd_dst->layers, gpl_dst); } - /* copy palettes */ - BLI_listbase_clear(&gpd_dst->palettes); - for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) { - bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */ - BLI_addtail(&gpd_dst->palettes, palette_dst); - } +} + +/* Standard API to make a copy of GP datablock, separate from copying its data */ +bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd) +{ + bGPdata *gpd_copy; + BKE_id_copy_ex(bmain, &gpd->id, (ID **)&gpd_copy, 0, false); + return gpd_copy; } /* make a copy of a given gpencil datablock */ +// XXX: Should this be deprecated? bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) { + bGPdata *gpd_dst; + /* Yuck and super-uber-hyper yuck!!! * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it, * so for now keep old code for that one. */ - if (internal_copy) { - const bGPDlayer *gpl_src; - bGPDlayer *gpl_dst; - bGPdata *gpd_dst; + /* error checking */ + if (gpd_src == NULL) { + return NULL; + } + + if (internal_copy) { /* make a straight copy for undo buffers used during stroke drawing */ gpd_dst = MEM_dupallocN(gpd_src); - - /* copy layers */ - BLI_listbase_clear(&gpd_dst->layers); - for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { - /* make a copy of source layer and its data */ - gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); - BLI_addtail(&gpd_dst->layers, gpl_dst); - } - - /* return new */ - return gpd_dst; } else { BLI_assert(bmain != NULL); - bGPdata *gpd_copy; - BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false); - return gpd_copy; + BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_dst, 0, false); } + + /* Copy internal data (layers, etc.) */ + BKE_gpencil_copy_data(gpd_dst, gpd_src, 0); + + /* return new */ + return gpd_dst; } void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) @@ -817,7 +727,8 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local); } -/* -------- GP-Stroke API --------- */ +/* ************************************************** */ +/* GP Stroke API */ /* ensure selection status of stroke is in sync with its points */ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps) @@ -842,7 +753,8 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps) } } -/* -------- GP-Frame API ---------- */ +/* ************************************************** */ +/* GP Frame API */ /* delete the last stroke of the given frame */ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) @@ -855,18 +767,25 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) return; /* free the stroke and its data */ - MEM_freeN(gps->points); + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } MEM_freeN(gps->triangles); BLI_freelinkN(&gpf->strokes, gps); /* if frame has no strokes after this, delete it */ if (BLI_listbase_is_empty(&gpf->strokes)) { BKE_gpencil_layer_delframe(gpl, gpf); - BKE_gpencil_layer_getframe(gpl, cfra, 0); + BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV); } } -/* -------- GP-Layer API ---------- */ +/* ************************************************** */ +/* GP Layer API */ /* Check if the given layer is able to be edited or not */ bool gpencil_layer_is_editable(const bGPDlayer *gpl) @@ -1048,8 +967,6 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) */ if (gpl->actframe == gpf) gpl->actframe = gpf->prev; - else - gpl->actframe = NULL; /* free the frame and its data */ changed = BKE_gpencil_free_strokes(gpf); @@ -1087,11 +1004,18 @@ void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) return; /* loop over layers deactivating all */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { gpl->flag &= ~GP_LAYER_ACTIVE; + if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) { + gpl->flag |= GP_LAYER_LOCKED; + } + } /* set as active one */ active->flag |= GP_LAYER_ACTIVE; + if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) { + active->flag &= ~GP_LAYER_LOCKED; + } } /* delete the active gp-layer */ @@ -1103,255 +1027,581 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl) /* free layer */ BKE_gpencil_free_frames(gpl); + + /* free icon providing preview of icon color */ + BKE_icon_delete(gpl->runtime.icon_id); + + /* free derived data */ + BKE_gpencil_clear_derived(gpl); + BLI_freelinkN(&gpd->layers, gpl); } -/* ************************************************** */ -/* get the active gp-brush for editing */ -bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts) +Material *BKE_gpencil_get_material_from_brush(Brush *brush) { - bGPDbrush *brush; + Material *ma = NULL; - /* error checking */ - if (ELEM(NULL, ts, ts->gp_brushes.first)) { - return NULL; + if ((brush != NULL) && (brush->gpencil_settings != NULL) && + (brush->gpencil_settings->material != NULL)) + { + ma = brush->gpencil_settings->material; } - /* loop over brushes until found (assume only one active) */ - for (brush = ts->gp_brushes.first; brush; brush = brush->next) { - if (brush->flag & GP_BRUSH_ACTIVE) { - return brush; + return ma; +} + +/* Get active color, and add all default settings if we don't find anything */ +Material *BKE_gpencil_material_ensure(Main *bmain, Object *ob) +{ + Material *ma = NULL; + + /* sanity checks */ + if (ELEM(NULL, bmain, ob)) + return NULL; + + ma = give_current_material(ob, ob->actcol); + if (ma == NULL) { + if (ob->totcol == 0) { + BKE_object_material_slot_add(bmain, ob); } + ma = BKE_material_add_gpencil(bmain, DATA_("Material")); + assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF); + } + else if (ma->gp_style == NULL) { + BKE_material_init_gpencil_settings(ma); } - /* no active brush found */ - return NULL; + return ma; } -/* set the active gp-brush */ -void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active) +/* ************************************************** */ +/* GP Object - Boundbox Support */ + +/** + * Get min/max coordinate bounds for single stroke + * \return Returns whether we found any selected points + */ +bool BKE_gpencil_stroke_minmax( + const bGPDstroke *gps, const bool use_select, + float r_min[3], float r_max[3]) { - bGPDbrush *brush; + const bGPDspoint *pt; + int i; + bool changed = false; - /* error checking */ - if (ELEM(NULL, ts, ts->gp_brushes.first, active)) { - return; - } + if (ELEM(NULL, gps, r_min, r_max)) + return false; - /* loop over brushes deactivating all */ - for (brush = ts->gp_brushes.first; brush; brush = brush->next) { - brush->flag &= ~GP_BRUSH_ACTIVE; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) { + minmax_v3v3_v3(r_min, r_max, &pt->x); + changed = true; + } } - - /* set as active one */ - active->flag |= GP_BRUSH_ACTIVE; + return changed; } -/* delete the active gp-brush */ -void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush) +/* get min/max bounds of all strokes in GP datablock */ +bool BKE_gpencil_data_minmax(Object *ob, const bGPdata *gpd, float r_min[3], float r_max[3]) { - /* error checking */ - if (ELEM(NULL, ts, brush)) { - return; - } + float bmat[3][3]; + bool changed = false; + + INIT_MINMAX(r_min, r_max); + + if (gpd == NULL) + return changed; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + bGPDframe *gpf = gpl->actframe; - /* free curves */ - if (brush->cur_sensitivity) { - curvemapping_free(brush->cur_sensitivity); + if (gpf != NULL) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); + } + } } - if (brush->cur_strength) { - curvemapping_free(brush->cur_strength); + + if ((changed) && (ob)) { + copy_m3_m4(bmat, ob->obmat); + mul_m3_v3(bmat, r_min); + add_v3_v3(r_min, ob->obmat[3]); + mul_m3_v3(bmat, r_max); + add_v3_v3(r_max, ob->obmat[3]); } - if (brush->cur_jitter) { - curvemapping_free(brush->cur_jitter); + + return changed; +} + +bool BKE_gpencil_stroke_select_check( + const bGPDstroke *gps) +{ + const bGPDspoint *pt; + int i; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + return true; + } } + return false; +} + +/* compute center of bounding box */ +void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3]) +{ + float min[3], max[3], tot[3]; + + BKE_gpencil_data_minmax(NULL, gpd, min, max); - /* free */ - BLI_freelinkN(&ts->gp_brushes, brush); + add_v3_v3v3(tot, min, max); + mul_v3_v3fl(r_centroid, tot, 0.5f); } -/* ************************************************** */ -/* get the active gp-palette for editing */ -bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd) + +/* create bounding box values */ +static void boundbox_gpencil(Object *ob) { - bGPDpalette *palette; + BoundBox *bb; + bGPdata *gpd; + float min[3], max[3]; - /* error checking */ - if (ELEM(NULL, gpd, gpd->palettes.first)) { - return NULL; + if (ob->bb == NULL) { + ob->bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); } - /* loop over palettes until found (assume only one active) */ - for (palette = gpd->palettes.first; palette; palette = palette->next) { - if (palette->flag & PL_PALETTE_ACTIVE) - return palette; - } + bb = ob->bb; + gpd = ob->data; - /* no active palette found */ - return NULL; + BKE_gpencil_data_minmax(NULL, gpd, min, max); + BKE_boundbox_init_from_minmax(bb, min, max); + + bb->flag &= ~BOUNDBOX_DIRTY; } -/* set the active gp-palette */ -void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active) +/* get bounding box */ +BoundBox *BKE_gpencil_boundbox_get(Object *ob) { - bGPDpalette *palette; + bGPdata *gpd; - /* error checking */ - if (ELEM(NULL, gpd, gpd->palettes.first, active)) { - return; - } + if (ELEM(NULL, ob, ob->data)) + return NULL; - /* loop over palettes deactivating all */ - for (palette = gpd->palettes.first; palette; palette = palette->next) { - palette->flag &= ~PL_PALETTE_ACTIVE; + gpd = ob->data; + if ((ob->bb) && ((ob->bb->flag & BOUNDBOX_DIRTY) == 0) && + ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0)) + { + return ob->bb; } - /* set as active one */ - active->flag |= PL_PALETTE_ACTIVE; - /* force color recalc */ - BKE_gpencil_palette_change_strokes(gpd); + boundbox_gpencil(ob); + + return ob->bb; } -/* delete the active gp-palette */ -void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette) +/* ************************************************** */ +/* Apply Transforms */ + +void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) { - /* error checking */ - if (ELEM(NULL, gpd, palette)) { + if (gpd == NULL) return; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* FIXME: For now, we just skip parented layers. + * Otherwise, we have to update each frame to find + * the current parent position/effects. + */ + if (gpl->parent) { + continue; + } + + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + int i; + + for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) { + mul_m4_v3(mat, &pt->x); + } + + /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */ + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + } + } } - /* free colors */ - free_gpencil_colors(palette); - BLI_freelinkN(&gpd->palettes, palette); - /* force color recalc */ - BKE_gpencil_palette_change_strokes(gpd); } -/* Set all strokes to recalc the palette color */ -void BKE_gpencil_palette_change_strokes(bGPdata *gpd) -{ - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps; +/* ************************************************** */ +/* GP Object - Vertex Groups */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (gps = gpf->strokes.first; gps; gps = gps->next) { - gps->flag |= GP_STROKE_RECALC_COLOR; +/* remove a vertex group */ +void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) +{ + bGPdata *gpd = ob->data; + MDeformVert *dvert = NULL; + const int def_nr = BLI_findindex(&ob->defbase, defgroup); + + /* Remove points data */ + if (gpd) { + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + if (gps->dvert != NULL) { + for (int i = 0; i < gps->totpoints; i++) { + dvert = &gps->dvert[i]; + MDeformWeight *dw = defvert_find_index(dvert, def_nr); + if (dw != NULL) { + defvert_remove_group(dvert, dw); + } + } + } + } } } } + + /* Remove the group */ + BLI_freelinkN(&ob->defbase, defgroup); + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); } -/* get the active gp-palettecolor for editing */ -bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette) +void BKE_gpencil_dvert_ensure(bGPDstroke *gps) { - bGPDpalettecolor *palcolor; + if (gps->dvert == NULL) { + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); + } +} - /* error checking */ - if (ELEM(NULL, palette, palette->colors.first)) { - return NULL; +/* ************************************************** */ + +/** + * Apply smooth to stroke point + * \param gps Stroke to smooth + * \param i Point index + * \param inf Amount of smoothing to apply + */ +bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf) +{ + bGPDspoint *pt = &gps->points[i]; + // float pressure = 0.0f; + float sco[3] = { 0.0f }; + + /* Do nothing if not enough points to smooth out */ + if (gps->totpoints <= 2) { + return false; } - /* loop over colors until found (assume only one active) */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - if (palcolor->flag & PC_COLOR_ACTIVE) { - return palcolor; + /* Only affect endpoints by a fraction of the normal strength, + * to prevent the stroke from shrinking too much + */ + if ((i == 0) || (i == gps->totpoints - 1)) { + inf *= 0.1f; + } + + /* Compute smoothed coordinate by taking the ones nearby */ + /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */ + { + // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total) + const int steps = 2; + const float average_fac = 1.0f / (float)(steps * 2 + 1); + int step; + + /* add the point itself */ + madd_v3_v3fl(sco, &pt->x, average_fac); + + /* n-steps before/after current point */ + // XXX: review how the endpoints are treated by this algorithm + // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight + for (step = 1; step <= steps; step++) { + bGPDspoint *pt1, *pt2; + int before = i - step; + int after = i + step; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pt1 = &gps->points[before]; + pt2 = &gps->points[after]; + + /* add both these points to the average-sum (s += p[i]/n) */ + madd_v3_v3fl(sco, &pt1->x, average_fac); + madd_v3_v3fl(sco, &pt2->x, average_fac); + } } - /* no active color found */ - return NULL; + /* Based on influence factor, blend between original and optimal smoothed coordinate */ + interp_v3_v3v3(&pt->x, &pt->x, sco, inf); + + return true; } -/* get the gp-palettecolor looking for name */ -bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name) + +/** + * Apply smooth for strength to stroke point */ +bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence) { - /* error checking */ - if (ELEM(NULL, palette, name)) { - return NULL; + bGPDspoint *ptb = &gps->points[point_index]; + + /* Do nothing if not enough points */ + if (gps->totpoints <= 2) { + return false; + } + + /* Compute theoretical optimal value using distances */ + bGPDspoint *pta, *ptc; + int before = point_index - 1; + int after = point_index + 1; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pta = &gps->points[before]; + ptc = &gps->points[after]; + + /* the optimal value is the corresponding to the interpolation of the strength + * at the distance of point b + */ + float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); + /* sometimes the factor can be wrong due stroke geometry, so use middle point */ + if ((fac < 0.0f) || (fac > 1.0f)) { + fac = 0.5f; } + const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength; - return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info)); + /* Based on influence factor, blend between original and optimal */ + ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal; + + return true; } -/* Change color name in all strokes */ -void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname) +/** + * Apply smooth for thickness to stroke point (use pressure) */ +bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence) { - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps; + bGPDspoint *ptb = &gps->points[point_index]; - /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */ - if (ELEM(NULL, gpd, oldname, newname)) - return; + /* Do nothing if not enough points */ + if ((gps->totpoints <= 2) || (point_index < 1)) { + return false; + } - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (gps = gpf->strokes.first; gps; gps = gps->next) { - if (STREQ(gps->colorname, oldname)) { - BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname)); - } - } - } + /* Compute theoretical optimal value using distances */ + bGPDspoint *pta, *ptc; + int before = point_index - 1; + int after = point_index + 1; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pta = &gps->points[before]; + ptc = &gps->points[after]; + + /* the optimal value is the corresponding to the interpolation of the pressure + * at the distance of point b + */ + float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); + /* sometimes the factor can be wrong due stroke geometry, so use middle point */ + if ((fac < 0.0f) || (fac > 1.0f)) { + fac = 0.5f; } + float optimal = interpf(ptc->pressure, pta->pressure, fac); + + /* Based on influence factor, blend between original and optimal */ + ptb->pressure = interpf(optimal, ptb->pressure, influence); + return true; } -/* Delete all strokes of the color */ -void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name) +/** +* Apply smooth for UV rotation to stroke point (use pressure) */ +bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence) { - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps, *gpsn; + bGPDspoint *ptb = &gps->points[point_index]; - /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */ - if (ELEM(NULL, gpd, name)) - return; + /* Do nothing if not enough points */ + if (gps->totpoints <= 2) { + return false; + } - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (gps = gpf->strokes.first; gps; gps = gpsn) { - gpsn = gps->next; - - if (STREQ(gps->colorname, name)) { - if (gps->points) MEM_freeN(gps->points); - if (gps->triangles) MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); - } + /* Compute theoretical optimal value */ + bGPDspoint *pta, *ptc; + int before = point_index - 1; + int after = point_index + 1; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pta = &gps->points[before]; + ptc = &gps->points[after]; + + /* the optimal value is the corresponding to the interpolation of the pressure + * at the distance of point b + */ + float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); + /* sometimes the factor can be wrong due stroke geometry, so use middle point */ + if ((fac < 0.0f) || (fac > 1.0f)) { + fac = 0.5f; + } + float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac); + + /* Based on influence factor, blend between original and optimal */ + ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence); + CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2); + + return true; +} + +/** + * Get range of selected frames in layer. + * Always the active frame is considered as selected, so if no more selected the range + * will be equal to the current active frame. + * \param gpl Layer + * \param r_initframe Number of first selected frame + * \param r_endframe Number of last selected frame + */ +void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe) +{ + *r_initframe = gpl->actframe->framenum; + *r_endframe = gpl->actframe->framenum; + + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if (gpf->flag & GP_FRAME_SELECT) { + if (gpf->framenum < *r_initframe) { + *r_initframe = gpf->framenum; + } + if (gpf->framenum > *r_endframe) { + *r_endframe = gpf->framenum; } } } +} +/** + * Get Falloff factor base on frame range + * \param gpf Frame + * \param actnum Number of active frame in layer + * \param f_init Number of first selected frame + * \param f_end Number of last selected frame + * \param cur_falloff Curve with falloff factors + */ +float BKE_gpencil_multiframe_falloff_calc(bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff) +{ + float fnum = 0.5f; /* default mid curve */ + float value; + + /* check curve is available */ + if (cur_falloff == NULL) { + return 1.0f; + } + + /* frames to the right of the active frame */ + if (gpf->framenum < actnum) { + fnum = (float)(gpf->framenum - f_init) / (actnum - f_init); + fnum *= 0.5f; + value = curvemapping_evaluateF(cur_falloff, 0, fnum); + } + /* frames to the left of the active frame */ + else if (gpf->framenum > actnum) { + fnum = (float)(gpf->framenum - actnum) / (f_end - actnum); + fnum *= 0.5f; + value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f); + } + else { + value = 1.0f; + } + + return value; } -/* set the active gp-palettecolor */ -void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active) +/* remove strokes using a material */ +void BKE_gpencil_material_index_remove(bGPdata *gpd, int index) { - bGPDpalettecolor *palcolor; + bGPDstroke *gps, *gpsn; - /* error checking */ - if (ELEM(NULL, palette, palette->colors.first, active)) { - return; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + if (gps->mat_nr == index) { + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + if (gps->triangles) MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + } + else { + /* reassign strokes */ + if (gps->mat_nr > index) { + gps->mat_nr--; + } + } + } + } + } +} + +void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len) +{ + const short remap_len_short = (short)remap_len; + +#define MAT_NR_REMAP(n) \ + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } ((void)0) + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* reassign strokes */ + MAT_NR_REMAP(gps->mat_nr); + } + } } - /* loop over colors deactivating all */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag &= ~PC_COLOR_ACTIVE; +#undef MAT_NR_REMAP + +} + +/* statistics functions */ +void BKE_gpencil_stats_update(bGPdata *gpd) +{ + gpd->totlayer = 0; + gpd->totframe = 0; + gpd->totstroke = 0; + gpd->totpoint = 0; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + gpd->totlayer++; + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + gpd->totframe++; + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + gpd->totstroke++; + gpd->totpoint += gps->totpoints; + } + } } - /* set as active one */ - active->flag |= PC_COLOR_ACTIVE; } -/* delete the active gp-palettecolor */ -void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor) +/* get material index */ +int BKE_gpencil_get_material_index(Object *ob, Material *ma) { - /* error checking */ - if (ELEM(NULL, palette, palcolor)) { - return; + short *totcol = give_totcolp(ob); + Material *read_ma = NULL; + for (short i = 0; i < *totcol; i++) { + read_ma = give_current_material(ob, i + 1); + if (ma == read_ma) { + return i + 1; + } } - /* free */ - BLI_freelinkN(&palette->colors, palcolor); + return 0; } diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c new file mode 100644 index 00000000000..68691cd3d05 --- /dev/null +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -0,0 +1,826 @@ +/* + * ***** 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) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + + /** \file blender/blenkernel/intern/gpencil_modifier.c + * \ingroup bke + */ + + +#include <stdio.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_string_utils.h" + +#include "BLT_translation.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_gpencil.h" +#include "BKE_lattice.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_object.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "MOD_gpencil_modifiertypes.h" + +static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL }; + +/* *************************************************** */ +/* Geometry Utilities */ + +/* calculate stroke normal using some points */ +void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3]) +{ + if (gps->totpoints < 3) { + zero_v3(r_normal); + return; + } + + bGPDspoint *points = gps->points; + int totpoints = gps->totpoints; + + const bGPDspoint *pt0 = &points[0]; + const bGPDspoint *pt1 = &points[1]; + const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; + + float vec1[3]; + float vec2[3]; + + /* initial vector (p0 -> p1) */ + sub_v3_v3v3(vec1, &pt1->x, &pt0->x); + + /* point vector at 3/4 */ + sub_v3_v3v3(vec2, &pt3->x, &pt0->x); + + /* vector orthogonal to polygon plane */ + cross_v3_v3v3(r_normal, vec1, vec2); + + /* Normalize vector */ + normalize_v3(r_normal); +} + +/* Get points of stroke always flat to view not affected by camera view or view position */ +static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d) +{ + const bGPDspoint *pt0 = &points[0]; + const bGPDspoint *pt1 = &points[1]; + const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; + + float locx[3]; + float locy[3]; + float loc3[3]; + float normal[3]; + + /* local X axis (p0 -> p1) */ + sub_v3_v3v3(locx, &pt1->x, &pt0->x); + + /* point vector at 3/4 */ + sub_v3_v3v3(loc3, &pt3->x, &pt0->x); + + /* vector orthogonal to polygon plane */ + cross_v3_v3v3(normal, locx, loc3); + + /* local Y axis (cross to normal/x axis) */ + cross_v3_v3v3(locy, normal, locx); + + /* Normalize vectors */ + normalize_v3(locx); + normalize_v3(locy); + + /* Get all points in local space */ + for (int i = 0; i < totpoints; i++) { + const bGPDspoint *pt = &points[i]; + float loc[3]; + + /* Get local space using first point as origin */ + sub_v3_v3v3(loc, &pt->x, &pt0->x); + + vec2f *point = &points2d[i]; + point->x = dot_v3v3(loc, locx); + point->y = dot_v3v3(loc, locy); + } + +} + +/* Stroke Simplify ------------------------------------- */ + +/* Reduce a series of points to a simplified version, but + * maintains the general shape of the series + * + * Ramer - Douglas - Peucker algorithm + * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm + */ +static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon) +{ + vec2f *old_points2d = points2d; + int totpoints = gps->totpoints; + char *marked = NULL; + char work; + + int start = 1; + int end = gps->totpoints - 2; + + marked = MEM_callocN(totpoints, "GP marked array"); + marked[start] = 1; + marked[end] = 1; + + work = 1; + int totmarked = 0; + /* while still reducing */ + while (work) { + int ls, le; + work = 0; + + ls = start; + le = start + 1; + + /* while not over interval */ + while (ls < end) { + int max_i = 0; + float v1[2]; + /* divided to get more control */ + float max_dist = epsilon / 10.0f; + + /* find the next marked point */ + while (marked[le] == 0) { + le++; + } + + /* perpendicular vector to ls-le */ + v1[1] = old_points2d[le].x - old_points2d[ls].x; + v1[0] = old_points2d[ls].y - old_points2d[le].y; + + for (int i = ls + 1; i < le; i++) { + float mul; + float dist; + float v2[2]; + + v2[0] = old_points2d[i].x - old_points2d[ls].x; + v2[1] = old_points2d[i].y - old_points2d[ls].y; + + if (v2[0] == 0 && v2[1] == 0) { + continue; + } + + mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]); + + dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]); + + if (dist > max_dist) { + max_dist = dist; + max_i = i; + } + } + + if (max_i != 0) { + work = 1; + marked[max_i] = 1; + totmarked++; + } + + ls = le; + le = ls + 1; + } + } + + /* adding points marked */ + bGPDspoint *old_points = MEM_dupallocN(gps->points); + MDeformVert *old_dvert = NULL; + MDeformVert *dvert_src = NULL; + + if (gps->dvert != NULL) { + old_dvert = MEM_dupallocN(gps->dvert); + } + /* resize gps */ + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + + int j = 0; + for (int i = 0; i < totpoints; i++) { + bGPDspoint *pt_src = &old_points[i]; + bGPDspoint *pt = &gps->points[j]; + + if ((marked[i]) || (i == 0) || (i == totpoints - 1)) { + memcpy(pt, pt_src, sizeof(bGPDspoint)); + if (gps->dvert != NULL) { + dvert_src = &old_dvert[i]; + MDeformVert *dvert = &gps->dvert[j]; + memcpy(dvert, dvert_src, sizeof(MDeformVert)); + if (dvert_src->dw) { + memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); + } + } + j++; + } + else { + if (gps->dvert != NULL) { + dvert_src = &old_dvert[i]; + BKE_gpencil_free_point_weights(dvert_src); + } + } + } + + gps->totpoints = j; + + MEM_SAFE_FREE(old_points); + MEM_SAFE_FREE(old_dvert); + MEM_SAFE_FREE(marked); +} + +/* Simplify stroke using Ramer-Douglas-Peucker algorithm */ +void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor) +{ + /* first create temp data and convert points to 2D */ + vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points"); + + gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d); + + gpencil_rdp_stroke(gps, points2d, factor); + + MEM_SAFE_FREE(points2d); +} + +/* Simplify alternate vertex of stroke except extrems */ +void BKE_gpencil_simplify_fixed(bGPDstroke *gps) +{ + if (gps->totpoints < 5) { + return; + } + + /* save points */ + bGPDspoint *old_points = MEM_dupallocN(gps->points); + MDeformVert *old_dvert = NULL; + MDeformVert *dvert_src = NULL; + + if (gps->dvert != NULL) { + old_dvert = MEM_dupallocN(gps->dvert); + } + + /* resize gps */ + int newtot = (gps->totpoints - 2) / 2; + if (((gps->totpoints - 2) % 2) > 0) { + newtot++; + } + newtot += 2; + + gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); + if (gps->dvert != NULL) { + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); + } + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + + int j = 0; + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt_src = &old_points[i]; + bGPDspoint *pt = &gps->points[j]; + + + if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) { + memcpy(pt, pt_src, sizeof(bGPDspoint)); + if (gps->dvert != NULL) { + dvert_src = &old_dvert[i]; + MDeformVert *dvert = &gps->dvert[j]; + memcpy(dvert, dvert_src, sizeof(MDeformVert)); + if (dvert_src->dw) { + memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight)); + } + } + j++; + } + else { + if (gps->dvert != NULL) { + dvert_src = &old_dvert[i]; + BKE_gpencil_free_point_weights(dvert_src); + } + } + } + + gps->totpoints = j; + + MEM_SAFE_FREE(old_points); + MEM_SAFE_FREE(old_dvert); +} + +/* *************************************************** */ +/* Modifier Utilities */ + +/* Lattice Modifier ---------------------------------- */ +/* Usually, evaluation of the lattice modifier is self-contained. + * However, since GP's modifiers operate on a per-stroke basis, + * we need to these two extra functions that called before/after + * each loop over all the geometry being evaluated. + */ + + /* init lattice deform data */ +void BKE_gpencil_lattice_init(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (md->type == eGpencilModifierType_Lattice) { + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + Object *latob = NULL; + + latob = mmd->object; + if ((!latob) || (latob->type != OB_LATTICE)) { + return; + } + if (mmd->cache_data) { + end_latt_deform((struct LatticeDeformData *)mmd->cache_data); + } + + /* init deform data */ + mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob); + } + } +} + +/* clear lattice deform data */ +void BKE_gpencil_lattice_clear(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (md->type == eGpencilModifierType_Lattice) { + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + if ((mmd) && (mmd->cache_data)) { + end_latt_deform((struct LatticeDeformData *)mmd->cache_data); + mmd->cache_data = NULL; + } + } + } +} + +/* *************************************************** */ +/* Modifier Methods - Evaluation Loops, etc. */ + +/* check if exist geometry modifiers */ +bool BKE_gpencil_has_geometry_modifiers(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti && mti->generateStrokes) { + return true; + } + } + return false; +} + +/* check if exist time modifiers */ +bool BKE_gpencil_has_time_modifiers(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti && mti->remapTime) { + return true; + } + } + return false; +} + +/* apply stroke modifiers */ +void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render) +{ + GpencilModifierData *md; + bGPdata *gpd = ob->data; + const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); + + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (GPENCIL_MODIFIER_EDIT(md, is_edit)) { + continue; + } + + if (mti && mti->deformStroke) { + mti->deformStroke(md, depsgraph, ob, gpl, gps); + + /* some modifiers could require a recalc of fill triangulation data */ + if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) { + if (ELEM(md->type, + eGpencilModifierType_Armature, + eGpencilModifierType_Hook, + eGpencilModifierType_Lattice, + eGpencilModifierType_Offset)) + { + + gps->flag |= GP_STROKE_RECALC_CACHES; + } + } + } + } + } +} + +/* apply stroke geometry modifiers */ +void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render) +{ + GpencilModifierData *md; + bGPdata *gpd = ob->data; + const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); + + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (GPENCIL_MODIFIER_EDIT(md, is_edit)) { + continue; + } + + if (mti->generateStrokes) { + mti->generateStrokes(md, depsgraph, ob, gpl, gpf); + } + } + } +} + +/* apply time modifiers */ +int BKE_gpencil_time_modifier(Depsgraph *depsgraph, Scene *scene, Object *ob, + bGPDlayer *gpl, int cfra, bool is_render) +{ + GpencilModifierData *md; + bGPdata *gpd = ob->data; + const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); + int nfra = cfra; + + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (GPENCIL_MODIFIER_EDIT(md, is_edit)) { + continue; + } + + if (mti->remapTime) { + nfra = mti->remapTime(md, depsgraph, scene, ob, gpl, cfra); + /* if the frame number changed, don't evaluate more and return */ + if (nfra != cfra) { + return nfra; + } + } + } + } + + /* if no time modifier, return original frame number */ + return nfra; +} +/* *************************************************** */ + +void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, + bGPdata *gpd) +{ + DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd); + int ctime = (int)DEG_get_ctime(depsgraph); + + /* update active frame */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV); + } + + /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()? + * This would be better than inventing our own logic for this stuff... + */ + + /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node) + * later when there's more happening here. For now, let's just keep this in here to avoid + * needing to have one more node slowing down evaluation... + */ + if (DEG_is_active(depsgraph)) { + bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id); + + /* sync "actframe" changes back to main-db too, + * so that editing tools work with copy-on-write + * when the current frame changes + */ + for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) { + gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV); + } + } +} + +void BKE_gpencil_modifier_init(void) +{ + /* Initialize modifier types */ + gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */ +} + +GpencilModifierData *BKE_gpencil_modifier_new(int type) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type); + GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name); + + /* note, this name must be made unique later */ + BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name)); + + md->type = type; + md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded; + md->flag = eGpencilModifierFlag_StaticOverride_Local; + + if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode) + md->mode |= eGpencilModifierMode_Editmode; + + if (mti->initData) mti->initData(md); + + return md; +} + +static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_min(id); + } +} + +void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL); + } + } + + if (mti->freeData) mti->freeData(md); + if (md->error) MEM_freeN(md->error); + + MEM_freeN(md); +} + +void BKE_gpencil_modifier_free(GpencilModifierData *md) +{ + BKE_gpencil_modifier_free_ex(md, 0); +} + +/* check unique name */ +bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd) +{ + if (modifiers && gmd) { + const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type); + return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name)); + } + return false; +} + +bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + return mti->dependsOnTime && mti->dependsOnTime(md); +} + +const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type) +{ + /* type unsigned, no need to check < 0 */ + if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') { + return modifier_gpencil_types[type]; + } + else { + return NULL; + } +} + +void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type); + + /* md_dst may have already be fully initialized with some extra allocated data, + * we need to free it now to avoid memleak. */ + if (mti->freeData) { + mti->freeData(md_dst); + } + + const size_t data_size = sizeof(GpencilModifierData); + const char *md_src_data = ((const char *)md_src) + data_size; + char *md_dst_data = ((char *)md_dst) + data_size; + BLI_assert(data_size <= (size_t)mti->struct_size); + memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size); +} + +static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(id); + } +} + +void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + target->mode = md->mode; + target->flag = md->flag; + + if (mti->copyData) { + mti->copyData(md, target); + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL); + } + } +} + +void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_ex(md, target, 0); +} + +GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + + for (; md; md = md->next) + if (md->type == type) + break; + + return md; +} + +void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + + for (; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti->foreachIDLink) { + mti->foreachIDLink(md, ob, walk, userData); + } + else if (mti->foreachObjectLink) { + /* each Object can masquerade as an ID, so this should be OK */ + GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk; + mti->foreachObjectLink(md, ob, fp, userData); + } + } +} + +void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + + for (; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti->foreachTexLink) + mti->foreachTexLink(md, ob, walk, userData); + } +} + +GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name) +{ + return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name)); +} + +void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) +{ + bGPDspoint *temp_points; + MDeformVert *temp_dverts = NULL; + MDeformVert *dvert = NULL; + MDeformVert *dvert_final = NULL; + MDeformVert *dvert_next = NULL; + int totnewpoints, oldtotpoints; + int i2; + + for (int s = 0; s < level; s++) { + totnewpoints = gps->totpoints - 1; + /* duplicate points in a temp area */ + temp_points = MEM_dupallocN(gps->points); + oldtotpoints = gps->totpoints; + + /* resize the points arrays */ + gps->totpoints += totnewpoints; + gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + if (gps->dvert != NULL) { + temp_dverts = MEM_dupallocN(gps->dvert); + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + } + gps->flag |= GP_STROKE_RECALC_CACHES; + + /* move points from last to first to new place */ + i2 = gps->totpoints - 1; + for (int i = oldtotpoints - 1; i > 0; i--) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *pt_final = &gps->points[i2]; + + copy_v3_v3(&pt_final->x, &pt->x); + pt_final->pressure = pt->pressure; + pt_final->strength = pt->strength; + pt_final->time = pt->time; + pt_final->flag = pt->flag; + + if (gps->dvert != NULL) { + dvert = &temp_dverts[i]; + dvert_final = &gps->dvert[i2]; + dvert_final->totweight = dvert->totweight; + dvert_final->dw = dvert->dw; + } + i2 -= 2; + } + /* interpolate mid points */ + i2 = 1; + for (int i = 0; i < oldtotpoints - 1; i++) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *next = &temp_points[i + 1]; + bGPDspoint *pt_final = &gps->points[i2]; + + /* add a half way point */ + interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); + pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f); + pt_final->strength = interpf(pt->strength, next->strength, 0.5f); + CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); + pt_final->time = interpf(pt->time, next->time, 0.5f); + + if (gps->dvert != NULL) { + dvert = &temp_dverts[i]; + dvert_next = &temp_dverts[i + 1]; + dvert_final = &gps->dvert[i2]; + + dvert_final->totweight = dvert->totweight; + dvert_final->dw = MEM_dupallocN(dvert->dw); + + /* interpolate weight values */ + for (int d = 0; d < dvert->totweight; d++) { + MDeformWeight *dw_a = &dvert->dw[d]; + if (dvert_next->totweight > d) { + MDeformWeight *dw_b = &dvert_next->dw[d]; + MDeformWeight *dw_final = &dvert_final->dw[d]; + dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f); + } + } + } + + i2 += 2; + } + + MEM_SAFE_FREE(temp_points); + MEM_SAFE_FREE(temp_dverts); + + /* move points to smooth stroke (not simple flag )*/ + if ((flag & GP_SUBDIV_SIMPLE) == 0) { + /* duplicate points in a temp area with the new subdivide data */ + temp_points = MEM_dupallocN(gps->points); + + /* extreme points are not changed */ + for (int i = 0; i < gps->totpoints - 2; i++) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *next = &temp_points[i + 1]; + bGPDspoint *pt_final = &gps->points[i + 1]; + + /* move point */ + interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); + } + /* free temp memory */ + MEM_SAFE_FREE(temp_points); + } + + } +} diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c deleted file mode 100644 index 62f608f8565..00000000000 --- a/source/blender/blenkernel/intern/group.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/group.c - * \ingroup bke - */ - - -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_group_types.h" -#include "DNA_material_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_particle_types.h" - -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" - - -#include "BKE_depsgraph.h" -#include "BKE_global.h" -#include "BKE_group.h" -#include "BKE_icons.h" -#include "BKE_library.h" -#include "BKE_main.h" -#include "BKE_object.h" -#include "BKE_scene.h" /* BKE_scene_base_find */ - -static void free_group_object(GroupObject *go) -{ - MEM_freeN(go); -} - -/** Free (or release) any data used by this group (does not free the group itself). */ -void BKE_group_free(Group *group) -{ - /* don't free group itself */ - GroupObject *go; - - /* No animdata here. */ - - while ((go = BLI_pophead(&group->gobject))) { - free_group_object(go); - } - - BKE_previewimg_free(&group->preview); -} - -Group *BKE_group_add(Main *bmain, const char *name) -{ - Group *group; - - group = BKE_libblock_alloc(bmain, ID_GR, name, 0); - id_us_min(&group->id); - id_us_ensure_real(&group->id); - group->layer = (1 << 20) - 1; - - group->preview = NULL; - - return group; -} - -/** - * Only copy internal data of Group ID from source to already allocated/initialized destination. - * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. - * - * WARNING! This function will not handle ID user count! - * - * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). - */ -void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag) -{ - BLI_duplicatelist(&group_dst->gobject, &group_src->gobject); - - /* Do not copy group's preview (same behavior as for objects). */ - if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ - BKE_previewimg_id_copy(&group_dst->id, &group_src->id); - } - else { - group_dst->preview = NULL; - } -} - -Group *BKE_group_copy(Main *bmain, const Group *group) -{ - Group *group_copy; - BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false); - return group_copy; -} - -void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local) -{ - BKE_id_make_local_generic(bmain, &group->id, true, lib_local); -} - -/* external */ -static bool group_object_add_internal(Group *group, Object *ob) -{ - GroupObject *go; - - if (group == NULL || ob == NULL) { - return false; - } - - /* check if the object has been added already */ - if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) { - return false; - } - - go = MEM_callocN(sizeof(GroupObject), "groupobject"); - BLI_addtail(&group->gobject, go); - - go->ob = ob; - id_us_ensure_real(&go->ob->id); - - return true; -} - -bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base) -{ - if (group_object_add_internal(group, object)) { - if ((object->flag & OB_FROMGROUP) == 0) { - - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - - object->flag |= OB_FROMGROUP; - - if (base) - base->flag |= OB_FROMGROUP; - } - return true; - } - else { - return false; - } -} - -/* also used for (ob == NULL) */ -static int group_object_unlink_internal(Group *group, Object *ob) -{ - GroupObject *go, *gon; - int removed = 0; - if (group == NULL) return 0; - - go = group->gobject.first; - while (go) { - gon = go->next; - if (go->ob == ob) { - BLI_remlink(&group->gobject, go); - free_group_object(go); - removed = 1; - /* should break here since an object being in a group twice cant happen? */ - } - go = gon; - } - return removed; -} - -static bool group_object_cyclic_check_internal(Object *object, Group *group) -{ - if (object->dup_group) { - Group *dup_group = object->dup_group; - if ((dup_group->id.tag & LIB_TAG_DOIT) == 0) { - /* Cycle already exists in groups, let's prevent further crappyness */ - return true; - } - /* flag the object to identify cyclic dependencies in further dupli groups */ - dup_group->id.tag &= ~LIB_TAG_DOIT; - - if (dup_group == group) - return true; - else { - GroupObject *gob; - for (gob = dup_group->gobject.first; gob; gob = gob->next) { - if (group_object_cyclic_check_internal(gob->ob, group)) { - return true; - } - } - } - - /* un-flag the object, it's allowed to have the same group multiple times in parallel */ - dup_group->id.tag |= LIB_TAG_DOIT; - } - - return false; -} - -bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group) -{ - /* first flag all groups */ - BKE_main_id_tag_listbase(&bmain->group, LIB_TAG_DOIT, true); - - return group_object_cyclic_check_internal(object, group); -} - -bool BKE_group_object_unlink(Main *bmain, Group *group, Object *object, Scene *scene, Base *base) -{ - if (group_object_unlink_internal(group, object)) { - /* object can be NULL */ - if (object && BKE_group_object_find(bmain, NULL, object) == NULL) { - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - - object->flag &= ~OB_FROMGROUP; - - if (base) - base->flag &= ~OB_FROMGROUP; - } - return true; - } - else { - return false; - } -} - -bool BKE_group_object_exists(Group *group, Object *ob) -{ - if (group == NULL || ob == NULL) { - return false; - } - else { - return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL); - } -} - -Group *BKE_group_object_find(Main *bmain, Group *group, Object *ob) -{ - if (group) - group = group->id.next; - else - group = bmain->group.first; - - while (group) { - if (BKE_group_object_exists(group, ob)) - return group; - group = group->id.next; - } - return NULL; -} - -bool BKE_group_is_animated(Group *group, Object *UNUSED(parent)) -{ - GroupObject *go; - -#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */ - if (parent->nlastrips.first) - return 1; -#endif - - for (go = group->gobject.first; go; go = go->next) - if (go->ob && go->ob->proxy) - return true; - - return false; -} - -#if 0 // add back when timeoffset & animsys work again -/* only replaces object strips or action when parent nla instructs it */ -/* keep checking nla.c though, in case internal structure of strip changes */ -static void group_replaces_nla(Object *parent, Object *target, char mode) -{ - static ListBase nlastrips = {NULL, NULL}; - static bAction *action = NULL; - static bool done = false; - bActionStrip *strip, *nstrip; - - if (mode == 's') { - - for (strip = parent->nlastrips.first; strip; strip = strip->next) { - if (strip->object == target) { - if (done == 0) { - /* clear nla & action from object */ - nlastrips = target->nlastrips; - BLI_listbase_clear(&target->nlastrips); - action = target->action; - target->action = NULL; - target->nlaflag |= OB_NLA_OVERRIDE; - done = true; - } - nstrip = MEM_dupallocN(strip); - BLI_addtail(&target->nlastrips, nstrip); - } - } - } - else if (mode == 'e') { - if (done) { - BLI_freelistN(&target->nlastrips); - target->nlastrips = nlastrips; - target->action = action; - - BLI_listbase_clear(&nlastrips); /* not needed, but yah... :) */ - action = NULL; - done = false; - } - } -} -#endif - -/* puts all group members in local timing system, after this call - * you can draw everything, leaves tags in objects to signal it needs further updating */ - -/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ -void BKE_group_handle_recalc_and_update( - Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group) -{ - GroupObject *go; - -#if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time, - * not just on frame change. - * This isn't working because the animation data is only re-evaluated on frame change so commenting for now - * but when its enabled at some point it will need to be changed so as not to update so much - campbell */ - - /* if animated group... */ - if (parent->nlastrips.first) { - int cfrao; - - /* switch to local time */ - cfrao = scene->r.cfra; - - /* we need a DAG per group... */ - for (go = group->gobject.first; go; go = go->next) { - if (go->ob && go->recalc) { - go->ob->recalc = go->recalc; - - group_replaces_nla(parent, go->ob, 's'); - BKE_object_handle_update(eval_ctx, scene, go->ob); - group_replaces_nla(parent, go->ob, 'e'); - - /* leave recalc tags in case group members are in normal scene */ - go->ob->recalc = go->recalc; - } - } - - /* restore */ - scene->r.cfra = cfrao; - } - else -#endif - { - /* only do existing tags, as set by regular depsgraph */ - for (go = group->gobject.first; go; go = go->next) { - if (go->ob) { - if (go->ob->recalc) { - BKE_object_handle_update(bmain, eval_ctx, scene, go->ob); - } - } - } - } -} diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index e49f24c8120..2a348751365 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -37,23 +37,27 @@ #include "MEM_guardedalloc.h" -#include "DNA_group_types.h" +#include "DNA_brush_types.h" +#include "DNA_collection_types.h" +#include "DNA_gpencil_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" -#include "DNA_brush_types.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_linklist_lockfree.h" #include "BLI_string.h" +#include "BLI_fileops.h" #include "BLI_threads.h" #include "BKE_icons.h" #include "BKE_global.h" /* only for G.background test */ +#include "BKE_studiolight.h" #include "BLI_sys_types.h" // for intptr_t support @@ -63,6 +67,14 @@ #include "IMB_imbuf_types.h" #include "IMB_thumbs.h" +/** + * Only allow non-managed icons to be removed (by Python for eg). + * Previews & ID's have their own functions to remove icons. + */ +enum { + ICON_FLAG_MANAGED = (1 << 0), +}; + /* GLOBALS */ static GHash *gIcons = NULL; @@ -85,6 +97,19 @@ static void icon_free(void *val) Icon *icon = val; if (icon) { + if (icon->obj_type == ICON_DATA_GEOM) { + struct Icon_Geom *obj = icon->obj; + if (obj->mem) { + /* coords & colors are part of this memory. */ + MEM_freeN((void *)obj->mem); + } + else { + MEM_freeN((void *)obj->coords); + MEM_freeN((void *)obj->colors); + } + MEM_freeN(icon->obj); + } + if (icon->drawinfo_free) { icon->drawinfo_free(icon->drawinfo); } @@ -95,6 +120,31 @@ static void icon_free(void *val) } } +static void icon_free_data(int icon_id, Icon *icon) +{ + if (icon->obj_type == ICON_DATA_ID) { + ((ID *)(icon->obj))->icon_id = 0; + } + else if (icon->obj_type == ICON_DATA_PREVIEW) { + ((PreviewImage *)(icon->obj))->icon_id = 0; + } + else if (icon->obj_type == ICON_DATA_GPLAYER) { + ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0; + } + else if (icon->obj_type == ICON_DATA_GEOM) { + ((struct Icon_Geom *)(icon->obj))->icon_id = 0; + } + else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) { + StudioLight *sl = icon->obj; + if (sl != NULL) { + BKE_studiolight_unset_icon_id(sl, icon_id); + } + } + else { + BLI_assert(0); + } +} + /* create an id for a new icon and make sure that ids from deleted icons get reused * after the integer number range is used up */ static int get_next_free_id(void) @@ -282,8 +332,9 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) ID_PRV_CASE(ID_IM, Image); ID_PRV_CASE(ID_BR, Brush); ID_PRV_CASE(ID_OB, Object); - ID_PRV_CASE(ID_GR, Group); + ID_PRV_CASE(ID_GR, Collection); ID_PRV_CASE(ID_SCE, Scene); + ID_PRV_CASE(ID_SCR, bScreen); #undef ID_PRV_CASE default: break; @@ -476,6 +527,7 @@ void BKE_icon_changed(const int icon_id) if (icon) { /* We *only* expect ID-tied icons here, not non-ID icon/preview! */ BLI_assert(icon->id_type != 0); + BLI_assert(icon->obj_type == ICON_DATA_ID); /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here , * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */ @@ -492,22 +544,31 @@ void BKE_icon_changed(const int icon_id) } } -static int icon_id_ensure_create_icon(struct ID *id) +static Icon *icon_create(int icon_id, int obj_type, void *obj) { - BLI_assert(BLI_thread_is_main()); + Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__); - Icon *new_icon = NULL; - - new_icon = MEM_mallocN(sizeof(Icon), __func__); - - new_icon->obj = id; - new_icon->id_type = GS(id->name); + new_icon->obj_type = obj_type; + new_icon->obj = obj; + new_icon->id_type = 0; + new_icon->flag = 0; /* next two lines make sure image gets created */ new_icon->drawinfo = NULL; new_icon->drawinfo_free = NULL; - BLI_ghash_insert(gIcons, POINTER_FROM_INT(id->icon_id), new_icon); + BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon); + + return new_icon; +} + +static int icon_id_ensure_create_icon(struct ID *id) +{ + BLI_assert(BLI_thread_is_main()); + + Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id); + icon->id_type = GS(id->name); + icon->flag = ICON_FLAG_MANAGED; return id->icon_id; } @@ -541,13 +602,49 @@ int BKE_icon_id_ensure(struct ID *id) return icon_id_ensure_create_icon(id); } + +static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl) +{ + BLI_assert(BLI_thread_is_main()); + + /* NOTE: The color previews for GP Layers don't really need + * to be "rendered" to image per se (as it will just be a plain + * colored rectangle), we need to define icon data here so that + * we can store a pointer to the layer data in icon->obj. + */ + Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl); + icon->flag = ICON_FLAG_MANAGED; + + return gpl->runtime.icon_id; +} + +int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl) +{ + /* Never handle icons in non-main thread! */ + BLI_assert(BLI_thread_is_main()); + + if (!gpl || G.background) { + return 0; + } + + if (gpl->runtime.icon_id) + return gpl->runtime.icon_id; + + gpl->runtime.icon_id = get_next_free_id(); + + if (!gpl->runtime.icon_id) { + printf("%s: Internal error - not enough IDs\n", __func__); + return 0; + } + + return icon_gplayer_color_ensure_create_icon(gpl); +} + /** * Return icon id of given preview, or create new icon if not found. */ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) { - Icon *new_icon = NULL; - if (!preview || G.background) return 0; @@ -578,16 +675,8 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) return icon_id_ensure_create_icon(id); } - new_icon = MEM_mallocN(sizeof(Icon), __func__); - - new_icon->obj = preview; - new_icon->id_type = 0; /* Special, tags as non-ID icon/preview. */ - - /* next two lines make sure image gets created */ - new_icon->drawinfo = NULL; - new_icon->drawinfo_free = NULL; - - BLI_ghash_insert(gIcons, POINTER_FROM_INT(preview->icon_id), new_icon); + Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview); + icon->flag = ICON_FLAG_MANAGED; return preview->icon_id; } @@ -649,21 +738,127 @@ void BKE_icon_id_delete(struct ID *id) /** * Remove icon and free data. */ -void BKE_icon_delete(const int icon_id) +bool BKE_icon_delete(const int icon_id) { - Icon *icon; + if (icon_id == 0) { + /* no icon defined for library object */ + return false; + } - if (!icon_id) return; /* no icon defined for library object */ + Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL); + if (icon) { + icon_free_data(icon_id, icon); + icon_free(icon); + return true; + } + else { + return false; + } +} - icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL); +bool BKE_icon_delete_unmanaged(const int icon_id) +{ + if (icon_id == 0) { + /* no icon defined for library object */ + return false; + } + Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL); if (icon) { - if (icon->id_type != 0) { - ((ID *)(icon->obj))->icon_id = 0; + if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) { + BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon); + return false; } else { - ((PreviewImage *)(icon->obj))->icon_id = 0; + icon_free_data(icon_id, icon); + icon_free(icon); + return true; } - icon_free(icon); } + else { + return false; + } +} + +/* -------------------------------------------------------------------- */ +/** \name Geometry Icon + * \{ */ + +int BKE_icon_geom_ensure(struct Icon_Geom *geom) +{ + BLI_assert(BLI_thread_is_main()); + + if (geom->icon_id) { + return geom->icon_id; + } + + geom->icon_id = get_next_free_id(); + + icon_create(geom->icon_id, ICON_DATA_GEOM, geom); + /* Not managed for now, we may want this to be configurable per icon). */ + + return geom->icon_id; +} + +struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len) +{ + BLI_assert(BLI_thread_is_main()); + if (data_len <= 8) { + goto fail; + } + /* Skip the header. */ + data_len -= 8; + const int div = 3 * 2 * 3; + const int coords_len = data_len / div; + if (coords_len * div != data_len) { + goto fail; + } + + const uchar header[4] = {'V', 'C', 'O', 0}; + const uchar *p = data; + if (memcmp(p, header, ARRAY_SIZE(header)) != 0) { + goto fail; + } + p += 4; + + struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__); + geom->coords_range[0] = (int)*p++; + geom->coords_range[1] = (int)*p++; + /* x, y ignored for now */ + p += 2; + + geom->coords_len = coords_len; + geom->coords = (const void *)p; + geom->colors = (const void *)(p + (data_len / 3)); + geom->icon_id = 0; + geom->mem = data; + return geom; + +fail: + MEM_freeN((void *)data); + return NULL; +} + +struct Icon_Geom *BKE_icon_geom_from_file(const char *filename) +{ + BLI_assert(BLI_thread_is_main()); + size_t data_len; + uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len); + if (data == NULL) { + return NULL; + } + return BKE_icon_geom_from_memory(data, data_len); +} + +/** \} */ + +/** \name Studio Light Icon + * \{ */ +int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type) +{ + int icon_id = get_next_free_id(); + Icon *icon = icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl); + icon->id_type = id_type; + return icon_id; } +/** \} */ diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c new file mode 100644 index 00000000000..24576c24953 --- /dev/null +++ b/source/blender/blenkernel/intern/icons_rasterize.c @@ -0,0 +1,146 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenkernel/intern/icons_rasterize.c + * \ingroup bke + */ +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_bitmap_draw_2d.h" +#include "BLI_math_geom.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_icons.h" + +#include "BLI_strict_flags.h" + +struct UserRasterInfo { + int pt[3][2]; + const uint *color; + /* only for smooth shading */ + struct { + float pt_fl[3][2]; + uint color_u[3][4]; + } smooth; + int rect_size[2]; + uint *rect; +}; + +static void tri_fill_flat(int x, int x_end, int y, void *user_data) +{ + struct UserRasterInfo *data = user_data; + uint *p = &data->rect[(y * data->rect_size[1]) + x]; + uint col = data->color[0]; + while (x++ != x_end) { + *p++ = col; + } +} + +static void tri_fill_smooth(int x, int x_end, int y, void *user_data) +{ + struct UserRasterInfo *data = user_data; + uint *p = &data->rect[(y * data->rect_size[1]) + x]; + float pt_step_fl[2] = {(float)x, (float)y}; + while (x++ != x_end) { + float w[3]; + barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w); + + uint col_u[4] = {0, 0, 0, 0}; + for (uint corner = 0; corner < 3; corner++) { + for (uint chan = 0; chan < 4; chan++) { + col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f); + } + } + union { + uint as_u32; + uchar as_bytes[4]; + } col; + col.as_bytes[0] = (uchar)(col_u[0] / 255); + col.as_bytes[1] = (uchar)(col_u[1] / 255); + col.as_bytes[2] = (uchar)(col_u[2] / 255); + col.as_bytes[3] = (uchar)(col_u[3] / 255); + *p++ = col.as_u32; + + pt_step_fl[0] += 1.0f; + } +} + +ImBuf *BKE_icon_geom_rasterize( + const struct Icon_Geom *geom, + const unsigned int size_x, const unsigned int size_y) +{ + const int coords_len = geom->coords_len; + + const uchar (*pos)[2] = geom->coords; + const uint *col = (void *)geom->colors; + + /* TODO(campbell): Currently rasterizes to fixed size, then scales. + * Should rasterize to double size for eg instead. */ + const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)}; + + ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect); + + struct UserRasterInfo data; + + data.rect_size[0] = rect_size[0]; + data.rect_size[1] = rect_size[1]; + + data.rect = ibuf->rect; + + float scale[2]; + const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256); + + if (use_scale) { + scale[0] = ((float)rect_size[0] / 256.0f); + scale[1] = ((float)rect_size[1] / 256.0f); + } + + for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) { + if (use_scale) { + ARRAY_SET_ITEMS(data.pt[0], (int)(pos[0][0] * scale[0]), (int)(pos[0][1] * scale[1])); + ARRAY_SET_ITEMS(data.pt[1], (int)(pos[1][0] * scale[0]), (int)(pos[1][1] * scale[1])); + ARRAY_SET_ITEMS(data.pt[2], (int)(pos[2][0] * scale[0]), (int)(pos[2][1] * scale[1])); + } + else { + ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0])); + ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1])); + ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2])); + } + data.color = col; + if ((col[0] == col[1]) && (col[0] == col[2])) { + BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data); + } + else { + ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], )); + ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], )); + ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], )); + ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), )); + ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), )); + ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), )); + BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data); + } + } + IMB_scaleImBuf(ibuf, size_x, size_y); + return ibuf; +} diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index d995dce1259..d97c00f8229 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -39,7 +39,7 @@ #include "BLT_translation.h" -#include "BKE_library.h" +#include "BKE_main.h" #include "BKE_idcode.h" typedef struct { @@ -56,44 +56,46 @@ typedef struct { /* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */ static IDType idtypes[] = { /** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */ - { ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE }, - { ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE }, - { ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE }, - { ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */ - { ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE }, - { ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */ - { ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 }, - { ID_LA, "Lamp", "lamps", BLT_I18NCONTEXT_ID_LAMP, IDTYPE_FLAGS_ISLINKABLE }, - { ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 }, - { ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE }, - { ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE }, - { ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE }, - { ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE }, - { ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE }, - { ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE }, - { ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE }, - { ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, 0 }, - { ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */ - { ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE }, - { ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE }, - { ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE }, - { ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE }, - { ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE }, - { ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE }, - { ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 }, + {ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE}, + {ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE}, + {ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE}, + {ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_GR, "Collection", "collections", BLT_I18NCONTEXT_ID_COLLECTION, IDTYPE_FLAGS_ISLINKABLE}, + {ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE}, /* rename gpencil */ + {ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE}, /* deprecated */ + {ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 }, + {ID_LA, "Light", "lights", BLT_I18NCONTEXT_ID_LAMP, IDTYPE_FLAGS_ISLINKABLE}, + {ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 }, + {ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE}, + {ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE}, + {ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE}, + {ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE}, + {ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE}, + {ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE}, + {ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE}, + {ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_LP, "LightProbe", "light_probes", BLT_I18NCONTEXT_ID_LIGHTPROBE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE}, + {ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */ + {ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE}, + {ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE}, + {ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE}, + {ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE}, + {ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE}, + {ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE}, + {ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 }, + {ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE}, /** Keep last, not an ID exactly, only include for completeness */ - { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */ + {ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */ }; /* -1 for ID_ID */ @@ -203,6 +205,7 @@ int BKE_idcode_to_idfilter(const short idcode) CASE_IDFILTER(PA); CASE_IDFILTER(PAL); CASE_IDFILTER(PC); + CASE_IDFILTER(LP); CASE_IDFILTER(SCE); CASE_IDFILTER(SPK); CASE_IDFILTER(SO); @@ -210,6 +213,7 @@ int BKE_idcode_to_idfilter(const short idcode) CASE_IDFILTER(TXT); CASE_IDFILTER(VF); CASE_IDFILTER(WO); + CASE_IDFILTER(WS); default: return 0; } @@ -247,6 +251,7 @@ short BKE_idcode_from_idfilter(const int idfilter) CASE_IDFILTER(PA); CASE_IDFILTER(PAL); CASE_IDFILTER(PC); + CASE_IDFILTER(LP); CASE_IDFILTER(SCE); CASE_IDFILTER(SPK); CASE_IDFILTER(SO); @@ -294,6 +299,7 @@ int BKE_idcode_to_index(const short idcode) CASE_IDINDEX(PA); CASE_IDINDEX(PAL); CASE_IDINDEX(PC); + CASE_IDINDEX(LP); CASE_IDINDEX(SCE); CASE_IDINDEX(SCR); CASE_IDINDEX(SPK); @@ -303,6 +309,7 @@ int BKE_idcode_to_index(const short idcode) CASE_IDINDEX(VF); CASE_IDINDEX(WM); CASE_IDINDEX(WO); + CASE_IDINDEX(WS); } BLI_assert(0); diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 7a526d31567..8cc40d4e74c 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -476,6 +476,7 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) BLI_assert(prop->type == IDP_GROUP); newp = idp_generic_copy(prop, flag); newp->len = prop->len; + newp->subtype = prop->subtype; for (link = prop->data.group.first; link; link = link->next) { BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); @@ -601,8 +602,9 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop) /** * If a property is missing in \a dest, add it. + * Do it recursively. */ -void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite) +void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag) { IDProperty *prop; @@ -611,14 +613,30 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw if (do_overwrite) { for (prop = src->data.group.first; prop; prop = prop->next) { - IDProperty *copy = IDP_CopyProperty(prop); + if (prop->type == IDP_GROUP) { + IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); + + if (prop_exist != NULL) { + IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag); + continue; + } + } + + IDProperty *copy = IDP_CopyProperty_ex(prop, flag); IDP_ReplaceInGroup(dest, copy); } } else { for (prop = src->data.group.first; prop; prop = prop->next) { - if (IDP_GetPropertyFromGroup(dest, prop->name) == NULL) { - IDProperty *copy = IDP_CopyProperty(prop); + IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); + if (prop_exist != NULL) { + if (prop->type == IDP_GROUP) { + IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag); + continue; + } + } + else { + IDProperty *copy = IDP_CopyProperty_ex(prop, flag); dest->len++; BLI_addtail(&dest->data.group, copy); } @@ -627,6 +645,15 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw } /** + * If a property is missing in \a dest, add it. + * Do it recursively. + */ +void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite) +{ + IDP_MergeGroup_ex(dest, src, do_overwrite, 0); +} + +/** * This function has a sanity check to make sure ID properties with the same name don't * get added to the group. * @@ -1067,4 +1094,15 @@ void IDP_ClearProperty(IDProperty *prop) prop->len = prop->totallen = 0; } +void IDP_Reset(IDProperty *prop, const IDProperty *reference) +{ + if (prop == NULL) { + return; + } + IDP_ClearProperty(prop); + if (reference != NULL) { + IDP_MergeGroup(prop, reference, true); + } +} + /** \} */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 1d209dec935..f1a921650f0 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -68,7 +68,6 @@ #include "BLI_timecode.h" /* for stamp timecode format */ #include "BLI_utildefines.h" -#include "BKE_bmfont.h" #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_icons.h" @@ -82,6 +81,7 @@ #include "BKE_scene.h" #include "BKE_node.h" #include "BKE_sequencer.h" /* seq_foreground_frame_get() */ +#include "BKE_workspace.h" #include "BLF_api.h" @@ -185,76 +185,6 @@ void BKE_images_exit(void) BLI_spin_end(&image_spin); } -/* ******** IMAGE PROCESSING ************* */ - -static void de_interlace_ng(struct ImBuf *ibuf) /* neogeo fields */ -{ - struct ImBuf *tbuf1, *tbuf2; - - if (ibuf == NULL) return; - if (ibuf->flags & IB_fields) return; - ibuf->flags |= IB_fields; - - if (ibuf->rect) { - /* make copies */ - tbuf1 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, (int)IB_rect); - tbuf2 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, (int)IB_rect); - - ibuf->x *= 2; - - IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); - IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y); - - ibuf->x /= 2; - IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y); - IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y); - - IMB_freeImBuf(tbuf1); - IMB_freeImBuf(tbuf2); - } - ibuf->y /= 2; -} - -static void de_interlace_st(struct ImBuf *ibuf) /* standard fields */ -{ - struct ImBuf *tbuf1, *tbuf2; - - if (ibuf == NULL) return; - if (ibuf->flags & IB_fields) return; - ibuf->flags |= IB_fields; - - if (ibuf->rect) { - /* make copies */ - tbuf1 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, IB_rect); - tbuf2 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, IB_rect); - - ibuf->x *= 2; - - IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y); - IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y); - - ibuf->x /= 2; - IMB_rectcpy(ibuf, tbuf2, 0, 0, 0, 0, tbuf2->x, tbuf2->y); - IMB_rectcpy(ibuf, tbuf1, 0, tbuf2->y, 0, 0, tbuf1->x, tbuf1->y); - - IMB_freeImBuf(tbuf1); - IMB_freeImBuf(tbuf2); - } - ibuf->y /= 2; -} - -void BKE_image_de_interlace(Image *ima, int odd) -{ - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - if (ibuf) { - if (odd) - de_interlace_st(ibuf); - else - de_interlace_ng(ibuf); - } - BKE_image_release_ibuf(ima, ibuf, NULL); -} - /* ***************** ALLOC & FREE, DATA MANAGING *************** */ static void image_free_cached_frames(Image *image) @@ -341,19 +271,18 @@ void BKE_image_free_buffers(Image *ima) /** Free (or release) any data used by this image (does not free the image itself). */ void BKE_image_free(Image *ima) { - int a; - /* Also frees animdata. */ BKE_image_free_buffers(ima); image_free_packedfiles(ima); - for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) { - if (ima->renders[a]) { - RE_FreeRenderResult(ima->renders[a]); - ima->renders[a] = NULL; + LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) { + if (slot->render) { + RE_FreeRenderResult(slot->render); + slot->render = NULL; } } + BLI_freelistN(&ima->renderslots); BKE_image_free_views(ima); MEM_SAFE_FREE(ima->stereo3d_format); @@ -369,7 +298,6 @@ static void image_init(Image *ima, short source, short type) ima->ok = IMA_OK; - ima->xrep = ima->yrep = 1; ima->aspx = ima->aspy = 1.0; ima->gen_x = 1024; ima->gen_y = 1024; ima->gen_type = IMA_GENTYPE_GRID; @@ -380,6 +308,12 @@ static void image_init(Image *ima, short source, short type) if (source == IMA_SRC_VIEWER) ima->flag |= IMA_VIEW_AS_RENDER; + if (type == IMA_TYPE_R_RESULT) { + for (int i = 0; i < 8; i++) { + BKE_image_add_renderslot(ima, NULL); + } + } + BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings); ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format"); } @@ -466,18 +400,17 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s /* Cleanup stuff that cannot be copied. */ ima_dst->cache = NULL; ima_dst->rr = NULL; - for (int i = 0; i < IMA_MAX_RENDER_SLOT; i++) { - ima_dst->renders[i] = NULL; + + BLI_duplicatelist(&ima_dst->renderslots, &ima_src->renderslots); + LISTBASE_FOREACH(RenderSlot *, slot, &ima_dst->renderslots) { + slot->render = NULL; } BLI_listbase_clear(&ima_dst->anims); - ima_dst->totbind = 0; for (int i = 0; i < TEXTARGET_COUNT; i++) { - ima_dst->bindcode[i] = 0; ima_dst->gputexture[i] = NULL; } - ima_dst->repbind = NULL; if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id); @@ -540,16 +473,14 @@ bool BKE_image_scale(Image *image, int width, int height) return (ibuf != NULL); } -bool BKE_image_has_bindcode(Image *ima) +bool BKE_image_has_opengl_texture(Image *ima) { - bool has_bindcode = false; for (int i = 0; i < TEXTARGET_COUNT; i++) { - if (ima->bindcode[i]) { - has_bindcode = true; - break; + if (ima->gputexture[i]) { + return true; } } - return has_bindcode; + return false; } static void image_init_color_management(Image *ima) @@ -932,21 +863,6 @@ void BKE_image_tag_time(Image *ima) ima->lastused = PIL_check_seconds_timer_i(); } -#if 0 -static void tag_all_images_time(Main *bmain) -{ - Image *ima; - int ctime = PIL_check_seconds_timer_i(); - - ima = bmain->image.first; - while (ima) { - if (ima->bindcode || ima->repbind || ima->ibufs.first) { - ima->lastused = ctime; - } - } -} -#endif - static uintptr_t image_mem_size(Image *image) { uintptr_t size = 0; @@ -1208,7 +1124,6 @@ bool BKE_imtype_is_movie(const char imtype) case R_IMF_IMTYPE_H264: case R_IMF_IMTYPE_THEORA: case R_IMF_IMTYPE_XVID: - case R_IMF_IMTYPE_FRAMESERVER: return true; } return false; @@ -1349,7 +1264,6 @@ char BKE_imtype_from_arg(const char *imtype_arg) else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER; #endif else if (STREQ(imtype_arg, "FFMPEG")) return R_IMF_IMTYPE_FFMPEG; - else if (STREQ(imtype_arg, "FRAMESERVER")) return R_IMF_IMTYPE_FRAMESERVER; #ifdef WITH_CINEON else if (STREQ(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON; else if (STREQ(imtype_arg, "DPX")) return R_IMF_IMTYPE_DPX; @@ -2654,19 +2568,19 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata, } } + for (Camera *cam = mainp->camera.first; cam; cam = cam->id.next) { + for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) { + callback(bgpic->ima, &bgpic->iuser, customdata); + } + } + /* image window, compo node users */ for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */ for (win = wm->windows.first; win; win = win->next) { - ScrArea *sa; - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_VIEW3D) { - View3D *v3d = sa->spacedata.first; - BGpic *bgpic; - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - callback(bgpic->ima, &bgpic->iuser, customdata); - } - } - else if (sa->spacetype == SPACE_IMAGE) { + const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + if (sa->spacetype == SPACE_IMAGE) { SpaceImage *sima = sa->spacedata.first; callback(sima->image, &sima->iuser, customdata); } @@ -2756,11 +2670,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) ima->name[0] = '\0'; } -#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) - BKE_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 unstable @@ -2769,7 +2678,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) * sequences behave stable */ BKE_image_free_buffers(ima); -#endif ima->ok = 1; if (iuser) @@ -3019,7 +2927,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) if (ima->render_slot == ima->last_render_slot) rr = RE_AcquireResultRead(RE_GetSceneRender(scene)); else - rr = ima->renders[ima->render_slot]; + rr = BKE_image_get_renderslot(ima, ima->render_slot)->render; /* set proper views */ image_init_multilayer_multiview(ima, rr); @@ -3053,27 +2961,39 @@ bool BKE_image_is_openexr(struct Image *ima) void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot) { - /* called right before rendering, ima->renders contains render + /* called right before rendering, ima->renderslots contains render * result pointers for everything but the current render */ Render *re = RE_GetSceneRender(scene); - int slot = ima->render_slot, last = ima->last_render_slot; - if (slot != last) { - ima->renders[last] = NULL; - RE_SwapResult(re, &ima->renders[last]); + /* Ensure we always have a valid render slot. */ + if (!ima->renderslots.first) { + BKE_image_add_renderslot(ima, NULL); + ima->render_slot = 0; + ima->last_render_slot = 0; + } + else if (ima->render_slot >= BLI_listbase_count(&ima->renderslots)) { + ima->render_slot = 0; + ima->last_render_slot = 0; + } + + RenderSlot *last_slot = BKE_image_get_renderslot(ima, ima->last_render_slot); + RenderSlot *cur_slot = BKE_image_get_renderslot(ima, ima->render_slot); - if (ima->renders[slot]) { + if (last_slot && ima->render_slot != ima->last_render_slot) { + last_slot->render = NULL; + RE_SwapResult(re, &last_slot->render); + + if (cur_slot->render) { if (free_current_slot) { - RE_FreeRenderResult(ima->renders[slot]); - ima->renders[slot] = NULL; + BKE_image_clear_renderslot(ima, NULL, ima->render_slot); } else { - RE_SwapResult(re, &ima->renders[slot]); + RE_SwapResult(re, &cur_slot->render); } } } - ima->last_render_slot = slot; + ima->last_render_slot = ima->render_slot; } /**************************** multiview load openexr *********************************/ @@ -3132,7 +3052,7 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) #endif /* WITH_OPENEXR */ /* common stuff to do with images after loading */ -static void image_initialize_after_load(Image *ima, ImBuf *ibuf) +static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf)) { /* Preview is NULL when it has never been used as an icon before. * Never handle previews/icons outside of main thread. */ @@ -3140,11 +3060,6 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf) BKE_icon_changed(BKE_icon_id_ensure(&ima->id)); } - /* fields */ - if (ima->flag & IMA_FIELDS) { - if (ima->flag & IMA_STD_FIELD) de_interlace_st(ibuf); - else de_interlace_ng(ibuf); - } /* timer */ BKE_image_tag_time(ima); @@ -3495,7 +3410,7 @@ static ImBuf *load_image_single( flag |= imbuf_alpha_flags_for_image(ima); /* get the correct filepath */ - BKE_image_user_frame_calc(iuser, cfra, 0); + BKE_image_user_frame_calc(iuser, cfra); if (iuser) iuser_t = *iuser; @@ -3528,9 +3443,6 @@ static ImBuf *load_image_single( image_initialize_after_load(ima, ibuf); *r_assign = true; - /* check if the image is a font image... */ - detectBitmapFont(ibuf); - /* make packed file for autopack */ if ((has_packed == false) && (G.fileflags & G_AUTOPACK)) { ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile"); @@ -3691,11 +3603,12 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO)) actview = iuser->multiview_eye; + RenderSlot *slot; if (from_render) { RE_AcquireResultImage(re, &rres, actview); } - else if (ima->renders[ima->render_slot]) { - rres = *(ima->renders[ima->render_slot]); + else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) { + rres = *(slot->render); rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL; } else @@ -4249,9 +4162,9 @@ void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool) } } -int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool *r_is_in_range) +int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, bool *r_is_in_range) { - const int len = (iuser->fie_ima * iuser->frames) / 2; + const int len = iuser->frames; if (r_is_in_range) { *r_is_in_range = false; @@ -4287,12 +4200,8 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool } } - /* convert current frame to current field */ - cfra = 2 * (cfra); - if (fieldnr) cfra++; - /* transform to images space */ - framenr = (cfra + iuser->fie_ima - 2) / iuser->fie_ima; + framenr = cfra; if (framenr > iuser->frames) framenr = iuser->frames; if (iuser->cycl) { @@ -4308,11 +4217,11 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool } } -void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr) +void BKE_image_user_frame_calc(ImageUser *iuser, int cfra) { if (iuser) { bool is_in_range; - const int framenr = BKE_image_user_frame_get(iuser, cfra, fieldnr, &is_in_range); + const int framenr = BKE_image_user_frame_get(iuser, cfra, &is_in_range); if (is_in_range) { iuser->flag |= IMA_USER_FRAME_IN_RANGE; @@ -4331,10 +4240,10 @@ void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr) } } -void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra, int fieldnr) +void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra) { if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC)) { - BKE_image_user_frame_calc(iuser, cfra, fieldnr); + BKE_image_user_frame_calc(iuser, cfra); iuser->flag &= ~IMA_NEED_FRAME_RECALC; } @@ -4345,7 +4254,7 @@ static void image_update_frame(struct Image *UNUSED(ima), struct ImageUser *iuse { int cfra = *(int *)customdata; - BKE_image_user_check_frame_calc(iuser, cfra, 0); + BKE_image_user_check_frame_calc(iuser, cfra); } void BKE_image_update_frame(const Main *bmain, int cfra) @@ -4553,15 +4462,6 @@ bool BKE_image_is_dirty(Image *image) void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options) { -#if 0 - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); - if (ibuf) { - ibuf->ftype = ftype; - ibuf->foptions = options; - } - BKE_image_release_ibuf(image, ibuf, NULL); -#endif - BLI_spin_lock(&image_spin); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -4725,3 +4625,97 @@ static void image_update_views_format(Image *ima, ImageUser *iuser) } } } + +/**************************** Render Slots ***************************/ + +RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name) +{ + RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image new Render Slot"); + if (name && name[0]) { + BLI_strncpy(slot->name, name, sizeof(slot->name)); + } + else { + int n = BLI_listbase_count(&ima->renderslots) + 1; + BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", n); + } + BLI_addtail(&ima->renderslots, slot); + return slot; +} + +bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int index) +{ + int num_slots = BLI_listbase_count(&ima->renderslots); + if (index >= num_slots || num_slots == 1) { + return false; + } + + RenderSlot *remove_slot = BLI_findlink(&ima->renderslots, index); + RenderSlot *current_slot = BLI_findlink(&ima->renderslots, ima->render_slot); + RenderSlot *current_last_slot = BLI_findlink(&ima->renderslots, ima->last_render_slot); + + RenderSlot *next_slot; + if (current_slot == remove_slot) { + next_slot = BLI_findlink(&ima->renderslots, (index == num_slots - 1) ? index - 1 : index + 1); + } + else { + next_slot = current_slot; + } + + /* If the slot to be removed is the slot with the last render, make another slot the last render slot. */ + if (remove_slot == current_last_slot) { + /* Choose the currently selected slot unless that one is being removed, in that case take the next one. */ + RenderSlot *next_last_slot; + if (current_slot == remove_slot) + next_last_slot = next_slot; + else + next_last_slot = current_slot; + + if (!iuser) return false; + Render *re = RE_GetSceneRender(iuser->scene); + if (!re) return false; + RE_SwapResult(re, ¤t_last_slot->render); + RE_SwapResult(re, &next_last_slot->render); + current_last_slot = next_last_slot; + } + + current_slot = next_slot; + + BLI_remlink(&ima->renderslots, remove_slot); + + ima->render_slot = BLI_findindex(&ima->renderslots, current_slot); + ima->last_render_slot = BLI_findindex(&ima->renderslots, current_last_slot); + + if (remove_slot->render) { + RE_FreeRenderResult(remove_slot->render); + } + MEM_freeN(remove_slot); + + return true; +} + +bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int index) +{ + if (index == ima->last_render_slot) { + if (!iuser) return false; + if (G.is_rendering) return false; + Render *re = RE_GetSceneRender(iuser->scene); + if (!re) return false; + RE_ClearResult(re); + return true; + } + else { + RenderSlot *slot = BLI_findlink(&ima->renderslots, index); + if (!slot) return false; + if (slot->render) { + RE_FreeRenderResult(slot->render); + slot->render = NULL; + } + return true; + } +} + +RenderSlot *BKE_image_get_renderslot(Image *ima, int index) +{ + /* Can be NULL for images without render slots. */ + return BLI_findlink(&ima->renderslots, index); +} diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index c11f2368197..d3ac5a39c9f 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -46,7 +46,6 @@ /* since we have versioning code here */ #define DNA_DEPRECATED_ALLOW -#include "DNA_actuator_types.h" #include "DNA_anim_types.h" #include "DNA_constraint_types.h" #include "DNA_camera_types.h" @@ -146,17 +145,6 @@ static AdrBit2Path ob_layer_bits[] = { {(1 << 19), "layers", 19} }; -/* Material mode */ -static AdrBit2Path ma_mode_bits[] = { -// {MA_TRACEBLE, "traceable", 0}, -// {MA_SHADOW, "shadow", 0}, -// {MA_SHLESS, "shadeless", 0}, -// ... - {MA_RAYTRANSP, "transparency", 0}, - {MA_RAYMIRROR, "raytrace_mirror.enabled", 0}, -// {MA_HALO, "type", MA_TYPE_HALO} -}; - /* ----------------- */ /* quick macro for returning the appropriate array for adrcode_bitmaps_to_paths() */ @@ -173,9 +161,6 @@ static AdrBit2Path *adrcode_bitmaps_to_paths(int blocktype, int adrcode, int *to if ((blocktype == ID_OB) && (adrcode == OB_LAY)) { RET_ABP(ob_layer_bits); } - else if ((blocktype == ID_MA) && (adrcode == MA_MODE)) { - RET_ABP(ma_mode_bits); - } // XXX TODO: add other types... /* Normal curve */ @@ -1767,23 +1752,6 @@ void do_versions_ipos_to_animato(Main *bmain) ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL); /* No need to id_us_min ipo ID here, ipo_to_animdata already does it. */ ob->ipo = NULL; - - { - /* If we have any empty action actuators, assume they were - * converted IPO Actuators using the object IPO */ - bActuator *act; - bActionActuator *aa; - - for (act = ob->actuators.first; act; act = act->next) { - /* Any actuators set to ACT_IPO at this point are actually Action Actuators that - * need this converted IPO to finish converting the actuator. */ - if (act->type == ACT_IPO) { - aa = (bActionActuator *)act->data; - aa->act = ob->adt->action; - act->type = ACT_ACTION; - } - } - } } } @@ -2030,7 +1998,7 @@ void do_versions_ipos_to_animato(Main *bmain) for (id = bmain->lamp.first; id; id = id->next) { Lamp *la = (Lamp *)id; - if (G.debug & G_DEBUG) printf("\tconverting lamp %s\n", id->name + 2); + if (G.debug & G_DEBUG) printf("\tconverting light %s\n", id->name + 2); /* we're only interested in the IPO */ if (la->ipo) { diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 4689575655e..a01d78f5c36 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -76,6 +76,12 @@ #define IPO_BEZTRIPLE 100 #define IPO_BPOINT 101 +/* Internal use only. */ +typedef struct WeightsArrayCache { + int num_defgroup_weights; + float **defgroup_weights; +} WeightsArrayCache; + /** Free (or release) any data used by this shapekey (does not free the key itself). */ void BKE_key_free(Key *key) @@ -119,31 +125,31 @@ Key *BKE_key_add(Main *bmain, ID *id) /* common function */ case ID_ME: el = key->elemstr; - el[0] = 3; + el[0] = KEYELEM_FLOAT_LEN_COORD; el[1] = IPO_FLOAT; el[2] = 0; - key->elemsize = 12; + key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]); break; case ID_LT: el = key->elemstr; - el[0] = 3; + el[0] = KEYELEM_FLOAT_LEN_COORD; el[1] = IPO_FLOAT; el[2] = 0; - key->elemsize = 12; + key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]); break; case ID_CU: el = key->elemstr; - el[0] = 4; + el[0] = KEYELEM_ELEM_SIZE_CURVE; el[1] = IPO_BPOINT; el[2] = 0; - key->elemsize = 16; + key->elemsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]); break; @@ -540,31 +546,33 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char ** /* currently only the first value of 'ofs' may be set. */ -static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs) +static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs, int *step) { if (key->from == NULL) { return false; } + *step = 1; + switch (GS(key->from->name)) { case ID_ME: - *ofs = sizeof(float) * 3; + *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]); *poinsize = *ofs; break; case ID_LT: - *ofs = sizeof(float) * 3; + *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]); *poinsize = *ofs; break; case ID_CU: if (mode == KEY_MODE_BPOINT) { - *ofs = sizeof(float) * 4; - *poinsize = *ofs; + *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]); + *step = KEYELEM_ELEM_LEN_BPOINT; } else { - ofs[0] = sizeof(float) * 12; - *poinsize = (*ofs) / 3; + *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]); + *step = KEYELEM_ELEM_LEN_BEZTRIPLE; } - + *poinsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]); break; default: BLI_assert(!"invalid 'key->from' ID type"); @@ -577,14 +585,14 @@ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int static void cp_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode) { float ktot = 0.0, kd = 0.0; - int elemsize, poinsize = 0, a, *ofsp, ofs[32], flagflo = 0; + int elemsize, poinsize = 0, a, step, *ofsp, ofs[32], flagflo = 0; char *k1, *kref, *freek1, *freekref; char *cp, elemstr[8]; /* currently always 0, in future key_pointer_size may assign */ ofs[1] = 0; - if (!key_pointer_size(key, mode, &poinsize, &ofs[0])) + if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step)) return; if (end > tot) end = tot; @@ -628,10 +636,9 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key } /* just do it here, not above! */ - elemsize = key->elemsize; - if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3; + elemsize = key->elemsize * step; - for (a = start; a < end; a++) { + for (a = start; a < end; a += step) { cp = key->elemstr; if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr; @@ -642,20 +649,20 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key switch (cp[1]) { case IPO_FLOAT: if (weights) { - memcpy(poin, kref, sizeof(float) * 3); + memcpy(poin, kref, sizeof(float[KEYELEM_FLOAT_LEN_COORD])); if (*weights != 0.0f) - rel_flerp(cp[0], (float *)poin, (float *)kref, (float *)k1, *weights); + rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)kref, (float *)k1, *weights); weights++; } else { - memcpy(poin, k1, sizeof(float) * 3); + memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_COORD])); } break; case IPO_BPOINT: - memcpy(poin, k1, sizeof(float) * 4); + memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BPOINT])); break; case IPO_BEZTRIPLE: - memcpy(poin, k1, sizeof(float) * 12); + memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE])); break; default: /* should never happen */ @@ -682,10 +689,6 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key k1 += elemsize; kref += elemsize; } - - if (mode == KEY_MODE_BEZTRIPLE) { - a += 2; - } } if (freek1) MEM_freeN(freek1); @@ -699,7 +702,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) { if (nu->bp) { - step = nu->pntsu * nu->pntsv; + step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv; a1 = max_ii(a, start); a2 = min_ii(a + step, end); @@ -707,7 +710,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BPOINT); } else if (nu->bezt) { - step = 3 * nu->pntsu; + step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu; /* exception because keys prefer to work with complete blocks */ a1 = max_ii(a, start); @@ -721,18 +724,19 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const } } -void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb, - float **per_keyblock_weights, const int mode) +static void key_evaluate_relative( + const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb, + float **per_keyblock_weights, const int mode) { KeyBlock *kb; - int *ofsp, ofs[3], elemsize, b; + int *ofsp, ofs[3], elemsize, b, step; char *cp, *poin, *reffrom, *from, elemstr[8]; int poinsize, keyblock_index; /* currently always 0, in future key_pointer_size may assign */ ofs[1] = 0; - if (!key_pointer_size(key, mode, &poinsize, &ofs[0])) + if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step)) return; if (end > tot) end = tot; @@ -743,8 +747,7 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba elemstr[2] = 0; /* just here, not above! */ - elemsize = key->elemsize; - if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3; + elemsize = key->elemsize * step; /* step 1 init */ cp_key(start, end, tot, basispoin, key, actkb, key->refkey, NULL, mode); @@ -773,7 +776,7 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba reffrom += key->elemsize * start; // key elemsize yes! from += key->elemsize * start; - for (b = start; b < end; b++) { + for (b = start; b < end; b += step) { weight = weights ? (*weights * icuval) : icuval; @@ -786,13 +789,13 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba switch (cp[1]) { case IPO_FLOAT: - rel_flerp(3, (float *)poin, (float *)reffrom, (float *)from, weight); + rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)reffrom, (float *)from, weight); break; case IPO_BPOINT: - rel_flerp(4, (float *)poin, (float *)reffrom, (float *)from, weight); + rel_flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)reffrom, (float *)from, weight); break; case IPO_BEZTRIPLE: - rel_flerp(12, (float *)poin, (float *)reffrom, (float *)from, weight); + rel_flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (float *)poin, (float *)reffrom, (float *)from, weight); break; default: /* should never happen */ @@ -811,7 +814,6 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba reffrom += elemsize; from += elemsize; - if (mode == KEY_MODE_BEZTRIPLE) b += 2; if (weights) weights++; } @@ -827,7 +829,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key { float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0; float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0; - int a, ofs[32], *ofsp; + int a, step, ofs[32], *ofsp; int flagdo = 15, flagflo = 0, elemsize, poinsize = 0; char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4; char *cp, elemstr[8]; @@ -835,7 +837,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key /* currently always 0, in future key_pointer_size may assign */ ofs[1] = 0; - if (!key_pointer_size(key, mode, &poinsize, &ofs[0])) + if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step)) return; if (end > tot) end = tot; @@ -953,11 +955,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key elemstr[2] = 0; /* only here, not above! */ - elemsize = key->elemsize; - if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3; - - for (a = start; a < end; a++) { + elemsize = key->elemsize * step; + for (a = start; a < end; a += step) { cp = key->elemstr; if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr; @@ -967,13 +967,13 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key switch (cp[1]) { case IPO_FLOAT: - flerp(3, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t); + flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t); break; case IPO_BPOINT: - flerp(4, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t); + flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t); break; case IPO_BEZTRIPLE: - flerp(12, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t); + flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t); break; default: /* should never happen */ @@ -1038,8 +1038,6 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key k4 += elemsize; } } - - if (mode == KEY_MODE_BEZTRIPLE) a += 2; } if (freek1) MEM_freeN(freek1); @@ -1120,7 +1118,7 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac return NULL; } -float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache) +static float **keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache) { KeyBlock *keyblock; float **per_keyblock_weights; @@ -1140,7 +1138,7 @@ float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCac return per_keyblock_weights; } -void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache) +static void keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache) { int a; @@ -1175,9 +1173,9 @@ static void do_mesh_key(Object *ob, Key *key, char *out, const int tot) if (key->type == KEY_RELATIVE) { WeightsArrayCache cache = {0, NULL}; float **per_keyblock_weights; - per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, &cache); - BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); - BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache); + per_keyblock_weights = keyblock_get_per_block_weights(ob, key, &cache); + key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); + keyblock_free_per_block_weights(key, per_keyblock_weights, &cache); } else { const float ctime_scaled = key->ctime / 100.0f; @@ -1200,11 +1198,11 @@ static void do_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock **k, float for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) { if (nu->bp) { - step = nu->pntsu * nu->pntsv; + step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv; do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BPOINT); } else if (nu->bezt) { - step = 3 * nu->pntsu; + step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu; do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BEZTRIPLE); } else { @@ -1220,12 +1218,12 @@ static void do_rel_cu_key(Curve *cu, Key *key, KeyBlock *actkb, char *out, const for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) { if (nu->bp) { - step = nu->pntsu * nu->pntsv; - BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT); + step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv; + key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT); } else if (nu->bezt) { - step = 3 * nu->pntsu; - BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE); + step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu; + key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE); } else { step = 0; @@ -1266,9 +1264,9 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot) if (key->type == KEY_RELATIVE) { float **per_keyblock_weights; - per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, NULL); - BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); - BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, NULL); + per_keyblock_weights = keyblock_get_per_block_weights(ob, key, NULL); + key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY); + keyblock_free_per_block_weights(key, per_keyblock_weights, NULL); } else { const float ctime_scaled = key->ctime / 100.0f; @@ -1304,28 +1302,19 @@ float *BKE_key_evaluate_object_ex( Mesh *me = ob->data; tot = me->totvert; - size = tot * 3 * sizeof(float); + size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; tot = lt->pntsu * lt->pntsv * lt->pntsw; - size = tot * 3 * sizeof(float); + size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; - Nurb *nu; - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->bezt) { - tot += 3 * nu->pntsu; - size += nu->pntsu * 12 * sizeof(float); - } - else if (nu->bp) { - tot += nu->pntsu * nu->pntsv; - size += nu->pntsu * nu->pntsv * 12 * sizeof(float); - } - } + tot = BKE_keyblock_curve_element_count(&cu->nurb); + size = tot * sizeof(float[KEYELEM_ELEM_SIZE_CURVE]); } /* if nothing to interpolate, cancel */ @@ -1457,7 +1446,7 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name) kb = MEM_callocN(sizeof(KeyBlock), "Keyblock"); BLI_addtail(&key->block, kb); - kb->type = KEY_CARDINAL; + kb->type = KEY_LINEAR; tot = BLI_listbase_count(&key->block); if (name) { @@ -1661,6 +1650,24 @@ void BKE_keyblock_convert_to_lattice(KeyBlock *kb, Lattice *lt) } /************************* Curve ************************/ + +int BKE_keyblock_curve_element_count(ListBase *nurb) +{ + Nurb *nu; + int tot = 0; + + nu = nurb->first; + while (nu) { + if (nu->bezt) + tot += KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu; + else if (nu->bp) + tot += KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv; + + nu = nu->next; + } + return tot; +} + void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *nurb) { Nurb *nu; @@ -1670,7 +1677,7 @@ void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *n int a, tot; /* count */ - BLI_assert(BKE_nurbList_verts_count(nurb) == kb->totelem); + BLI_assert(BKE_keyblock_curve_element_count(nurb) == kb->totelem); tot = kb->totelem; if (tot == 0) return; @@ -1679,21 +1686,20 @@ void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *n for (nu = nurb->first; nu; nu = nu->next) { if (nu->bezt) { for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) { - int i; - - for (i = 0; i < 3; i++, fp += 3) { - copy_v3_v3(fp, bezt->vec[i]); + for (int i = 0; i < 3; i++) { + copy_v3_v3(&fp[i * 3], bezt->vec[i]); } - fp[0] = bezt->alfa; - fp += 3; /* alphas */ + fp[9] = bezt->alfa; + fp[10] = bezt->radius; + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; } } else { - - ; - for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, fp += 4, bp++) { + for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++) { copy_v3_v3(fp, bp->vec); fp[3] = bp->alfa; + fp[4] = bp->radius; + fp += KEYELEM_FLOAT_LEN_BPOINT; } } } @@ -1704,7 +1710,7 @@ void BKE_keyblock_convert_from_curve(Curve *cu, KeyBlock *kb, ListBase *nurb) int tot; /* count */ - tot = BKE_nurbList_verts_count(nurb); + tot = BKE_keyblock_curve_element_count(nurb); if (tot == 0) return; MEM_SAFE_FREE(kb->data); @@ -1723,26 +1729,27 @@ void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nu const float *fp; int a, tot; - tot = BKE_nurbList_verts_count(nurb); + tot = BKE_keyblock_curve_element_count(nurb); tot = min_ii(kb->totelem, tot); fp = kb->data; for (nu = nurb->first; nu && tot > 0; nu = nu->next) { if (nu->bezt) { - for (a = nu->pntsu, bezt = nu->bezt; a && tot > 0; a--, tot -= 3, bezt++) { - int i; - - for (i = 0; i < 3; i++, fp += 3) { - copy_v3_v3(bezt->vec[i], fp); + for (a = nu->pntsu, bezt = nu->bezt; a && (tot -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; a--, bezt++) { + for (int i = 0; i < 3; i++) { + copy_v3_v3(bezt->vec[i], &fp[i * 3]); } - bezt->alfa = fp[0]; - fp += 3; /* alphas */ + bezt->alfa = fp[9]; + bezt->radius = fp[10]; + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; } } else { - for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && tot; a--, tot--, fp += 4, bp++) { + for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && (tot -= KEYELEM_ELEM_LEN_BPOINT) >= 0; a--, bp++) { copy_v3_v3(bp->vec, fp); bp->alfa = fp[3]; + bp->radius = fp[4]; + fp += KEYELEM_FLOAT_LEN_BPOINT; } } } @@ -1767,16 +1774,16 @@ void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb) } } -void BKE_keyblock_convert_from_mesh(Mesh *me, KeyBlock *kb) +void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb) { - int tot = me->totvert; + const int len = me->totvert; if (me->totvert == 0) return; MEM_SAFE_FREE(kb->data); - kb->data = MEM_mallocN(me->key->elemsize * tot, __func__); - kb->totelem = tot; + kb->data = MEM_malloc_arrayN((size_t)len, (size_t)key->elemsize, __func__); + kb->totelem = len; BKE_keyblock_update_from_mesh(me, kb); } @@ -1871,7 +1878,7 @@ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos) } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; - BLI_assert(BKE_nurbList_verts_count(&cu->nurb) == kb->totelem); + BLI_assert(BKE_keyblock_curve_element_count(&cu->nurb) == kb->totelem); } else if (ob->type == OB_MESH) { Mesh *me = ob->data; @@ -1900,17 +1907,16 @@ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos) for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->bezt) { for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) { - int i; - - for (i = 0; i < 3; i++, fp += 3, co++) { - copy_v3_v3(fp, *co); + for (int i = 0; i < 3; i++, co++) { + copy_v3_v3(&fp[i * 3], *co); } - fp += 3; /* skip alphas */ + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; } } else { - for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, co++) { + for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) { copy_v3_v3(fp, *co); + fp += KEYELEM_FLOAT_LEN_BPOINT; } } } @@ -1937,7 +1943,7 @@ void BKE_keyblock_convert_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = (Curve *)ob->data; elemsize = cu->key->elemsize; - tot = BKE_nurbList_verts_count(&cu->nurb); + tot = BKE_keyblock_curve_element_count(&cu->nurb); } if (tot == 0) return; @@ -1987,17 +1993,16 @@ float (*BKE_keyblock_convert_to_vertcos(Object *ob, KeyBlock *kb))[3] for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->bezt) { for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) { - int i; - - for (i = 0; i < 3; i++, fp += 3, co++) { - copy_v3_v3(*co, fp); + for (int i = 0; i < 3; i++, co++) { + copy_v3_v3(*co, &fp[i * 3]); } - fp += 3; /* skip alphas */ + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; } } else { - for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, co++) { + for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) { copy_v3_v3(*co, fp); + fp += KEYELEM_FLOAT_LEN_BPOINT; } } } @@ -2026,17 +2031,16 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3]) for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->bezt) { for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) { - int i; - - for (i = 0; i < 3; i++, fp += 3, ofs++) { - add_v3_v3(fp, *ofs); + for (int i = 0; i < 3; i++, ofs++) { + add_v3_v3(&fp[i * 3], *ofs); } - fp += 3; /* skip alphas */ + fp += KEYELEM_FLOAT_LEN_BEZTRIPLE; } } else { - for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, ofs++) { + for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, ofs++) { add_v3_v3(fp, *ofs); + fp += KEYELEM_FLOAT_LEN_BPOINT; } } } diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 23cd81b6da9..2c57a2bdb0a 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -59,47 +59,36 @@ void BKE_lamp_init(Lamp *la) BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(la, id)); la->r = la->g = la->b = la->k = 1.0f; - la->haint = la->energy = 1.0f; + la->energy = 10.0f; la->dist = 25.0f; la->spotsize = DEG2RADF(45.0f); la->spotblend = 0.15f; la->att2 = 1.0f; - la->mode = LA_SHAD_BUF; + la->mode = LA_SHADOW; la->bufsize = 512; la->clipsta = 0.5f; la->clipend = 40.0f; + la->bleedexp = 2.5f; la->samp = 3; la->bias = 1.0f; la->soft = 3.0f; - la->compressthresh = 0.05f; - la->ray_samp = la->ray_sampy = la->ray_sampz = 1; - la->area_size = la->area_sizey = la->area_sizez = 0.1f; + la->area_size = la->area_sizey = la->area_sizez = 0.25f; la->buffers = 1; - la->buftype = LA_SHADBUF_HALFWAY; - la->ray_samp_method = LA_SAMP_HALTON; - la->adapt_thresh = 0.001f; la->preview = NULL; la->falloff_type = LA_FALLOFF_INVSQUARE; la->coeff_const = 1.0f; la->coeff_lin = 0.0f; la->coeff_quad = 0.0f; la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f); - la->sun_effect_type = 0; - la->horizon_brightness = 1.0; - la->spread = 1.0; - la->sun_brightness = 1.0; - la->sun_size = 1.0; - la->backscattered_light = 1.0f; - la->atm_turbidity = 2.0f; - la->atm_inscattering_factor = 1.0f; - la->atm_extinction_factor = 1.0f; - la->atm_distance_factor = 1.0f; - la->sun_intensity = 1.0f; - la->skyblendtype = MA_RAMP_ADD; - la->skyblendfac = 1.0f; - la->sky_colorspace = BLI_XYZ_CIE; - la->sky_exposure = 1.0f; - la->shadow_frustum_size = 10.0f; + la->cascade_max_dist = 1000.0f; + la->cascade_count = 4; + la->cascade_exponent = 0.8f; + la->cascade_fade = 0.1f; + la->contact_dist = 0.2f; + la->contact_bias = 0.03f; + la->contact_spread = 0.2f; + la->contact_thickness = 0.2f; + la->spec_fac = 1.0f; curvemapping_initialize(la->curfalloff); } @@ -125,13 +114,6 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name) */ void BKE_lamp_copy_data(Main *bmain, Lamp *la_dst, const Lamp *la_src, const int flag) { - for (int a = 0; a < MAX_MTEX; a++) { - if (la_dst->mtex[a]) { - la_dst->mtex[a] = MEM_mallocN(sizeof(*la_dst->mtex[a]), __func__); - *la_dst->mtex[a] = *la_src->mtex[a]; - } - } - la_dst->curfalloff = curvemapping_copy(la_src->curfalloff); if (la_src->nodetree) { @@ -164,17 +146,7 @@ Lamp *BKE_lamp_localize(Lamp *la) * * ... Once f*** nodes are fully converted to that too :( */ - Lamp *lan; - int a; - - lan = BKE_libblock_copy_nolib(&la->id, false); - - for (a = 0; a < MAX_MTEX; a++) { - if (lan->mtex[a]) { - lan->mtex[a] = MEM_mallocN(sizeof(MTex), __func__); - memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex)); - } - } + Lamp *lan = BKE_libblock_copy_nolib(&la->id, false); lan->curfalloff = curvemapping_copy(la->curfalloff); @@ -193,12 +165,6 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local) void BKE_lamp_free(Lamp *la) { - int a; - - for (a = 0; a < MAX_MTEX; a++) { - MEM_SAFE_FREE(la->mtex[a]); - } - BKE_animdata_free((ID *)la, false); curvemapping_free(la->curfalloff); @@ -214,40 +180,3 @@ void BKE_lamp_free(Lamp *la) BKE_icon_id_delete(&la->id); la->id.icon_id = 0; } - -/* Calculate all drivers for lamps, see material_drivers_update for why this is a bad hack */ - -static void lamp_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime) -{ - bNode *node; - - /* nodetree itself */ - if (ntree->adt && ntree->adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS); - - /* nodes */ - for (node = ntree->nodes.first; node; node = node->next) - if (node->id && node->type == NODE_GROUP) - lamp_node_drivers_update(scene, (bNodeTree *)node->id, ctime); -} - -void lamp_drivers_update(Scene *scene, Lamp *la, float ctime) -{ - /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited already - * (see BKE_scene_update_tagged()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] */ - if (la->id.tag & LIB_TAG_DOIT) - return; - - la->id.tag |= LIB_TAG_DOIT; - - /* lamp itself */ - if (la->adt && la->adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, &la->id, la->adt, ctime, ADT_RECALC_DRIVERS); - - /* nodes */ - if (la->nodetree) - lamp_node_drivers_update(scene, la->nodetree, ctime); - - la->id.tag &= ~LIB_TAG_DOIT; -} diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 1e99712f47a..a04f32adece 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -53,7 +53,6 @@ #include "BKE_anim.h" #include "BKE_cdderivedmesh.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -66,10 +65,7 @@ #include "BKE_deform.h" -/* Workaround for cyclic dependency with curves. - * In such case curve_cache might not be ready yet, - */ -#define CYCLIC_DEPENDENCY_WORKAROUND +#include "DEG_depsgraph_query.h" int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w) @@ -215,9 +211,9 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) /* works best if we force to linear type (endpoints match) */ lt->typeu = lt->typev = lt->typew = KEY_LINEAR; - /* prevent using deformed locations */ - if (ltOb->curve_cache != NULL) { - BKE_displist_free(<Ob->curve_cache->disp); + if (ltOb->runtime.curve_cache) { + /* prevent using deformed locations */ + BKE_displist_free(<Ob->runtime.curve_cache->disp); } copy_m4_m4(mat, ltOb->obmat); @@ -290,7 +286,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src, { lt_dst->def = MEM_dupallocN(lt_src->def); - if (lt_src->key) { + if (lt_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { BKE_id_copy_ex(bmain, <_src->key->id, (ID **)<_dst->key, flag, false); } @@ -306,7 +302,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src, Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt) { Lattice *lt_copy; - BKE_id_copy_ex(bmain, <->id, (ID **)<_copy, 0, false); + BKE_id_copy_ex(bmain, <->id, (ID **)<_copy, LIB_ID_COPY_SHAPEKEY, false); return lt_copy; } @@ -315,6 +311,8 @@ void BKE_lattice_free(Lattice *lt) { BKE_animdata_free(<->id, false); + BKE_lattice_batch_cache_free(lt); + MEM_SAFE_FREE(lt->def); if (lt->dvert) { BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); @@ -351,7 +349,7 @@ LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob) /* we make an array with all differences */ Lattice *lt = oblatt->data; BPoint *bp; - DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = oblatt->runtime.curve_cache ? BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : NULL; const float *co = dl ? dl->verts : NULL; float *fp, imat[4][4]; float fu, fv, fw; @@ -422,10 +420,11 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float int defgrp_index = -1; float co_prev[3], weight_blend = 0.0f; MDeformVert *dvert = BKE_lattice_deform_verts_get(ob); + float *__restrict latticedata = lattice_deform_data->latticedata; if (lt->editlatt) lt = lt->editlatt->latt; - if (lattice_deform_data->latticedata == NULL) return; + if (latticedata == NULL) return; if (lt->vgroup[0] && dvert) { defgrp_index = defgroup_name_index(ob, lt->vgroup); @@ -506,7 +505,7 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float idx_u = idx_v; } - madd_v3_v3fl(co, &lattice_deform_data->latticedata[idx_u * 3], u); + madd_v3_v3fl(co, &latticedata[idx_u * 3], u); if (defgrp_index != -1) weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index)); @@ -559,7 +558,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di int cycl = 0; /* test for cyclic */ - bl = ob->curve_cache->bev.first; + bl = ob->runtime.curve_cache->bev.first; if (!bl->nr) return false; if (bl->poly > -1) cycl = 1; @@ -574,7 +573,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) { if (cycl == 0) { - Path *path = ob->curve_cache->path; + Path *path = ob->runtime.curve_cache->path; float dvec[3]; if (ctime < 0.0f) { @@ -603,7 +602,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di /* co: local coord, result local too */ /* returns quaternion for rotation, using cd->no_rot_axis */ /* axis is using another define!!! */ -static bool calc_curve_deform(Scene *scene, Object *par, float co[3], +static bool calc_curve_deform(Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4]) { Curve *cu = par->data; @@ -611,14 +610,12 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], short index; const bool is_neg_axis = (axis > 2); - /* to be sure, mostly after file load, also cyclic dependencies */ -#ifdef CYCLIC_DEPENDENCY_WORKAROUND - if (par->curve_cache == NULL) { - BKE_displist_make_curveTypes(scene, par, false); + if (par->runtime.curve_cache == NULL) { + /* Happens with a cyclic dependencies. */ + return false; } -#endif - if (par->curve_cache->path == NULL) { + if (par->runtime.curve_cache->path == NULL) { return false; /* happens on append, cyclic dependencies and empty curves */ } @@ -628,7 +625,7 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], if (cu->flag & CU_STRETCH) fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); else - fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist); + fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist); } else { index = axis; @@ -636,8 +633,8 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); } else { - if (LIKELY(par->curve_cache->path->totdist > FLT_EPSILON)) { - fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist); + if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) { + fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist); } else { fac = 0.0f; @@ -707,7 +704,7 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], } void curve_deform_verts( - Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], + Object *cuOb, Object *target, Mesh *mesh, float (*vertexCos)[3], int numVerts, const char *vgroup, short defaxis) { Curve *cu; @@ -743,8 +740,8 @@ void curve_deform_verts( if (defgrp_index != -1) { /* if there's derived data without deformverts, don't use vgroups */ - if (dm) { - dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + if (mesh) { + dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); } else if (target->type == OB_LATTICE) { dvert = ((Lattice *)target->data)->dvert; @@ -766,7 +763,7 @@ void curve_deform_verts( if (weight > 0.0f) { mul_m4_v3(cd.curvespace, vertexCos[a]); copy_v3_v3(vec, vertexCos[a]); - calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); + calc_curve_deform(cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } @@ -789,7 +786,7 @@ void curve_deform_verts( if (weight > 0.0f) { /* already in 'cd.curvespace', prev for loop */ copy_v3_v3(vec, vertexCos[a]); - calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); + calc_curve_deform(cuOb, vec, defaxis, &cd, NULL); interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); mul_m4_v3(cd.objectspace, vertexCos[a]); } @@ -800,7 +797,7 @@ void curve_deform_verts( if (cu->flag & CU_DEFORM_BOUNDS_OFF) { for (a = 0; a < numVerts; a++) { mul_m4_v3(cd.curvespace, vertexCos[a]); - calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); + calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } @@ -815,7 +812,7 @@ void curve_deform_verts( for (a = 0; a < numVerts; a++) { /* already in 'cd.curvespace', prev for loop */ - calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); + calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL); mul_m4_v3(cd.objectspace, vertexCos[a]); } } @@ -825,7 +822,7 @@ void curve_deform_verts( /* input vec and orco = local coord in armature space */ /* orco is original not-animated or deformed reference point */ /* result written in vec and mat */ -void curve_deform_vector(Scene *scene, Object *cuOb, Object *target, +void curve_deform_vector(Object *cuOb, Object *target, float orco[3], float vec[3], float mat[3][3], int no_rot_axis) { CurveDeform cd; @@ -844,7 +841,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target, mul_m4_v3(cd.curvespace, vec); - if (calc_curve_deform(scene, cuOb, vec, target->trackflag, &cd, quat)) { + if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) { float qmat[3][3]; quat_to_mat3(qmat, quat); @@ -857,7 +854,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target, } -void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, +void lattice_deform_verts(Object *laOb, Object *target, Mesh *mesh, float (*vertexCos)[3], int numVerts, const char *vgroup, float fac) { LatticeDeformData *lattice_deform_data; @@ -878,8 +875,8 @@ void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, if (defgrp_index != -1) { /* if there's derived data without deformverts, don't use vgroups */ - if (dm) { - dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + if (mesh) { + dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); } else if (target->type == OB_LATTICE) { dvert = ((Lattice *)target->data)->dvert; @@ -1027,47 +1024,54 @@ void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3]) } } -void BKE_lattice_modifiers_calc(Scene *scene, Object *ob) +void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob) { Lattice *lt = ob->data; + /* Get vertex coordinates from the original copy; otherwise we get already-modified coordinates. */ + Object *ob_orig = DEG_get_original_object(ob); VirtualModifierData virtualModifierData; ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); float (*vertexCos)[3] = NULL; int numVerts, editmode = (lt->editlatt != NULL); + const ModifierEvalContext mectx = {depsgraph, ob, 0}; - if (ob->curve_cache) { - BKE_displist_free(&ob->curve_cache->disp); + if (ob->runtime.curve_cache) { + BKE_displist_free(&ob->runtime.curve_cache->disp); } else { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); } for (; md; md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue; if (!(md->mode & eModifierMode_Realtime)) continue; if (editmode && !(md->mode & eModifierMode_Editmode)) continue; - if (mti->isDisabled && mti->isDisabled(md, 0)) continue; + if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue; if (mti->type != eModifierTypeType_OnlyDeform) continue; - if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts); - mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0); + if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts); + mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts); } - /* always displist to make this work like derivedmesh */ - if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts); + if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) { + if (vertexCos) { + BKE_lattice_vertexcos_apply(ob, vertexCos); + MEM_freeN(vertexCos); + } + } + else { + /* Displist won't do anything; this is just for posterity's sake until we remove it. */ + if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts); - { DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl"); dl->type = DL_VERTS; dl->parts = 1; dl->nr = numVerts; dl->verts = (float *) vertexCos; - BLI_addtail(&ob->curve_cache->disp, dl); + BLI_addtail(&ob->runtime.curve_cache->disp, dl); } } @@ -1141,7 +1145,7 @@ BoundBox *BKE_lattice_boundbox_get(Object *ob) void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3]) { - DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL; if (!dl) { BKE_lattice_minmax(lt, min, max); @@ -1226,9 +1230,42 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys) } } +bool BKE_lattice_is_any_selected(const Lattice *lt) +{ + /* Intentionally don't handle 'lt->editlatt' (caller must do this). */ + const BPoint *bp = lt->def; + int a = lt->pntsu * lt->pntsv * lt->pntsw; + while (a--) { + if (bp->hide == 0) { + if (bp->f1 & SELECT) { + return true; + } + } + bp++; + } + return false; +} + /* **** Depsgraph evaluation **** */ -void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx), +void BKE_lattice_eval_geometry(struct Depsgraph *UNUSED(depsgraph), Lattice *UNUSED(latt)) { } + +/* Draw Engine */ +void (*BKE_lattice_batch_cache_dirty_tag_cb)(Lattice *lt, int mode) = NULL; +void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL; + +void BKE_lattice_batch_cache_dirty_tag(Lattice *lt, int mode) +{ + if (lt->batch_cache) { + BKE_lattice_batch_cache_dirty_tag_cb(lt, mode); + } +} +void BKE_lattice_batch_cache_free(Lattice *lt) +{ + if (lt->batch_cache) { + BKE_lattice_batch_cache_free_cb(lt); + } +} diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c new file mode 100644 index 00000000000..fbfa47c8939 --- /dev/null +++ b/source/blender/blenkernel/intern/layer.c @@ -0,0 +1,1479 @@ +/* + * ***** 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. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/layer.c + * \ingroup bke + */ + +#include <string.h> + +#include "BLI_array.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_string_utils.h" +#include "BLI_threads.h" +#include "BLT_translation.h" + +#include "BKE_animsys.h" +#include "BKE_collection.h" +#include "BKE_freestyle.h" +#include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_object.h" + +#include "DNA_ID.h" +#include "DNA_collection_types.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_node_types.h" +#include "DNA_scene_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_debug.h" +#include "DEG_depsgraph_query.h" + +#include "DRW_engine.h" + +#include "MEM_guardedalloc.h" + + +/* prototype */ +static void object_bases_iterator_next(BLI_Iterator *iter, const int flag); + + +/*********************** Layer Collections and bases *************************/ + +static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection) +{ + LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); + lc->collection = collection; + BLI_addtail(lb_parent, lc); + + return lc; +} + +static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc) +{ + if (lc == view_layer->active_collection) { + view_layer->active_collection = NULL; + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_free(view_layer, nlc); + } + + BLI_freelistN(&lc->layer_collections); +} + +static Base *object_base_new(Object *ob) +{ + Base *base = MEM_callocN(sizeof(Base), "Object Base"); + base->object = ob; + return base; +} + +/********************************* View Layer ********************************/ + + +/* RenderLayer */ + +/* Returns the default view layer to view in workspaces if there is + * none linked to the workspace yet. */ +ViewLayer *BKE_view_layer_default_view(const Scene *scene) +{ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (!(view_layer->flag & VIEW_LAYER_RENDER)) { + return view_layer; + } + } + + BLI_assert(scene->view_layers.first); + return scene->view_layers.first; +} + +/* Returns the default view layer to render if we need to render just one. */ +ViewLayer *BKE_view_layer_default_render(const Scene *scene) +{ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (view_layer->flag & VIEW_LAYER_RENDER) { + return view_layer; + } + } + + BLI_assert(scene->view_layers.first); + return scene->view_layers.first; +} + +/* Returns view layer with matching name, or NULL if not found. */ +ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name) +{ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (STREQ(view_layer->name, layer_name)) { + return view_layer; + } + } + + return NULL; +} + +/** + * This is a placeholder to know which areas of the code need to be addressed + * for the Workspace changes. Never use this, you should typically get the + * active layer from the context or window. + */ +ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene) +{ + BLI_assert(scene->view_layers.first); + return scene->view_layers.first; +} + +static ViewLayer *view_layer_add(const char *name) +{ + if (!name) { + name = DATA_("View Layer"); + } + + ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer"); + view_layer->flag = VIEW_LAYER_RENDER | VIEW_LAYER_FREESTYLE; + + BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name)); + + /* Pure rendering pipeline settings. */ + view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */ + view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z; + view_layer->pass_alpha_threshold = 0.5f; + BKE_freestyle_config_init(&view_layer->freestyle_config); + + return view_layer; +} + +/** + * Add a new view layer + * by default, a view layer has the master collection + */ +ViewLayer *BKE_view_layer_add(Scene *scene, const char *name) +{ + ViewLayer *view_layer = view_layer_add(name); + + BLI_addtail(&scene->view_layers, view_layer); + + /* unique name */ + BLI_uniquename( + &scene->view_layers, view_layer, DATA_("ViewLayer"), '.', + offsetof(ViewLayer, name), sizeof(view_layer->name)); + + BKE_layer_collection_sync(scene, view_layer); + + return view_layer; +} + +void BKE_view_layer_free(ViewLayer *view_layer) +{ + BKE_view_layer_free_ex(view_layer, true); +} + +/** + * Free (or release) any data used by this ViewLayer. + */ +void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) +{ + view_layer->basact = NULL; + + BLI_freelistN(&view_layer->object_bases); + + if (view_layer->object_bases_hash) { + BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL); + } + + for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) { + layer_collection_free(view_layer, lc); + } + BLI_freelistN(&view_layer->layer_collections); + + for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) { + if (sled->storage) { + if (sled->free) { + sled->free(sled->storage); + } + MEM_freeN(sled->storage); + } + } + BLI_freelistN(&view_layer->drawdata); + + MEM_SAFE_FREE(view_layer->stats); + + BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user); + + if (view_layer->id_properties) { + IDP_FreeProperty(view_layer->id_properties); + MEM_freeN(view_layer->id_properties); + } + + MEM_SAFE_FREE(view_layer->object_bases_array); + + MEM_freeN(view_layer); +} + +/** + * Tag all the selected objects of a renderlayer + */ +void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag) +{ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + base->object->flag |= tag; + } + else { + base->object->flag &= ~tag; + } + } +} + +static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc) +{ + for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) { + if (lcn == lc) { + return true; + } + if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) { + return true; + } + } + return false; +} + +/** + * Fallback for when a Scene has no camera to use + * + * \param view_layer: in general you want to use the same ViewLayer that is used + * for depsgraph. If rendering you pass the scene active layer, when viewing in the viewport + * you want to get ViewLayer from context. + */ +Object *BKE_view_layer_camera_find(ViewLayer *view_layer) +{ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->object->type == OB_CAMERA) { + return base->object; + } + } + + return NULL; +} + +/** + * Find the ViewLayer a LayerCollection belongs to + */ +ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc) +{ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) { + return view_layer; + } + } + + return NULL; +} + +/* Base */ + +static void view_layer_bases_hash_create(ViewLayer *view_layer) +{ + static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER; + + if (view_layer->object_bases_hash == NULL) { + BLI_mutex_lock(&hash_lock); + + if (view_layer->object_bases_hash == NULL) { + view_layer->object_bases_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->object) { + BLI_ghash_insert(view_layer->object_bases_hash, base->object, base); + } + } + } + + BLI_mutex_unlock(&hash_lock); + } +} + +Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob) +{ + if (!view_layer->object_bases_hash) { + view_layer_bases_hash_create(view_layer); + } + + return BLI_ghash_lookup(view_layer->object_bases_hash, ob); +} + +void BKE_view_layer_base_deselect_all(ViewLayer *view_layer) +{ + Base *base; + + for (base = view_layer->object_bases.first; base; base = base->next) { + base->flag &= ~BASE_SELECTED; + } +} + +void BKE_view_layer_base_select(Base *selbase) +{ + if ((selbase->flag & BASE_SELECTABLE) != 0) { + selbase->flag |= BASE_SELECTED; + } +} + +void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Base *selbase) +{ + view_layer->basact = selbase; + BKE_view_layer_base_select(selbase); +} + +/**************************** Copy View Layer and Layer Collections ***********************/ + +static void layer_collections_copy_data( + ViewLayer *view_layer_dst, const ViewLayer *view_layer_src, + ListBase *layer_collections_dst, const ListBase *layer_collections_src) +{ + BLI_duplicatelist(layer_collections_dst, layer_collections_src); + + LayerCollection *layer_collection_dst = layer_collections_dst->first; + const LayerCollection *layer_collection_src = layer_collections_src->first; + + while (layer_collection_dst != NULL) { + layer_collections_copy_data( + view_layer_dst, + view_layer_src, + &layer_collection_dst->layer_collections, + &layer_collection_src->layer_collections); + + if (layer_collection_src == view_layer_src->active_collection) { + view_layer_dst->active_collection = layer_collection_dst; + } + + layer_collection_dst = layer_collection_dst->next; + layer_collection_src = layer_collection_src->next; + } +} + +/** + * Only copy internal data of ViewLayer from source to already allocated/initialized destination. + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_view_layer_copy_data( + Scene *scene_dst, const Scene *UNUSED(scene_src), + ViewLayer *view_layer_dst, const ViewLayer *view_layer_src, + const int flag) +{ + if (view_layer_dst->id_properties != NULL) { + view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag); + } + BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag); + + view_layer_dst->stats = NULL; + + /* Clear temporary data. */ + BLI_listbase_clear(&view_layer_dst->drawdata); + view_layer_dst->object_bases_array = NULL; + view_layer_dst->object_bases_hash = NULL; + + /* Copy layer collections and object bases. */ + /* Inline 'BLI_duplicatelist' and update the active base. */ + BLI_listbase_clear(&view_layer_dst->object_bases); + for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) { + Base *base_dst = MEM_dupallocN(base_src); + BLI_addtail(&view_layer_dst->object_bases, base_dst); + if (view_layer_src->basact == base_src) { + view_layer_dst->basact = base_dst; + } + } + + view_layer_dst->active_collection = NULL; + layer_collections_copy_data( + view_layer_dst, + view_layer_src, + &view_layer_dst->layer_collections, + &view_layer_src->layer_collections); + + LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first; + lc_scene_dst->collection = scene_dst->master_collection; +} + +void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname) +{ + char oldname[sizeof(view_layer->name)]; + + BLI_strncpy(oldname, view_layer->name, sizeof(view_layer->name)); + + BLI_strncpy_utf8(view_layer->name, newname, sizeof(view_layer->name)); + BLI_uniquename(&scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name)); + + if (scene->nodetree) { + bNode *node; + int index = BLI_findindex(&scene->view_layers, view_layer); + + for (node = scene->nodetree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) { + if (node->custom1 == index) + BLI_strncpy(node->name, view_layer->name, NODE_MAXSTR); + } + } + } + + /* Fix all the animation data and windows which may link to this. */ + BKE_animdata_fix_paths_rename_all(NULL, "view_layers", oldname, view_layer->name); + + /* WM can be missing on startup. */ + wmWindowManager *wm = bmain->wm.first; + if (wm) { + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (win->scene == scene && STREQ(win->view_layer_name, oldname)) { + STRNCPY(win->view_layer_name, view_layer->name); + } + } + } + + /* Dependency graph uses view layer name based lookups. */ + DEG_id_tag_update(&scene->id, 0); +} + +/* LayerCollection */ + +/** + * Recursively get the collection for a given index + */ +static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + if (*i == number) { + return lc; + } + + (*i)++; + } + + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i); + if (lc_nested) { + return lc_nested; + } + } + return NULL; +} + +/** + * Get the collection for a given index + */ +LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index) +{ + int i = 0; + return collection_from_index(&view_layer->layer_collections, index, &i); +} + +/** + * Get the active collection + */ +LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer) +{ + return view_layer->active_collection; +} + +/* + * Activate collection + */ +bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc) +{ + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + return false; + } + + view_layer->active_collection = lc; + return true; +} + +/** + * Activate first parent collection + */ +LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc) +{ + CollectionParent *parent = lc->collection->parents.first; + + if (parent) { + lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection); + } + else { + lc = NULL; + } + + if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) { + /* Don't activate excluded collections. */ + return BKE_layer_collection_activate_parent(view_layer, lc); + } + + if (!lc) { + lc = view_layer->layer_collections.first; + } + + view_layer->active_collection = lc; + return lc; +} + +/** + * Recursively get the count of collections + */ +static int collection_count(ListBase *lb) +{ + int i = 0; + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + i += collection_count(&lc->layer_collections) + 1; + } + return i; +} + +/** + * Get the total number of collections + * (including all the nested collections) + */ +int BKE_layer_collection_count(ViewLayer *view_layer) +{ + return collection_count(&view_layer->layer_collections); +} + +/** + * Recursively get the index for a given collection + */ +static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i) +{ + for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) { + if (lcol == lc) { + return *i; + } + + (*i)++; + } + + for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) { + int i_nested = index_from_collection(&lcol->layer_collections, lc, i); + if (i_nested != -1) { + return i_nested; + } + } + return -1; +} + +/** + * Return -1 if not found + */ +int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc) +{ + int i = 0; + return index_from_collection(&view_layer->layer_collections, lc, &i); +} + +/*********************************** Syncing ********************************* + * + * The layer collection tree mirrors the scene collection tree. Whenever that + * changes we need to synchronize them so that there is a corresponding layer + * collection for each collection. Note that the scene collection tree can + * contain link or override collections, and so this is also called on .blend + * file load to ensure any new or removed collections are synced. + * + * The view layer also contains a list of bases for each object that exists + * in at least one layer collection. That list is also synchronized here, and + * stores state like selection. */ + +static short layer_collection_sync( + ViewLayer *view_layer, const ListBase *lb_scene, + ListBase *lb_layer, ListBase *new_object_bases, + short parent_exclude, short parent_restrict) +{ + /* TODO: support recovery after removal of intermediate collections, reordering, .. + * For local edits we can make editing operating do the appropriate thing, but for + * linking we can only sync after the fact. */ + + /* Remove layer collections that no longer have a corresponding scene collection. */ + for (LayerCollection *lc = lb_layer->first; lc;) { + /* Note ID remap can set lc->collection to NULL when deleting collections. */ + LayerCollection *lc_next = lc->next; + Collection *collection = (lc->collection) ? + BLI_findptr(lb_scene, lc->collection, offsetof(CollectionChild, collection)) : NULL; + + if (!collection) { + if (lc == view_layer->active_collection) { + view_layer->active_collection = NULL; + } + + /* Free recursively. */ + layer_collection_free(view_layer, lc); + BLI_freelinkN(lb_layer, lc); + } + + lc = lc_next; + } + + /* Add layer collections for any new scene collections, and ensure order is the same. */ + ListBase new_lb_layer = {NULL, NULL}; + short runtime_flag = 0; + + for (const CollectionChild *child = lb_scene->first; child; child = child->next) { + Collection *collection = child->collection; + LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection)); + + if (lc) { + BLI_remlink(lb_layer, lc); + BLI_addtail(&new_lb_layer, lc); + } + else { + lc = layer_collection_add(&new_lb_layer, collection); + lc->flag = parent_exclude; + } + + /* Collection restrict is inherited. */ + short child_restrict = parent_restrict; + if (!(collection->flag & COLLECTION_IS_MASTER)) { + child_restrict |= collection->flag; + } + + /* Sync child collections. */ + short child_runtime_flag = layer_collection_sync( + view_layer, &collection->children, + &lc->layer_collections, new_object_bases, + lc->flag, child_restrict); + + /* Layer collection exclude is not inherited. */ + if (lc->flag & LAYER_COLLECTION_EXCLUDE) { + lc->runtime_flag = 0; + continue; + } + else { + lc->runtime_flag = child_runtime_flag; + } + + /* Sync objects, except if collection was excluded. */ + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + if (cob->ob == NULL) { + continue; + } + + Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob); + + if (base) { + /* Move from old base list to new base list. Base might have already + * been moved to the new base list and the first/last test ensure that + * case also works. */ + if (!ELEM(base, new_object_bases->first, new_object_bases->last)) { + BLI_remlink(&view_layer->object_bases, base); + BLI_addtail(new_object_bases, base); + } + } + else { + /* Create new base. */ + base = object_base_new(cob->ob); + BLI_addtail(new_object_bases, base); + BLI_ghash_insert(view_layer->object_bases_hash, base->object, base); + } + + int object_restrict = base->object->restrictflag; + + if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) && + ((object_restrict & OB_RESTRICT_VIEW) == 0)) + { + base->flag |= BASE_VISIBLE | BASE_ENABLED | BASE_ENABLED_VIEWPORT; + + if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) && + ((object_restrict & OB_RESTRICT_SELECT) == 0)) + { + base->flag |= BASE_SELECTABLE; + } + } + + if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) && + ((object_restrict & OB_RESTRICT_RENDER) == 0)) + + { + base->flag |= BASE_ENABLED_RENDER; + } + + /* Update runtime flags used for display and tools. */ + if (base->flag & BASE_VISIBLE) { + lc->runtime_flag |= LAYER_COLLECTION_HAS_ENABLED_OBJECTS; + } + + if (base->flag & BASE_HIDDEN) { + view_layer->runtime_flag |= VIEW_LAYER_HAS_HIDE; + } + else if (base->flag & BASE_VISIBLE) { + lc->runtime_flag |= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS; + } + + /* Holdout and indirect only */ + if (lc->flag & LAYER_COLLECTION_HOLDOUT) { + base->flag |= BASE_HOLDOUT; + } + if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) { + base->flag |= BASE_INDIRECT_ONLY; + } + + lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS; + } + + runtime_flag |= lc->runtime_flag; + } + + /* Replace layer collection list with new one. */ + *lb_layer = new_lb_layer; + BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer)); + + return runtime_flag; +} + +/** + * Update view layer collection tree from collections used in the scene. + * This is used when collections are removed or added, both while editing + * and on file loaded in case linked data changed or went missing. + */ +void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) +{ + if (!scene->master_collection) { + /* Happens for old files that don't have versioning applied yet. */ + return; + } + + /* Free cache. */ + MEM_SAFE_FREE(view_layer->object_bases_array); + + /* Create object to base hash if it does not exist yet. */ + if (!view_layer->object_bases_hash) { + view_layer_bases_hash_create(view_layer); + } + + /* Clear visible and selectable flags to be reset. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->flag &= ~(BASE_VISIBLE | + BASE_ENABLED | + BASE_SELECTABLE | + BASE_ENABLED_VIEWPORT | + BASE_ENABLED_RENDER | + BASE_HOLDOUT | + BASE_INDIRECT_ONLY); + } + + view_layer->runtime_flag = 0; + + /* Generate new layer connections and object bases when collections changed. */ + CollectionChild child = {NULL, NULL, scene->master_collection}; + const ListBase collections = {&child, &child}; + ListBase new_object_bases = {NULL, NULL}; + + const short parent_exclude = 0, parent_restrict = 0; + layer_collection_sync( + view_layer, &collections, + &view_layer->layer_collections, &new_object_bases, + parent_exclude, parent_restrict); + + /* Any remaning object bases are to be removed. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (view_layer->basact == base) { + view_layer->basact = NULL; + } + + if (base->object) { + BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL); + } + } + + BLI_freelistN(&view_layer->object_bases); + view_layer->object_bases = new_object_bases; + + /* Always set a valid active collection. */ + LayerCollection *active = view_layer->active_collection; + + if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) { + BKE_layer_collection_activate_parent(view_layer, active); + } + else if (active == NULL) { + view_layer->active_collection = view_layer->layer_collections.first; + } +} + +void BKE_scene_collection_sync(const Scene *scene) +{ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + BKE_layer_collection_sync(scene, view_layer); + } +} + +void BKE_main_collection_sync(const Main *bmain) +{ + /* TODO: if a single collection changed, figure out which + * scenes it belongs to and only update those. */ + + /* TODO: optimize for file load so only linked collections get checked? */ + + for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + BKE_scene_collection_sync(scene); + } +} + +void BKE_main_collection_sync_remap(const Main *bmain) +{ + /* On remapping of object or collection pointers free caches. */ + /* TODO: try to make this faster */ + + for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + MEM_SAFE_FREE(view_layer->object_bases_array); + + if (view_layer->object_bases_hash) { + BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL); + view_layer->object_bases_hash = NULL; + } + } + } + + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + BKE_collection_object_cache_free(collection); + DEG_id_tag_update_ex((Main *)bmain, &collection->id, DEG_TAG_COPY_ON_WRITE); + } + + BKE_main_collection_sync(bmain); +} + +/* ---------------------------------------------------------------------- */ + +/** + * Select all the objects of this layer collection + * + * It also select the objects that are in nested collections. + * \note Recursive + */ +bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect) +{ + if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) { + return false; + } + + bool changed = false; + + if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); + + if (base) { + if (deselect) { + if (base->flag & BASE_SELECTED) { + base->flag &= ~BASE_SELECTED; + changed = true; + } + } + else { + if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) { + base->flag |= BASE_SELECTED; + changed = true; + } + } + } + } + } + + for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) { + changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect); + } + + return changed; +} + +bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerCollection *lc) +{ + if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) { + return false; + } + + if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(view_layer, cob->ob); + + if (base && (base->flag & BASE_SELECTED)) { + return true; + } + } + } + + for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) { + if (BKE_layer_collection_has_selected_objects(view_layer, iter)) { + return true; + } + } + + return false; +} + +/* ---------------------------------------------------------------------- */ + +/* Update after toggling visibility of an object base. */ +void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend) +{ + if (!extend) { + /* Make only one base visible. */ + for (Base *other = view_layer->object_bases.first; other; other = other->next) { + other->flag |= BASE_HIDDEN; + } + + base->flag &= ~BASE_HIDDEN; + } + else { + /* Toggle visibility of one base. */ + base->flag ^= BASE_HIDDEN; + } + + BKE_layer_collection_sync(scene, view_layer); +} + +void BKE_layer_collection_set_visible(Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool extend) +{ + if (!extend) { + /* Make only objects from one collection visible. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->flag |= BASE_HIDDEN; + } + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob) + { + Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob); + + if (base) { + base->flag &= ~BASE_HIDDEN; + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + BKE_layer_collection_activate(view_layer, lc); + } + else { + /* Toggle visibility of objects from collection. */ + bool hide = (lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS) != 0; + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob) + { + Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob); + + if (base) { + if (hide) { + base->flag |= BASE_HIDDEN; + } + else { + base->flag &= ~BASE_HIDDEN; + } + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + + BKE_layer_collection_sync(scene, view_layer); +} + +/* ---------------------------------------------------------------------- */ + +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const Collection *collection) +{ + if (lc->collection == collection) { + return lc; + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection); + if (found) { + return found; + } + } + return NULL; +} + +/** + * Return the first matching LayerCollection in the ViewLayer for the Collection. + */ +LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const Collection *collection) +{ + for (LayerCollection *layer_collection = view_layer->layer_collections.first; + layer_collection != NULL; + layer_collection = layer_collection->next) + { + LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, collection); + + if (found != NULL) { + return found; + } + } + return NULL; +} + +/** + * See if view layer has the scene collection linked directly, or indirectly (nested) + */ +bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *collection) +{ + return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL; +} + +/** + * See if the object is in any of the scene layers of the scene + */ +bool BKE_scene_has_object(Scene *scene, Object *ob) +{ + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { + return true; + } + } + return false; +} + +/* ---------------------------------------------------------------------- */ +/* Override */ + +/** + * Add a new datablock override + */ +void BKE_override_view_layer_datablock_add( + ViewLayer *view_layer, int id_type, const char *data_path, const ID *owner_id) +{ + UNUSED_VARS(view_layer, id_type, data_path, owner_id); + TODO_LAYER_OVERRIDE; +} + +/** + * Add a new int override + */ +void BKE_override_view_layer_int_add( + ViewLayer *view_layer, int id_type, const char *data_path, const int value) +{ + UNUSED_VARS(view_layer, id_type, data_path, value); + TODO_LAYER_OVERRIDE; +} + +/** + * Add a new boolean override + */ +void BKE_override_layer_collection_boolean_add( + struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value) +{ + UNUSED_VARS(layer_collection, id_type, data_path, value); + TODO_LAYER_OVERRIDE; +} + +/** \} */ + +/* Iterators */ + +/* -------------------------------------------------------------------- */ +/** \name Private Iterator Helpers + * \{ */ + +static void object_bases_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag) +{ + ViewLayer *view_layer = data_in; + Base *base = view_layer->object_bases.first; + + /* when there are no objects */ + if (base == NULL) { + iter->valid = false; + return; + } + + iter->data = base; + + if ((base->flag & flag) == 0) { + object_bases_iterator_next(iter, flag); + } + else { + iter->current = base; + } +} + +static void object_bases_iterator_next(BLI_Iterator *iter, const int flag) +{ + Base *base = ((Base *)iter->data)->next; + + while (base) { + if ((base->flag & flag) != 0) { + iter->current = base; + iter->data = base; + return; + } + base = base->next; + } + + iter->valid = false; +} + +static void objects_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag) +{ + object_bases_iterator_begin(iter, data_in, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +static void objects_iterator_next(BLI_Iterator *iter, const int flag) +{ + object_bases_iterator_next(iter, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +/* -------------------------------------------------------------------- */ +/** \name BKE_view_layer_selected_objects_iterator + * See: #FOREACH_SELECTED_OBJECT_BEGIN + * \{ */ + +void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + objects_iterator_begin(iter, data_in, BASE_SELECTED); +} + +void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter) +{ + objects_iterator_next(iter, BASE_SELECTED); +} + +void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BKE_view_layer_visible_objects_iterator + * \{ */ + +void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + objects_iterator_begin(iter, data_in, BASE_VISIBLE); +} + +void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter) +{ + objects_iterator_next(iter, BASE_VISIBLE); +} + +void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BKE_view_layer_selected_editable_objects_iterator + * \{ */ + +void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + objects_iterator_begin(iter, data_in, BASE_SELECTED); + if (iter->valid) { + if (BKE_object_is_libdata((Object *)iter->current) == false) { + // First object is valid (selectable and not libdata) -> all good. + return; + } + else { + // Object is selectable but not editable -> search for another one. + BKE_view_layer_selected_editable_objects_iterator_next(iter); + } + } +} + +void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter) +{ + // Search while there are objects and the one we have is not editable (editable = not libdata). + do { + objects_iterator_next(iter, BASE_SELECTED); + } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false); +} + +void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BKE_view_layer_selected_bases_iterator + * \{ */ + +void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + object_bases_iterator_begin(iter, data_in, BASE_SELECTED); +} + +void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter) +{ + object_bases_iterator_next(iter, BASE_SELECTED); +} + +void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BKE_view_layer_visible_bases_iterator + * \{ */ + +void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + object_bases_iterator_begin(iter, data_in, BASE_VISIBLE); +} + +void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter) +{ + object_bases_iterator_next(iter, BASE_VISIBLE); +} + +void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BKE_view_layer_renderable_objects_iterator + * \{ */ + +void BKE_view_layer_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + struct ObjectsRenderableIteratorData *data = data_in; + + /* Tag objects to prevent going over the same object twice. */ + for (Scene *scene = data->scene; scene; scene = scene->set) { + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->object->id.flag |= LIB_TAG_DOIT; + } + } + } + + ViewLayer *view_layer = data->scene->view_layers.first; + data->iter.view_layer = view_layer; + + data->base_temp.next = view_layer->object_bases.first; + data->iter.base = &data->base_temp; + + data->iter.set = NULL; + + iter->data = data_in; + BKE_view_layer_renderable_objects_iterator_next(iter); +} + +void BKE_view_layer_renderable_objects_iterator_next(BLI_Iterator *iter) +{ + /* Set it early in case we need to exit and we are running from within a loop. */ + iter->skip = true; + + struct ObjectsRenderableIteratorData *data = iter->data; + Base *base = data->iter.base->next; + + /* There is still a base in the current scene layer. */ + if (base != NULL) { + Object *ob = base->object; + + /* We need to set the iter.base even if the rest fail otherwise + * we keep checking the exactly same base over and over again. */ + data->iter.base = base; + + if (ob->id.flag & LIB_TAG_DOIT) { + ob->id.flag &= ~LIB_TAG_DOIT; + + if ((base->flag & BASE_VISIBLE) != 0) { + iter->skip = false; + iter->current = ob; + } + } + return; + } + + /* Time to go to the next scene layer. */ + if (data->iter.set == NULL) { + while ((data->iter.view_layer = data->iter.view_layer->next)) { + ViewLayer *view_layer = data->iter.view_layer; + if (view_layer->flag & VIEW_LAYER_RENDER) { + data->base_temp.next = view_layer->object_bases.first; + data->iter.base = &data->base_temp; + return; + } + } + + /* Setup the "set" for the next iteration. */ + data->scene_temp.set = data->scene; + data->iter.set = &data->scene_temp; + return; + } + + /* Look for an object in the next set. */ + while ((data->iter.set = data->iter.set->set)) { + ViewLayer *view_layer = BKE_view_layer_default_render(data->iter.set); + data->base_temp.next = view_layer->object_bases.first; + data->iter.base = &data->base_temp; + return; + } + + iter->valid = false; +} + +void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* Do nothing - iter->data was static allocated, we can't free it. */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BKE_view_layer_bases_in_mode_iterator + * \{ */ + +void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in) +{ + struct ObjectsInModeIteratorData *data = data_in; + Base *base = data->base_active; + + /* when there are no objects */ + if (base == NULL) { + iter->valid = false; + return; + } + iter->data = data_in; + iter->current = base; +} + +void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter) +{ + struct ObjectsInModeIteratorData *data = iter->data; + Base *base = iter->current; + + if (base == data->base_active) { + /* first step */ + base = data->view_layer->object_bases.first; + if (base == data->base_active) { + base = base->next; + } + } + else { + base = base->next; + } + + while (base) { + if ((base->object->type == data->base_active->object->type) && + (base != data->base_active) && + (base->object->mode & data->object_mode)) + { + iter->current = base; + return; + } + base = base->next; + } + iter->valid = false; +} + +void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +/** \} */ + +/* Evaluation */ + +void BKE_layer_eval_view_layer( + struct Depsgraph *depsgraph, + struct Scene *UNUSED(scene), + ViewLayer *view_layer) +{ + DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer); + + /* Visibility based on depsgraph mode. */ + const eEvaluationMode mode = DEG_get_mode(depsgraph); + const int base_flag = (mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; + + /* Create array of bases, for fast index-based lookup. */ + const int num_object_bases = BLI_listbase_count(&view_layer->object_bases); + MEM_SAFE_FREE(view_layer->object_bases_array); + view_layer->object_bases_array = MEM_malloc_arrayN( + num_object_bases, sizeof(Base *), "view_layer->object_bases_array"); + int base_index = 0; + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + /* Compute visibility for depsgraph evaluation mode. */ + if (base->flag & base_flag) { + base->flag |= BASE_ENABLED | BASE_VISIBLE; + + if (mode == DAG_EVAL_VIEWPORT && (base->flag & BASE_HIDDEN)) { + base->flag &= ~BASE_VISIBLE; + } + } + else { + base->flag &= ~(BASE_ENABLED | BASE_VISIBLE | BASE_SELECTABLE); + } + + /* If base is not selectabled, clear select. */ + if ((base->flag & BASE_SELECTABLE) == 0) { + base->flag &= ~BASE_SELECTED; + } + + view_layer->object_bases_array[base_index++] = base; + } + + /* Flush back base flag to the original view layer for editing. */ + if (view_layer == DEG_get_evaluated_view_layer(depsgraph)) { + ViewLayer *view_layer_orig = DEG_get_input_view_layer(depsgraph); + Base *base_orig = view_layer_orig->object_bases.first; + const Base *base_eval = view_layer->object_bases.first; + while (base_orig != NULL) { + base_orig->flag = base_eval->flag; + base_orig = base_orig->next; + base_eval = base_eval->next; + } + } +} + +void BKE_layer_eval_view_layer_indexed( + struct Depsgraph *depsgraph, + struct Scene *scene, + int view_layer_index) +{ + BLI_assert(view_layer_index >= 0); + ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index); + BLI_assert(view_layer != NULL); + BKE_layer_eval_view_layer(depsgraph, scene, view_layer); +} diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c new file mode 100644 index 00000000000..94bac8a33d6 --- /dev/null +++ b/source/blender/blenkernel/intern/layer_utils.c @@ -0,0 +1,125 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/layer_utils.c + * \ingroup bke + */ + +#include <string.h> + +#include "BLI_array.h" +#include "BLI_listbase.h" + +#include "BKE_collection.h" +#include "BKE_editmesh.h" +#include "BKE_layer.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +Base **BKE_view_layer_array_from_bases_in_mode_params( + ViewLayer *view_layer, uint *r_len, + const struct ObjectsInModeParams *params) +{ + if (params->no_dup_data) { + FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) { + ID *id = base_iter->object->data; + if (id) { + id->tag |= LIB_TAG_DOIT; + } + } FOREACH_BASE_IN_MODE_END; + } + + Base **base_array = NULL; + BLI_array_declare(base_array); + + FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) { + if (params->filter_fn) { + if (!params->filter_fn(base_iter->object, params->filter_userdata)) { + continue; + } + } + if (params->no_dup_data) { + ID *id = base_iter->object->data; + if (id) { + if (id->tag & LIB_TAG_DOIT) { + id->tag &= ~LIB_TAG_DOIT; + } + else { + continue; + } + } + } + BLI_array_append(base_array, base_iter); + } FOREACH_BASE_IN_MODE_END; + + if (base_array != NULL) { + base_array = MEM_reallocN(base_array, sizeof(*base_array) * BLI_array_len(base_array)); + } + *r_len = BLI_array_len(base_array); + return base_array; +} + +Object **BKE_view_layer_array_from_objects_in_mode_params( + ViewLayer *view_layer, uint *r_len, + const struct ObjectsInModeParams *params) +{ + Base **base_array = BKE_view_layer_array_from_bases_in_mode_params( + view_layer, r_len, params); + if (base_array != NULL) { + for (uint i = 0; i < *r_len; i++) { + ((Object **)base_array)[i] = base_array[i]->object; + } + } + return (Object **)base_array; +} + +bool BKE_view_layer_filter_edit_mesh_has_uvs(Object *ob, void *UNUSED(user_data)) +{ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + if (em != NULL) { + if (CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV) != -1) { + return true; + } + } + } + return false; +} + +bool BKE_view_layer_filter_edit_mesh_has_edges(Object *ob, void *UNUSED(user_data)) +{ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + if (em != NULL) { + if (em->bm->totedge != 0) { + return true; + } + } + } + return false; +} diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index a6cee54d81f..aa6cbcc343e 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -47,7 +47,7 @@ #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" #include "DNA_ipo_types.h" #include "DNA_key_types.h" @@ -62,6 +62,7 @@ #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" @@ -70,6 +71,7 @@ #include "DNA_vfont_types.h" #include "DNA_windowmanager_types.h" #include "DNA_world_types.h" +#include "DNA_workspace_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -78,8 +80,8 @@ #include "BLI_memarena.h" #include "BLI_mempool.h" #include "BLI_string_utils.h" - #include "BLI_threads.h" + #include "BLT_translation.h" #include "BKE_action.h" @@ -89,12 +91,11 @@ #include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_font.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_gpencil.h" #include "BKE_idcode.h" #include "BKE_idprop.h" @@ -103,6 +104,7 @@ #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -117,6 +119,7 @@ #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" +#include "BKE_lightprobe.h" #include "BKE_sound.h" #include "BKE_speaker.h" #include "BKE_scene.h" @@ -418,6 +421,9 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) case ID_SPK: if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local); return true; + case ID_LP: + if (!test) BKE_lightprobe_make_local(bmain, (LightProbe *)id, lib_local); + return true; case ID_WO: if (!test) BKE_world_make_local(bmain, (World *)id, lib_local); return true; @@ -431,7 +437,7 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local); return true; case ID_GR: - if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local); + if (!test) BKE_collection_make_local(bmain, (Collection *)id, lib_local); return true; case ID_AR: if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local); @@ -469,7 +475,11 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local) case ID_CF: if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local); return true; + case ID_WS: case ID_SCR: + /* A bit special: can be appended but not linked. Return false + * since supporting make-local doesn't make much sense. */ + return false; case ID_LI: case ID_KE: case ID_WM: @@ -589,6 +599,9 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con case ID_SPK: BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag); break; + case ID_LP: + BKE_lightprobe_copy_data(bmain, (LightProbe *)*r_newid, (LightProbe *)id, flag); + break; case ID_CA: BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag); break; @@ -602,7 +615,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag); break; case ID_GR: - BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag); + BKE_collection_copy_data(bmain, (Collection *)*r_newid, (Collection *)id, flag); break; case ID_AR: BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag); @@ -620,7 +633,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con BKE_particlesettings_copy_data(bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag); break; case ID_GD: - BKE_gpencil_copy_data(bmain, (bGPdata *)*r_newid, (bGPdata *)id, flag); + BKE_gpencil_copy_data((bGPdata *)*r_newid, (bGPdata *)id, flag); break; case ID_MC: BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag); @@ -649,6 +662,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con case ID_LI: case ID_SCR: case ID_WM: + case ID_WS: case ID_IP: BLI_assert(0); /* Should have been rejected at start of function! */ break; @@ -677,7 +691,76 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con */ bool id_copy(Main *bmain, const ID *id, ID **newid, bool test) { - return BKE_id_copy_ex(bmain, id, newid, 0, test); + return BKE_id_copy_ex(bmain, id, newid, LIB_ID_COPY_SHAPEKEY, test); +} + +/** Does a mere memory swap over the whole IDs data (including type-specific memory). + * \note Most internal ID data itself is not swapped (only IDProperties are). */ +void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b) +{ + BLI_assert(GS(id_a->name) == GS(id_b->name)); + + const ID id_a_back = *id_a; + const ID id_b_back = *id_b; + +#define CASE_SWAP(_gs, _type) \ + case _gs: \ + SWAP(_type, *(_type *)id_a, *(_type *)id_b); \ + break + + switch ((ID_Type)GS(id_a->name)) { + CASE_SWAP(ID_SCE, Scene); + CASE_SWAP(ID_LI, Library); + CASE_SWAP(ID_OB, Object); + CASE_SWAP(ID_ME, Mesh); + CASE_SWAP(ID_CU, Curve); + CASE_SWAP(ID_MB, MetaBall); + CASE_SWAP(ID_MA, Material); + CASE_SWAP(ID_TE, Tex); + CASE_SWAP(ID_IM, Image); + CASE_SWAP(ID_LT, Lattice); + CASE_SWAP(ID_LA, Lamp); + CASE_SWAP(ID_LP, LightProbe); + CASE_SWAP(ID_CA, Camera); + CASE_SWAP(ID_KE, Key); + CASE_SWAP(ID_WO, World); + CASE_SWAP(ID_SCR, bScreen); + CASE_SWAP(ID_VF, VFont); + CASE_SWAP(ID_TXT, Text); + CASE_SWAP(ID_SPK, Speaker); + CASE_SWAP(ID_SO, bSound); + CASE_SWAP(ID_GR, Collection); + CASE_SWAP(ID_AR, bArmature); + CASE_SWAP(ID_AC, bAction); + CASE_SWAP(ID_NT, bNodeTree); + CASE_SWAP(ID_BR, Brush); + CASE_SWAP(ID_PA, ParticleSettings); + CASE_SWAP(ID_WM, wmWindowManager); + CASE_SWAP(ID_WS, WorkSpace); + CASE_SWAP(ID_GD, bGPdata); + CASE_SWAP(ID_MC, MovieClip); + CASE_SWAP(ID_MSK, Mask); + CASE_SWAP(ID_LS, FreestyleLineStyle); + CASE_SWAP(ID_PAL, Palette); + CASE_SWAP(ID_PC, PaintCurve); + CASE_SWAP(ID_CF, CacheFile); + case ID_IP: + break; /* Deprecated. */ + } + +#undef CASE_SWAP + + /* Restore original ID's internal data. */ + *id_a = id_a_back; + *id_b = id_b_back; + + /* Exception: IDProperties. */ + id_a->properties = id_b_back.properties; + id_b->properties = id_a_back.properties; + + /* Swap will have broken internal references to itself, restore them. */ + BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false); + BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false); } /** Does *not* set ID->newid pointer. */ @@ -693,15 +776,23 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) if (id_copy(bmain, id, &newid, false) && newid) { /* copy animation actions too */ BKE_animdata_copy_id_action(bmain, id, false); - /* us is 1 by convention, but RNA_property_pointer_set - * will also increment it, so set it to zero */ - newid->us = 0; + /* us is 1 by convention with new IDs, but RNA_property_pointer_set + * will also increment it, decrement it here. */ + id_us_min(newid); /* assign copy */ RNA_id_pointer_create(newid, &idptr); RNA_property_pointer_set(ptr, prop, idptr); RNA_property_update(C, ptr, prop); + /* tag grease pencil datablock and disable onion */ + if (GS(id->name) == ID_GD) { + DEG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(newid, OB_RECALC_OB | OB_RECALC_DATA); + bGPdata *gpd = (bGPdata *)newid; + gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS; + } + return true; } } @@ -807,81 +898,6 @@ void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv) id->tag |= LIB_TAG_NO_USER_REFCOUNT; } -ListBase *which_libbase(Main *mainlib, short type) -{ - switch ((ID_Type)type) { - case ID_SCE: - return &(mainlib->scene); - case ID_LI: - return &(mainlib->library); - case ID_OB: - return &(mainlib->object); - case ID_ME: - return &(mainlib->mesh); - case ID_CU: - return &(mainlib->curve); - case ID_MB: - return &(mainlib->mball); - case ID_MA: - return &(mainlib->mat); - case ID_TE: - return &(mainlib->tex); - case ID_IM: - return &(mainlib->image); - case ID_LT: - return &(mainlib->latt); - case ID_LA: - return &(mainlib->lamp); - case ID_CA: - return &(mainlib->camera); - case ID_IP: - return &(mainlib->ipo); - case ID_KE: - return &(mainlib->key); - case ID_WO: - return &(mainlib->world); - case ID_SCR: - return &(mainlib->screen); - case ID_VF: - return &(mainlib->vfont); - case ID_TXT: - return &(mainlib->text); - case ID_SPK: - return &(mainlib->speaker); - case ID_SO: - return &(mainlib->sound); - case ID_GR: - return &(mainlib->group); - case ID_AR: - return &(mainlib->armature); - case ID_AC: - return &(mainlib->action); - case ID_NT: - return &(mainlib->nodetree); - case ID_BR: - return &(mainlib->brush); - case ID_PA: - return &(mainlib->particle); - case ID_WM: - return &(mainlib->wm); - case ID_GD: - return &(mainlib->gpencil); - case ID_MC: - return &(mainlib->movieclip); - case ID_MSK: - return &(mainlib->mask); - case ID_LS: - return &(mainlib->linestyle); - case ID_PAL: - return &(mainlib->palettes); - case ID_PC: - return &(mainlib->paintcurves); - case ID_CF: - return &(mainlib->cachefiles); - } - return NULL; -} - /** * Clear or set given tags for all ids in listbase (runtime tags). */ @@ -963,72 +979,11 @@ void BKE_main_lib_objects_recalc_all(Main *bmain) /* flag for full recalc */ for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ID_IS_LINKED(ob)) { - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } } - DAG_id_type_tag(bmain, ID_OB); -} - -/** - * puts into array *lb pointers to all the ListBase structs in main, - * and returns the number of them as the function result. This is useful for - * generic traversal of all the blocks in a Main (by traversing all the - * lists in turn), without worrying about block types. - * - * \note MAX_LIBARRAY define should match this code */ -int set_listbasepointers(Main *main, ListBase **lb) -{ - /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last. - * This is important because freeing data decreases usercounts of other datablocks, - * if this data is its self freed it can crash. */ - lb[INDEX_ID_LI] = &(main->library); /* Libraries may be accessed from pretty much any other ID... */ - lb[INDEX_ID_IP] = &(main->ipo); - lb[INDEX_ID_AC] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */ - lb[INDEX_ID_KE] = &(main->key); - lb[INDEX_ID_GD] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */ - lb[INDEX_ID_NT] = &(main->nodetree); - lb[INDEX_ID_IM] = &(main->image); - lb[INDEX_ID_TE] = &(main->tex); - lb[INDEX_ID_MA] = &(main->mat); - lb[INDEX_ID_VF] = &(main->vfont); - - /* Important!: When adding a new object type, - * the specific data should be inserted here - */ - - lb[INDEX_ID_AR] = &(main->armature); - - lb[INDEX_ID_CF] = &(main->cachefiles); - lb[INDEX_ID_ME] = &(main->mesh); - lb[INDEX_ID_CU] = &(main->curve); - lb[INDEX_ID_MB] = &(main->mball); - - lb[INDEX_ID_LT] = &(main->latt); - lb[INDEX_ID_LA] = &(main->lamp); - lb[INDEX_ID_CA] = &(main->camera); - - lb[INDEX_ID_TXT] = &(main->text); - lb[INDEX_ID_SO] = &(main->sound); - lb[INDEX_ID_GR] = &(main->group); - lb[INDEX_ID_PAL] = &(main->palettes); - lb[INDEX_ID_PC] = &(main->paintcurves); - lb[INDEX_ID_BR] = &(main->brush); - lb[INDEX_ID_PA] = &(main->particle); - lb[INDEX_ID_SPK] = &(main->speaker); - - lb[INDEX_ID_WO] = &(main->world); - lb[INDEX_ID_MC] = &(main->movieclip); - lb[INDEX_ID_SCR] = &(main->screen); - lb[INDEX_ID_OB] = &(main->object); - lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */ - lb[INDEX_ID_SCE] = &(main->scene); - lb[INDEX_ID_WM] = &(main->wm); - lb[INDEX_ID_MSK] = &(main->mask); - - lb[INDEX_ID_NULL] = NULL; - - return (MAX_LIBARRAY - 1); + DEG_id_type_tag(bmain, ID_OB); } /* *********** ALLOC AND FREE ***************** @@ -1075,8 +1030,9 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name) CASE_RETURN(ID_VF, VFont); CASE_RETURN(ID_TXT, Text); CASE_RETURN(ID_SPK, Speaker); + CASE_RETURN(ID_LP, LightProbe); CASE_RETURN(ID_SO, bSound); - CASE_RETURN(ID_GR, Group); + CASE_RETURN(ID_GR, Collection); CASE_RETURN(ID_AR, bArmature); CASE_RETURN(ID_AC, bAction); CASE_RETURN(ID_NT, bNodeTree); @@ -1090,6 +1046,7 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name) CASE_RETURN(ID_PAL, Palette); CASE_RETURN(ID_PC, PaintCurve); CASE_RETURN(ID_CF, CacheFile); + CASE_RETURN(ID_WS, WorkSpace); } return 0; #undef CASE_RETURN @@ -1147,7 +1104,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl /* TODO to be removed from here! */ if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) { - DAG_id_type_tag(bmain, type); + DEG_id_type_tag(bmain, type); } } else { @@ -1206,6 +1163,9 @@ void BKE_libblock_init_empty(ID *id) case ID_SPK: BKE_speaker_init((Speaker *)id); break; + case ID_LP: + BKE_lightprobe_init((LightProbe *)id); + break; case ID_CA: BKE_camera_init((Camera *)id); break; @@ -1270,21 +1230,47 @@ void BKE_libblock_init_empty(ID *id) /* Should not be needed - animation from lib pre-2.5 is broken anyway. */ BLI_assert(0); break; + case ID_PAL: + BKE_palette_init((Palette *)id); + break; default: BLI_assert(0); /* Should never reach this point... */ } } -/* by spec, animdata is first item after ID */ -/* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */ -static void id_copy_animdata(Main *bmain, ID *id, const bool do_action) +/** Generic helper to create a new empty datablock of given type in given \a bmain database. + * + * \param name can be NULL, in which case we get default name for this ID type. */ +void *BKE_id_new(Main *bmain, const short type, const char *name) { - AnimData *adt = BKE_animdata_from_id(id); + BLI_assert(bmain != NULL); + + if (name == NULL) { + name = DATA_(BKE_idcode_to_name(type)); + } + + ID *id = BKE_libblock_alloc(bmain, type, name, 0); + BKE_libblock_init_empty(id); + + return id; +} - if (adt) { - IdAdtTemplate *iat = (IdAdtTemplate *)id; - iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */ +/** Generic helper to create a new temporary empty datablock of given type, *outside* of any Main database. + * + * \param name can be NULL, in which case we get default name for this ID type. */ +void *BKE_id_new_nomain(const short type, const char *name) +{ + if (name == NULL) { + name = DATA_(BKE_idcode_to_name(type)); } + + ID *id = BKE_libblock_alloc(NULL, type, name, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG); + BKE_libblock_init_empty(id); + + return id; } void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag) @@ -1299,6 +1285,8 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL); BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0); BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0); + /* Never implicitly copy shapekeys when generating temp data outside of Main database. */ + BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0); if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) { /* r_newid already contains pointer to allocated memory. */ @@ -1326,12 +1314,30 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla new_id->properties = IDP_CopyProperty_ex(id->properties, flag); } - /* the duplicate should get a copy of the animdata */ - BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0); - id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0); + /* XXX Again... We need a way to control what we copy in a much more refined way. + * We cannot always copy this, some internal copying will die on it! */ + /* For now, upper level code will have to do that itself when required. */ +#if 0 + if (id->override != NULL) { + BKE_override_copy(new_id, id); + } +#endif + + if (id_can_have_animdata(new_id)) { + IdAdtTemplate *iat = (IdAdtTemplate *)new_id; + + /* the duplicate should get a copy of the animdata */ + if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) { + BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0); + iat->adt = BKE_animdata_copy(bmain, iat->adt, flag); + } + else { + iat->adt = NULL; + } + } if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) { - DAG_id_type_tag(bmain, GS(new_id->name)); + DEG_id_type_tag(bmain, GS(new_id->name)); } *r_newid = new_id; @@ -1362,256 +1368,6 @@ void BKE_library_free(Library *lib) freePackedFile(lib->packedfile); } -Main *BKE_main_new(void) -{ - Main *bmain = MEM_callocN(sizeof(Main), "new main"); - bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT); - bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock"); - BLI_spin_init((SpinLock *)bmain->lock); - return bmain; -} - -void BKE_main_free(Main *mainvar) -{ - /* also call when reading a file, erase all, etc */ - ListBase *lbarray[MAX_LIBARRAY]; - int a; - - MEM_SAFE_FREE(mainvar->blen_thumb); - - a = set_listbasepointers(mainvar, lbarray); - while (a--) { - ListBase *lb = lbarray[a]; - ID *id; - - while ( (id = lb->first) ) { -#if 1 - BKE_libblock_free_ex(mainvar, id, false, false); -#else - /* errors freeing ID's can be hard to track down, - * enable this so valgrind will give the line number in its error log */ - switch (a) { - case 0: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 1: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 2: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 3: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 4: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 5: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 6: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 7: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 8: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 9: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 10: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 11: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 12: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 13: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 14: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 15: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 16: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 17: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 18: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 19: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 20: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 21: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 22: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 23: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 24: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 25: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 26: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 27: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 28: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 29: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 30: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 31: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 32: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 33: BKE_libblock_free_ex(mainvar, id, false, false); break; - case 34: BKE_libblock_free_ex(mainvar, id, false, false); break; - default: - BLI_assert(0); - break; - } -#endif - } - } - - if (mainvar->relations) { - BKE_main_relations_free(mainvar); - } - - BLI_spin_end((SpinLock *)mainvar->lock); - MEM_freeN(mainvar->lock); - DEG_evaluation_context_free(mainvar->eval_ctx); - MEM_freeN(mainvar); -} - -void BKE_main_lock(struct Main *bmain) -{ - BLI_spin_lock((SpinLock *) bmain->lock); -} - -void BKE_main_unlock(struct Main *bmain) -{ - BLI_spin_unlock((SpinLock *) bmain->lock); -} - - -static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag) -{ - MainIDRelations *rel = user_data; - - if (*id_pointer) { - MainIDRelationsEntry *entry, **entry_p; - - entry = BLI_mempool_alloc(rel->entry_pool); - if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) { - entry->next = *entry_p; - } - else { - entry->next = NULL; - } - entry->id_pointer = id_pointer; - entry->usage_flag = cb_flag; - *entry_p = entry; - - entry = BLI_mempool_alloc(rel->entry_pool); - if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) { - entry->next = *entry_p; - } - else { - entry->next = NULL; - } - entry->id_pointer = (ID **)id_self; - entry->usage_flag = cb_flag; - *entry_p = entry; - } - - return IDWALK_RET_NOP; -} - -/** Generate the mappings between used IDs and their users, and vice-versa. */ -void BKE_main_relations_create(Main *bmain) -{ - ListBase *lbarray[MAX_LIBARRAY]; - ID *id; - int a; - - if (bmain->relations != NULL) { - BKE_main_relations_free(bmain); - } - - bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__); - bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP); - - for (a = set_listbasepointers(bmain, lbarray); a--; ) { - for (id = lbarray[a]->first; id; id = id->next) { - BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY); - } - } -} - -void BKE_main_relations_free(Main *bmain) -{ - if (bmain->relations) { - if (bmain->relations->id_used_to_user) { - BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL); - } - if (bmain->relations->id_user_to_used) { - BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL); - } - BLI_mempool_destroy(bmain->relations->entry_pool); - MEM_freeN(bmain->relations); - bmain->relations = NULL; - } -} - -/** - * Generates a raw .blend file thumbnail data from given image. - * - * \param bmain If not NULL, also store generated data in this Main. - * \param img ImBuf image to generate thumbnail data from. - * \return The generated .blend file raw thumbnail data. - */ -BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img) -{ - BlendThumbnail *data = NULL; - - if (bmain) { - MEM_SAFE_FREE(bmain->blen_thumb); - } - - if (img) { - const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y); - data = MEM_mallocN(sz, __func__); - - IMB_rect_from_float(img); /* Just in case... */ - data->width = img->x; - data->height = img->y; - memcpy(data->rect, img->rect, sz - sizeof(*data)); - } - - if (bmain) { - bmain->blen_thumb = data; - } - return data; -} - -/** - * Generates an image from raw .blend file thumbnail \a data. - * - * \param bmain Use this bmain->blen_thumb data if given \a data is NULL. - * \param data Raw .blend file thumbnail data. - * \return An ImBuf from given data, or NULL if invalid. - */ -ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data) -{ - ImBuf *img = NULL; - - if (!data && bmain) { - data = bmain->blen_thumb; - } - - if (data) { - /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail - * here (we do not want to pass the first two ints!). */ - img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata); - memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data)); - } - - return img; -} - -/** - * Generates an empty (black) thumbnail for given Main. - */ -void BKE_main_thumbnail_create(struct Main *bmain) -{ - MEM_SAFE_FREE(bmain->blen_thumb); - - bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__); - bmain->blen_thumb->width = BLEN_THUMB_SIZE; - bmain->blen_thumb->height = BLEN_THUMB_SIZE; -} - -/** - * Return filepath of given \a main. - */ -const char *BKE_main_blendfile_path(const Main *bmain) -{ - return bmain->name; -} - -/** - * Return filepath of global main (G_MAIN). - * - * \warning Usage is not recommended, you should always try to get a valid Main pointer from context... - */ -const char *BKE_main_blendfile_path_from_global(void) -{ - return BKE_main_blendfile_path(G_MAIN); -} - /* ***************** ID ************************ */ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name) { @@ -2320,7 +2076,7 @@ void BKE_library_make_local( * Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(ob, ob->data); + BKE_pose_rebuild(bmain, ob, ob->data, true); } } @@ -2368,16 +2124,58 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name) } /** - * Returns in name the name of the block, with a 3-character prefix prepended - * indicating whether it comes from a library, has a fake user, or no users. + * Generate full name of the data-block (without ID code, but with library is any) + * + * \note Result is unique to a given ID type in a given Main database. + * + * \param name An allocated string of minimal length MAX_ID_FULL_NAME, will be filled with generated string. + */ +void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id) +{ + strcpy(name, id->name + 2); + + if (id->lib != NULL) { + const size_t idname_len = strlen(id->name + 2); + const size_t libname_len = strlen(id->lib->id.name + 2); + + name[idname_len] = ' '; + name[idname_len + 1] = '['; + strcpy(name + idname_len + 2, id->lib->id.name + 2); + name[idname_len + 2 + libname_len] = ']'; + name[idname_len + 2 + libname_len + 1] = '\0'; + } +} + +/** + * Generate full name of the data-block (without ID code, but with library is any), with a 3-character prefix prepended + * indicating whether it comes from a library, is overriding, has a fake or no user, etc. + * + * \note Result is unique to a given ID type in a given Main database. + * + * \param name An allocated string of minimal length MAX_ID_FULL_NAME_UI, will be filled with generated string. */ -void BKE_id_ui_prefix(char name[MAX_ID_NAME + 1], const ID *id) +void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id) { - name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ' '; + name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_STATIC_OVERRIDE(id) ? 'O' : ' '; name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' '); name[2] = ' '; - strcpy(name + 3, id->name + 2); + BKE_id_full_name_get(name + 3, id); +} + +/** + * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any. + * + * \return A unique allocated string key for any ID in the whole Main database. + */ +char *BKE_id_to_unique_string_key(const struct ID *id) +{ + char name[MAX_ID_FULL_NAME + 2]; + name[0] = id->name[0]; + name[1] = id->name[1]; + BKE_id_full_name_get(name + 2, id); + + return BLI_strdup(name); } void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath) @@ -2417,8 +2215,103 @@ void BKE_id_tag_clear_atomic(ID *id, int tag) /** Check that given ID pointer actually is in G_MAIN. * Main intended use is for debug asserts in places we cannot easily get rid of G_Main... */ -bool BKE_id_is_in_gobal_main(ID *id) +bool BKE_id_is_in_global_main(ID *id) { /* We do not want to fail when id is NULL here, even though this is a bit strange behavior... */ return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1); } + +/************************* Datablock order in UI **************************/ + +static int *id_order_get(ID *id) +{ + /* Only for workspace tabs currently. */ + switch (GS(id->name)) { + case ID_WS: + return &((WorkSpace *)id)->order; + default: + return NULL; + } +} + +static int id_order_compare(const void *a, const void *b) +{ + ID *id_a = ((LinkData *)a)->data; + ID *id_b = ((LinkData *)b)->data; + + int *order_a = id_order_get(id_a); + int *order_b = id_order_get(id_b); + + if (order_a && order_b) { + if (*order_a < *order_b) { + return -1; + } + else if (*order_a > *order_b) { + return 1; + } + } + + return strcmp(id_a->name, id_b->name); +} + +/** + * Returns ordered list of datablocks for display in the UI. + * Result is list of LinkData of IDs that must be freed. + */ +void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb) +{ + BLI_listbase_clear(ordered_lb); + + for (ID *id = lb->first; id; id = id->next) { + BLI_addtail(ordered_lb, BLI_genericNodeN(id)); + } + + BLI_listbase_sort(ordered_lb, id_order_compare); + + int num = 0; + for (LinkData *link = ordered_lb->first; link; link = link->next) { + int *order = id_order_get(link->data); + if (order) { + *order = num++; + } + } +} + +/** + * Reorder ID in the list, before or after the "relative" ID. + */ +void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after) +{ + int *id_order = id_order_get(id); + int relative_order; + + if (relative) { + relative_order = *id_order_get(relative); + } + else { + relative_order = (after) ? BLI_listbase_count(lb) : 0; + } + + if (after) { + /* Insert after. */ + for (ID *other = lb->first; other; other = other->next) { + int *order = id_order_get(other); + if (*order > relative_order) { + (*order)++; + } + } + + *id_order = relative_order + 1; + } + else { + /* Insert before. */ + for (ID *other = lb->first; other; other = other->next) { + int *order = id_order_get(other); + if (*order < relative_order) { + (*order)--; + } + } + + *id_order = relative_order - 1; + } +} diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c index daf097b9f0b..1cc13b39a97 100644 --- a/source/blender/blenkernel/intern/library_idmap.c +++ b/source/blender/blenkernel/intern/library_idmap.c @@ -32,6 +32,7 @@ #include "BKE_idcode.h" #include "BKE_library.h" #include "BKE_library_idmap.h" /* own include */ +#include "BKE_main.h" /** \file blender/blenkernel/intern/library_idmap.c * \ingroup bke diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c new file mode 100644 index 00000000000..714730b2f52 --- /dev/null +++ b/source/blender/blenkernel/intern/library_override.c @@ -0,0 +1,789 @@ +/* + * ***** 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) 2016 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/library_override.c + * \ingroup bke + */ + +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_object_types.h" + +#include "DEG_depsgraph.h" +#include "BKE_library.h" +#include "BKE_library_override.h" +#include "BKE_library_remap.h" +#include "BKE_main.h" + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#include "PIL_time.h" +#include "PIL_time_utildefines.h" + +#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */ + +static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src); +static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src); + +static void bke_override_property_clear(IDOverrideStaticProperty *op); +static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop); + +/* Temp, for until static override is ready and tested enough to go 'public', we hide it by default in UI and such. */ +static bool _override_static_enabled = false; + +void BKE_override_static_enable(const bool do_enable) +{ + _override_static_enabled = do_enable; +} + +bool BKE_override_static_is_enabled() +{ + return _override_static_enabled; +} + +/** Initialize empty overriding of \a reference_id by \a local_id. */ +IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id) +{ + /* If reference_id is NULL, we are creating an override template for purely local data. + * Else, reference *must* be linked data. */ + BLI_assert(reference_id == NULL || reference_id->lib != NULL); + BLI_assert(local_id->override_static == NULL); + + ID *ancestor_id; + for (ancestor_id = reference_id; + ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL; + ancestor_id = ancestor_id->override_static->reference); + + if (ancestor_id != NULL && ancestor_id->override_static != NULL) { + /* Original ID has a template, use it! */ + BKE_override_static_copy(local_id, ancestor_id); + if (local_id->override_static->reference != reference_id) { + id_us_min(local_id->override_static->reference); + local_id->override_static->reference = reference_id; + id_us_plus(local_id->override_static->reference); + } + return local_id->override_static; + } + + /* Else, generate new empty override. */ + local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__); + local_id->override_static->reference = reference_id; + id_us_plus(local_id->override_static->reference); + local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + /* TODO do we want to add tag or flag to referee to mark it as such? */ + return local_id->override_static; +} + +/** Deep copy of a whole override from \a src_id to \a dst_id. */ +void BKE_override_static_copy(ID *dst_id, const ID *src_id) +{ + BLI_assert(src_id->override_static != NULL); + + if (dst_id->override_static != NULL) { + if (src_id->override_static == NULL) { + BKE_override_static_free(&dst_id->override_static); + return; + } + else { + BKE_override_static_clear(dst_id->override_static); + } + } + else if (src_id->override_static == NULL) { + return; + } + else { + BKE_override_static_init(dst_id, NULL); + } + + /* Source is already overriding data, we copy it but reuse its reference for dest ID. + * otherwise, source is only an override template, it then becomes reference of dest ID. */ + dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id; + id_us_plus(dst_id->override_static->reference); + + BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties); + for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first; + op_dst; + op_dst = op_dst->next, op_src = op_src->next) + { + bke_override_property_copy(op_dst, op_src); + } + + dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; +} + +/** Clear any overriding data from given \a override. */ +void BKE_override_static_clear(IDOverrideStatic *override) +{ + BLI_assert(override != NULL); + + for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) { + bke_override_property_clear(op); + } + BLI_freelistN(&override->properties); + + id_us_min(override->reference); + /* override->storage should never be refcounted... */ +} + +/** Free given \a override. */ +void BKE_override_static_free(struct IDOverrideStatic **override) +{ + BLI_assert(*override != NULL); + + BKE_override_static_clear(*override); + MEM_freeN(*override); + *override = NULL; +} + +static ID *override_static_create_from(Main *bmain, ID *reference_id) +{ + ID *local_id; + + if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) { + return NULL; + } + id_us_min(local_id); + + BKE_override_static_init(local_id, reference_id); + local_id->override_static->flag |= STATICOVERRIDE_AUTO; + + return local_id; +} + + +/** Create an overridden local copy of linked reference. */ +ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id) +{ + BLI_assert(reference_id != NULL); + BLI_assert(reference_id->lib != NULL); + + ID *local_id = override_static_create_from(bmain, reference_id); + + /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */ + BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); + + return local_id; +} + +/** Create overridden local copies of all tagged data-blocks in given Main. + * + * \note Set id->newid of overridden libs with newly created overrides, caller is responsible to clean those pointers + * before/after usage as needed. + * + * \return \a true on success, \a false otherwise. + */ +bool BKE_override_static_create_from_tag(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int a; + bool ret = true; + + const int num_types = a = set_listbasepointers(bmain, lbarray); + while (a--) { + for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) { + if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) { + ret = false; + } + } + } + } + + /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */ + a = num_types; + while (a--) { + for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) { + if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) { + ID *local_id = reference_id->newid; + BKE_libblock_remap(bmain, reference_id, local_id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE); + } + } + } + + return ret; +} + +/** + * Find override property from given RNA path, if it exists. + */ +IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path) +{ + /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */ + return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path)); +} + +/** + * Find override property from given RNA path, or create it if it does not exist. + */ +IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created) +{ + /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */ + IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path); + + if (op == NULL) { + op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__); + op->rna_path = BLI_strdup(rna_path); + BLI_addtail(&override->properties, op); + + if (r_created) { + *r_created = true; + } + } + else if (r_created) { + *r_created = false; + } + + return op; +} + +void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src) +{ + op_dst->rna_path = BLI_strdup(op_src->rna_path); + BLI_duplicatelist(&op_dst->operations, &op_src->operations); + + for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first; + opop_dst; + opop_dst = opop_dst->next, opop_src = opop_src->next) + { + bke_override_property_operation_copy(opop_dst, opop_src); + } +} + +void bke_override_property_clear(IDOverrideStaticProperty *op) +{ + BLI_assert(op->rna_path != NULL); + + MEM_freeN(op->rna_path); + + for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) { + bke_override_property_operation_clear(opop); + } + BLI_freelistN(&op->operations); +} + +/** + * Remove and free given \a override_property from given ID \a override. + */ +void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property) +{ + bke_override_property_clear(override_property); + BLI_freelinkN(&override->properties, override_property); +} + +/** + * Find override property operation from given sub-item(s), if it exists. + */ +IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find( + IDOverrideStaticProperty *override_property, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict) +{ + IDOverrideStaticPropertyOperation *opop; + const int subitem_defindex = -1; + + if (r_strict) { + *r_strict = true; + } + + if (subitem_locname != NULL) { + opop = BLI_findstring_ptr(&override_property->operations, subitem_locname, + offsetof(IDOverrideStaticPropertyOperation, subitem_local_name)); + + if (opop == NULL) { + return NULL; + } + + if (subitem_refname == NULL || opop->subitem_reference_name == NULL) { + return subitem_refname == opop->subitem_reference_name ? opop : NULL; + } + return (subitem_refname != NULL && opop->subitem_reference_name != NULL && + STREQ(subitem_refname, opop->subitem_reference_name)) ? opop : NULL; + } + + if (subitem_refname != NULL) { + opop = BLI_findstring_ptr(&override_property->operations, subitem_refname, + offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name)); + + if (opop == NULL) { + return NULL; + } + + if (subitem_locname == NULL || opop->subitem_local_name == NULL) { + return subitem_locname == opop->subitem_local_name ? opop : NULL; + } + return (subitem_locname != NULL && opop->subitem_local_name != NULL && + STREQ(subitem_locname, opop->subitem_local_name)) ? opop : NULL; + } + + if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) + { + return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL; + } + + if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index)))) + { + return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL; + } + + /* index == -1 means all indices, that is valid fallback in case we requested specific index. */ + if (!strict && (subitem_locindex != subitem_defindex) && + (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex), + offsetof(IDOverrideStaticPropertyOperation, subitem_local_index)))) + { + if (r_strict) { + *r_strict = false; + } + return opop; + } + + return NULL; +} + +/** + * Find override property operation from given sub-item(s), or create it if it does not exist. + */ +IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get( + IDOverrideStaticProperty *override_property, const short operation, + const char *subitem_refname, const char *subitem_locname, + const int subitem_refindex, const int subitem_locindex, + const bool strict, bool *r_strict, bool *r_created) +{ + IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property, + subitem_refname, subitem_locname, + subitem_refindex, subitem_locindex, + strict, r_strict); + + if (opop == NULL) { + opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__); + opop->operation = operation; + if (subitem_locname) { + opop->subitem_local_name = BLI_strdup(subitem_locname); + } + if (subitem_refname) { + opop->subitem_reference_name = BLI_strdup(subitem_refname); + } + opop->subitem_local_index = subitem_locindex; + opop->subitem_reference_index = subitem_refindex; + + BLI_addtail(&override_property->operations, opop); + + if (r_created) { + *r_created = true; + } + } + else if (r_created) { + *r_created = false; + } + + return opop; +} + +void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src) +{ + if (opop_src->subitem_reference_name) { + opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name); + } + if (opop_src->subitem_local_name) { + opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name); + } +} + +void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop) +{ + if (opop->subitem_reference_name) { + MEM_freeN(opop->subitem_reference_name); + } + if (opop->subitem_local_name) { + MEM_freeN(opop->subitem_local_name); + } +} + +/** + * Remove and free given \a override_property_operation from given ID \a override_property. + */ +void BKE_override_static_property_operation_delete( + IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation) +{ + bke_override_property_operation_clear(override_property_operation); + BLI_freelinkN(&override_property->operations, override_property_operation); +} + +/** + * Check that status of local data-block is still valid against current reference one. + * + * It means that all overridable, but not overridden, properties' local values must be equal to reference ones. + * Clears LIB_TAG_OVERRIDE_OK if they do not. + * + * This is typically used to detect whether some property has been changed in local and a new IDOverrideProperty + * (of IDOverridePropertyOperation) has to be added. + * + * \return true if status is OK, false otherwise. */ +bool BKE_override_static_status_check_local(Main *bmain, ID *local) +{ + BLI_assert(local->override_static != NULL); + + ID *reference = local->override_static->reference; + + if (reference == NULL) { + /* This is an override template, local status is always OK! */ + return true; + } + + BLI_assert(GS(local->name) == GS(reference->name)); + + /* Note that reference is assumed always valid, caller has to ensure that itself. */ + + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(reference, &rnaptr_reference); + + if (!RNA_struct_override_matches( + bmain, + &rnaptr_local, &rnaptr_reference, NULL, local->override_static, + RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) + { + local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + return false; + } + + return true; +} + +/** + * Check that status of reference data-block is still valid against current local one. + * + * It means that all non-overridden properties' local values must be equal to reference ones. + * Clears LIB_TAG_OVERRIDE_OK if they do not. + * + * This is typically used to detect whether some reference has changed and local needs to be updated against it. + * + * \return true if status is OK, false otherwise. */ +bool BKE_override_static_status_check_reference(Main *bmain, ID *local) +{ + BLI_assert(local->override_static != NULL); + + ID *reference = local->override_static->reference; + + if (reference == NULL) { + /* This is an override template, reference is virtual, so its status is always OK! */ + return true; + } + + BLI_assert(GS(local->name) == GS(reference->name)); + + if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) { + if (!BKE_override_static_status_check_reference(bmain, reference)) { + /* If reference is also override of another data-block, and its status is not OK, + * then this override is not OK either. + * Note that this should only happen when reloading libraries... */ + local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + return false; + } + } + + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(reference, &rnaptr_reference); + + if (!RNA_struct_override_matches( + bmain, + &rnaptr_local, &rnaptr_reference, NULL, local->override_static, + RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL)) + { + local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK; + return false; + } + + return true; +} + +/** + * Compares local and reference data-blocks and create new override operations as needed, + * or reset to reference values if overriding is not allowed. + * + * \note Defining override operations is only mandatory before saving a .blend file on disk (not for undo!). + * Knowing that info at runtime is only useful for UI/UX feedback. + * + * \note This is by far the biggest operation (the more time-consuming) of the three so far, since it has to go over + * all properties in depth (all overridable ones at least). Generating diff values and applying overrides + * are much cheaper. + * + * \return true if new overriding op was created, or some local data was reset. */ +bool BKE_override_static_operations_create(Main *bmain, ID *local, const bool force_auto) +{ + BLI_assert(local->override_static != NULL); + const bool is_template = (local->override_static->reference == NULL); + bool ret = false; + + if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) { + PointerRNA rnaptr_local, rnaptr_reference; + RNA_id_pointer_create(local, &rnaptr_local); + RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); + + eRNAOverrideMatchResult report_flags = 0; + RNA_struct_override_matches( + bmain, + &rnaptr_local, &rnaptr_reference, NULL, local->override_static, + RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags); + if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { + ret = true; + } +#ifndef NDEBUG + if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) { + printf("We did restore some properties of %s from its reference.\n", local->name); + } + if (ret) { + printf("We did generate static override rules for %s\n", local->name); + } + else { + printf("No new static override rules for %s\n", local->name); + } +#endif + } + return ret; +} + +/** Check all overrides from given \a bmain and create/update overriding operations as needed. */ +void BKE_main_override_static_operations_create(Main *bmain, const bool force_auto) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(bmain, lbarray); + + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + if (force_auto || + (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH))) + { + BKE_override_static_operations_create(bmain, id, force_auto); + id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH; + } + } + } +} + +/** Update given override from its reference (re-applying overridden properties). */ +void BKE_override_static_update(Main *bmain, ID *local) +{ + if (local->override_static == NULL || local->override_static->reference == NULL) { + return; + } + + /* Recursively do 'ancestors' overrides first, if any. */ + if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) { + BKE_override_static_update(bmain, local->override_static->reference); + } + + /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based + * on reference than on current override. + * So we work on temp copy of reference, and 'swap' its content with local. */ + + /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)! + * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do, + * as innefficient as it is. :/ + * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep + * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data + * also remain correct). */ + /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). + * Not impossible to do, but would rather see first if extra useless usual user handling is actually + * a (performances) issue here. */ + + ID *tmp_id; + id_copy(bmain, local->override_static->reference, &tmp_id, false); + + if (tmp_id == NULL) { + return; + } + + PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL; + RNA_id_pointer_create(local, &rnaptr_src); + RNA_id_pointer_create(tmp_id, &rnaptr_dst); + if (local->override_static->storage) { + rnaptr_storage = &rnaptr_storage_stack; + RNA_id_pointer_create(local->override_static->storage, rnaptr_storage); + } + + RNA_struct_override_apply(bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static); + + /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id, + * we'll actually free old, outdated data from local. */ + BKE_id_swap(bmain, local, tmp_id); + + /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */ + /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */ + BKE_libblock_free_ex(bmain, tmp_id, true, false); + + if (local->override_static->storage) { + /* We know this datablock is not used anywhere besides local->override->storage. */ + /* XXX For until we get fully shadow copies, we still need to ensure storage releases + * its usage of any ID pointers it may have. */ + BKE_libblock_free_ex(bmain, local->override_static->storage, true, false); + local->override_static->storage = NULL; + } + + local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK; + + /* Full rebuild of Depsgraph! */ + DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */ +} + +/** Update all overrides from given \a bmain. */ +void BKE_main_override_static_update(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(bmain, lbarray); + + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + if (id->override_static != NULL && id->lib == NULL) { + BKE_override_static_update(bmain, id); + } + } + } +} + +/*********************************************************************************************************************** + * Storage (how to wtore overriding data into .blend files). + * + * Basically: + * I) Only 'differential' storage needs special handling here. All others (replacing values or + * inserting/removing items from a collection) can be handled with simply storing current content of local data-block. + * II) We store the differential value into a second 'ghost' data-block, which is an empty ID of same type as local one, + * where we only define values that need differential data. + * + * This avoids us having to modify 'real' data-block at write time (and restoring it afterwards), which is inneficient, + * and potentially dangerous (in case of concurrent access...), while not using much extra memory in typical cases. + * It also ensures stored data-block always contains exact same data as "desired" ones (kind of "baked" data-blocks). + */ + +/** Initialize an override storage. */ +OverrideStaticStorage *BKE_override_static_operations_store_initialize(void) +{ + return BKE_main_new(); +} + +/** + * Generate suitable 'write' data (this only affects differential override operations). + * + * Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */ +ID *BKE_override_static_operations_store_start(Main *bmain, OverrideStaticStorage *override_storage, ID *local) +{ + BLI_assert(local->override_static != NULL); + BLI_assert(override_storage != NULL); + const bool is_template = (local->override_static->reference == NULL); + + if (is_template) { + /* This is actually purely local data with an override template, nothing to do here! */ + return NULL; + } + + /* Forcefully ensure we know about all needed override operations. */ + BKE_override_static_operations_create(bmain, local, false); + + ID *storage_id; +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_START_AVERAGED(BKE_override_operations_store_start); +#endif + + /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable + * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */ + /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code). + * Not impossible to do, but would rather see first is extra useless usual user handling is actually + * a (performances) issue here, before doing it. */ + id_copy((Main *)override_storage, local, &storage_id, false); + + if (storage_id != NULL) { + PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage; + RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference); + RNA_id_pointer_create(local, &rnaptr_final); + RNA_id_pointer_create(storage_id, &rnaptr_storage); + + if (!RNA_struct_override_store( + bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) + { + BKE_libblock_free_ex(override_storage, storage_id, true, false); + storage_id = NULL; + } + } + + local->override_static->storage = storage_id; + +#ifdef DEBUG_OVERRIDE_TIMEIT + TIMEIT_END_AVERAGED(BKE_override_operations_store_start); +#endif + return storage_id; +} + +/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */ +void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local) +{ + BLI_assert(local->override_static != NULL); + + /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until + * whole file is written anyway (otherwise we'd get mem pointers overlap...). */ + local->override_static->storage = NULL; +} + +void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage) +{ + /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs + * without increasing usercount of used data-blocks... */ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(override_storage, lbarray); + + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + while ((id = lb->first)) { + BKE_libblock_free_ex(override_storage, id, true, false); + } + } + + BKE_main_free(override_storage); +} diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index d59658a2a07..ea1b35e4c1e 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -31,14 +31,12 @@ #include "MEM_guardedalloc.h" -#include "DNA_actuator_types.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_brush_types.h" #include "DNA_camera_types.h" +#include "DNA_collection_types.h" #include "DNA_constraint_types.h" -#include "DNA_controller_types.h" -#include "DNA_group_types.h" #include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_lamp_types.h" @@ -52,15 +50,17 @@ #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_force_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -#include "DNA_sensor_types.h" #include "DNA_sequence_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" #include "DNA_sound_types.h" #include "DNA_text_types.h" #include "DNA_vfont_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" #include "DNA_world_types.h" #include "BLI_utildefines.h" @@ -69,8 +69,10 @@ #include "BLI_linklist_stack.h" #include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" +#include "BKE_gpencil_modifier.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -79,9 +81,9 @@ #include "BKE_node.h" #include "BKE_particle.h" #include "BKE_rigidbody.h" -#include "BKE_sca.h" #include "BKE_sequencer.h" #include "BKE_tracking.h" +#include "BKE_workspace.h" #define FOREACH_FINALIZE _finalize @@ -194,27 +196,8 @@ static void library_foreach_modifiersForeachIDLink( FOREACH_FINALIZE_VOID; } -static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer, - bool is_reference, void *user_data) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_particlesystemsObjectLooper( - ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag) -{ - LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); - - FOREACH_FINALIZE_VOID; -} - -static void library_foreach_sensorsObjectLooper( - bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag) +static void library_foreach_gpencil_modifiersForeachIDLink( + void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); @@ -222,17 +205,18 @@ static void library_foreach_sensorsObjectLooper( FOREACH_FINALIZE_VOID; } -static void library_foreach_controllersObjectLooper( - bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag) +static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer, + bool is_reference, void *user_data) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; + const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } -static void library_foreach_actuatorsObjectLooper( - bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag) +static void library_foreach_particlesystemsObjectLooper( + ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); @@ -296,6 +280,9 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex) static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) { FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER); + for (int i = 0; i < paint->tool_slots_len; i++) { + FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER); + } FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER); FOREACH_FINALIZE_VOID; @@ -312,6 +299,16 @@ static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone) FOREACH_FINALIZE_VOID; } +static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + FOREACH_CALLBACK_INVOKE(data, lc->collection, IDWALK_CB_NOP); + library_foreach_layer_collection(data, &lc->layer_collections); + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_ID_as_subdata_link( ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data) { @@ -384,6 +381,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call continue; } + if (id->override_static != NULL) { + CALLBACK_INVOKE_ID(id->override_static->reference, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE); + CALLBACK_INVOKE_ID(id->override_static->storage, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE); + } + library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER); AnimData *adt = BKE_animdata_from_id(id); @@ -402,8 +404,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call { Scene *scene = (Scene *) id; ToolSettings *toolsett = scene->toolsettings; - SceneRenderLayer *srl; - Base *base; CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP); CALLBACK_INVOKE(scene->world, IDWALK_CB_USER); @@ -413,35 +413,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data); } - /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later, - * since basact is just a pointer to one of those items. */ - CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP); - - for (srl = scene->r.layers.first; srl; srl = srl->next) { - FreestyleModuleConfig *fmc; - FreestyleLineSet *fls; - - if (srl->mat_override) { - CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER); - } - if (srl->light_override) { - CALLBACK_INVOKE(srl->light_override, IDWALK_CB_USER); - } - for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { - if (fmc->script) { - CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP); - } - } - for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { - if (fls->group) { - CALLBACK_INVOKE(fls->group, IDWALK_CB_USER); - } - if (fls->linestyle) { - CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER); - } - } - } - if (scene->ed) { Sequence *seq; SEQP_BEGIN(scene->ed, seq) @@ -459,10 +430,37 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call SEQ_END } - CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); - for (base = scene->base.first; base; base = base->next) { - CALLBACK_INVOKE(base->object, IDWALK_CB_USER); + for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) { + CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER); + } + for (CollectionChild *child = scene->master_collection->children.first; child; child = child->next) { + CALLBACK_INVOKE(child->collection, IDWALK_CB_USER); + } + + ViewLayer *view_layer; + for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + CALLBACK_INVOKE(base->object, IDWALK_CB_NOP); + } + + library_foreach_layer_collection(&data, &view_layer->layer_collections); + + for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) { + if (fmc->script) { + CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP); + } + } + + for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) { + if (fls->group) { + CALLBACK_INVOKE(fls->group, IDWALK_CB_USER); + } + + if (fls->linestyle) { + CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER); + } + } } for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) { @@ -470,8 +468,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call } if (toolsett) { - CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_NOP); - CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP); CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP); CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP); @@ -494,14 +490,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call if (toolsett->uvsculpt) { library_foreach_paint(&data, &toolsett->uvsculpt->paint); } + if (toolsett->gp_paint) { + library_foreach_paint(&data, &toolsett->gp_paint->paint); + } } if (scene->rigidbody_world) { BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data); } - CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP); - break; } @@ -586,6 +583,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call } modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data); + BKE_gpencil_modifiers_foreachIDLink(object, library_foreach_gpencil_modifiersForeachIDLink, &data); BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data); for (psys = object->particlesystem.first; psys; psys = psys->next) { @@ -599,10 +597,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP); } } - - BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data); - BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data); - BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data); break; } @@ -624,31 +618,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call for (i = 0; i < mesh->totcol; i++) { CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER); } - - /* XXX Really not happy with this - probably texface should rather use some kind of - * 'texture slots' and just set indices in each poly/face item - would also save some memory. - * Maybe a nice TODO for blender2.8? */ - if (mesh->mtface || mesh->mtpoly) { - for (i = 0; i < mesh->pdata.totlayer; i++) { - if (mesh->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data; - - for (int j = 0; j < mesh->totpoly; j++, txface++) { - CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE); - } - } - } - - for (i = 0; i < mesh->fdata.totlayer; i++) { - if (mesh->fdata.layers[i].type == CD_MTFACE) { - MTFace *tface = (MTFace *)mesh->fdata.layers[i].data; - - for (int j = 0; j < mesh->totface; j++, tface++) { - CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE); - } - } - } - } break; } @@ -681,19 +650,17 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_MA: { Material *material = (Material *) id; - for (i = 0; i < MAX_MTEX; i++) { - if (material->mtex[i]) { - library_foreach_mtex(&data, material->mtex[i]); - } - } if (material->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data); } - CALLBACK_INVOKE(material->group, IDWALK_CB_USER); if (material->texpaintslot != NULL) { CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP); } + if (material->gp_style != NULL) { + CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER); + CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER); + } break; } @@ -705,16 +672,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data); } CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER); - if (texture->env) { - CALLBACK_INVOKE(texture->env->object, IDWALK_CB_NOP); - CALLBACK_INVOKE(texture->env->ima, IDWALK_CB_USER); - } - if (texture->pd) - CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP); - if (texture->vd) - CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP); - if (texture->ot) - CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP); break; } @@ -728,11 +685,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_LA: { Lamp *lamp = (Lamp *) id; - for (i = 0; i < MAX_MTEX; i++) { - if (lamp->mtex[i]) { - library_foreach_mtex(&data, lamp->mtex[i]); - } - } if (lamp->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data); @@ -744,6 +696,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call { Camera *camera = (Camera *) id; CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP); + for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) { + if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) { + CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER); + } + else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) { + CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER); + } + } + break; } @@ -754,21 +715,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call break; } - case ID_SCR: - { - bScreen *screen = (bScreen *) id; - CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE); - break; - } - case ID_WO: { World *world = (World *) id; - for (i = 0; i < MAX_MTEX; i++) { - if (world->mtex[i]) { - library_foreach_mtex(&data, world->mtex[i]); - } - } if (world->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data); @@ -783,12 +732,22 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call break; } + case ID_LP: + { + LightProbe *probe = (LightProbe *) id; + CALLBACK_INVOKE(probe->image, IDWALK_CB_USER); + CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP); + break; + } + case ID_GR: { - Group *group = (Group *) id; - GroupObject *gob; - for (gob = group->gobject.first; gob; gob = gob->next) { - CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE); + Collection *collection = (Collection *) id; + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER); + } + for (CollectionChild *child = collection->children.first; child; child = child->next) { + CALLBACK_INVOKE(child->collection, IDWALK_CB_USER); } break; } @@ -828,6 +787,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP); CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP); CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER); + if (brush->gpencil_settings) { + CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER); + } library_foreach_mtex(&data, &brush->mtex); library_foreach_mtex(&data, &brush->mask_mtex); break; @@ -877,6 +839,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call } } } + + for (ParticleDupliWeight *dw = psett->dupliweights.first; dw; dw = dw->next) { + CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP); + } break; } @@ -971,22 +937,60 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call } break; } + + case ID_WM: + { + wmWindowManager *wm = (wmWindowManager *)id; + + for (wmWindow *win = wm->windows.first; win; win = win->next) { + ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); + + CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE); + + CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP); + /* allow callback to set a different workspace */ + BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); + } + break; + } + + case ID_WS: + { + WorkSpace *workspace = (WorkSpace *)id; + ListBase *layouts = BKE_workspace_layouts_get(workspace); + + for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) { + bScreen *screen = BKE_workspace_layout_screen_get(layout); + + /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer. + * However we can't access layout->screen here since we are outside the workspace project. */ + CALLBACK_INVOKE(screen, IDWALK_CB_USER); + /* allow callback to set a different screen */ + BKE_workspace_layout_screen_set(layout, screen); + } + break; + } case ID_GD: { bGPdata *gpencil = (bGPdata *) id; + /* materials */ + for (i = 0; i < gpencil->totcol; i++) { + CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER); + } - for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) { - CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP); + for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) { + CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP); } + break; } /* Nothing needed for those... */ + case ID_SCR: case ID_IM: case ID_VF: case ID_TXT: case ID_SO: - case ID_WM: case ID_PAL: case ID_PC: case ID_CF: @@ -1063,14 +1067,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT, ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT)); case ID_OB: - /* Could be the following, but simpler to just always say 'yes' here. */ -#if 0 - return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */ - ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC - /* + constraints, modifiers and game logic ID types... */); -#else + /* Could be more specific, but simpler to just always say 'yes' here. */ return true; -#endif case ID_ME: return ELEM(id_type_used, ID_ME, ID_KE, ID_MA, ID_IM); case ID_CU: @@ -1096,16 +1094,12 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) case ID_SPK: return ELEM(id_type_used, ID_SO); case ID_GR: - return ELEM(id_type_used, ID_OB); + return ELEM(id_type_used, ID_OB, ID_GR); case ID_NT: - /* Could be the following, but node.id has no type restriction... */ -#if 0 - return ELEM(id_type_used, ID_GD /* + node.id types... */); -#else + /* Could be more specific, but node.id has no type restriction... */ return true; -#endif case ID_BR: - return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE); + return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA); case ID_PA: return ELEM(id_type_used, ID_OB, ID_GR, ID_TE); case ID_MC: @@ -1114,13 +1108,18 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */ case ID_LS: return (ELEM(id_type_used, ID_TE, ID_OB)); + case ID_LP: + return ELEM(id_type_used, ID_IM); + case ID_GD: + return ELEM(id_type_used, ID_MA); + case ID_WS: + return ELEM(id_type_used, ID_SCR, ID_SCE); case ID_IM: case ID_VF: case ID_TXT: case ID_SO: case ID_AR: case ID_AC: - case ID_GD: case ID_WM: case ID_PAL: case ID_PC: diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index f791d9a6591..404028f336e 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -39,7 +39,7 @@ #include "DNA_brush_types.h" #include "DNA_camera_types.h" #include "DNA_cachefile_types.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" #include "DNA_ipo_types.h" #include "DNA_key_types.h" @@ -53,6 +53,7 @@ #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" @@ -60,6 +61,7 @@ #include "DNA_text_types.h" #include "DNA_vfont_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" #include "DNA_world_types.h" #include "BLI_blenlib.h" @@ -71,11 +73,10 @@ #include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_font.h" -#include "BKE_group.h" #include "BKE_gpencil.h" #include "BKE_idprop.h" #include "BKE_image.h" @@ -83,7 +84,9 @@ #include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -99,15 +102,19 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" -#include "BKE_sca.h" +#include "BKE_lightprobe.h" #include "BKE_speaker.h" #include "BKE_sound.h" #include "BKE_screen.h" #include "BKE_scene.h" #include "BKE_text.h" #include "BKE_texture.h" +#include "BKE_workspace.h" #include "BKE_world.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -173,6 +180,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id } if (*id_p && (*id_p == old_id)) { + const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0; const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0; const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, @@ -183,11 +191,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); + const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0; const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; #ifdef DEBUG_PRINT - printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n", - id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect); + printf("In %s (lib %p): Remapping %s (%p) to %s (%p) " + "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n", + id->name, id->lib, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, + is_indirect, skip_indirect, is_reference, skip_reference); #endif if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) { @@ -199,7 +210,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id * (skipped_indirect too). */ if ((is_never_null && skip_never_null) || (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) || - (skip_indirect && is_indirect)) + (skip_indirect && is_indirect) || + (is_reference && skip_reference)) { if (is_indirect) { id_remap_data->skipped_indirect++; @@ -212,7 +224,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id } } } - else if (is_never_null || is_obj_editmode) { + else if (is_never_null || is_obj_editmode || is_reference) { id_remap_data->skipped_direct++; } else { @@ -229,7 +241,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id else { if (!is_never_null) { *id_p = new_id; - DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update_ex(id_remap_data->bmain, id_self, DEG_TAG_TRANSFORM | DEG_TAG_TIME | DEG_TAG_GEOMETRY); } if (cb_flag & IDWALK_CB_USER) { id_us_min(old_id); @@ -251,58 +263,9 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id return IDWALK_RET_NOP; } -/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */ -static void libblock_remap_data_preprocess_scene_base_unlink( - IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect) -{ - if (skip_indirect && is_indirect) { - r_id_remap_data->skipped_indirect++; - r_id_remap_data->skipped_refcounted++; - } - else { - id_us_min((ID *)base->object); - BKE_scene_base_unlink(sce, base); - MEM_freeN(base); - if (!is_indirect) { - r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; - } - } -} - static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) { switch (GS(r_id_remap_data->id->name)) { - case ID_SCE: - { - Scene *sce = (Scene *)r_id_remap_data->id; - - if (!r_id_remap_data->new_id) { - const bool is_indirect = (sce->id.lib != NULL); - const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; - - /* In case we are unlinking... */ - if (!r_id_remap_data->old_id) { - /* ... everything from scene. */ - Base *base, *base_next; - for (base = sce->base.first; base; base = base_next) { - base_next = base->next; - libblock_remap_data_preprocess_scene_base_unlink( - r_id_remap_data, sce, base, skip_indirect, is_indirect); - } - } - else if (GS(r_id_remap_data->old_id->name) == ID_OB) { - /* ... a specific object from scene. */ - Object *old_ob = (Object *)r_id_remap_data->old_id; - Base *base = BKE_scene_base_find(sce, old_ob); - - if (base) { - libblock_remap_data_preprocess_scene_base_unlink( - r_id_remap_data, sce, base, skip_indirect, is_indirect); - } - } - } - break; - } case ID_OB: { ID *old_id = r_id_remap_data->old_id; @@ -328,58 +291,49 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) } } +/* Can be called with both old_ob and new_ob being NULL, this means we have to check whole Main database then. */ static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob) { - if (old_ob->flag & OB_FROMGROUP) { - /* Note that for Scene's BaseObject->flag, either we: - * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already. - * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is. - * So in any case, no need to update them here. */ - if (BKE_group_object_find(bmain, NULL, old_ob) == NULL) { - old_ob->flag &= ~OB_FROMGROUP; - } - if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ - for (Group *group = bmain->group.first; group; group = group->id.next) { - BKE_group_object_unlink(bmain, group, NULL, NULL, NULL); + if (new_ob == NULL) { + /* In case we unlinked old_ob (new_ob is NULL), the object has already + * been removed from the scenes and their collections. We still have + * to remove the NULL children from collections not used in any scene. */ + BKE_collections_object_remove_nulls(bmain); + } + + BKE_main_collection_sync_remap(bmain); + + if (old_ob == NULL) { + for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) { + if (ob->type == OB_MBALL && BKE_mball_is_basis(ob)) { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } } - else { - new_ob->flag |= OB_FROMGROUP; - } } - if (old_ob->type == OB_MBALL) { - for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + else { + for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) { if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + break; /* There is only one basis... */ } } } } -static void libblock_remap_data_postprocess_group_scene_unlink(Main *bmain, Scene *sce, ID *old_id) +/* Can be called with both old_collection and new_collection being NULL, + * this means we have to check whole Main database then. */ +static void libblock_remap_data_postprocess_collection_update( + Main *bmain, Collection *UNUSED(old_collection), Collection *new_collection) { - /* Note that here we assume no object has no base (i.e. all objects are assumed instanced - * in one scene...). */ - for (Base *base = sce->base.first; base; base = base->next) { - if (base->flag & OB_FROMGROUP) { - Object *ob = base->object; - - if (ob->flag & OB_FROMGROUP) { - Group *grp = BKE_group_object_find(bmain, NULL, ob); - - /* Unlinked group (old_id) is still in bmain... */ - if (grp && (&grp->id == old_id || grp->id.us == 0)) { - grp = BKE_group_object_find(bmain, grp, ob); - } - if (!grp) { - ob->flag &= ~OB_FROMGROUP; - } - } - if (!(ob->flag & OB_FROMGROUP)) { - base->flag &= ~OB_FROMGROUP; - } - } + if (new_collection == NULL) { + /* XXX Complex cases can lead to NULL pointers in other collections than old_collection, + * and BKE_main_collection_sync_remap() does not tolerate any of those, so for now always check whole + * existing collections for NULL pointers. + * I'd consider optimizing that whole collection remapping process a TODO for later. */ + BKE_collections_child_remove_nulls(bmain, NULL /*old_collection*/); } + + BKE_main_collection_sync_remap(bmain); } static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *ob, ID *new_id) @@ -480,10 +434,6 @@ ATTR_NONNULL(1) static void libblock_remap_data( } } - if (old_id && GS(old_id->name) == ID_OB) { - BKE_sca_logic_links_remap(bmain, (Object *)old_id, (Object *)new_id); - } - /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior * though, we can always add an option (flag) to control this later if needed. */ if (old_id && (old_id->flag & LIB_FAKEUSER)) { @@ -567,11 +517,7 @@ void BKE_libblock_remap_locked( libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; case ID_GR: - if (!new_id) { /* Only affects us in case group was unlinked. */ - for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { - libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); - } - } + libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id); break; case ID_ME: case ID_CU: @@ -594,8 +540,8 @@ void BKE_libblock_remap_locked( libblock_remap_data_postprocess_nodetree_update(bmain, new_id); BKE_main_lock(bmain); - /* Full rebuild of DAG! */ - DAG_relations_tag_update(bmain); + /* Full rebuild of DEG! */ + DEG_relations_tag_update(bmain); } void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags) @@ -668,32 +614,22 @@ void BKE_libblock_relink_ex( switch (GS(id->name)) { case ID_SCE: { - Scene *sce = (Scene *)id; - if (old_id) { switch (GS(old_id->name)) { case ID_OB: - { libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id); break; - } case ID_GR: - if (!new_id) { /* Only affects us in case group was unlinked. */ - libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); - } + libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id); break; default: break; } } else { - /* No choice but to check whole objects/groups. */ - for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { - libblock_remap_data_postprocess_object_update(bmain, ob, NULL); - } - for (Group *grp = bmain->group.first; grp; grp = grp->id.next) { - libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); - } + /* No choice but to check whole objects/collections. */ + libblock_remap_data_postprocess_collection_update(bmain, NULL, NULL); + libblock_remap_data_postprocess_object_update(bmain, NULL, NULL); } break; } @@ -747,6 +683,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) MEM_freeN(id->properties); } + if (id->override_static) { + BKE_override_static_free(&id->override_static); + } + /* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */ } @@ -755,7 +695,7 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag)) const short type = GS(id->name); switch (type) { case ID_SCE: - BKE_scene_free((Scene *)id); + BKE_scene_free_ex((Scene *)id, false); break; case ID_LI: BKE_library_free((Library *)id); @@ -811,11 +751,14 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag)) case ID_SPK: BKE_speaker_free((Speaker *)id); break; + case ID_LP: + BKE_lightprobe_free((LightProbe *)id); + break; case ID_SO: BKE_sound_free((bSound *)id); break; case ID_GR: - BKE_group_free((Group *)id); + BKE_collection_free((Collection *)id); break; case ID_AR: BKE_armature_free((bArmature *)id); @@ -857,6 +800,9 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag)) case ID_CF: BKE_cachefile_free((CacheFile *)id); break; + case ID_WS: + BKE_workspace_free((WorkSpace *)id); + break; } } @@ -867,7 +813,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i if (use_flag_from_idtag) { if ((id->tag & LIB_TAG_NO_MAIN) != 0) { - flag |= LIB_ID_FREE_NO_MAIN; + flag |= LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER | LIB_ID_FREE_NO_DEG_TAG; } else { flag &= ~LIB_ID_FREE_NO_MAIN; @@ -895,7 +841,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i const short type = GS(id->name); if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) { - DAG_id_type_tag(bmain, type); + DEG_id_type_tag(bmain, type); } #ifdef WITH_PYTHON @@ -958,7 +904,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b short type = GS(id->name); ListBase *lb = which_libbase(bmain, type); - DAG_id_type_tag(bmain, type); + DEG_id_type_tag(bmain, type); #ifdef WITH_PYTHON #ifdef WITH_PYTHON_SAFETY @@ -1007,8 +953,8 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ id_us_min(id); - /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. - * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, + /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object. + * Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes, * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets * fully unlinked. * But only for local objects, not linked ones! diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c new file mode 100644 index 00000000000..4cb2b450afe --- /dev/null +++ b/source/blender/blenkernel/intern/lightprobe.c @@ -0,0 +1,101 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/lightprobe.c + * \ingroup bke + */ + +#include "DNA_object_types.h" +#include "DNA_lightprobe_types.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_animsys.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_lightprobe.h" +#include "BKE_main.h" + +void BKE_lightprobe_init(LightProbe *probe) +{ + BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(probe, id)); + + probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4; + probe->distinf = 2.5f; + probe->distpar = 2.5f; + probe->falloff = 0.2f; + probe->clipsta = 0.8f; + probe->clipend = 40.0f; + probe->vis_bias = 1.0f; + probe->vis_blur = 0.2f; + probe->intensity = 1.0f; + + probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA; +} + +void *BKE_lightprobe_add(Main *bmain, const char *name) +{ + LightProbe *probe; + + probe = BKE_libblock_alloc(bmain, ID_LP, name, 0); + + BKE_lightprobe_init(probe); + + return probe; +} + +/** + * Only copy internal data of LightProbe ID from source to already allocated/initialized destination. + * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * + * WARNING! This function will not handle ID user count! + * + * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). + */ +void BKE_lightprobe_copy_data( + Main *UNUSED(bmain), LightProbe *UNUSED(probe_dst), const LightProbe *UNUSED(probe_src), const int UNUSED(flag)) +{ + /* Nothing to do here. */ +} + +LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe) +{ + LightProbe *probe_copy; + BKE_id_copy_ex(bmain, &probe->id, (ID **)&probe_copy, 0, false); + return probe_copy; +} + +void BKE_lightprobe_make_local(Main *bmain, LightProbe *probe, const bool lib_local) +{ + BKE_id_make_local_generic(bmain, &probe->id, true, lib_local); +} + +void BKE_lightprobe_free(LightProbe *probe) +{ + BKE_animdata_free((ID *)probe, false); +} diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index e00884c8a9d..5757ae7480b 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -212,20 +212,11 @@ void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local); } -FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene) +FreestyleLineStyle *BKE_linestyle_active_from_view_layer(ViewLayer *view_layer) { - SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay); - if (!actsrl) { - return NULL; - } - - FreestyleConfig *config = &actsrl->freestyleConfig; + FreestyleConfig *config = &view_layer->freestyle_config; FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config); - - if (lineset) { - return lineset->linestyle; - } - return NULL; + return (lineset) ? lineset->linestyle : NULL; } static LineStyleModifier *new_modifier(const char *name, int type, size_t size) diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c new file mode 100644 index 00000000000..6291e35e968 --- /dev/null +++ b/source/blender/blenkernel/intern/main.c @@ -0,0 +1,446 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/main.c + * \ingroup bke + * + * Contains management of Main database itself. + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_mempool.h" +#include "BLI_threads.h" + +#include "DNA_ID.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_main.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +Main *BKE_main_new(void) +{ + Main *bmain = MEM_callocN(sizeof(Main), "new main"); + bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock"); + BLI_spin_init((SpinLock *)bmain->lock); + return bmain; +} + +void BKE_main_free(Main *mainvar) +{ + /* also call when reading a file, erase all, etc */ + ListBase *lbarray[MAX_LIBARRAY]; + int a; + + MEM_SAFE_FREE(mainvar->blen_thumb); + + a = set_listbasepointers(mainvar, lbarray); + while (a--) { + ListBase *lb = lbarray[a]; + ID *id; + + while ( (id = lb->first) ) { +#if 1 + BKE_libblock_free_ex(mainvar, id, false, false); +#else + /* errors freeing ID's can be hard to track down, + * enable this so valgrind will give the line number in its error log */ + switch (a) { + case 0: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 1: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 2: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 3: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 4: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 5: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 6: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 7: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 8: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 9: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 10: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 11: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 12: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 13: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 14: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 15: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 16: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 17: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 18: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 19: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 20: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 21: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 22: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 23: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 24: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 25: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 26: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 27: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 28: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 29: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 30: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 31: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 32: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 33: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 34: BKE_libblock_free_ex(mainvar, id, false, false); break; + default: + BLI_assert(0); + break; + } +#endif + } + } + + if (mainvar->relations) { + BKE_main_relations_free(mainvar); + } + + BLI_spin_end((SpinLock *)mainvar->lock); + MEM_freeN(mainvar->lock); + MEM_freeN(mainvar); +} + +void BKE_main_lock(struct Main *bmain) +{ + BLI_spin_lock((SpinLock *) bmain->lock); +} + +void BKE_main_unlock(struct Main *bmain) +{ + BLI_spin_unlock((SpinLock *) bmain->lock); +} + + +static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag) +{ + MainIDRelations *rel = user_data; + + if (*id_pointer) { + MainIDRelationsEntry *entry, **entry_p; + + entry = BLI_mempool_alloc(rel->entry_pool); + if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) { + entry->next = *entry_p; + } + else { + entry->next = NULL; + } + entry->id_pointer = id_pointer; + entry->usage_flag = cb_flag; + *entry_p = entry; + + entry = BLI_mempool_alloc(rel->entry_pool); + if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) { + entry->next = *entry_p; + } + else { + entry->next = NULL; + } + entry->id_pointer = (ID **)id_self; + entry->usage_flag = cb_flag; + *entry_p = entry; + } + + return IDWALK_RET_NOP; +} + +/** Generate the mappings between used IDs and their users, and vice-versa. */ +void BKE_main_relations_create(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a; + + if (bmain->relations != NULL) { + BKE_main_relations_free(bmain); + } + + bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__); + bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP); + + for (a = set_listbasepointers(bmain, lbarray); a--; ) { + for (id = lbarray[a]->first; id; id = id->next) { + BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY); + } + } +} + +void BKE_main_relations_free(Main *bmain) +{ + if (bmain->relations) { + if (bmain->relations->id_used_to_user) { + BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL); + } + if (bmain->relations->id_user_to_used) { + BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL); + } + BLI_mempool_destroy(bmain->relations->entry_pool); + MEM_freeN(bmain->relations); + bmain->relations = NULL; + } +} + +/** + * Generates a raw .blend file thumbnail data from given image. + * + * \param bmain If not NULL, also store generated data in this Main. + * \param img ImBuf image to generate thumbnail data from. + * \return The generated .blend file raw thumbnail data. + */ +BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img) +{ + BlendThumbnail *data = NULL; + + if (bmain) { + MEM_SAFE_FREE(bmain->blen_thumb); + } + + if (img) { + const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y); + data = MEM_mallocN(sz, __func__); + + IMB_rect_from_float(img); /* Just in case... */ + data->width = img->x; + data->height = img->y; + memcpy(data->rect, img->rect, sz - sizeof(*data)); + } + + if (bmain) { + bmain->blen_thumb = data; + } + return data; +} + +/** + * Generates an image from raw .blend file thumbnail \a data. + * + * \param bmain Use this bmain->blen_thumb data if given \a data is NULL. + * \param data Raw .blend file thumbnail data. + * \return An ImBuf from given data, or NULL if invalid. + */ +ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data) +{ + ImBuf *img = NULL; + + if (!data && bmain) { + data = bmain->blen_thumb; + } + + if (data) { + /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail + * here (we do not want to pass the first two ints!). */ + img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata); + memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data)); + } + + return img; +} + +/** + * Generates an empty (black) thumbnail for given Main. + */ +void BKE_main_thumbnail_create(struct Main *bmain) +{ + MEM_SAFE_FREE(bmain->blen_thumb); + + bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__); + bmain->blen_thumb->width = BLEN_THUMB_SIZE; + bmain->blen_thumb->height = BLEN_THUMB_SIZE; +} + +/** + * Return filepath of given \a main. + */ +const char *BKE_main_blendfile_path(const Main *bmain) +{ + return bmain->name; +} + +/** + * Return filepath of global main (G_MAIN). + * + * \warning Usage is not recommended, you should always try to get a valid Main pointer from context... + */ +const char *BKE_main_blendfile_path_from_global(void) +{ + return BKE_main_blendfile_path(G_MAIN); +} + +/** + * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type. + */ +ListBase *which_libbase(Main *bmain, short type) +{ + switch ((ID_Type)type) { + case ID_SCE: + return &(bmain->scene); + case ID_LI: + return &(bmain->library); + case ID_OB: + return &(bmain->object); + case ID_ME: + return &(bmain->mesh); + case ID_CU: + return &(bmain->curve); + case ID_MB: + return &(bmain->mball); + case ID_MA: + return &(bmain->mat); + case ID_TE: + return &(bmain->tex); + case ID_IM: + return &(bmain->image); + case ID_LT: + return &(bmain->latt); + case ID_LA: + return &(bmain->lamp); + case ID_CA: + return &(bmain->camera); + case ID_IP: + return &(bmain->ipo); + case ID_KE: + return &(bmain->key); + case ID_WO: + return &(bmain->world); + case ID_SCR: + return &(bmain->screen); + case ID_VF: + return &(bmain->vfont); + case ID_TXT: + return &(bmain->text); + case ID_SPK: + return &(bmain->speaker); + case ID_LP: + return &(bmain->lightprobe); + case ID_SO: + return &(bmain->sound); + case ID_GR: + return &(bmain->collection); + case ID_AR: + return &(bmain->armature); + case ID_AC: + return &(bmain->action); + case ID_NT: + return &(bmain->nodetree); + case ID_BR: + return &(bmain->brush); + case ID_PA: + return &(bmain->particle); + case ID_WM: + return &(bmain->wm); + case ID_GD: + return &(bmain->gpencil); + case ID_MC: + return &(bmain->movieclip); + case ID_MSK: + return &(bmain->mask); + case ID_LS: + return &(bmain->linestyle); + case ID_PAL: + return &(bmain->palettes); + case ID_PC: + return &(bmain->paintcurves); + case ID_CF: + return &(bmain->cachefiles); + case ID_WS: + return &(bmain->workspaces); + } + return NULL; +} + +/** + * puts into array *lb pointers to all the ListBase structs in main, + * and returns the number of them as the function result. This is useful for + * generic traversal of all the blocks in a Main (by traversing all the + * lists in turn), without worrying about block types. + * + * \note MAX_LIBARRAY define should match this code */ +int set_listbasepointers(Main *bmain, ListBase **lb) +{ + /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last. + * This is important because freeing data decreases usercounts of other datablocks, + * if this data is its self freed it can crash. */ + lb[INDEX_ID_LI] = &(bmain->library); /* Libraries may be accessed from pretty much any other ID... */ + lb[INDEX_ID_IP] = &(bmain->ipo); + lb[INDEX_ID_AC] = &(bmain->action); /* moved here to avoid problems when freeing with animato (aligorith) */ + lb[INDEX_ID_KE] = &(bmain->key); + lb[INDEX_ID_PAL] = &(bmain->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */ + lb[INDEX_ID_GD] = &(bmain->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */ + lb[INDEX_ID_NT] = &(bmain->nodetree); + lb[INDEX_ID_IM] = &(bmain->image); + lb[INDEX_ID_TE] = &(bmain->tex); + lb[INDEX_ID_MA] = &(bmain->mat); + lb[INDEX_ID_VF] = &(bmain->vfont); + + /* Important!: When adding a new object type, + * the specific data should be inserted here + */ + + lb[INDEX_ID_AR] = &(bmain->armature); + + lb[INDEX_ID_CF] = &(bmain->cachefiles); + lb[INDEX_ID_ME] = &(bmain->mesh); + lb[INDEX_ID_CU] = &(bmain->curve); + lb[INDEX_ID_MB] = &(bmain->mball); + + lb[INDEX_ID_LT] = &(bmain->latt); + lb[INDEX_ID_LA] = &(bmain->lamp); + lb[INDEX_ID_CA] = &(bmain->camera); + + lb[INDEX_ID_TXT] = &(bmain->text); + lb[INDEX_ID_SO] = &(bmain->sound); + lb[INDEX_ID_GR] = &(bmain->collection); + lb[INDEX_ID_PAL] = &(bmain->palettes); + lb[INDEX_ID_PC] = &(bmain->paintcurves); + lb[INDEX_ID_BR] = &(bmain->brush); + lb[INDEX_ID_PA] = &(bmain->particle); + lb[INDEX_ID_SPK] = &(bmain->speaker); + lb[INDEX_ID_LP] = &(bmain->lightprobe); + + lb[INDEX_ID_WO] = &(bmain->world); + lb[INDEX_ID_MC] = &(bmain->movieclip); + lb[INDEX_ID_SCR] = &(bmain->screen); + lb[INDEX_ID_OB] = &(bmain->object); + lb[INDEX_ID_LS] = &(bmain->linestyle); /* referenced by scenes */ + lb[INDEX_ID_SCE] = &(bmain->scene); + lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */ + lb[INDEX_ID_WM] = &(bmain->wm); + lb[INDEX_ID_MSK] = &(bmain->mask); + + lb[INDEX_ID_NULL] = NULL; + + return (MAX_LIBARRAY - 1); +} + diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index b5742dbdbb7..97058467fd9 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -51,7 +51,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" + #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mask.h" @@ -61,6 +61,8 @@ #include "BKE_movieclip.h" #include "BKE_image.h" +#include "DEG_depsgraph_build.h" + static struct { ListBase splines; struct GHash *id_hash; @@ -817,7 +819,7 @@ Mask *BKE_mask_new(Main *bmain, const char *name) mask->sfra = 1; mask->efra = 100; - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); return mask; } @@ -1417,34 +1419,6 @@ void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe) * for now re-evaluate all. eventually this might work differently */ void BKE_mask_update_display(Mask *mask, float ctime) { -#if 0 - MaskLayer *masklay; - - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - MaskSpline *spline; - - for (spline = masklay->splines.first; spline; spline = spline->next) { - if (spline->points_deform) { - int i = 0; - - for (i = 0; i < spline->tot_point; i++) { - MaskSplinePoint *point; - - if (spline->points_deform) { - point = &spline->points_deform[i]; - BKE_mask_point_free(point); - } - } - if (spline->points_deform) { - MEM_freeN(spline->points_deform); - } - - spline->points_deform = NULL; - } - } - } -#endif - BKE_mask_evaluate(mask, ctime, false); } @@ -1457,18 +1431,6 @@ void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newfram } } -void BKE_mask_update_scene(Main *bmain, Scene *scene) -{ - Mask *mask; - - for (mask = bmain->mask.first; mask; mask = mask->id.next) { - if (mask->id.recalc & ID_RECALC_ALL) { - bool do_new_frame = (mask->id.recalc & ID_RECALC_DATA) != 0; - BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame); - } - } -} - void BKE_mask_parent_init(MaskParent *parent) { parent->id_type = ID_MC; @@ -1667,19 +1629,6 @@ MaskLayerShape *BKE_mask_layer_shape_verify_frame(MaskLayer *masklay, const int BKE_mask_layer_shape_sort(masklay); } -#if 0 - { - MaskLayerShape *masklay_shape; - int i = 0; - for (masklay_shape = masklay->splines_shapes.first; - masklay_shape; - masklay_shape = masklay_shape->next) - { - printf("mask %d, %d\n", i++, masklay_shape->frame); - } - } -#endif - return masklay_shape; } diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index e2a9691e577..55939f8eadf 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -40,12 +40,13 @@ #include "BLI_math.h" #include "DNA_mask_types.h" +#include "DNA_object_types.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_mask.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height) { @@ -897,24 +898,26 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime) } } -void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask) +void BKE_mask_eval_animation(struct Depsgraph *depsgraph, Mask *mask) { - DEG_debug_print_eval(__func__, mask->id.name, mask); + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask); for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) { - BKE_mask_layer_evaluate_animation(mask_layer, eval_ctx->ctime); + BKE_mask_layer_evaluate_animation(mask_layer, ctime); } } -void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask) +void BKE_mask_eval_update(struct Depsgraph *depsgraph, Mask *mask) { - DEG_debug_print_eval(__func__, mask->id.name, mask); + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask); for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) { - BKE_mask_layer_evaluate_deform(mask_layer, eval_ctx->ctime); + BKE_mask_layer_evaluate_deform(mask_layer, ctime); } } diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 2f2b82a00eb..ecdd30edc36 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -749,12 +749,6 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas for (j = 0; j < tot_diff_feather_points; j++) { copy_v2_v2(co_feather, diff_feather_points[j]); sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather); - - /* no need for these attrs */ -#if 0 - sf_vert->tmp.u = sf_vert_tot; - sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */ -#endif sf_vert->keyindex = SF_KEYINDEX_TEMP_ID; sf_vert_tot++; } @@ -1217,7 +1211,6 @@ static float maskrasterize_layer_z_depth_tri(const float pt[2], } #endif -#if 1 static float maskrasterize_layer_z_depth_quad(const float pt[2], const float v1[3], const float v2[3], const float v3[3], const float v4[3]) { @@ -1226,7 +1219,6 @@ static float maskrasterize_layer_z_depth_quad(const float pt[2], //return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]); return w[2] + w[3]; /* we can make this assumption for small speedup */ } -#endif static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], const float dist_orig, const float xy[2]) { @@ -1247,10 +1239,8 @@ static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], cons } #else /* we know all tris are close for now */ - if (1) { - if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { - return 0.0f; - } + if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) { + return 0.0f; } #endif } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 376e819268d..4d764e70ef1 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -37,12 +37,13 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_customdata_types.h" +#include "DNA_gpencil_types.h" #include "DNA_ID.h" #include "DNA_meta_types.h" #include "DNA_node_types.h" @@ -56,9 +57,10 @@ #include "BLI_array_utils.h" #include "BKE_animsys.h" +#include "BKE_brush.h" #include "BKE_displist.h" #include "BKE_global.h" -#include "BKE_depsgraph.h" +#include "BKE_gpencil.h" #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_library.h" @@ -73,6 +75,9 @@ #include "BKE_editmesh.h" #include "BKE_font.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "GPU_material.h" /* used in UI and render */ @@ -87,16 +92,10 @@ void init_def_material(void) /** Free (or release) any data used by this material (does not free the material itself). */ void BKE_material_free(Material *ma) { - int a; - BKE_animdata_free((ID *)ma, false); - for (a = 0; a < MAX_MTEX; a++) { - MEM_SAFE_FREE(ma->mtex[a]); - } - - MEM_SAFE_FREE(ma->ramp_col); - MEM_SAFE_FREE(ma->ramp_spec); + /* Free gpu material before the ntree */ + GPU_material_free(&ma->gpumaterial); /* is no lib link block, but material extension */ if (ma->nodetree) { @@ -107,105 +106,51 @@ void BKE_material_free(Material *ma) MEM_SAFE_FREE(ma->texpaintslot); - GPU_material_free(&ma->gpumaterial); + MEM_SAFE_FREE(ma->gp_style); BKE_icon_id_delete((ID *)ma); BKE_previewimg_free(&ma->preview); } +void BKE_material_init_gpencil_settings(Material *ma) +{ + if ((ma) && (ma->gp_style == NULL)) { + ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings"); + + MaterialGPencilStyle *gp_style = ma->gp_style; + /* set basic settings */ + gp_style->stroke_rgba[3] = 1.0f; + gp_style->pattern_gridsize = 0.1f; + gp_style->gradient_radius = 0.5f; + ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f); + ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f); + ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f); + gp_style->texture_opacity = 1.0f; + gp_style->texture_pixsize = 100.0f; + + gp_style->flag |= GP_STYLE_STROKE_SHOW; + gp_style->flag |= GP_STYLE_FILL_SHOW; + } +} + void BKE_material_init(Material *ma) { BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id)); - ma->r = ma->g = ma->b = ma->ref = 0.8; + ma->r = ma->g = ma->b = 0.8; ma->specr = ma->specg = ma->specb = 1.0; - ma->mirr = ma->mirg = ma->mirb = 1.0; - ma->spectra = 1.0; - ma->amb = 1.0; - ma->alpha = 1.0; - ma->spec = ma->hasize = 0.5; - ma->har = 50; - ma->starc = ma->ringc = 4; - ma->linec = 12; - ma->flarec = 1; - ma->flaresize = ma->subsize = 1.0; - ma->flareboost = 1; - ma->seed2 = 6; - ma->friction = 0.5; - ma->refrac = 4.0; - ma->roughness = 0.5; - ma->param[0] = 0.5; - ma->param[1] = 0.1; - ma->param[2] = 0.5; - ma->param[3] = 0.1; - ma->rms = 0.1; - ma->darkness = 1.0; - - ma->strand_sta = ma->strand_end = 1.0f; - - ma->ang = 1.0; - ma->ray_depth = 2; - ma->ray_depth_tra = 2; - ma->fresnel_mir = 0.0; - ma->fresnel_tra = 0.0; - ma->fresnel_tra_i = 1.25; - ma->fresnel_mir_i = 1.25; - ma->tx_limit = 0.0; - ma->tx_falloff = 1.0; - ma->shad_alpha = 1.0f; - ma->vcol_alpha = 0; - - ma->gloss_mir = ma->gloss_tra = 1.0; - ma->samp_gloss_mir = ma->samp_gloss_tra = 18; - ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005; - ma->dist_mir = 0.0; - ma->fadeto_mir = MA_RAYMIR_FADETOSKY; - - ma->rampfac_col = 1.0; - ma->rampfac_spec = 1.0; + // ma->alpha = 1.0; /* DEPRECATED */ + ma->spec = 0.5; + + ma->roughness = 0.25f; + ma->pr_lamp = 3; /* two lamps, is bits */ ma->pr_type = MA_SPHERE; - ma->sss_radius[0] = 1.0f; - ma->sss_radius[1] = 1.0f; - ma->sss_radius[2] = 1.0f; - ma->sss_col[0] = 1.0f; - ma->sss_col[1] = 1.0f; - ma->sss_col[2] = 1.0f; - ma->sss_error = 0.05f; - ma->sss_scale = 0.1f; - ma->sss_ior = 1.3f; - ma->sss_colfac = 1.0f; - ma->sss_texfac = 0.0f; - ma->sss_front = 1.0f; - ma->sss_back = 1.0f; - - ma->vol.density = 1.0f; - ma->vol.emission = 0.0f; - ma->vol.scattering = 1.0f; - ma->vol.reflection = 1.0f; - ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f; - ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f; - ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f; - ma->vol.density_scale = 1.0f; - ma->vol.depth_cutoff = 0.01f; - ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED; - ma->vol.stepsize = 0.2f; - ma->vol.shade_type = MA_VOL_SHADE_SHADED; - ma->vol.shadeflag |= MA_VOL_PRECACHESHADING; - ma->vol.precache_resolution = 50; - ma->vol.ms_spread = 0.2f; - ma->vol.ms_diff = 1.f; - ma->vol.ms_intensity = 1.f; - - ma->game.flag = GEMAT_BACKCULL; - ma->game.alpha_blend = 0; - ma->game.face_orientation = 0; - - ma->mode = MA_TRACEBLE | MA_SHADBUF | MA_SHADOW | MA_RAYBIAS | MA_TANGENT_STR | MA_ZTRANSP; - ma->mode2 = MA_CASTSHADOW; - ma->shade_flag = MA_APPROX_OCCLUSION; ma->preview = NULL; + + ma->alpha_threshold = 0.5f; + } Material *BKE_material_add(Main *bmain, const char *name) @@ -219,6 +164,21 @@ Material *BKE_material_add(Main *bmain, const char *name) return ma; } +Material *BKE_material_add_gpencil(Main *bmain, const char *name) +{ + Material *ma; + + ma = BKE_material_add(bmain, name); + + /* grease pencil settings */ + if (ma != NULL) { + BKE_material_init_gpencil_settings(ma); + BKE_brush_update_material(bmain, ma, NULL); + } + return ma; +} + + /** * Only copy internal data of Material ID from source to already allocated/initialized destination. * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. @@ -229,20 +189,6 @@ Material *BKE_material_add(Main *bmain, const char *name) */ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag) { - for (int a = 0; a < MAX_MTEX; a++) { - if (ma_src->mtex[a]) { - ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__); - *ma_dst->mtex[a] = *ma_src->mtex[a]; - } - } - - if (ma_src->ramp_col) { - ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col); - } - if (ma_src->ramp_spec) { - ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec); - } - if (ma_src->nodetree) { /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level * (see BKE_libblock_copy_ex()). */ @@ -260,7 +206,13 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot); } + if (ma_src->gp_style != NULL) { + ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style); + } + BLI_listbase_clear(&ma_dst->gpumaterial); + + /* TODO Duplicate Engine Settings and set runtime to NULL */ } Material *BKE_material_copy(Main *bmain, const Material *ma) @@ -281,29 +233,25 @@ Material *BKE_material_localize(Material *ma) * ... Once f*** nodes are fully converted to that too :( */ Material *man; - int a; - - man = BKE_libblock_copy_nolib(&ma->id, false); - /* no increment for texture ID users, in previewrender.c it prevents decrement */ - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a]) { - man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial"); - memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex)); - } - } - - if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); - if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); + BKE_id_copy_ex( + NULL, &ma->id, (ID **)&man, + (LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_COPY_NO_PREVIEW | + LIB_ID_COPY_NO_ANIMDATA), + false); man->texpaintslot = NULL; man->preview = NULL; - if (ma->nodetree) - man->nodetree = ntreeLocalize(ma->nodetree); - + /* man->gp_style = NULL; */ /* XXX: We probably don't want to clear here, or else we may get problems with COW later? */ BLI_listbase_clear(&man->gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ + + man->id.tag |= LIB_TAG_LOCALIZED; + return man; } @@ -317,6 +265,7 @@ Material ***give_matarar(Object *ob) Mesh *me; Curve *cu; MetaBall *mb; + bGPdata *gpd; if (ob->type == OB_MESH) { me = ob->data; @@ -330,6 +279,10 @@ Material ***give_matarar(Object *ob) mb = ob->data; return &(mb->mat); } + else if (ob->type == OB_GPENCIL) { + gpd = ob->data; + return &(gpd->mat); + } return NULL; } @@ -338,6 +291,7 @@ short *give_totcolp(Object *ob) Mesh *me; Curve *cu; MetaBall *mb; + bGPdata *gpd; if (ob->type == OB_MESH) { me = ob->data; @@ -351,6 +305,10 @@ short *give_totcolp(Object *ob) mb = ob->data; return &(mb->totcol); } + else if (ob->type == OB_GPENCIL) { + gpd = ob->data; + return &(gpd->totcol); + } return NULL; } @@ -367,6 +325,8 @@ Material ***give_matarar_id(ID *id) return &(((Curve *)id)->mat); case ID_MB: return &(((MetaBall *)id)->mat); + case ID_GD: + return &(((bGPdata *)id)->mat); default: break; } @@ -385,6 +345,8 @@ short *give_totcolp_id(ID *id) return &(((Curve *)id)->totcol); case ID_MB: return &(((MetaBall *)id)->totcol); + case ID_GD: + return &(((bGPdata *)id)->totcol); default: break; } @@ -406,6 +368,9 @@ static void material_data_index_remove_id(ID *id, short index) case ID_MB: /* meta-elems don't have materials atm */ break; + case ID_GD: + BKE_gpencil_material_index_remove((bGPdata *)id, index); + break; default: break; } @@ -458,7 +423,8 @@ void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user) } *totcolp = totcol; - DAG_relations_tag_update(bmain); + DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } void BKE_material_append_id(Main *bmain, ID *id, Material *ma) @@ -475,7 +441,9 @@ void BKE_material_append_id(Main *bmain, ID *id, Material *ma) id_us_plus((ID *)ma); test_all_objects_materials(bmain, id); - DAG_relations_tag_update(bmain); + + DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } } @@ -509,7 +477,8 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data material_data_index_remove_id(id, index); } - DAG_relations_tag_update(bmain); + DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } } @@ -536,7 +505,8 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data) material_data_index_clear_id(id); } - DAG_relations_tag_update(bmain); + DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } } @@ -581,6 +551,21 @@ Material *give_current_material(Object *ob, short act) return ma; } +MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act) +{ + Material *ma = give_current_material(ob, act); + if (ma != NULL) { + if (ma->gp_style == NULL) { + BKE_material_init_gpencil_settings(ma); + } + + return ma->gp_style; + } + else { + return NULL; + } +} + Material *give_node_material(Material *ma) { if (ma && ma->use_nodes && ma->nodetree) { @@ -631,7 +616,8 @@ void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, boo if (ob->totcol && ob->actcol == 0) ob->actcol = 1; if (ob->actcol > ob->totcol) ob->actcol = ob->totcol; - DAG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_GEOMETRY); + DEG_relations_tag_update(bmain); } void test_object_materials(Main *bmain, Object *ob, ID *id) @@ -673,14 +659,6 @@ void assign_material_id(Main *bmain, ID *id, Material *ma, short act) if (act > MAXMAT) return; if (act < 1) act = 1; - /* this is needed for Python overrides, - * we just have to take care that the UI can't do this */ -#if 0 - /* prevent crashing when using accidentally */ - BLI_assert(id->lib == NULL); - if (id->lib) return; -#endif - /* test arraylens */ totcolp = give_totcolp_id(id); @@ -820,6 +798,9 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap) else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { BKE_curve_material_remap(ob->data, remap, ob->totcol); } + else if (ob->type == OB_GPENCIL) { + BKE_gpencil_material_remap(ob->data, remap, ob->totcol); + } else { /* add support for this object data! */ BLI_assert(matar == NULL); @@ -936,278 +917,8 @@ bool BKE_object_material_slot_add(Main *bmain, Object *ob) return true; } -static void do_init_render_material(Main *bmain, Material *ma, int r_mode, float *amb) -{ - MTex *mtex; - int a, needuv = 0, needtang = 0; - - if (ma->flarec == 0) ma->flarec = 1; - - /* add all texcoflags from mtex, texco and mapto were cleared in advance */ - for (a = 0; a < MAX_MTEX; a++) { - - /* separate tex switching */ - if (ma->septex & (1 << a)) continue; - - mtex = ma->mtex[a]; - if (mtex && mtex->tex && (mtex->tex->type | (mtex->tex->use_nodes && mtex->tex->nodetree) )) { - - ma->texco |= mtex->texco; - ma->mapto |= mtex->mapto; - - /* always get derivatives for these textures */ - if (ELEM(mtex->tex->type, TEX_IMAGE, TEX_ENVMAP)) ma->texco |= TEXCO_OSA; - else if (mtex->texflag & (MTEX_COMPAT_BUMP | MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) ma->texco |= TEXCO_OSA; - - if (ma->texco & (TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM | TEXCO_STRAND | TEXCO_STRESS)) needuv = 1; - else if (ma->texco & (TEXCO_GLOB | TEXCO_UV | TEXCO_OBJECT | TEXCO_SPEED)) needuv = 1; - else if (ma->texco & (TEXCO_LAVECTOR | TEXCO_VIEW)) needuv = 1; - - if ((ma->mapto & MAP_NORM) && (mtex->normapspace == MTEX_NSPACE_TANGENT)) - needtang = 1; - } - } - - if (needtang) ma->mode |= MA_NORMAP_TANG; - else ma->mode &= ~MA_NORMAP_TANG; - - if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) { - needuv = 1; - if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */ - } - if (needuv) ma->texco |= NEED_UV; - - /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */ - if (r_mode & R_RAYTRACE) { - if ((ma->mode & (MA_RAYMIRROR | MA_SHADOW_TRA)) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_RAYTRANSP))) { - ma->texco |= NEED_UV | TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM; - if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; - } - } - - if (amb) { - ma->ambr = ma->amb * amb[0]; - ma->ambg = ma->amb * amb[1]; - ma->ambb = ma->amb * amb[2]; - } - - /* local group override */ - if ((ma->shade_flag & MA_GROUP_LOCAL) && ma->id.lib && ma->group && ma->group->id.lib) { - Group *group; - - for (group = bmain->group.first; group; group = group->id.next) { - if (!ID_IS_LINKED(group) && STREQ(group->id.name, ma->group->id.name)) { - ma->group = group; - } - } - } -} - -static void init_render_nodetree(Main *bmain, bNodeTree *ntree, Material *basemat, int r_mode, float *amb) -{ - bNode *node; - - /* parses the geom+tex nodes */ - ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l); - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - if (GS(node->id->name) == ID_MA) { - Material *ma = (Material *)node->id; - if (ma != basemat) { - do_init_render_material(bmain, ma, r_mode, amb); - basemat->texco |= ma->texco; - } - - basemat->mode_l |= ma->mode & ~(MA_MODE_PIPELINE | MA_SHLESS); - basemat->mode2_l |= ma->mode2 & ~MA_MODE2_PIPELINE; - /* basemat only considered shadeless if all node materials are too */ - if (!(ma->mode & MA_SHLESS)) - basemat->mode_l &= ~MA_SHLESS; - - if (ma->strand_surfnor > 0.0f) - basemat->mode_l |= MA_STR_SURFDIFF; - } - else if (node->type == NODE_GROUP) - init_render_nodetree(bmain, (bNodeTree *)node->id, basemat, r_mode, amb); - } - else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) { - basemat->mode2_l |= MA_TANGENT_CONCRETE; - NodeShaderNormalMap *nm = node->storage; - bool taken_into_account = false; - for (int i = 0; i < basemat->nmap_tangent_names_count; i++) { - if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) { - taken_into_account = true; - break; - } - } - if (!taken_into_account) { - BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1); - strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map); - } - } - } -} - -void init_render_material(Main *bmain, Material *mat, int r_mode, float *amb) -{ - - do_init_render_material(bmain, mat, r_mode, amb); - - if (mat->nodetree && mat->use_nodes) { - /* mode_l will take the pipeline options from the main material, and the or-ed - * result of non-pipeline options from the nodes. shadeless is an exception, - * mode_l will have it set when all node materials are shadeless. */ - mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS; - mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE; - mat->nmap_tangent_names_count = 0; - init_render_nodetree(bmain, mat->nodetree, mat, r_mode, amb); - - if (!mat->nodetree->execdata) - mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree); - } - else { - mat->mode_l = mat->mode; - mat->mode2_l = mat->mode2; - - if (mat->strand_surfnor > 0.0f) - mat->mode_l |= MA_STR_SURFDIFF; - } -} - -void init_render_materials(Main *bmain, int r_mode, float *amb, bool do_default_material) -{ - Material *ma; - - /* clear these flags before going over materials, to make sure they - * are cleared only once, otherwise node materials contained in other - * node materials can go wrong */ - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->id.us) { - ma->texco = 0; - ma->mapto = 0; - } - } - - /* two steps, first initialize, then or the flags for layers */ - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - /* is_used flag comes back in convertblender.c */ - ma->flag &= ~MA_IS_USED; - if (ma->id.us) - init_render_material(bmain, ma, r_mode, amb); - } - - if (do_default_material) { - init_render_material(bmain, &defmaterial, r_mode, amb); - } -} - -/* only needed for nodes now */ -void end_render_material(Material *mat) -{ - if (mat && mat->nodetree && mat->use_nodes) { - if (mat->nodetree->execdata) - ntreeShaderEndExecTree(mat->nodetree->execdata); - } -} - -void end_render_materials(Main *bmain) -{ - Material *ma; - for (ma = bmain->mat.first; ma; ma = ma->id.next) - if (ma->id.us) - end_render_material(ma); -} - -static bool material_in_nodetree(bNodeTree *ntree, Material *mat) -{ - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - if (GS(node->id->name) == ID_MA) { - if (node->id == (ID *)mat) { - return true; - } - } - else if (node->type == NODE_GROUP) { - if (material_in_nodetree((bNodeTree *)node->id, mat)) { - return true; - } - } - } - } - - return false; -} - -bool material_in_material(Material *parmat, Material *mat) -{ - if (parmat == mat) - return true; - else if (parmat->nodetree && parmat->use_nodes) - return material_in_nodetree(parmat->nodetree, mat); - else - return false; -} - - /* ****************** */ -/* Update drivers for materials in a nodetree */ -static void material_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime) -{ - bNode *node; - - /* nodetree itself */ - if (ntree->adt && ntree->adt->drivers.first) { - BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* nodes */ - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - if (GS(node->id->name) == ID_MA) { - material_drivers_update(scene, (Material *)node->id, ctime); - } - else if (node->type == NODE_GROUP) { - material_node_drivers_update(scene, (bNodeTree *)node->id, ctime); - } - } - } -} - -/* Calculate all drivers for materials - * FIXME: this is really a terrible method which may result in some things being calculated - * multiple times. However, without proper despgraph support for these things, we are forced - * into this sort of thing... - */ -void material_drivers_update(Scene *scene, Material *ma, float ctime) -{ - //if (G.f & G_DEBUG) - // printf("material_drivers_update(%s, %s)\n", scene->id.name, ma->id.name); - - /* Prevent infinite recursion by checking (and tagging the material) as having been visited already - * (see BKE_scene_update_tagged()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (ma->id.tag & LIB_TAG_DOIT) - return; - - ma->id.tag |= LIB_TAG_DOIT; - - /* material itself */ - if (ma->adt && ma->adt->drivers.first) { - BKE_animsys_evaluate_animdata(scene, &ma->id, ma->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* nodes */ - if (ma->nodetree) { - material_node_drivers_update(scene, ma->nodetree, ctime); - } - - ma->id.tag &= ~LIB_TAG_DOIT; -} - bool BKE_object_material_slot_remove(Main *bmain, Object *ob) { Material *mao, ***matarar; @@ -1287,23 +998,16 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob) } /* check indices from mesh */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) { material_data_index_remove_id((ID *)ob->data, actcol - 1); - if (ob->curve_cache) { - BKE_displist_free(&ob->curve_cache->disp); + if (ob->runtime.curve_cache) { + BKE_displist_free(&ob->runtime.curve_cache->disp); } } return true; } -static bool get_mtex_slot_valid_texpaint(struct MTex *mtex) -{ - return (mtex && (mtex->texco == TEXCO_UV) && - mtex->tex && (mtex->tex->type == TEX_IMAGE) && - mtex->tex->ima); -} - static bNode *nodetree_uv_node_recursive(bNode *node) { bNode *inode; @@ -1324,14 +1028,58 @@ static bNode *nodetree_uv_node_recursive(bNode *node) return NULL; } -void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) +static int count_texture_nodes_recursive(bNodeTree *nodetree) { - MTex **mtex; - short count = 0; - short index = 0, i; + int tex_nodes = 0; + + for (bNode *node = nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { + tex_nodes++; + } + else if (node->type == NODE_GROUP) { + /* recurse into the node group and see if it contains any textures */ + tex_nodes += count_texture_nodes_recursive((bNodeTree *)node->id); + } + } + + return tex_nodes; +} + +static void fill_texpaint_slots_recursive(bNodeTree *nodetree, bNode *active_node, Material *ma, int *index) +{ + for (bNode *node = nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { + if (active_node == node) { + ma->paint_active_slot = *index; + } + ma->texpaintslot[*index].ima = (Image *)node->id; + + /* for new renderer, we need to traverse the treeback in search of a UV node */ + bNode *uvnode = nodetree_uv_node_recursive(node); + + if (uvnode) { + NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage; + ma->texpaintslot[*index].uvname = storage->uv_map; + /* set a value to index so UI knows that we have a valid pointer for the mesh */ + ma->texpaintslot[*index].valid = true; + } + else { + /* just invalidate the index here so UV map does not get displayed on the UI */ + ma->texpaintslot[*index].valid = false; + } + (*index)++; + } + else if (node->type == NODE_GROUP) { + /* recurse into the node group and see if it contains any textures */ + fill_texpaint_slots_recursive((bNodeTree *)node->id, active_node, ma, index); + } + } +} - bool use_nodes = BKE_scene_use_new_shading_nodes(scene); - bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene); +void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) +{ + int count = 0; + int index = 0; if (!ma) return; @@ -1348,88 +1096,25 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) return; } - if (use_nodes || ma->use_nodes) { - bNode *node, *active_node; - - if (!(ma->nodetree)) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } - - for (node = ma->nodetree->nodes.first; node; node = node->next) { - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) - count++; - } - - if (count == 0) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } - ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); - - active_node = nodeGetActiveTexture(ma->nodetree); - - for (node = ma->nodetree->nodes.first; node; node = node->next) { - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { - if (active_node == node) - ma->paint_active_slot = index; - ma->texpaintslot[index].ima = (Image *)node->id; - - /* for new renderer, we need to traverse the treeback in search of a UV node */ - if (use_nodes) { - bNode *uvnode = nodetree_uv_node_recursive(node); - - if (uvnode) { - NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage; - ma->texpaintslot[index].uvname = storage->uv_map; - /* set a value to index so UI knows that we have a valid pointer for the mesh */ - ma->texpaintslot[index].index = 0; - } - else { - /* just invalidate the index here so UV map does not get displayed on the UI */ - ma->texpaintslot[index].index = -1; - } - } - else { - ma->texpaintslot[index].index = -1; - } - index++; - } - } + if (!(ma->nodetree)) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; } - else if (is_bi) { - for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { - if (get_mtex_slot_valid_texpaint(*mtex)) { - count++; - } - } - - if (count == 0) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } - ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + count = count_texture_nodes_recursive(ma->nodetree); - for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { - if (get_mtex_slot_valid_texpaint(*mtex)) { - ma->texpaintslot[index].ima = (*mtex)->tex->ima; - ma->texpaintslot[index].uvname = (*mtex)->uvname; - ma->texpaintslot[index].index = i; - - index++; - } - } - } - else { + if (count == 0) { ma->paint_active_slot = 0; ma->paint_clone_slot = 0; return; } + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + + bNode *active_node = nodeGetActiveTexture(ma->nodetree); + + fill_texpaint_slots_recursive(ma->nodetree, active_node, ma, &index); ma->tot_slots = count; @@ -1685,21 +1370,6 @@ void clear_matcopybuf(void) void free_matcopybuf(void) { - int a; - - for (a = 0; a < MAX_MTEX; a++) { - if (matcopybuf.mtex[a]) { - MEM_freeN(matcopybuf.mtex[a]); - matcopybuf.mtex[a] = NULL; - } - } - - if (matcopybuf.ramp_col) MEM_freeN(matcopybuf.ramp_col); - if (matcopybuf.ramp_spec) MEM_freeN(matcopybuf.ramp_spec); - - matcopybuf.ramp_col = NULL; - matcopybuf.ramp_spec = NULL; - if (matcopybuf.nodetree) { ntreeFreeTree(matcopybuf.nodetree); MEM_freeN(matcopybuf.nodetree); @@ -1711,574 +1381,42 @@ void free_matcopybuf(void) void copy_matcopybuf(Main *bmain, Material *ma) { - int a; - MTex *mtex; - if (matcopied) free_matcopybuf(); memcpy(&matcopybuf, ma, sizeof(Material)); - if (matcopybuf.ramp_col) matcopybuf.ramp_col = MEM_dupallocN(matcopybuf.ramp_col); - if (matcopybuf.ramp_spec) matcopybuf.ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec); - for (a = 0; a < MAX_MTEX; a++) { - mtex = matcopybuf.mtex[a]; - if (mtex) { - matcopybuf.mtex[a] = MEM_dupallocN(mtex); - } - } matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false); matcopybuf.preview = NULL; BLI_listbase_clear(&matcopybuf.gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ matcopied = 1; } void paste_matcopybuf(Main *bmain, Material *ma) { - int a; - MTex *mtex; ID id; if (matcopied == 0) return; - /* free current mat */ - if (ma->ramp_col) MEM_freeN(ma->ramp_col); - if (ma->ramp_spec) MEM_freeN(ma->ramp_spec); - for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); - } + + /* Free gpu material before the ntree */ + GPU_material_free(&ma->gpumaterial); if (ma->nodetree) { ntreeFreeTree(ma->nodetree); MEM_freeN(ma->nodetree); } - GPU_material_free(&ma->gpumaterial); - id = (ma->id); memcpy(ma, &matcopybuf, sizeof(Material)); (ma->id) = id; - if (matcopybuf.ramp_col) ma->ramp_col = MEM_dupallocN(matcopybuf.ramp_col); - if (matcopybuf.ramp_spec) ma->ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec); - - for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; - if (mtex) { - ma->mtex[a] = MEM_dupallocN(mtex); - if (mtex->tex) { - /* first check this is in main (we may have loaded another file) [#35500] */ - if (BLI_findindex(&bmain->tex, mtex->tex) != -1) { - id_us_plus((ID *)mtex->tex); - } - else { - ma->mtex[a]->tex = NULL; - } - } - } - } - ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false); } - -/*********************** texface to material convert functions **********************/ -/* encode all the TF information into a single int */ -static int encode_tfaceflag(MTFace *tf, int convertall) -{ - /* calculate the flag */ - int flag = tf->mode; - - /* options that change the material offline render */ - if (!convertall) { - flag &= ~TF_OBCOL; - } - - /* clean flags that are not being converted */ - flag &= ~TF_TEX; - flag &= ~TF_SHAREDVERT; - flag &= ~TF_SHAREDCOL; - flag &= ~TF_CONVERTED; - - /* light tface flag is ignored in GLSL mode */ - flag &= ~TF_LIGHT; - - /* 15 is how big the flag can be - hardcoded here and in decode_tfaceflag() */ - flag |= tf->transp << 15; - - /* increase 1 so flag 0 is different than no flag yet */ - return flag + 1; -} - -/* set the material options based in the tface flag */ -static void decode_tfaceflag(Material *ma, int flag, int convertall) -{ - int alphablend; - GameSettings *game = &ma->game; - - /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */ - flag -= 1; - - alphablend = flag >> 15; /* encoded in the encode_tfaceflag function */ - (*game).flag = 0; - - /* General Material Options */ - if ((flag & TF_DYNAMIC) == 0) (*game).flag |= GEMAT_NOPHYSICS; - - /* Material Offline Rendering Properties */ - if (convertall) { - if (flag & TF_OBCOL) ma->shade_flag |= MA_OBCOLOR; - } - - /* Special Face Properties */ - if ((flag & TF_TWOSIDE) == 0) (*game).flag |= GEMAT_BACKCULL; - if (flag & TF_INVISIBLE) (*game).flag |= GEMAT_INVISIBLE; - if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT; - - /* Face Orientation */ - if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO; - else if (flag & TF_BILLBOARD2) (*game).face_orientation |= GEMAT_BILLBOARD; - else if (flag & TF_SHADOW) (*game).face_orientation |= GEMAT_SHADOW; - - /* Alpha Blend */ - if (flag & TF_ALPHASORT && ELEM(alphablend, TF_ALPHA, TF_ADD)) (*game).alpha_blend = GEMAT_ALPHA_SORT; - else if (alphablend & TF_ALPHA) (*game).alpha_blend = GEMAT_ALPHA; - else if (alphablend & TF_ADD) (*game).alpha_blend = GEMAT_ADD; - else if (alphablend & TF_CLIP) (*game).alpha_blend = GEMAT_CLIP; -} - -/* boolean check to see if the mesh needs a material */ -static int check_tfaceneedmaterial(int flag) +void BKE_material_eval(struct Depsgraph *depsgraph, Material *material) { - /* check if the flags we have are not deprecated != than default material options - * also if only flags are visible and collision see if all objects using this mesh have this option in physics */ - - /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */ - flag -= 1; - - /* deprecated flags */ - flag &= ~TF_OBCOL; - flag &= ~TF_SHAREDVERT; - flag &= ~TF_SHAREDCOL; - - /* light tface flag is ignored in GLSL mode */ - flag &= ~TF_LIGHT; - - /* automatic detected if tex image has alpha */ - flag &= ~(TF_ALPHA << 15); - /* automatic detected if using texture */ - flag &= ~TF_TEX; - - /* settings for the default NoMaterial */ - if (flag == TF_DYNAMIC) - return 0; - - else - return 1; -} - -/* return number of digits of an integer */ -/* XXX to be optmized or replaced by an equivalent blender internal function */ -static int integer_getdigits(int number) -{ - int i = 0; - if (number == 0) return 1; - - while (number != 0) { - number = (int)(number / 10); - i++; - } - return i; -} - -static void calculate_tface_materialname(char *matname, char *newname, int flag) -{ - /* if flag has only light and collision and material matches those values - * you can do strcpy(name, mat_name); - * otherwise do: */ - int digits = integer_getdigits(flag); - /* clamp the old name, remove the MA prefix and add the .TF.flag suffix - * e.g. matname = "MALoooooooooooooongName"; newname = "Loooooooooooooon.TF.2" */ - BLI_snprintf(newname, MAX_ID_NAME, "%.*s.TF.%0*d", MAX_ID_NAME - (digits + 5), matname, digits, flag); -} - -/* returns -1 if no match */ -static short mesh_getmaterialnumber(Mesh *me, Material *ma) -{ - short a; - - for (a = 0; a < me->totcol; a++) { - if (me->mat[a] == ma) { - return a; - } - } - - return -1; -} - -/* append material */ -static short mesh_addmaterial(Main *bmain, Mesh *me, Material *ma) -{ - BKE_material_append_id(bmain, &me->id, NULL); - me->mat[me->totcol - 1] = ma; - - id_us_plus(&ma->id); - - return me->totcol - 1; -} - -static void set_facetexture_flags(Material *ma, Image *image) -{ - if (image) { - ma->mode |= MA_FACETEXTURE; - /* we could check if the texture has alpha, but then more meshes sharing the same - * material may need it. Let's make it simple. */ - if (BKE_image_has_alpha(image)) - ma->mode |= MA_FACETEXTURE_ALPHA; - } -} - -/* returns material number */ -static short convert_tfacenomaterial(Main *bmain, Mesh *me, MTFace *tf, int flag) -{ - Material *ma; - char idname[MAX_ID_NAME]; - short mat_nr = -1; - - /* new material, the name uses the flag*/ - BLI_snprintf(idname, sizeof(idname), "MAMaterial.TF.%0*d", integer_getdigits(flag), flag); - - if ((ma = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) { - mat_nr = mesh_getmaterialnumber(me, ma); - /* assign the material to the mesh */ - if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, ma); - - /* if needed set "Face Textures [Alpha]" Material options */ - set_facetexture_flags(ma, tf->tpage); - } - /* create a new material */ - else { - ma = BKE_material_add(bmain, idname + 2); - - if (ma) { - printf("TexFace Convert: Material \"%s\" created.\n", idname + 2); - mat_nr = mesh_addmaterial(bmain, me, ma); - - /* if needed set "Face Textures [Alpha]" Material options */ - set_facetexture_flags(ma, tf->tpage); - - decode_tfaceflag(ma, flag, 1); - /* the final decoding will happen after, outside the main loop - * for now store the flag into the material and change light/tex/collision - * store the flag as a negative number */ - ma->game.flag = -flag; - id_us_min((ID *)ma); - } - else { - printf("Error: Unable to create Material \"%s\" for Mesh \"%s\".", idname + 2, me->id.name + 2); - } - } - - /* set as converted, no need to go bad to this face */ - tf->mode |= TF_CONVERTED; - return mat_nr; -} - -/* Function to fully convert materials */ -static void convert_tfacematerial(Main *bmain, Material *ma) -{ - Mesh *me; - Material *mat_new; - MFace *mf; - MTFace *tf; - int flag, index; - int a; - short mat_nr; - CustomDataLayer *cdl; - char idname[MAX_ID_NAME]; - - for (me = bmain->mesh.first; me; me = me->id.next) { - /* check if this mesh uses this material */ - for (a = 0; a < me->totcol; a++) - if (me->mat[a] == ma) break; - - /* no material found */ - if (a == me->totcol) continue; - - /* get the active tface layer */ - index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); - cdl = (index == -1) ? NULL : &me->fdata.layers[index]; - if (!cdl) continue; - - /* loop over all the faces and stop at the ones that use the material*/ - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - if (me->mat[mf->mat_nr] != ma) continue; - - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - flag = encode_tfaceflag(tf, 1); - - /* the name of the new material */ - calculate_tface_materialname(ma->id.name, (char *)&idname, flag); - - if ((mat_new = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) { - /* material already existent, see if the mesh has it */ - mat_nr = mesh_getmaterialnumber(me, mat_new); - /* material is not in the mesh, add it */ - if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, mat_new); - } - /* create a new material */ - else { - mat_new = BKE_material_copy(bmain, ma); - if (mat_new) { - /* rename the material*/ - BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name)); - id_us_min((ID *)mat_new); - - mat_nr = mesh_addmaterial(bmain, me, mat_new); - decode_tfaceflag(mat_new, flag, 1); - } - else { - printf("Error: Unable to create Material \"%s\" for Mesh \"%s.", idname + 2, me->id.name + 2); - mat_nr = mf->mat_nr; - continue; - } - } - - /* if the material has a texture but no texture channel - * set "Face Textures [Alpha]" Material options - * actually we need to run it always, because of old behavior - * of using face texture if any texture channel was present (multitex) */ - //if ((!mat_new->mtex[0]) && (!mat_new->mtex[0]->tex)) - set_facetexture_flags(mat_new, tf->tpage); - - /* set the material number to the face*/ - mf->mat_nr = mat_nr; - } - /* remove material from mesh */ - for (a = 0; a < me->totcol; ) { - if (me->mat[a] == ma) { - BKE_material_pop_id(bmain, &me->id, a, true); - } - else { - a++; - } - } - } -} - - -#define MAT_BGE_DISPUTED -99999 - -int do_version_tface(Main *main) -{ - Mesh *me; - Material *ma; - MFace *mf; - MTFace *tf; - CustomDataLayer *cdl; - int a; - int flag; - int index; - - /* Operator in help menu has been removed for 2.7x */ - int fileload = 1; - - /* sometimes mesh has no materials but will need a new one. In those - * cases we need to ignore the mf->mat_nr and only look at the face - * mode because it can be zero as uninitialized or the 1st created material - */ - int nomaterialslots; - - /* alert to user to check the console */ - int nowarning = 1; - - /* mark all the materials to conversion with a flag - * if there is tface create a complete flag for that storing in flag - * if there is tface and flag > 0: creates a new flag based on this face - * if flags are different set flag to -1 - */ - - /* 1st part: marking mesh materials to update */ - for (me = main->mesh.first; me; me = me->id.next) { - if (ID_IS_LINKED(me)) continue; - - /* get the active tface layer */ - index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); - cdl = (index == -1) ? NULL : &me->fdata.layers[index]; - if (!cdl) continue; - - nomaterialslots = (me->totcol == 0 ? 1 : 0); - - /* loop over all the faces*/ - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - - /* conversion should happen only once */ - if (fileload) - tf->mode &= ~TF_CONVERTED; - else { - if ((tf->mode & TF_CONVERTED)) continue; - else tf->mode |= TF_CONVERTED; - } - - /* no material slots */ - if (nomaterialslots) { - flag = encode_tfaceflag(tf, 1); - - /* create/find a new material and assign to the face */ - if (check_tfaceneedmaterial(flag)) { - mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag); - } - /* else mark them as no-material to be reverted to 0 later */ - else { - mf->mat_nr = -1; - } - } - else if (mf->mat_nr < me->totcol) { - ma = me->mat[mf->mat_nr]; - - /* no material create one if necessary */ - if (!ma) { - /* find a new material and assign to the face */ - flag = encode_tfaceflag(tf, 1); - - /* create/find a new material and assign to the face */ - if (check_tfaceneedmaterial(flag)) - mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag); - - continue; - } - - /* we can't read from this if it comes from a library, - * at doversion time: direct_link might not have happened on it, - * so ma->mtex is not pointing to valid memory yet. - * later we could, but it's better not */ - else if (ID_IS_LINKED(ma)) - continue; - - /* material already marked as disputed */ - else if (ma->game.flag == MAT_BGE_DISPUTED) - continue; - - /* found a material */ - else { - flag = encode_tfaceflag(tf, ((fileload) ? 0 : 1)); - - /* first time changing this material */ - if (ma->game.flag == 0) - ma->game.flag = -flag; - - /* mark material as disputed */ - else if (ma->game.flag != -flag) { - ma->game.flag = MAT_BGE_DISPUTED; - continue; - } - - /* material ok so far */ - else { - ma->game.flag = -flag; - - /* some people uses multitexture with TexFace by creating a texture - * channel which not necessarily the tf->tpage image. But the game engine - * was enabling it. Now it's required to set "Face Texture [Alpha] in the - * material settings. */ - if (!fileload) - set_facetexture_flags(ma, tf->tpage); - } - } - } - else { - continue; - } - } - - /* if we didn't have material slot and now we do, we need to - * make sure the materials are correct */ - if (nomaterialslots) { - if (me->totcol > 0) { - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - if (mf->mat_nr == -1) { - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - mf->mat_nr = convert_tfacenomaterial(main, me, tf, encode_tfaceflag(tf, 1)); - } - } - } - else { - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - mf->mat_nr = 0; - } - } - } - - } - - /* 2nd part - conversion */ - /* skip library files */ - - /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */ - for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) { - if (ID_IS_LINKED(ma)) continue; - - /* disputed material */ - if (ma->game.flag == MAT_BGE_DISPUTED) { - ma->game.flag = 0; - if (fileload) { - printf("Warning: material \"%s\" skipped.\n", ma->id.name + 2); - nowarning = 0; - } - else { - convert_tfacematerial(main, ma); - } - continue; - } - - /* no conflicts in this material - 90% of cases - * convert from tface system to material */ - else if (ma->game.flag < 0) { - decode_tfaceflag(ma, -(ma->game.flag), 1); - - /* material is good make sure all faces using - * this material are set to converted */ - if (fileload) { - for (me = main->mesh.first; me; me = me->id.next) { - /* check if this mesh uses this material */ - for (a = 0; a < me->totcol; a++) - if (me->mat[a] == ma) break; - - /* no material found */ - if (a == me->totcol) continue; - - /* get the active tface layer */ - index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); - cdl = (index == -1) ? NULL : &me->fdata.layers[index]; - if (!cdl) continue; - - /* loop over all the faces and stop at the ones that use the material*/ - for (a = 0, mf = me->mface; a < me->totface; a++, mf++) { - if (me->mat[mf->mat_nr] == ma) { - /* texface data for this face */ - tf = ((MTFace *)cdl->data) + a; - tf->mode |= TF_CONVERTED; - } - } - } - } - } - /* material is not used by faces with texface - * set the default flag - do it only once */ - else { - if (fileload) { - ma->game.flag = GEMAT_BACKCULL; - } - } - } - - return nowarning; + DEG_debug_print_eval(depsgraph, __func__, material->id.name, material); + GPU_material_free(&material->gpumaterial); } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 9e926e5ef53..63adcfc3cae 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -57,7 +57,6 @@ #include "BKE_animsys.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_scene.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -74,6 +73,8 @@ void BKE_mball_free(MetaBall *mb) { BKE_animdata_free((ID *)mb, false); + BKE_mball_batch_cache_free(mb); + MEM_SAFE_FREE(mb->mat); BLI_freelistN(&mb->elems); @@ -119,6 +120,7 @@ void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall * mb_dst->editelems = NULL; mb_dst->lastelem = NULL; + mb_dst->batch_cache = NULL; } MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb) @@ -203,7 +205,7 @@ void BKE_mball_texspace_calc(Object *ob) (min)[0] = (min)[1] = (min)[2] = 1.0e30f; (max)[0] = (max)[1] = (max)[2] = -1.0e30f; - dl = ob->curve_cache->disp.first; + dl = ob->runtime.curve_cache->disp.first; while (dl) { tot = dl->nr; if (tot) do_it = true; @@ -220,20 +222,29 @@ void BKE_mball_texspace_calc(Object *ob) min[0] = min[1] = min[2] = -1.0f; max[0] = max[1] = max[2] = 1.0f; } -#if 0 - loc[0] = (min[0] + max[0]) / 2.0f; - loc[1] = (min[1] + max[1]) / 2.0f; - loc[2] = (min[2] + max[2]) / 2.0f; - - size[0] = (max[0] - min[0]) / 2.0f; - size[1] = (max[1] - min[1]) / 2.0f; - size[2] = (max[2] - min[2]) / 2.0f; -#endif + BKE_boundbox_init_from_minmax(bb, min, max); bb->flag &= ~BOUNDBOX_DIRTY; } +/** Return or compute bbox for given metaball object. */ +BoundBox *BKE_mball_boundbox_get(Object *ob) +{ + BLI_assert(ob->type == OB_MBALL); + + if (ob->bb != NULL && (ob->bb->flag & BOUNDBOX_DIRTY) == 0) { + return ob->bb; + } + + /* This should always only be called with evaluated objects, but currently RNA is a problem here... */ + if (ob->runtime.curve_cache != NULL) { + BKE_mball_texspace_calc(ob); + } + + return ob->bb; +} + float *BKE_mball_make_orco(Object *ob, ListBase *dispbase) { BoundBox *bb; @@ -299,6 +310,11 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2) int basis1nr, basis2nr; char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME]; + if (ob1->id.name[2] != ob2->id.name[2]) { + /* Quick return in case first char of both ID's names is not the same... */ + return false; + } + BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.'); BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.'); @@ -310,13 +326,46 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2) } } +bool BKE_mball_is_any_selected(const MetaBall *mb) +{ + for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) { + if (ml->flag & SELECT) { + return true; + } + } + return false; +} + + +bool BKE_mball_is_any_selected_multi(Object **objects, int objects_len) +{ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + MetaBall *mb = (MetaBall *)obedit->data; + if (BKE_mball_is_any_selected(mb)) { + return true; + } + } + return false; +} + +bool BKE_mball_is_any_unselected(const MetaBall *mb) +{ + for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) { + if ((ml->flag & SELECT) == 0) { + return true; + } + } + return false; +} + /* \brief copy some properties from object to other metaball object with same base name * * When some properties (wiresize, threshold, update flags) of metaball are changed, then this properties * are copied to all metaballs in same "group" (metaballs with same base name: MBall, * MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball, * because this metaball influence polygonisation of metaballs. */ -void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *active_object) +void BKE_mball_properties_copy(Scene *scene, Object *active_object) { Scene *sce_iter = scene; Base *base; @@ -328,8 +377,11 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene * BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); - BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { + /* Pass depsgraph as NULL, which means we will not expand into + * duplis unlike when we generate the mball. Expanding duplis + * would not be compatible when editing multiple view layers. */ + BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL); + while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob != active_object) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); @@ -359,28 +411,27 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene * * * warning!, is_basis_mball() can fail on returned object, see long note above. */ -Object *BKE_mball_basis_find(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *basis) +Object *BKE_mball_basis_find(Scene *scene, Object *basis) { - Scene *sce_iter = scene; - Base *base; - Object *ob, *bob = basis; + Object *bob = basis; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; - SceneBaseIter iter; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); - BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { - if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { - if (ob != bob) { - BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - - /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ - if (STREQ(obname, basisname)) { - if (obnr < basisnr) { - basis = ob; - basisnr = obnr; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + Object *ob = base->object; + if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROMDUPLI)) { + if (ob != bob) { + BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); + + /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ + if (STREQ(obname, basisname)) { + if (obnr < basisnr) { + basis = ob; + basisnr = obnr; + } } } } @@ -390,17 +441,17 @@ Object *BKE_mball_basis_find(Main *bmain, EvaluationContext *eval_ctx, Scene *sc return basis; } -bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3], - float obmat[4][4], const short flag) +bool BKE_mball_minmax_ex( + const MetaBall *mb, float min[3], float max[3], + const float obmat[4][4], const short flag) { const float scale = obmat ? mat4_to_scale(obmat) : 1.0f; - MetaElem *ml; bool changed = false; float centroid[3], vec[3]; INIT_MINMAX(min, max); - for (ml = mb->elems.first; ml; ml = ml->next) { + for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) { if ((ml->flag & flag) == flag) { const float scale_mb = (ml->rad * 0.5f) * scale; int i; @@ -427,27 +478,24 @@ bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3], /* basic vertex data functions */ -bool BKE_mball_minmax(MetaBall *mb, float min[3], float max[3]) +bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3]) { - MetaElem *ml; - INIT_MINMAX(min, max); - for (ml = mb->elems.first; ml; ml = ml->next) { + for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) { minmax_v3v3_v3(min, max, &ml->x); } return (BLI_listbase_is_empty(&mb->elems) == false); } -bool BKE_mball_center_median(MetaBall *mb, float r_cent[3]) +bool BKE_mball_center_median(const MetaBall *mb, float r_cent[3]) { - MetaElem *ml; int total = 0; zero_v3(r_cent); - for (ml = mb->elems.first; ml; ml = ml->next) { + for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) { add_v3_v3(r_cent, &ml->x); total++; } @@ -459,7 +507,7 @@ bool BKE_mball_center_median(MetaBall *mb, float r_cent[3]) return (total != 0); } -bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) +bool BKE_mball_center_bounds(const MetaBall *mb, float r_cent[3]) { float min[3], max[3]; @@ -473,26 +521,25 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props) { - MetaElem *me; float quat[4]; const float scale = mat4_to_scale(mat); const float scale_sqrt = sqrtf(scale); mat4_to_quat(quat, mat); - for (me = mb->elems.first; me; me = me->next) { - mul_m4_v3(mat, &me->x); - mul_qt_qtqt(me->quat, quat, me->quat); + for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) { + mul_m4_v3(mat, &ml->x); + mul_qt_qtqt(ml->quat, quat, ml->quat); if (do_props) { - me->rad *= scale; + ml->rad *= scale; /* hrmf, probably elems shouldn't be * treating scale differently - campbell */ - if (!MB_TYPE_SIZE_SQUARED(me->type)) { - mul_v3_fl(&me->expx, scale); + if (!MB_TYPE_SIZE_SQUARED(ml->type)) { + mul_v3_fl(&ml->expx, scale); } else { - mul_v3_fl(&me->expx, scale_sqrt); + mul_v3_fl(&ml->expx, scale_sqrt); } } } @@ -500,44 +547,99 @@ void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props) void BKE_mball_translate(MetaBall *mb, const float offset[3]) { - MetaElem *ml; - - for (ml = mb->elems.first; ml; ml = ml->next) { + for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) { add_v3_v3(&ml->x, offset); } } /* *** select funcs *** */ -void BKE_mball_select_all(struct MetaBall *mb) +int BKE_mball_select_count(const MetaBall *mb) { - MetaElem *ml; + int sel = 0; + for (const MetaElem *ml = mb->editelems->first; ml; ml = ml->next) { + if (ml->flag & SELECT) { + sel++; + } + } + return sel; +} - for (ml = mb->editelems->first; ml; ml = ml->next) { +int BKE_mball_select_count_multi(Object **objects, int objects_len) +{ + int sel = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + const Object *obedit = objects[ob_index]; + const MetaBall *mb = (MetaBall *)obedit->data; + sel += BKE_mball_select_count(mb); + } + return sel; +} + +void BKE_mball_select_all(MetaBall *mb) +{ + for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) { ml->flag |= SELECT; } } -void BKE_mball_deselect_all(MetaBall *mb) +void BKE_mball_select_all_multi(Object **objects, int objects_len) { - MetaElem *ml; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + MetaBall *mb = obedit->data; + BKE_mball_select_all(mb); + } +} - for (ml = mb->editelems->first; ml; ml = ml->next) { +void BKE_mball_deselect_all(MetaBall *mb) +{ + for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) { ml->flag &= ~SELECT; } } -void BKE_mball_select_swap(struct MetaBall *mb) +void BKE_mball_deselect_all_multi(Object **objects, int objects_len) { - MetaElem *ml; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + MetaBall *mb = obedit->data; + + BKE_mball_deselect_all(mb); + } +} - for (ml = mb->editelems->first; ml; ml = ml->next) { +void BKE_mball_select_swap(MetaBall *mb) +{ + for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) { ml->flag ^= SELECT; } } +void BKE_mball_select_swap_multi(Object **objects, int objects_len) +{ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + MetaBall *mb = (MetaBall *)obedit->data; + BKE_mball_select_swap(mb); + } +} + /* **** Depsgraph evaluation **** */ -void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx), - MetaBall *UNUSED(mball)) +/* Draw Engine */ + +void (*BKE_mball_batch_cache_dirty_tag_cb)(MetaBall *mb, int mode) = NULL; +void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = NULL; + +void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode) { + if (mb->batch_cache) { + BKE_mball_batch_cache_dirty_tag_cb(mb, mode); + } +} +void BKE_mball_batch_cache_free(MetaBall *mb) +{ + if (mb->batch_cache) { + BKE_mball_batch_cache_free_cb(mb); + } } diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 840062df3a3..5525c41c9dd 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -48,12 +48,14 @@ #include "BKE_global.h" -#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_main.h" #include "BKE_mball_tessellate.h" /* own include */ #include "BKE_scene.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "BLI_strict_flags.h" /* experimental (faster) normal calculation */ @@ -837,27 +839,6 @@ static void vnormal(PROCESS *process, const float point[3], float r_no[3]) r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f; r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f; r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f; - -#if 0 - f = normalize_v3(r_no); - - if (0) { - float tvec[3]; - - delta *= 2.0f; - - f = process->function(process, point[0], point[1], point[2]); - - tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f; - tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f; - tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f; - - if (normalize_v3(tvec) != 0.0f) { - add_v3_v3(r_no, tvec); - normalize_v3(r_no); - } - } -#endif } #endif /* USE_ACCUM_NORMAL */ @@ -1056,7 +1037,7 @@ static void polygonize(PROCESS *process) * Iterates over ALL objects in the scene and all of its sets, including * making all duplis(not only metas). Copies metas to mainb array. * Computes bounding boxes for building BVH. */ -static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) +static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Object *ob) { Scene *sce_iter = scene; Base *base; @@ -1075,13 +1056,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); /* make main array */ - BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &bob)) { + BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, NULL, NULL); + while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) { if (bob->type == OB_MBALL) { zero_size = 0; ml = NULL; - if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { + if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) { mb = ob->data; if (mb->editelems) ml = mb->editelems->first; @@ -1233,12 +1214,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process } } -void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase) +void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase) { MetaBall *mb; DispList *dl; unsigned int a; PROCESS process = {0}; + bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER; mb = ob->data; @@ -1249,10 +1231,10 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene else if (process.thresh < 0.1f) process.converge_res = 4; else process.converge_res = 2; - if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return; + if (is_render && (mb->flag == MB_UPDATE_NEVER)) return; if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return; - if (eval_ctx->mode == DAG_EVAL_RENDER) { + if (is_render) { process.size = mb->rendersize; } else { @@ -1267,7 +1249,7 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena"); /* initialize all mainb (MetaElems) */ - init_meta(bmain, eval_ctx, &process, scene, ob); + init_meta(depsgraph, &process, scene, ob); if (process.totelem > 0) { build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 5758e00a28d..6a00aaf576b 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -32,8 +32,10 @@ #include "DNA_object_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "BLI_utildefines.h" +#include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_linklist.h" #include "BLI_memarena.h" @@ -41,15 +43,15 @@ #include "BLI_string.h" #include "BKE_animsys.h" +#include "BKE_idcode.h" #include "BKE_main.h" -#include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_library.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_multires.h" -#include "BKE_depsgraph.h" #include "BKE_object.h" #include "BKE_editmesh.h" @@ -109,7 +111,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 for (i = 0; i < c1->totlayer; i++) { if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i1++; } @@ -117,7 +119,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 for (i = 0; i < c2->totlayer; i++) { if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i2++; } @@ -131,14 +133,14 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 i1 = 0; i2 = 0; for (i = 0; i < tot; i++) { while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i1++; l1++; } while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) { i2++; l2++; @@ -306,7 +308,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) * Callers could also check but safer to do here - campbell */ } else { - const int tottex_original = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE); @@ -317,16 +319,16 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) { BKE_mesh_tessface_clear(me); - CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface); + CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface); /* TODO - add some --debug-mesh option */ if (G.debug & G_DEBUG) { /* note: this warning may be un-called for if we are initializing the mesh for the * first time from bmesh, rather then giving a warning about this we could be smarter * and check if there was any data to begin with, for now just print the warning with - * some info to help troubleshoot whats going on - campbell */ + * some info to help troubleshoot what's going on - campbell */ printf("%s: warning! Tessellation uvs or vcol data got out of sync, " - "had to reset!\n CD_MTFACE: %d != CD_MTEXPOLY: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n", + "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n", __func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original); } } @@ -372,6 +374,49 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) } } +bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) +{ + BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL; + bool changed = false; + if (bm) { + if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { + BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP); + changed = true; + } + } + else { + if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { + CustomData_add_layer( + &me->pdata, + CD_FACEMAP, + CD_DEFAULT, + NULL, + me->totpoly); + changed = true; + } + } + return changed; +} + +bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) +{ + BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL; + bool changed = false; + if (bm) { + if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { + BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP); + changed = true; + } + } + else { + if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) { + CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly); + changed = true; + } + } + return changed; +} + /* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or * mloopcol and mcol) have the same relative active/render/clone/mask indices. * @@ -380,14 +425,11 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) * versions of the mesh. - campbell*/ static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd) { - if (me->edit_btmesh) - BKE_editmesh_update_linked_customdata(me->edit_btmesh); - if (do_ensure_tess_cd) { mesh_ensure_tessellation_customdata(me); } - CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata); + CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata); } void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) @@ -406,7 +448,6 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); - me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY); me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); } @@ -426,6 +467,8 @@ void BKE_mesh_free(Mesh *me) { BKE_animdata_free(&me->id, false); + BKE_mesh_runtime_clear_cache(me); + CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); @@ -460,12 +503,7 @@ void BKE_mesh_init(Mesh *me) me->size[0] = me->size[1] = me->size[2] = 1.0; me->smoothresh = DEG2RADF(30); me->texflag = ME_AUTOSPACE; - - /* disable because its slow on many GPU's, see [#37518] */ -#if 0 - me->flag = ME_TWOSIDED; -#endif - me->drawflag = ME_DRAWEDGES | ME_DRAWFACES | ME_DRAWCREASES; + me->drawflag = 0; CustomData_reset(&me->vdata); CustomData_reset(&me->edata); @@ -496,15 +534,22 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag) { const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */ + CustomDataMask mask = CD_MASK_MESH; + + if (me_src->id.tag & LIB_TAG_NO_MAIN) { + /* For copies in depsgraph, keep data like origindex and orco. */ + mask |= CD_MASK_DERIVEDMESH; + } me_dst->mat = MEM_dupallocN(me_src->mat); - CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert); - CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge); - CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop); - CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly); + const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; + CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, alloc_type, me_dst->totvert); + CustomData_copy(&me_src->edata, &me_dst->edata, mask, alloc_type, me_dst->totedge); + CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, alloc_type, me_dst->totloop); + CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, alloc_type, me_dst->totpoly); if (do_tessface) { - CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface); + CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, alloc_type, me_dst->totface); } else { mesh_tessface_clear_intern(me_dst, false); @@ -514,37 +559,223 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int me_dst->edit_btmesh = NULL; + /* Call BKE_mesh_runtime_reset? */ + me_dst->runtime.batch_cache = NULL; + me_dst->runtime.looptris.array = NULL; + me_dst->runtime.bvh_cache = NULL; + me_dst->runtime.shrinkwrap_data = NULL; + + if (me_src->id.tag & LIB_TAG_NO_MAIN) { + me_dst->runtime.deformed_only = me_src->runtime.deformed_only; + } + else { + /* This is a direct copy of a main mesh, so for now it has the same topology. */ + me_dst->runtime.deformed_only = 1; + } + me_dst->runtime.is_original = false; + me_dst->mselect = MEM_dupallocN(me_dst->mselect); me_dst->bb = MEM_dupallocN(me_dst->bb); /* TODO Do we want to add flag to prevent this? */ - if (me_src->key) { + if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false); } } +/* Custom data layer functions; those assume that totXXX are set correctly. */ +static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) +{ + if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); + if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); + + if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface); +} +static void mesh_ensure_cdlayers_origindex(Mesh *mesh, bool do_tessface) +{ + if (!CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert); + if (!CustomData_get_layer(&mesh->edata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge); + if (!CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly); + + if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX)) + CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface); +} + +Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len) +{ + Mesh *mesh = BKE_libblock_alloc( + NULL, ID_ME, + BKE_idcode_to_name(ID_ME), + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG); + BKE_libblock_init_empty(&mesh->id); + + /* don't use CustomData_reset(...); because we dont want to touch customdata */ + copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1); + copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1); + copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1); + copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); + copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1); + + mesh->totvert = verts_len; + mesh->totedge = edges_len; + mesh->totface = tessface_len; + mesh->totloop = loops_len; + mesh->totpoly = polys_len; + + mesh_ensure_cdlayers_primary(mesh, true); + mesh_ensure_cdlayers_origindex(mesh, true); + BKE_mesh_update_customdata_pointers(mesh, false); + + return mesh; +} + +static Mesh *mesh_new_nomain_from_template_ex( + const Mesh *me_src, + int verts_len, int edges_len, int tessface_len, + int loops_len, int polys_len, + CustomDataMask mask) +{ + /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ + const bool do_tessface = (tessface_len || + ((me_src->totface != 0) && (me_src->totpoly == 0))); + + Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL); + + me_dst->mat = MEM_dupallocN(me_src->mat); + me_dst->mselect = MEM_dupallocN(me_dst->mselect); + + me_dst->totvert = verts_len; + me_dst->totedge = edges_len; + me_dst->totface = tessface_len; + me_dst->totloop = loops_len; + me_dst->totpoly = polys_len; + + CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, CD_CALLOC, verts_len); + CustomData_copy(&me_src->edata, &me_dst->edata, mask, CD_CALLOC, edges_len); + CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, CD_CALLOC, loops_len); + CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, CD_CALLOC, polys_len); + if (do_tessface) { + CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, CD_CALLOC, tessface_len); + } + else { + mesh_tessface_clear_intern(me_dst, false); + } + + /* The destination mesh should at least have valid primary CD layers, + * even in cases where the source mesh does not. */ + mesh_ensure_cdlayers_primary(me_dst, do_tessface); + mesh_ensure_cdlayers_origindex(me_dst, false); + BKE_mesh_update_customdata_pointers(me_dst, false); + + return me_dst; +} + +Mesh *BKE_mesh_new_nomain_from_template( + const Mesh *me_src, + int verts_len, int edges_len, int tessface_len, + int loops_len, int polys_len) +{ + return mesh_new_nomain_from_template_ex( + me_src, + verts_len, edges_len, tessface_len, + loops_len, polys_len, + CD_MASK_EVERYTHING); +} + +Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference) +{ + int flags = (LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW); + + if (reference) { + flags |= LIB_ID_COPY_CD_REFERENCE; + } + + Mesh *result; + BKE_id_copy_ex(NULL, &source->id, (ID **)&result, flags, false); + return result; +} + Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me) { Mesh *me_copy; - BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false); + BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, LIB_ID_COPY_SHAPEKEY, false); return me_copy; } +BMesh *BKE_mesh_to_bmesh_ex( + Mesh *me, + const struct BMeshCreateParams *create_params, + const struct BMeshFromMeshParams *convert_params) +{ + BMesh *bm; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); + + bm = BM_mesh_create(&allocsize, create_params); + BM_mesh_bm_from_me(bm, me, convert_params); + + return bm; +} + BMesh *BKE_mesh_to_bmesh( Mesh *me, Object *ob, const bool add_key_index, const struct BMeshCreateParams *params) { - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); + return BKE_mesh_to_bmesh_ex( + me, params, + &(struct BMeshFromMeshParams){ + .calc_face_normal = false, + .add_key_index = add_key_index, + .use_shapekey = true, + .active_shapekey = ob->shapenr, + }); +} - bm = BM_mesh_create(&allocsize, params); +Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params) +{ + BLI_assert(params->calc_object_remap == false); + Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); + BM_mesh_bm_to_me(NULL, bm, mesh, params); + return mesh; +} - BM_mesh_bm_from_me( - bm, me, (&(struct BMeshFromMeshParams){ - .add_key_index = add_key_index, .use_shapekey = true, .active_shapekey = ob->shapenr, - })); +Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const int64_t cd_mask_extra) +{ + Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); + BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra); + return mesh; +} - return bm; +/** + * TODO(campbell): support mesh with only an edit-mesh which is lazy initialized. + */ +Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap( + BMEditMesh *em, CustomDataMask data_mask, float (*vertexCos)[3]) +{ + Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask); + /* Use editmesh directly where possible. */ + me->runtime.is_original = true; + if (vertexCos) { + /* We will own this array in the future. */ + BKE_mesh_apply_vert_coords(me, vertexCos); + MEM_freeN(vertexCos); + me->runtime.is_original = false; + } + return me; } void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local) @@ -553,121 +784,82 @@ void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local) } bool BKE_mesh_uv_cdlayer_rename_index( - Mesh *me, const int poly_index, const int loop_index, const int face_index, + Mesh *me, const int loop_index, const int face_index, const char *new_name, const bool do_tessface) { - CustomData *pdata, *ldata, *fdata; - CustomDataLayer *cdlp, *cdlu, *cdlf; - const int step = do_tessface ? 3 : 2; - int i; + CustomData *ldata, *fdata; + CustomDataLayer *cdlu, *cdlf; if (me->edit_btmesh) { - pdata = &me->edit_btmesh->bm->pdata; ldata = &me->edit_btmesh->bm->ldata; fdata = NULL; /* No tessellated data in BMesh! */ } else { - pdata = &me->pdata; ldata = &me->ldata; fdata = &me->fdata; } - cdlp = &pdata->layers[poly_index]; + cdlu = &ldata->layers[loop_index]; - cdlf = fdata && do_tessface ? &fdata->layers[face_index] : NULL; + cdlf = (face_index != -1) && fdata && do_tessface ? &fdata->layers[face_index] : NULL; - if (cdlp->name != new_name) { + if (cdlu->name != new_name) { /* Mesh validate passes a name from the CD layer as the new name, * Avoid memcpy from self to self in this case. */ - BLI_strncpy(cdlp->name, new_name, sizeof(cdlp->name)); - CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers); + BLI_strncpy(cdlu->name, new_name, sizeof(cdlu->name)); + CustomData_set_layer_unique_name(ldata, loop_index); } - /* Loop until we do have exactly the same name for all layers! */ - for (i = 1; !STREQ(cdlp->name, cdlu->name) || (cdlf && !STREQ(cdlp->name, cdlf->name)); i++) { - switch (i % step) { - case 0: - BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name)); - CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers); - break; - case 1: - BLI_strncpy(cdlu->name, cdlp->name, sizeof(cdlu->name)); - CustomData_set_layer_unique_name(ldata, cdlu - ldata->layers); - break; - case 2: - if (cdlf) { - BLI_strncpy(cdlf->name, cdlp->name, sizeof(cdlf->name)); - CustomData_set_layer_unique_name(fdata, cdlf - fdata->layers); - } - break; - } + if (cdlf == NULL) { + return false; } + BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name)); + CustomData_set_layer_unique_name(fdata, face_index); + return true; } bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface) { - CustomData *pdata, *ldata, *fdata; + CustomData *ldata, *fdata; if (me->edit_btmesh) { - pdata = &me->edit_btmesh->bm->pdata; ldata = &me->edit_btmesh->bm->ldata; /* No tessellated data in BMesh! */ fdata = NULL; do_tessface = false; } else { - pdata = &me->pdata; ldata = &me->ldata; fdata = &me->fdata; do_tessface = (do_tessface && fdata->totlayer); } { - const int pidx_start = CustomData_get_layer_index(pdata, CD_MTEXPOLY); const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV); const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1; - int pidx = CustomData_get_named_layer(pdata, CD_MTEXPOLY, old_name); int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name); int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1; /* None of those cases should happen, in theory! * Note this assume we have the same number of mtexpoly, mloopuv and mtface layers! */ - if (pidx == -1) { - if (lidx == -1) { - if (fidx == -1) { - /* No layer found with this name! */ - return false; - } - else { - lidx = fidx; - } - } - pidx = lidx; - } - else { - if (lidx == -1) { - lidx = pidx; + if (lidx == -1) { + if (fidx == -1) { + /* No layer found with this name! */ + return false; } - if (fidx == -1 && do_tessface) { - fidx = pidx; + else { + lidx = fidx; } } -#if 0 - /* For now, we do not consider mismatch in indices (i.e. same name leading to (relative) different indices). */ - else if (pidx != lidx) { - lidx = pidx; - } -#endif /* Go back to absolute indices! */ - pidx += pidx_start; lidx += lidx_start; if (fidx != -1) fidx += fidx_start; - return BKE_mesh_uv_cdlayer_rename_index(me, pidx, lidx, fidx, new_name, do_tessface); + return BKE_mesh_uv_cdlayer_rename_index(me, lidx, fidx, new_name, do_tessface); } } @@ -745,6 +937,18 @@ void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_siz if (r_size) copy_v3_v3(r_size, me->size); } +void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_rot, float **r_size) +{ + if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { + BKE_mesh_texspace_calc(me); + } + + if (r_texflag != NULL) *r_texflag = &me->texflag; + if (r_loc != NULL) *r_loc = me->loc; + if (r_rot != NULL) *r_rot = me->rot; + if (r_size != NULL) *r_size = me->size; +} + void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) { float *texloc, *texrot, *texsize; @@ -904,7 +1108,6 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) test_object_modifiers(ob); } - void BKE_mesh_material_index_remove(Mesh *me, short index) { MPoly *mp; @@ -999,15 +1202,15 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) /** * Return a newly MEM_malloc'd array of all the mesh vertex locations - * \note \a r_numVerts may be NULL + * \note \a r_verts_len may be NULL */ -float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3] +float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_verts_len))[3] { - int i, numVerts = me->totvert; - float (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "vertexcos1"); + int i, verts_len = me->totvert; + float (*cos)[3] = MEM_malloc_arrayN(verts_len, sizeof(*cos), "vertexcos1"); - if (r_numVerts) *r_numVerts = numVerts; - for (i = 0; i < numVerts; i++) + if (r_verts_len) *r_verts_len = verts_len; + for (i = 0; i < verts_len; i++) copy_v3_v3(cos[i], me->mvert[i].co); return cos; @@ -1046,10 +1249,6 @@ int poly_get_adj_loops_from_vert( vert); if (corner != -1) { -#if 0 /* unused - this loop */ - const MLoop *ml = &mloop[poly->loopstart + corner]; -#endif - /* vertex was found */ r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v; r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v; @@ -1072,6 +1271,21 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v) return -1; } +/** + * Sets each output array element to the edge index if it is a real edge, or -1. + */ +void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3]) +{ + for (int i = 2, i_next = 0; i_next < 3; i = i_next++) { + const MLoop *l1 = &mesh->mloop[looptri->tri[i]], *l2 = &mesh->mloop[looptri->tri[i_next]]; + const MEdge *e = &mesh->medge[l1->e]; + + bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1); + + r_edges[i] = is_real ? l1->e : -1; + } +} + /* basic vertex data functions */ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) { @@ -1139,13 +1353,13 @@ void BKE_mesh_ensure_navmesh(Mesh *me) { if (!CustomData_has_layer(&me->pdata, CD_RECAST)) { int i; - int numFaces = me->totpoly; + int polys_len = me->totpoly; int *recastData; - recastData = (int *)MEM_malloc_arrayN(numFaces, sizeof(int), __func__); - for (i = 0; i < numFaces; i++) { + recastData = (int *)MEM_malloc_arrayN(polys_len, sizeof(int), __func__); + for (i = 0; i < polys_len; i++) { recastData[i] = i + 1; } - CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, numFaces, "recastData"); + CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, polys_len, "recastData"); } } @@ -1337,6 +1551,37 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) (me->mselect[me->totselect - 1].type == type)); } + +void BKE_mesh_apply_vert_coords(Mesh *mesh, float (*vertCoords)[3]) +{ + MVert *vert; + int i; + + /* this will just return the pointer if it wasn't a referenced layer */ + vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + mesh->mvert = vert; + + for (i = 0; i < mesh->totvert; ++i, ++vert) + copy_v3_v3(vert->co, vertCoords[i]); + + mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; +} + +void BKE_mesh_apply_vert_normals(Mesh *mesh, short (*vertNormals)[3]) +{ + MVert *vert; + int i; + + /* this will just return the pointer if it wasn't a referenced layer */ + vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + mesh->mvert = vert; + + for (i = 0; i < mesh->totvert; ++i, ++vert) + copy_v3_v3_short(vert->no, vertNormals[i]); + + mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; +} + /** * Compute 'split' (aka loop, or per face corner's) normals. * @@ -1388,6 +1633,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac if (free_polynors) { MEM_freeN(polynors); } + + mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; } void BKE_mesh_calc_normals_split(Mesh *mesh) @@ -1421,25 +1668,25 @@ static int split_faces_prepare_new_verts( * dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */ BLI_assert(lnors_spacearr != NULL); - const int num_loops = mesh->totloop; - int num_verts = mesh->totvert; + const int loops_len = mesh->totloop; + int verts_len = mesh->totvert; MVert *mvert = mesh->mvert; MLoop *mloop = mesh->mloop; - BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__); - BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__); + BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__); + BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__); MLoop *ml = mloop; MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr; BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX); - for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) { + for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) { if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { const int vert_idx = ml->v; const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx); /* If vert is already used by another smooth fan, we need a new vert for this one. */ - const int new_vert_idx = vert_used ? num_verts++ : vert_idx; + const int new_vert_idx = vert_used ? verts_len++ : vert_idx; BLI_assert(*lnor_space); @@ -1484,7 +1731,7 @@ static int split_faces_prepare_new_verts( MEM_freeN(done_loops); MEM_freeN(verts_used); - return num_verts - mesh->totvert; + return verts_len - mesh->totvert; } /* Detect needed new edges, and update accordingly loops' edge indices. @@ -1552,12 +1799,12 @@ static int split_faces_prepare_new_edges( static void split_faces_split_new_verts( Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts) { - const int num_verts = mesh->totvert - num_new_verts; + const int verts_len = mesh->totvert - num_new_verts; MVert *mvert = mesh->mvert; /* Remember new_verts is a single linklist, so its items are in reversed order... */ MVert *new_mv = &mvert[mesh->totvert - 1]; - for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) { + for (int i = mesh->totvert - 1; i >= verts_len ; i--, new_mv--, new_verts = new_verts->next) { BLI_assert(new_verts->new_index == i); BLI_assert(new_verts->new_index != new_verts->orig_index); CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1); @@ -1652,14 +1899,13 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) #endif } - /* **** Depsgraph evaluation **** */ void BKE_mesh_eval_geometry( - EvaluationContext *UNUSED(eval_ctx), + Depsgraph *depsgraph, Mesh *mesh) { - DEG_debug_print_eval(__func__, mesh->id.name, mesh); + DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh); if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) { BKE_mesh_texspace_calc(mesh); } diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index bfee7f3924c..eed02dae824 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -22,9 +22,11 @@ * \ingroup bke */ + #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" +#include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" @@ -39,24 +41,33 @@ #include "BKE_main.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_key.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" #include "BKE_displist.h" #include "BKE_library.h" #include "BKE_material.h" -#include "BKE_modifier.h" #include "BKE_mball.h" -#include "BKE_depsgraph.h" +/* these 2 are only used by conversion functions */ #include "BKE_curve.h" /* -- */ #include "BKE_object.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" /* Define for cases when you want extra validation of mesh * after certain modifications. */ // #undef VALIDATE_MESH +#ifdef VALIDATE_MESH +# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true))) +#else +# define ASSERT_IS_VALID_MESH(mesh) +#endif + void BKE_mesh_from_metaball(ListBase *lb, Mesh *me) { DispList *dl; @@ -206,8 +217,8 @@ int BKE_mesh_nurbs_to_mdata( { ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } return BKE_mesh_nurbs_displist_to_mdata( @@ -480,13 +491,65 @@ int BKE_mesh_nurbs_displist_to_mdata( return 0; } +Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase) +{ + Curve *cu = ob->data; + Mesh *mesh; + MVert *allvert; + MEdge *alledge; + MLoop *allloop; + MPoly *allpoly; + MLoopUV *alluv = NULL; + int totvert, totedge, totloop, totpoly; + bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0; + + if (BKE_mesh_nurbs_displist_to_mdata( + ob, dispbase, &allvert, &totvert, &alledge, + &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL, + &totloop, &totpoly) != 0) + { + /* Error initializing mdata. This often happens when curve is empty */ + return BKE_mesh_new_nomain(0, 0, 0, 0, 0); + } + + mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly); + mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + + memcpy(mesh->mvert, allvert, totvert * sizeof(MVert)); + memcpy(mesh->medge, alledge, totedge * sizeof(MEdge)); + memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop)); + memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly)); + + if (alluv) { + const char *uvname = "Orco"; + CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname); + } + + MEM_freeN(allvert); + MEM_freeN(alledge); + MEM_freeN(allloop); + MEM_freeN(allpoly); + + return mesh; +} + +Mesh *BKE_mesh_new_nomain_from_curve(Object *ob) +{ + ListBase disp = {NULL, NULL}; + + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; + } + + return BKE_mesh_new_nomain_from_curve_displist(ob, &disp); +} /* this may fail replacing ob->data, be sure to check ob->type */ void BKE_mesh_from_nurbs_displist( - Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name) + Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary) { Object *ob1; - DerivedMesh *dm = ob->derivedFinal; + Mesh *me_eval = ob->runtime.mesh_eval; Mesh *me; Curve *cu; MVert *allvert = NULL; @@ -498,7 +561,7 @@ void BKE_mesh_from_nurbs_displist( cu = ob->data; - if (dm == NULL) { + if (me_eval == NULL) { if (BKE_mesh_nurbs_displist_to_mdata( ob, dispbase, &allvert, &totvert, &alledge, &totedge, &allloop, @@ -523,7 +586,6 @@ void BKE_mesh_from_nurbs_displist( if (alluv) { const char *uvname = "Orco"; - me->mtpoly = CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname); me->mloopuv = CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname); } @@ -531,7 +593,8 @@ void BKE_mesh_from_nurbs_displist( } else { me = BKE_mesh_add(bmain, obdata_name); - DM_to_mesh(dm, me, ob, CD_MASK_MESH, false); + ob->runtime.mesh_eval = NULL; + BKE_mesh_nomain_to_mesh(me_eval, me, ob, CD_MASK_MESH, false); } me->totcol = cu->totcol; @@ -570,7 +633,16 @@ void BKE_mesh_from_nurbs_displist( ob1 = ob1->id.next; } - BKE_libblock_free_us(bmain, cu); + if (temporary) { + /* For temporary objects in BKE_mesh_new_from_object don't remap + * the entire scene with associated depsgraph updates, which are + * problematic for renderers exporting data. */ + id_us_min(&cu->id); + BKE_libblock_free(bmain, cu); + } + else { + BKE_libblock_free_us(bmain, cu); + } } void BKE_mesh_from_nurbs(Main *bmain, Object *ob) @@ -579,11 +651,11 @@ void BKE_mesh_from_nurbs(Main *bmain, Object *ob) bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0; ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } - BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name); + BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false); } typedef struct EdgeLink { @@ -610,15 +682,15 @@ static void appendPolyLineVert(ListBase *lb, unsigned int index) BLI_addtail(lb, vl); } -void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int edge_users_test) +void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int edge_users_test) { - MVert *mvert = dm->getVertArray(dm); - MEdge *med, *medge = dm->getEdgeArray(dm); - MPoly *mp, *mpoly = dm->getPolyArray(dm); - MLoop *mloop = dm->getLoopArray(dm); + MVert *mvert = me->mvert; + MEdge *med, *medge = me->medge; + MPoly *mp, *mpoly = me->mpoly; + MLoop *mloop = me->mloop; - int dm_totedge = dm->getNumEdges(dm); - int dm_totpoly = dm->getNumPolys(dm); + int medge_len = me->totedge; + int mpoly_len = me->totpoly; int totedges = 0; int i; @@ -628,8 +700,8 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e ListBase edges = {NULL, NULL}; /* get boundary edges */ - edge_users = MEM_calloc_arrayN(dm_totedge, sizeof(int), __func__); - for (i = 0, mp = mpoly; i < dm_totpoly; i++, mp++) { + edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__); + for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) { MLoop *ml = &mloop[mp->loopstart]; int j; for (j = 0; j < mp->totloop; j++, ml++) { @@ -639,7 +711,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e /* create edges from all faces (so as to find edges not in any faces) */ med = medge; - for (i = 0; i < dm_totedge; i++, med++) { + for (i = 0; i < medge_len; i++, med++) { if (edge_users[i] == edge_users_test) { EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink"); edl->edge = med; @@ -743,15 +815,14 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e } } -void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob) +void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) { /* make new mesh data from the original copy */ - DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_MESH); + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_MESH); ListBase nurblist = {NULL, NULL}; - bool needsFree = false; - BKE_mesh_to_curve_nurblist(dm, &nurblist, 0); - BKE_mesh_to_curve_nurblist(dm, &nurblist, 1); + BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0); + BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1); if (nurblist.first) { Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVE); @@ -763,33 +834,19 @@ void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob) ob->data = cu; ob->type = OB_CURVE; - /* curve objects can't contain DM in usual cases, we could free memory */ - needsFree = true; - } - - dm->needsFree = needsFree; - dm->release(dm); - - if (needsFree) { - ob->derivedFinal = NULL; - - /* curve object could have got bounding box only in special cases */ - if (ob->bb) { - MEM_freeN(ob->bb); - ob->bb = NULL; - } + BKE_object_free_derived_caches(ob); } } /* settings: 1 - preview, 2 - render */ Mesh *BKE_mesh_new_from_object( - Main *bmain, Scene *sce, Object *ob, - int apply_modifiers, int settings, int calc_tessface, int calc_undeformed) + Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob, + const bool apply_modifiers, const bool calc_undeformed) { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; int i; - const bool render = (settings == eModifierMode_Render); + const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); const bool cage = !apply_modifiers; bool do_mat_id_data_us = true; @@ -800,15 +857,14 @@ Mesh *BKE_mesh_new_from_object( case OB_SURF: { ListBase dispbase = {NULL, NULL}; - DerivedMesh *derivedFinal = NULL; + Mesh *me_eval_final = NULL; int uv_from_orco; /* copies object and modifiers (but not the data) */ Object *tmpobj; /* TODO: make it temp copy outside bmain! */ - BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false); + BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES | LIB_ID_CREATE_NO_DEG_TAG, false); tmpcu = (Curve *)tmpobj->data; - id_us_min(&tmpcu->id); /* Copy cached display list, it might be needed by the stack evaluation. * Ideally stack should be able to use render-time display list, but doing @@ -816,11 +872,11 @@ Mesh *BKE_mesh_new_from_object( * * TODO(sergey): Look into more proper solution. */ - if (ob->curve_cache != NULL) { - if (tmpobj->curve_cache == NULL) { - tmpobj->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); + if (ob->runtime.curve_cache != NULL) { + if (tmpobj->runtime.curve_cache == NULL) { + tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); } - BKE_displist_copy(&tmpobj->curve_cache->disp, &ob->curve_cache->disp); + BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &ob->runtime.curve_cache->disp); } /* if getting the original caged mesh, delete object modifiers */ @@ -828,7 +884,8 @@ Mesh *BKE_mesh_new_from_object( BKE_object_free_modifiers(tmpobj, 0); /* copies the data */ - copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data); + BKE_id_copy_ex(bmain, ob->data, (ID **)©cu, LIB_ID_CREATE_NO_DEG_TAG, false); + tmpobj->data = copycu; /* make sure texture space is calculated for a copy of curve, * it will be used for the final result. @@ -842,16 +899,16 @@ Mesh *BKE_mesh_new_from_object( copycu->editnurb = tmpcu->editnurb; /* get updated display list, and convert to a mesh */ - BKE_displist_make_curveTypes_forRender(sce, tmpobj, &dispbase, &derivedFinal, false, render); + BKE_displist_make_curveTypes_forRender(depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, render); copycu->editfont = NULL; copycu->editnurb = NULL; - tmpobj->derivedFinal = derivedFinal; + tmpobj->runtime.mesh_eval = me_eval_final; /* convert object type to mesh */ uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0; - BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2); + BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true); tmpmesh = tmpobj->data; @@ -861,11 +918,11 @@ Mesh *BKE_mesh_new_from_object( * if it didn't the curve did not have any segments or otherwise * would have generated an empty mesh */ if (tmpobj->type != OB_MESH) { - BKE_libblock_free_us(bmain, tmpobj); + BKE_libblock_free(bmain, tmpobj); return NULL; } - BKE_libblock_free_us(bmain, tmpobj); + BKE_libblock_free(bmain, tmpobj); /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist() * already transfers the ownership of materials from the temp copy of the Curve ID to the new @@ -878,7 +935,7 @@ Mesh *BKE_mesh_new_from_object( case OB_MBALL: { /* metaballs don't have modifiers, so just convert to mesh */ - Object *basis_ob = BKE_mball_basis_find(bmain, bmain->eval_ctx, sce, ob); + Object *basis_ob = BKE_mball_basis_find(sce, ob); /* todo, re-generatre for render-res */ /* metaball_polygonize(scene, ob) */ @@ -891,20 +948,14 @@ Mesh *BKE_mesh_new_from_object( if (render) { ListBase disp = {NULL, NULL}; - /* TODO(sergey): This is gonna to work for until EvaluationContext - * only contains for_render flag. As soon as CoW is - * implemented, this is to be rethought. - */ - EvaluationContext eval_ctx; - DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER); - BKE_displist_make_mball_forRender(bmain, &eval_ctx, sce, ob, &disp); + BKE_displist_make_mball_forRender(depsgraph, sce, ob, &disp); BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); } else { ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } BKE_mesh_from_metaball(&disp, tmpmesh); } @@ -926,7 +977,7 @@ Mesh *BKE_mesh_new_from_object( /* if not getting the original caged mesh, get final derived mesh */ else { /* Make a dummy mesh, saves copying */ - DerivedMesh *dm; + Mesh *me_eval; /* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */ CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter, * for example, needs CD_MASK_MDEFORMVERT */ @@ -934,14 +985,15 @@ Mesh *BKE_mesh_new_from_object( if (calc_undeformed) mask |= CD_MASK_ORCO; - /* Write the display mesh into the dummy mesh */ - if (render) - dm = mesh_create_derived_render(sce, ob, mask); - else - dm = mesh_create_derived_view(sce, ob, mask); + if (render) { + me_eval = mesh_create_eval_final_render(depsgraph, sce, ob, mask); + } + else { + me_eval = mesh_create_eval_final_view(depsgraph, sce, ob, mask); + } tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2); - DM_to_mesh(dm, tmpmesh, ob, mask, true); + BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, ob, mask, true); /* Copy autosmooth settings from original mesh. */ Mesh *me = (Mesh *)ob->data; @@ -1019,10 +1071,345 @@ Mesh *BKE_mesh_new_from_object( break; } /* end copy materials */ - if (calc_tessface) { - /* cycles and exporters rely on this still */ - BKE_mesh_tessface_ensure(tmpmesh); + return tmpmesh; +} + + +static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) +{ + KeyBlock *kb; + Key *key = mesh_src->key; + int i; + + if (!mesh_src->key) + return; + + /* ensure we can use mesh vertex count for derived mesh custom data */ + if (mesh_src->totvert != mesh_dest->totvert) { + fprintf(stderr, + "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n", + __func__, mesh_src->id.name + 2, mesh_src->totvert, mesh_dest->totvert); + return; } - return tmpmesh; + for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) { + int ci; + float *array; + + if (mesh_src->totvert != kb->totelem) { + fprintf(stderr, + "%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n", + __func__, mesh_src->id.name + 2, mesh_src->totvert, kb->name, kb->totelem); + array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__); + } + else { + array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__); + memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float)); + } + + CustomData_add_layer_named(&mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name); + ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i); + + mesh_dest->vdata.layers[ci].uid = kb->uid; + } +} + + +Mesh *BKE_mesh_create_derived_for_modifier( + struct Depsgraph *depsgraph, Scene *scene, Object *ob, + ModifierData *md, int build_shapekey_layers) +{ + Mesh *me = ob->data; + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + Mesh *result; + KeyBlock *kb; + ModifierEvalContext mectx = {depsgraph, ob, 0}; + + if (!(md->mode & eModifierMode_Realtime)) { + return NULL; + } + + if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { + return NULL; + } + + if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) { + BKE_keyblock_convert_to_mesh(kb, me); + } + + if (mti->type == eModifierTypeType_OnlyDeform) { + int numVerts; + float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts); + + mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts); + BKE_id_copy_ex( + NULL, &me->id, (ID **)&result, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); + BKE_mesh_apply_vert_coords(result, deformedVerts); + + if (build_shapekey_layers) + add_shapekey_layers(result, me); + + MEM_freeN(deformedVerts); + } + else { + Mesh *mesh_temp; + BKE_id_copy_ex( + NULL, &me->id, (ID **)&mesh_temp, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); + + if (build_shapekey_layers) + add_shapekey_layers(mesh_temp, me); + + result = mti->applyModifier(md, &mectx, mesh_temp); + ASSERT_IS_VALID_MESH(result); + + if (mesh_temp != result) { + BKE_id_free(NULL, mesh_temp); + } + } + + return result; +} + +/* This is a Mesh-based copy of the same function in DerivedMesh.c */ +static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid) +{ + KeyBlock *kb; + int i, j, tot; + + if (!mesh_dst->key) + return; + + tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY); + for (i = 0; i < tot; i++) { + CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)]; + float (*cos)[3], (*kbcos)[3]; + + for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { + if (kb->uid == layer->uid) + break; + } + + if (!kb) { + kb = BKE_keyblock_add(mesh_dst->key, layer->name); + kb->uid = layer->uid; + } + + if (kb->data) + MEM_freeN(kb->data); + + cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i); + kb->totelem = mesh_src->totvert; + + kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__); + if (kb->uid == actshape_uid) { + MVert *mvert = mesh_src->mvert; + + for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) { + copy_v3_v3(*kbcos, mvert->co); + } + } + else { + for (j = 0; j < kb->totelem; j++, cos++, kbcos++) { + copy_v3_v3(*kbcos, *cos); + } + } + } + + for (kb = mesh_dst->key->block.first; kb; kb = kb->next) { + if (kb->totelem != mesh_src->totvert) { + if (kb->data) + MEM_freeN(kb->data); + + kb->totelem = mesh_src->totvert; + kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__); + fprintf(stderr, "%s: lost a shapekey layer: '%s'! (bmesh internal error)\n", __func__, kb->name); + } + } +} + + +/* This is a Mesh-based copy of DM_to_mesh() */ +void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership) +{ + /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */ + /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */ + Mesh tmp = *mesh_dst; + int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly; + int did_shapekeys = 0; + eCDAllocType alloctype = CD_DUPLICATE; + + if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) { + bool has_any_referenced_layers = + CustomData_has_referenced(&mesh_src->vdata) || + CustomData_has_referenced(&mesh_src->edata) || + CustomData_has_referenced(&mesh_src->ldata) || + CustomData_has_referenced(&mesh_src->fdata) || + CustomData_has_referenced(&mesh_src->pdata); + if (!has_any_referenced_layers) { + alloctype = CD_ASSIGN; + } + } + CustomData_reset(&tmp.vdata); + CustomData_reset(&tmp.edata); + CustomData_reset(&tmp.fdata); + CustomData_reset(&tmp.ldata); + CustomData_reset(&tmp.pdata); + + BKE_mesh_ensure_normals(mesh_src); + + totvert = tmp.totvert = mesh_src->totvert; + totedge = tmp.totedge = mesh_src->totedge; + totloop = tmp.totloop = mesh_src->totloop; + totpoly = tmp.totpoly = mesh_src->totpoly; + tmp.totface = 0; + + CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask, alloctype, totvert); + CustomData_copy(&mesh_src->edata, &tmp.edata, mask, alloctype, totedge); + CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask, alloctype, totloop); + CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask, alloctype, totpoly); + tmp.cd_flag = mesh_src->cd_flag; + tmp.runtime.deformed_only = mesh_src->runtime.deformed_only; + + if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) { + KeyBlock *kb; + int uid; + + if (ob) { + kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1); + if (kb) { + uid = kb->uid; + } + else { + printf("%s: error - could not find active shapekey %d!\n", + __func__, ob->shapenr - 1); + + uid = INT_MAX; + } + } + else { + /* if no object, set to INT_MAX so we don't mess up any shapekey layers */ + uid = INT_MAX; + } + + shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid); + did_shapekeys = 1; + } + + /* copy texture space */ + if (ob) { + BKE_mesh_texspace_copy_from_object(&tmp, ob); + } + + /* not all DerivedMeshes store their verts/edges/faces in CustomData, so + * we set them here in case they are missing */ + /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and always directly pass mesh_src->mxxx, + * instead of using a ternary operator. */ + if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) { + CustomData_add_layer( + &tmp.vdata, CD_MVERT, CD_ASSIGN, + (alloctype == CD_ASSIGN) ? mesh_src->mvert : MEM_dupallocN(mesh_src->mvert), + totvert); + } + if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) { + CustomData_add_layer( + &tmp.edata, CD_MEDGE, CD_ASSIGN, + (alloctype == CD_ASSIGN) ? mesh_src->medge : MEM_dupallocN(mesh_src->medge), + totedge); + } + if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) { + /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the + * BKE_mesh_update_customdata_pointers() call below. */ + tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop); + tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly); + + CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop); + CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly); + } + + /* object had got displacement layer, should copy this layer to save sculpted data */ + /* NOTE: maybe some other layers should be copied? nazgul */ + if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) { + if (totloop == mesh_dst->totloop) { + MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS); + CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop); + } + } + + /* yes, must be before _and_ after tessellate */ + BKE_mesh_update_customdata_pointers(&tmp, false); + + /* since 2.65 caller must do! */ + // BKE_mesh_tessface_calc(&tmp); + + CustomData_free(&mesh_dst->vdata, mesh_dst->totvert); + CustomData_free(&mesh_dst->edata, mesh_dst->totedge); + CustomData_free(&mesh_dst->fdata, mesh_dst->totface); + CustomData_free(&mesh_dst->ldata, mesh_dst->totloop); + CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly); + + /* ok, this should now use new CD shapekey data, + * which should be fed through the modifier + * stack */ + if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) { + printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name); + if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) { + id_us_min(&tmp.key->id); + } + tmp.key = NULL; + } + + /* Clear selection history */ + MEM_SAFE_FREE(tmp.mselect); + tmp.totselect = 0; + BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb)); + if (mesh_dst->bb) { + MEM_freeN(mesh_dst->bb); + tmp.bb = NULL; + } + + /* skip the listbase */ + MEMCPY_STRUCT_OFS(mesh_dst, &tmp, id.prev); + + if (take_ownership) { + if (alloctype == CD_ASSIGN) { + CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask); + CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask); + CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask); + CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask); + } + BKE_id_free(NULL, mesh_src); + } +} + +/* This is a Mesh-based copy of DM_to_meshkey() */ +void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb) +{ + int a, totvert = mesh_src->totvert; + float *fp; + MVert *mvert; + + if (totvert == 0 || mesh_dst->totvert == 0 || mesh_dst->totvert != totvert) { + return; + } + + if (kb->data) MEM_freeN(kb->data); + kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data"); + kb->totelem = totvert; + + fp = kb->data; + mvert = mesh_src->mvert; + + for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) { + copy_v3_v3(fp, mvert->co); + } } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index e3b1f20e583..fd117734aaf 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -88,6 +88,20 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts) } } +/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(), + * and remove the function of the same name below, as that one doesn't seem to be + * called anywhere. */ +void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh) +{ + const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT); + + BKE_mesh_calc_normals_mapping_ex( + mesh->mvert, mesh->totvert, + mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, + mesh->mface, mesh->totface, NULL, NULL, + only_face_normals); +} + /* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL * and vertex normals are stored in actual mverts. */ @@ -332,6 +346,44 @@ void BKE_mesh_calc_normals_poly( MEM_freeN(lnors_weighted); } +void BKE_mesh_ensure_normals(Mesh *mesh) +{ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + BKE_mesh_calc_normals(mesh); + } + BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0); +} + +/** + * Called after calculating all modifiers. + */ +void BKE_mesh_ensure_normals_for_display(Mesh *mesh) +{ + /* Note: mesh *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.). + * We do not use it here, though. And it should be tagged as temp! + */ + /* BLI_assert((CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false)); */ + + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL || !CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { + float (*poly_nors)[3] = NULL; + poly_nors = MEM_malloc_arrayN((size_t)mesh->totpoly, sizeof(*poly_nors), __func__); + + /* if normals are dirty we want to calculate vertex normals too */ + bool only_face_normals = !(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL); + + /* calculate face normals */ + BKE_mesh_calc_normals_poly( + mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly, + mesh->totloop, mesh->totpoly, poly_nors, + only_face_normals); + + CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly); + + mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; + } +} + +/* Note that this does not update the CD_NORMAL layer, but does update the normals in the CD_MVERT layer. */ void BKE_mesh_calc_normals(Mesh *mesh) { #ifdef DEBUG_TIME @@ -344,6 +396,7 @@ void BKE_mesh_calc_normals(Mesh *mesh) #ifdef DEBUG_TIME TIMEIT_END_AVERAGED(BKE_mesh_calc_normals); #endif + mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; } void BKE_mesh_calc_normals_tessface( @@ -456,6 +509,8 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo mem = lnors_spacearr->mem; lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops); lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops); + + lnors_spacearr->num_spaces = 0; } BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX)); lnors_spacearr->data_type = data_type; @@ -463,21 +518,24 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr) { - BLI_memarena_clear(lnors_spacearr->mem); + lnors_spacearr->num_spaces = 0; lnors_spacearr->lspacearr = NULL; lnors_spacearr->loops_pool = NULL; + BLI_memarena_clear(lnors_spacearr->mem); } void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr) { - BLI_memarena_free(lnors_spacearr->mem); + lnors_spacearr->num_spaces = 0; lnors_spacearr->lspacearr = NULL; lnors_spacearr->loops_pool = NULL; + BLI_memarena_free(lnors_spacearr->mem); lnors_spacearr->mem = NULL; } MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) { + lnors_spacearr->num_spaces++; return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace)); } @@ -1835,155 +1893,6 @@ void BKE_mesh_normals_loop_to_vertex( /* -------------------------------------------------------------------- */ -/** \name Mesh Tangent Calculations - * \{ */ - -/* Tangent space utils. */ - -/* User data. */ -typedef struct { - const MPoly *mpolys; /* faces */ - const MLoop *mloops; /* faces's vertices */ - const MVert *mverts; /* vertices */ - const MLoopUV *luvs; /* texture coordinates */ - float (*lnors)[3]; /* loops' normals */ - float (*tangents)[4]; /* output tangents */ - int num_polys; /* number of polygons */ -} BKEMeshToTangent; - -/* Mikktspace's API */ -static int get_num_faces(const SMikkTSpaceContext *pContext) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - return p_mesh->num_polys; -} - -static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - return p_mesh->mpolys[face_idx].totloop; -} - -static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx; - copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co); -} - -static void get_texture_coordinate( - const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx, - const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv); -} - -static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]); -} - -static void set_tspace( - const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign, - const int face_idx, const int vert_idx) -{ - BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; - float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx]; - copy_v3_v3(p_res, fv_tangent); - p_res[3] = face_sign; -} - -/** - * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with - * split normals can be used to recreate the full tangent space. - * Note: * The mesh should be made of only tris and quads! - */ -void BKE_mesh_loop_tangents_ex( - const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops, - float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs, - const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys, - ReportList *reports) -{ - BKEMeshToTangent mesh_to_tangent = {NULL}; - SMikkTSpaceContext s_context = {NULL}; - SMikkTSpaceInterface s_interface = {NULL}; - - const MPoly *mp; - int mp_index; - - /* First check we do have a tris/quads only mesh. */ - for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { - if (mp->totloop > 4) { - BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting"); - return; - } - } - - /* Compute Mikktspace's tangent normals. */ - mesh_to_tangent.mpolys = mpolys; - mesh_to_tangent.mloops = mloops; - mesh_to_tangent.mverts = mverts; - mesh_to_tangent.luvs = loopuvs; - mesh_to_tangent.lnors = loopnors; - mesh_to_tangent.tangents = r_looptangent; - mesh_to_tangent.num_polys = numPolys; - - s_context.m_pUserData = &mesh_to_tangent; - s_context.m_pInterface = &s_interface; - s_interface.m_getNumFaces = get_num_faces; - s_interface.m_getNumVerticesOfFace = get_num_verts_of_face; - s_interface.m_getPosition = get_position; - s_interface.m_getTexCoord = get_texture_coordinate; - s_interface.m_getNormal = get_normal; - s_interface.m_setTSpaceBasic = set_tspace; - - /* 0 if failed */ - if (genTangSpaceDefault(&s_context) == false) { - BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!"); - } -} - -/** - * Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code. - * \note - * - There must be a valid loop's CD_NORMALS available. - * - The mesh should be made of only tris and quads! - */ -void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports) -{ - MLoopUV *loopuvs; - float (*loopnors)[3]; - - /* Check we have valid texture coordinates first! */ - if (uvmap) { - loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap); - } - else { - loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV); - } - if (!loopuvs) { - BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap); - return; - } - - loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); - if (!loopnors) { - BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting"); - return; - } - - BKE_mesh_loop_tangents_ex( - mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents, - loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - /** \name Polygon Calculations * \{ */ @@ -2256,30 +2165,6 @@ static float mesh_calc_poly_area_centroid( return total_area; } -#if 0 /* slow version of the function below */ -void BKE_mesh_calc_poly_angles( - MPoly *mpoly, MLoop *loopstart, - MVert *mvarray, float angles[]) -{ - MLoop *ml; - MLoop *mloop = &loopstart[-mpoly->loopstart]; - - int j; - for (j = 0, ml = loopstart; j < mpoly->totloop; j++, ml++) { - MLoop *ml_prev = ME_POLY_LOOP_PREV(mloop, mpoly, j); - MLoop *ml_next = ME_POLY_LOOP_NEXT(mloop, mpoly, j); - - float e1[3], e2[3]; - - sub_v3_v3v3(e1, mvarray[ml_next->v].co, mvarray[ml->v].co); - sub_v3_v3v3(e2, mvarray[ml_prev->v].co, mvarray[ml->v].co); - - angles[j] = (float)M_PI - angle_v3v3(e1, e2); - } -} - -#else /* equivalent the function above but avoid multiple subtractions + normalize */ - void BKE_mesh_calc_poly_angles( const MPoly *mpoly, const MLoop *loopstart, const MVert *mvarray, float angles[]) @@ -2304,7 +2189,6 @@ void BKE_mesh_calc_poly_angles( i_next++; } } -#endif void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop) { @@ -2556,12 +2440,12 @@ void BKE_mesh_calc_volume( */ void BKE_mesh_loops_to_mface_corners( CustomData *fdata, CustomData *ldata, - CustomData *pdata, unsigned int lindex[4], int findex, - const int polyindex, + CustomData *UNUSED(pdata), unsigned int lindex[4], int findex, + const int UNUSED(polyindex), const int mf_len, /* 3 or 4 */ /* cache values to avoid lookups every time */ - const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */ + const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */ const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */ const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */ const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */ @@ -2569,17 +2453,13 @@ void BKE_mesh_loops_to_mface_corners( ) { MTFace *texface; - MTexPoly *texpoly; MCol *mcol; MLoopCol *mloopcol; MLoopUV *mloopuv; int i, j; - for (i = 0; i < numTex; i++) { + for (i = 0; i < numUV; i++) { texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); - texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i); - - ME_MTEXFACE_CPY(texface, texpoly); for (j = 0; j < mf_len; j++) { mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i); @@ -2632,14 +2512,14 @@ void BKE_mesh_loops_to_mface_corners( * \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used. */ void BKE_mesh_loops_to_tessdata( - CustomData *fdata, CustomData *ldata, CustomData *pdata, MFace *mface, + CustomData *fdata, CustomData *ldata, MFace *mface, int *polyindices, unsigned int (*loopindices)[4], const int num_faces) { /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code... * Issue is, unless having two different functions with nearly the same code, there's not much ways to solve * this. Better imho to live with it for now. :/ --mont29 */ - const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV); const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); @@ -2649,17 +2529,14 @@ void BKE_mesh_loops_to_tessdata( const int *pidx; unsigned int (*lidx)[4]; - for (i = 0; i < numTex; i++) { + for (i = 0; i < numUV; i++) { MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i); - MTexPoly *texpoly = CustomData_get_layer_n(pdata, CD_MTEXPOLY, i); MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i); for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces; pidx++, lidx++, findex++, texface++) { - ME_MTEXFACE_CPY(texface, &texpoly[*pidx]); - for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) { copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv); } @@ -2982,7 +2859,7 @@ int BKE_mesh_recalc_tessellation( /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons * they are directly tessellated from */ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + CustomData_from_bmeshpoly(fdata, ldata, totface); if (do_face_nor_copy) { /* If polys have a normals layer, copying that to faces can help @@ -3003,7 +2880,7 @@ int BKE_mesh_recalc_tessellation( * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test. * ... */ - BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, mface_to_poly_map, lindices, totface); + BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface); /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx: * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad. @@ -3173,11 +3050,10 @@ void BKE_mesh_recalc_looptri( } static void bm_corners_to_loops_ex( - ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, + ID *id, CustomData *fdata, CustomData *ldata, MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol) { MTFace *texface; - MTexPoly *texpoly; MCol *mcol; MLoopCol *mloopcol; MLoopUV *mloopuv; @@ -3188,9 +3064,6 @@ static void bm_corners_to_loops_ex( for (i = 0; i < numTex; i++) { texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); - texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i); - - ME_MTEXFACE_CPY(texpoly, texface); mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i); copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++; @@ -3300,7 +3173,7 @@ void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) mesh->medge, mesh->mface, &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly); - CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata); + CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata); BKE_mesh_update_customdata_pointers(mesh, true); } @@ -3344,7 +3217,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex( CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); - CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly); + CustomData_to_bmeshpoly(fdata, ldata, totloop); if (id) { /* ensure external data is transferred */ @@ -3394,7 +3267,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex( # undef ML - bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol); + bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol); if (polyindex) { *polyindex = i; diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c new file mode 100644 index 00000000000..73dcd912f48 --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_iterators.c @@ -0,0 +1,211 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_iterators.c + * \ingroup bke + * + * Functions for iterating mesh features. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_mesh.h" +#include "BKE_mesh_iterators.h" + +#include "BLI_bitmap.h" +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +/* Copied from cdDM_foreachMappedVert */ +void BKE_mesh_foreach_mapped_vert( + Mesh *mesh, + void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]), + void *userData, + MeshForeachFlag flag) +{ + const MVert *mv = mesh->mvert; + const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); + + if (index) { + for (int i = 0; i < mesh->totvert; i++, mv++) { + const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL; + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + func(userData, orig, mv->co, NULL, no); + } + } + else { + for (int i = 0; i < mesh->totvert; i++, mv++) { + const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL; + func(userData, i, mv->co, NULL, no); + } + } +} + +/* Copied from cdDM_foreachMappedEdge */ +void BKE_mesh_foreach_mapped_edge( + Mesh *mesh, + void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), + void *userData) +{ + const MVert *mv = mesh->mvert; + const MEdge *med = mesh->medge; + const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX); + + if (index) { + for (int i = 0; i < mesh->totedge; i++, med++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + func(userData, orig, mv[med->v1].co, mv[med->v2].co); + } + } + else { + for (int i = 0; i < mesh->totedge; i++, med++) { + func(userData, i, mv[med->v1].co, mv[med->v2].co); + } + } +} + +/* Copied from cdDM_foreachMappedLoop */ +void BKE_mesh_foreach_mapped_loop( + Mesh *mesh, + void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]), + void *userData, + MeshForeachFlag flag) +{ + /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would + * return loop data from bmesh itself. */ + const float (*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? CustomData_get_layer(&mesh->ldata, CD_NORMAL) : NULL; + + const MVert *mv = mesh->mvert; + const MLoop *ml = mesh->mloop; + const MPoly *mp = mesh->mpoly; + const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); + const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + int p_idx, i; + + if (v_index || f_index) { + for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { + for (i = 0; i < mp->totloop; i++, ml++) { + const int v_idx = v_index ? v_index[ml->v] : ml->v; + const int f_idx = f_index ? f_index[p_idx] : p_idx; + const float *no = lnors ? *lnors++ : NULL; + if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) { + continue; + } + func(userData, v_idx, f_idx, mv[ml->v].co, no); + } + } + } + else { + for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) { + for (i = 0; i < mp->totloop; i++, ml++) { + const int v_idx = ml->v; + const int f_idx = p_idx; + const float *no = lnors ? *lnors++ : NULL; + func(userData, v_idx, f_idx, mv[ml->v].co, no); + } + } + } +} + +/* Copied from cdDM_foreachMappedFaceCenter */ +void BKE_mesh_foreach_mapped_face_center( + Mesh *mesh, + void (*func)(void *userData, int index, const float cent[3], const float no[3]), + void *userData, + MeshForeachFlag flag) +{ + const MVert *mvert = mesh->mvert; + const MPoly *mp = mesh->mpoly; + const MLoop *ml; + float _no_buf[3]; + float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL; + const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + + if (index) { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + const int orig = *index++; + if (orig == ORIGINDEX_NONE) { + continue; + } + float cent[3]; + ml = &mesh->mloop[mp->loopstart]; + BKE_mesh_calc_poly_center(mp, ml, mvert, cent); + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + } + func(userData, orig, cent, no); + } + } + else { + for (int i = 0; i < mesh->totpoly; i++, mp++) { + float cent[3]; + ml = &mesh->mloop[mp->loopstart]; + BKE_mesh_calc_poly_center(mp, ml, mvert, cent); + if (flag & MESH_FOREACH_USE_NORMAL) { + BKE_mesh_calc_poly_normal(mp, ml, mvert, no); + } + func(userData, i, cent, no); + } + } +} + + +/* Helpers based on above foreach loopers> */ + +typedef struct MappedVCosData { + float (*vertexcos)[3]; + BLI_bitmap *vertex_visit; +} MappedVCosData; + +static void get_vertexcos__mapFunc( + void *user_data, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data; + + if (BLI_BITMAP_TEST(mapped_vcos_data->vertex_visit, index) == 0) { + /* We need coord from prototype vertex, not from copies, + * we assume they stored in the beginning of vertex array stored in evaluated mesh + * (mirror modifier for eg does this). */ + copy_v3_v3(mapped_vcos_data->vertexcos[index], co); + BLI_BITMAP_ENABLE(mapped_vcos_data->vertex_visit, index); + } +} + +void BKE_mesh_foreach_mapped_vert_coords_get(Mesh *me_eval, float (*r_cos)[3], const int totcos) +{ + MappedVCosData user_data; + memset(r_cos, 0, sizeof(*r_cos) * totcos); + user_data.vertexcos = r_cos; + user_data.vertex_visit = BLI_BITMAP_NEW(totcos, __func__); + BKE_mesh_foreach_mapped_vert(me_eval, get_vertexcos__mapFunc, &user_data, MESH_FOREACH_NOP); + MEM_freeN(user_data.vertex_visit); +} diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c new file mode 100644 index 00000000000..5324c397ebf --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_merge.c @@ -0,0 +1,685 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_merge.c + * \ingroup bke + */ +#include <string.h> // for memcpy + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_utildefines_stack.h" +#include "BLI_edgehash.h" +#include "BLI_ghash.h" + +#include "BKE_customdata.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" + + +/** + * Poly compare with vtargetmap + * Function used by #BKE_mesh_merge_verts. + * The function compares poly_source after applying vtargetmap, with poly_target. + * The two polys are identical if they share the same vertices in the same order, or in reverse order, + * but starting position loopstart may be different. + * The function is called with direct_reverse=1 for same order (i.e. same normal), + * and may be called again with direct_reverse=-1 for reverse order. + * \return 1 if polys are identical, 0 if polys are different. + */ +static int cddm_poly_compare( + MLoop *mloop_array, + MPoly *mpoly_source, MPoly *mpoly_target, + const int *vtargetmap, const int direct_reverse) +{ + int vert_source, first_vert_source, vert_target; + int i_loop_source; + int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted; + bool compare_completed = false; + bool same_loops = false; + + MLoop *mloop_source, *mloop_target; + + BLI_assert(direct_reverse == 1 || direct_reverse == -1); + + i_loop_source = 0; + mloop_source = mloop_array + mpoly_source->loopstart; + vert_source = mloop_source->v; + + if (vtargetmap[vert_source] != -1) { + vert_source = vtargetmap[vert_source]; + } + else { + /* All source loop vertices should be mapped */ + BLI_assert(false); + } + + /* Find same vertex within mpoly_target's loops */ + mloop_target = mloop_array + mpoly_target->loopstart; + for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) { + if (mloop_target->v == vert_source) { + break; + } + } + + /* If same vertex not found, then polys cannot be equal */ + if (i_loop_target >= mpoly_target->totloop) { + return false; + } + + /* Now mloop_source and m_loop_target have one identical vertex */ + /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */ + /* Go around the loop and check that all vertices match in same order */ + /* Skipping source loops when consecutive source vertices are mapped to same target vertex */ + + i_loop_target_start = i_loop_target; + i_loop_target_offset = 0; + first_vert_source = vert_source; + + compare_completed = false; + same_loops = false; + + while (!compare_completed) { + + vert_target = mloop_target->v; + + /* First advance i_loop_source, until it points to different vertex, after mapping applied */ + do { + i_loop_source++; + + if (i_loop_source == mpoly_source->totloop) { + /* End of loops for source, must match end of loop for target. */ + if (i_loop_target_offset == mpoly_target->totloop - 1) { + compare_completed = true; + same_loops = true; + break; /* Polys are identical */ + } + else { + compare_completed = true; + same_loops = false; + break; /* Polys are different */ + } + } + + mloop_source++; + vert_source = mloop_source->v; + + if (vtargetmap[vert_source] != -1) { + vert_source = vtargetmap[vert_source]; + } + else { + /* All source loop vertices should be mapped */ + BLI_assert(false); + } + + } while (vert_source == vert_target); + + if (compare_completed) { + break; + } + + /* Now advance i_loop_target as well */ + i_loop_target_offset++; + + if (i_loop_target_offset == mpoly_target->totloop) { + /* End of loops for target only, that means no match */ + /* except if all remaining source vertices are mapped to first target */ + for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) { + vert_source = vtargetmap[mloop_source->v]; + if (vert_source != first_vert_source) { + compare_completed = true; + same_loops = false; + break; + } + } + if (!compare_completed) { + same_loops = true; + } + break; + } + + /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */ + i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop; + if (i_loop_target_adjusted < 0) { + i_loop_target_adjusted += mpoly_target->totloop; + } + mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted; + vert_target = mloop_target->v; + + if (vert_target != vert_source) { + same_loops = false; /* Polys are different */ + break; + } + } + return same_loops; +} + + +/* Utility stuff for using GHash with polys, used by vertex merging. */ + +typedef struct PolyKey { + int poly_index; /* index of the MPoly within the derived mesh */ + int totloops; /* number of loops in the poly */ + unsigned int hash_sum; /* Sum of all vertices indices */ + unsigned int hash_xor; /* Xor of all vertices indices */ +} PolyKey; + + +static unsigned int poly_gset_hash_fn(const void *key) +{ + const PolyKey *pk = key; + return pk->hash_sum; +} + +static bool poly_gset_compare_fn(const void *k1, const void *k2) +{ + const PolyKey *pk1 = k1; + const PolyKey *pk2 = k2; + if ((pk1->hash_sum == pk2->hash_sum) && + (pk1->hash_xor == pk2->hash_xor) && + (pk1->totloops == pk2->totloops)) + { + /* Equality - note that this does not mean equality of polys */ + return false; + } + else { + return true; + } +} + +/** + * Merge Verts + * + * This frees the given mesh and returns a new mesh. + * + * \param vtargetmap The table that maps vertices to target vertices. a value of -1 + * indicates a vertex is a target, and is to be kept. + * This array is aligned with 'mesh->totvert' + * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported + * and will likely generate corrupted geometry. + * + * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size) + * + * \param merge_mode enum with two modes. + * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED + * When called by the Mirror Modifier, + * In this mode it skips any faces that have all vertices merged (to avoid creating pairs + * of faces sharing the same set of vertices) + * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL + * When called by the Array Modifier, + * In this mode, faces where all vertices are merged are double-checked, + * to see whether all target vertices actually make up a poly already. + * Indeed it could be that all of a poly's vertices are merged, + * but merged to vertices that do not make up a single poly, + * in which case the original poly should not be dumped. + * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are + * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror. + * + * \note #BKE_mesh_recalc_tessellation has to run on the returned DM if you want to access tessfaces. + */ +Mesh *BKE_mesh_merge_verts(Mesh *mesh, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode) +{ + /* This was commented out back in 2013, see commit f45d8827bafe6b9eaf9de42f4054e9d84a21955d. */ +// #define USE_LOOPS + + Mesh *result = NULL; + + const int totvert = mesh->totvert; + const int totedge = mesh->totedge; + const int totloop = mesh->totloop; + const int totpoly = mesh->totpoly; + + const int totvert_final = totvert - tot_vtargetmap; + + MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__); + int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__); + int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__); + STACK_DECLARE(mvert); + STACK_DECLARE(oldv); + + /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require + * generating new edges, and while in 99% cases we'll still end with less final edges than totedge, + * cases can be forged that would end requiring more... */ + MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__); + int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__); + int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__); + STACK_DECLARE(medge); + STACK_DECLARE(olde); + + MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__); + int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__); +#ifdef USE_LOOPS + int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__); +#endif + STACK_DECLARE(mloop); + STACK_DECLARE(oldl); + + MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__); + int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__); + STACK_DECLARE(mpoly); + STACK_DECLARE(oldp); + + EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge); + + int i, j, c; + + PolyKey *poly_keys; + GSet *poly_gset = NULL; + MeshElemMap *poly_map = NULL; + int *poly_map_mem = NULL; + + STACK_INIT(oldv, totvert_final); + STACK_INIT(olde, totedge); + STACK_INIT(oldl, totloop); + STACK_INIT(oldp, totpoly); + + STACK_INIT(mvert, totvert_final); + STACK_INIT(medge, totedge); + STACK_INIT(mloop, totloop); + STACK_INIT(mpoly, totpoly); + + /* fill newv with destination vertex indices */ + mv = mesh->mvert; + c = 0; + for (i = 0; i < totvert; i++, mv++) { + if (vtargetmap[i] == -1) { + STACK_PUSH(oldv, i); + STACK_PUSH(mvert, *mv); + newv[i] = c++; + } + else { + /* dummy value */ + newv[i] = 0; + } + } + + /* now link target vertices to destination indices */ + for (i = 0; i < totvert; i++) { + if (vtargetmap[i] != -1) { + newv[i] = newv[vtargetmap[i]]; + } + } + + /* Don't remap vertices in cddm->mloop, because we need to know the original + * indices in order to skip faces with all vertices merged. + * The "update loop indices..." section further down remaps vertices in mloop. + */ + + /* now go through and fix edges and faces */ + med = mesh->medge; + c = 0; + for (i = 0; i < totedge; i++, med++) { + const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; + const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; + if (LIKELY(v1 != v2)) { + void **val_p; + + if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) { + newe[i] = POINTER_AS_INT(*val_p); + } + else { + STACK_PUSH(olde, i); + STACK_PUSH(medge, *med); + newe[i] = c; + *val_p = POINTER_FROM_INT(c); + c++; + } + } + else { + newe[i] = -1; + } + } + + if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) { + /* In this mode, we need to determine, whenever a poly' vertices are all mapped */ + /* if the targets already make up a poly, in which case the new poly is dropped */ + /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */ + PolyKey *mpgh; + poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__); + poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly); + /* Duplicates allowed because our compare function is not pure equality */ + BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES); + + mp = mesh->mpoly; + mpgh = poly_keys; + for (i = 0; i < totpoly; i++, mp++, mpgh++) { + mpgh->poly_index = i; + mpgh->totloops = mp->totloop; + ml = mesh->mloop + mp->loopstart; + mpgh->hash_sum = mpgh->hash_xor = 0; + for (j = 0; j < mp->totloop; j++, ml++) { + mpgh->hash_sum += ml->v; + mpgh->hash_xor ^= ml->v; + } + BLI_gset_insert(poly_gset, mpgh); + } + + /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */ + /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */ + BKE_mesh_vert_poly_map_create( + &poly_map, &poly_map_mem, + mesh->mpoly, mesh->mloop, + totvert, totpoly, totloop); + } /* done preparing for fast poly compare */ + + + mp = mesh->mpoly; + mv = mesh->mvert; + for (i = 0; i < totpoly; i++, mp++) { + MPoly *mp_new; + + ml = mesh->mloop + mp->loopstart; + + /* check faces with all vertices merged */ + bool all_vertices_merged = true; + + for (j = 0; j < mp->totloop; j++, ml++) { + if (vtargetmap[ml->v] == -1) { + all_vertices_merged = false; + /* This will be used to check for poly using several time the same vert. */ + mv[ml->v].flag &= ~ME_VERT_TMP_TAG; + } + else { + /* This will be used to check for poly using several time the same vert. */ + mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG; + } + } + + if (UNLIKELY(all_vertices_merged)) { + if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_MAPPED) { + /* In this mode, all vertices merged is enough to dump face */ + continue; + } + else if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) { + /* Additional condition for face dump: target vertices must make up an identical face */ + /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */ + /* (2) second step is thorough but more costly poly compare */ + int i_poly, v_target; + bool found = false; + PolyKey pkey; + + /* Use poly_gset for fast (although not 100% certain) identification of same poly */ + /* First, make up a poly_summary structure */ + ml = mesh->mloop + mp->loopstart; + pkey.hash_sum = pkey.hash_xor = 0; + pkey.totloops = 0; + for (j = 0; j < mp->totloop; j++, ml++) { + v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */ + pkey.hash_sum += v_target; + pkey.hash_xor ^= v_target; + pkey.totloops++; + } + if (BLI_gset_haskey(poly_gset, &pkey)) { + + /* There might be a poly that matches this one. + * We could just leave it there and say there is, and do a "continue". + * ... but we are checking whether there is an exact poly match. + * It's not so costly in terms of CPU since it's very rare, just a lot of complex code. + */ + + /* Consider current loop again */ + ml = mesh->mloop + mp->loopstart; + /* Consider the target of the loop's first vert */ + v_target = vtargetmap[ml->v]; + /* Now see if v_target belongs to a poly that shares all vertices with source poly, + * in same order, or reverse order */ + + for (i_poly = 0; i_poly < poly_map[v_target].count; i_poly++) { + MPoly *target_poly = mesh->mpoly + *(poly_map[v_target].indices + i_poly); + + if (cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, +1) || + cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, -1)) + { + found = true; + break; + } + } + if (found) { + /* Current poly's vertices are mapped to a poly that is strictly identical */ + /* Current poly is dumped */ + continue; + } + } + } + } + + + /* Here either the poly's vertices were not all merged + * or they were all merged, but targets do not make up an identical poly, + * the poly is retained. + */ + ml = mesh->mloop + mp->loopstart; + + c = 0; + MLoop *last_valid_ml = NULL; + MLoop *first_valid_ml = NULL; + bool need_edge_from_last_valid_ml = false; + bool need_edge_to_first_valid_ml = false; + int created_edges = 0; + for (j = 0; j < mp->totloop; j++, ml++) { + const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v; +#ifndef NDEBUG + { + MLoop *next_ml = mesh->mloop + mp->loopstart + ((j + 1) % mp->totloop); + uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v; + med = mesh->medge + ml->e; + uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; + uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; + BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1)); + } +#endif + /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */ + if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) { + mv[mlv].flag |= ME_VERT_TMP_TAG; + + if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) { + /* We need to create a new edge between last valid loop and this one! */ + void **val_p; + + uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v; + uint v2 = mlv; + BLI_assert(v1 != v2); + if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) { + last_valid_ml->e = POINTER_AS_INT(*val_p); + } + else { + const int new_eidx = STACK_SIZE(medge); + STACK_PUSH(olde, olde[last_valid_ml->e]); + STACK_PUSH(medge, mesh->medge[last_valid_ml->e]); + medge[new_eidx].v1 = last_valid_ml->v; + medge[new_eidx].v2 = ml->v; + /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */ + *val_p = POINTER_FROM_INT(new_eidx); + created_edges++; + + last_valid_ml->e = new_eidx; + } + need_edge_from_last_valid_ml = false; + } + +#ifdef USE_LOOPS + newl[j + mp->loopstart] = STACK_SIZE(mloop); +#endif + STACK_PUSH(oldl, j + mp->loopstart); + last_valid_ml = STACK_PUSH_RET_PTR(mloop); + *last_valid_ml = *ml; + if (first_valid_ml == NULL) { + first_valid_ml = last_valid_ml; + } + c++; + + /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges + * in that part of code make remapping later totally unreliable. */ + BLI_assert(newe[ml->e] != -1); + last_valid_ml->e = newe[ml->e]; + } + else { + if (last_valid_ml != NULL) { + need_edge_from_last_valid_ml = true; + } + else { + need_edge_to_first_valid_ml = true; + } + } + } + if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) && + (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml))) + { + /* We need to create a new edge between last valid loop and first valid one! */ + void **val_p; + + uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v; + uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v; + BLI_assert(v1 != v2); + if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) { + last_valid_ml->e = POINTER_AS_INT(*val_p); + } + else { + const int new_eidx = STACK_SIZE(medge); + STACK_PUSH(olde, olde[last_valid_ml->e]); + STACK_PUSH(medge, mesh->medge[last_valid_ml->e]); + medge[new_eidx].v1 = last_valid_ml->v; + medge[new_eidx].v2 = first_valid_ml->v; + /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */ + *val_p = POINTER_FROM_INT(new_eidx); + created_edges++; + + last_valid_ml->e = new_eidx; + } + need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false; + } + + if (UNLIKELY(c == 0)) { + BLI_assert(created_edges == 0); + continue; + } + else if (UNLIKELY(c < 3)) { + STACK_DISCARD(oldl, c); + STACK_DISCARD(mloop, c); + if (created_edges > 0) { + for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) { + BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL); + } + STACK_DISCARD(olde, created_edges); + STACK_DISCARD(medge, created_edges); + } + continue; + } + + mp_new = STACK_PUSH_RET_PTR(mpoly); + *mp_new = *mp; + mp_new->totloop = c; + BLI_assert(mp_new->totloop >= 3); + mp_new->loopstart = STACK_SIZE(mloop) - c; + + STACK_PUSH(oldp, i); + } /* end of the loop that tests polys */ + + + if (poly_gset) { + // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset)); + + BLI_gset_free(poly_gset, NULL); + MEM_freeN(poly_keys); + } + + /*create new cddm*/ + result = BKE_mesh_new_nomain_from_template( + mesh, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly)); + + /*update edge indices and copy customdata*/ + med = medge; + for (i = 0; i < result->totedge; i++, med++) { + BLI_assert(newv[med->v1] != -1); + med->v1 = newv[med->v1]; + BLI_assert(newv[med->v2] != -1); + med->v2 = newv[med->v2]; + + /* Can happen in case vtargetmap contains some double chains, we do not support that. */ + BLI_assert(med->v1 != med->v2); + + CustomData_copy_data(&mesh->edata, &result->edata, olde[i], i, 1); + } + + /*update loop indices and copy customdata*/ + ml = mloop; + for (i = 0; i < result->totloop; i++, ml++) { + /* Edge remapping has already be done in main loop handling part above. */ + BLI_assert(newv[ml->v] != -1); + ml->v = newv[ml->v]; + + CustomData_copy_data(&mesh->ldata, &result->ldata, oldl[i], i, 1); + } + + /*copy vertex customdata*/ + mv = mvert; + for (i = 0; i < result->totvert; i++, mv++) { + CustomData_copy_data(&mesh->vdata, &result->vdata, oldv[i], i, 1); + } + + /*copy poly customdata*/ + mp = mpoly; + for (i = 0; i < result->totpoly; i++, mp++) { + CustomData_copy_data(&mesh->pdata, &result->pdata, oldp[i], i, 1); + } + + /*copy over data. CustomData_add_layer can do this, need to look it up.*/ + memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert)); + memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge)); + memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop)); + memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly)); + + MEM_freeN(mvert); + MEM_freeN(medge); + MEM_freeN(mloop); + MEM_freeN(mpoly); + + MEM_freeN(newv); + MEM_freeN(newe); +#ifdef USE_LOOPS + MEM_freeN(newl); +#endif + + MEM_freeN(oldv); + MEM_freeN(olde); + MEM_freeN(oldl); + MEM_freeN(oldp); + + BLI_edgehash_free(ehash, NULL); + + if (poly_map != NULL) + MEM_freeN(poly_map); + if (poly_map_mem != NULL) + MEM_freeN(poly_map_mem); + + BKE_id_free(NULL, mesh); + + return result; +} diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 62c81bf8cba..bdf5b3fddcc 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -28,6 +28,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BLI_utildefines.h" @@ -41,10 +42,10 @@ #include "BKE_bvhutils.h" #include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" /* own include */ +#include "BKE_mesh_runtime.h" #include "BLI_strict_flags.h" @@ -121,8 +122,8 @@ static bool mesh_remap_bvhtree_query_raycast( * In other words, beyond a certain (relatively small) distance, all differences have more or less the same weight * in final result, which allows to reduce influence of a few high differences, in favor of a global good matching. */ -float BKE_mesh_remap_calc_difference_from_dm( - const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src) +float BKE_mesh_remap_calc_difference_from_mesh( + const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, Mesh *me_src) { BVHTreeFromMesh treedata = {NULL}; BVHTreeNearest nearest = {0}; @@ -131,7 +132,7 @@ float BKE_mesh_remap_calc_difference_from_dm( float result = 0.0f; int i; - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); nearest.index = -1; for (i = 0; i < numverts_dst; i++) { @@ -250,8 +251,8 @@ static void mesh_calc_eigen_matrix( /** * Set r_space_transform so that best bbox of dst matches best bbox of src. */ -void BKE_mesh_remap_find_best_match_from_dm( - const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src, SpaceTransform *r_space_transform) +void BKE_mesh_remap_find_best_match_from_mesh( + const MVert *verts_dst, const int numverts_dst, Mesh *me_src, SpaceTransform *r_space_transform) { /* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */ const float mirrors[][3] = { @@ -269,15 +270,14 @@ void BKE_mesh_remap_find_best_match_from_dm( float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4]; float best_match = FLT_MAX, match; - const int numverts_src = dm_src->getNumVerts(dm_src); - float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)numverts_src, __func__); - dm_src->getVertCos(dm_src, vcos_src); + const int numverts_src = me_src->totvert; + float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); mesh_calc_eigen_matrix(NULL, (const float (*)[3])vcos_src, numverts_src, mat_src); mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst); BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src); - match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src); + match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src); best_match = match; copy_m4_m4(best_mat_dst, mat_dst); @@ -288,7 +288,7 @@ void BKE_mesh_remap_find_best_match_from_dm( mul_v3_fl(mat_dst[2], (*mirr)[2]); BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src); - match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src); + match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src); if (match < best_match) { best_match = match; copy_m4_m4(best_mat_dst, mat_dst); @@ -430,9 +430,9 @@ typedef struct IslandResult { /* Will be enough in 99% of cases. */ #define MREMAP_DEFAULT_BUFSIZE 32 -void BKE_mesh_remap_calc_verts_from_dm( +void BKE_mesh_remap_calc_verts_from_mesh( const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, - const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src, + const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), Mesh *me_src, MeshPairRemap *r_map) { const float full_weight = 1.0f; @@ -444,7 +444,7 @@ void BKE_mesh_remap_calc_verts_from_dm( BKE_mesh_remap_init(r_map, numverts_dst); if (mode == MREMAP_MODE_TOPOLOGY) { - BLI_assert(numverts_dst == dm_src->getNumVerts(dm_src)); + BLI_assert(numverts_dst == me_src->totvert); for (i = 0; i < numverts_dst; i++) { mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); } @@ -457,7 +457,7 @@ void BKE_mesh_remap_calc_verts_from_dm( float tmp_co[3], tmp_no[3]; if (mode == MREMAP_MODE_VERT_NEAREST) { - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); nearest.index = -1; for (i = 0; i < numverts_dst; i++) { @@ -478,11 +478,10 @@ void BKE_mesh_remap_calc_verts_from_dm( } } else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) { - MEdge *edges_src = dm_src->getEdgeArray(dm_src); - float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); - dm_src->getVertCos(dm_src, vcos_src); + MEdge *edges_src = me_src->medge; + float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); nearest.index = -1; for (i = 0; i < numverts_dst; i++) { @@ -530,18 +529,16 @@ void BKE_mesh_remap_calc_verts_from_dm( else if (ELEM(mode, MREMAP_MODE_VERT_POLY_NEAREST, MREMAP_MODE_VERT_POLYINTERP_NEAREST, MREMAP_MODE_VERT_POLYINTERP_VNORPROJ)) { - MPoly *polys_src = dm_src->getPolyArray(dm_src); - MLoop *loops_src = dm_src->getLoopArray(dm_src); - float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); + MPoly *polys_src = me_src->mpoly; + MLoop *loops_src = me_src->mloop; + float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE; float (*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__); int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__); float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__); - dm_src->getVertCos(dm_src, vcos_src); - - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) { for (i = 0; i < numverts_dst; i++) { @@ -625,10 +622,10 @@ void BKE_mesh_remap_calc_verts_from_dm( } } -void BKE_mesh_remap_calc_edges_from_dm( +void BKE_mesh_remap_calc_edges_from_mesh( const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, const MVert *verts_dst, const int numverts_dst, const MEdge *edges_dst, const int numedges_dst, - const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src, MeshPairRemap *r_map) + const bool UNUSED(dirty_nors_dst), Mesh *me_src, MeshPairRemap *r_map) { const float full_weight = 1.0f; const float max_dist_sq = max_dist * max_dist; @@ -639,7 +636,7 @@ void BKE_mesh_remap_calc_edges_from_dm( BKE_mesh_remap_init(r_map, numedges_dst); if (mode == MREMAP_MODE_TOPOLOGY) { - BLI_assert(numedges_dst == dm_src->getNumEdges(dm_src)); + BLI_assert(numedges_dst == me_src->totedge); for (i = 0; i < numedges_dst; i++) { mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); } @@ -652,10 +649,10 @@ void BKE_mesh_remap_calc_edges_from_dm( float tmp_co[3], tmp_no[3]; if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) { - const int num_verts_src = dm_src->getNumVerts(dm_src); - const int num_edges_src = dm_src->getNumEdges(dm_src); - MEdge *edges_src = dm_src->getEdgeArray(dm_src); - float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); + const int num_verts_src = me_src->totvert; + const int num_edges_src = me_src->totedge; + MEdge *edges_src = me_src->medge; + float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); MeshElemMap *vert_to_edge_src_map; int *vert_to_edge_src_map_mem; @@ -673,9 +670,7 @@ void BKE_mesh_remap_calc_edges_from_dm( &vert_to_edge_src_map, &vert_to_edge_src_map_mem, edges_src, num_verts_src, num_edges_src); - dm_src->getVertCos(dm_src, vcos_src); - - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); nearest.index = -1; for (i = 0; i < numedges_dst; i++) { @@ -775,7 +770,7 @@ void BKE_mesh_remap_calc_edges_from_dm( MEM_freeN(vert_to_edge_src_map_mem); } else if (mode == MREMAP_MODE_EDGE_NEAREST) { - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); nearest.index = -1; for (i = 0; i < numedges_dst; i++) { @@ -796,13 +791,12 @@ void BKE_mesh_remap_calc_edges_from_dm( } } else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) { - MEdge *edges_src = dm_src->getEdgeArray(dm_src); - MPoly *polys_src = dm_src->getPolyArray(dm_src); - MLoop *loops_src = dm_src->getLoopArray(dm_src); - float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__); + MEdge *edges_src = me_src->medge; + MPoly *polys_src = me_src->mpoly; + MLoop *loops_src = me_src->mloop; + float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL); - dm_src->getVertCos(dm_src, vcos_src); - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); for (i = 0; i < numedges_dst; i++) { interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f); @@ -821,9 +815,9 @@ void BKE_mesh_remap_calc_edges_from_dm( int best_eidx_src = -1; for (; nloops--; ml_src++) { - MEdge *me_src = &edges_src[ml_src->e]; - float *co1_src = vcos_src[me_src->v1]; - float *co2_src = vcos_src[me_src->v2]; + MEdge *med_src = &edges_src[ml_src->e]; + float *co1_src = vcos_src[med_src->v1]; + float *co2_src = vcos_src[med_src->v2]; float co_src[3]; float dist_sq; @@ -848,14 +842,14 @@ void BKE_mesh_remap_calc_edges_from_dm( } else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) { const int num_rays_min = 5, num_rays_max = 100; - const int numedges_src = dm_src->getNumEdges(dm_src); + const int numedges_src = me_src->totedge; /* Subtleness - this one we can allocate only max number of cast rays per edges! */ int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), __func__); /* Here it's simpler to just allocate for all edges :/ */ float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__); - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); for (i = 0; i < numedges_dst; i++) { /* For each dst edge, we sample some rays from it (interpolated from its vertices) @@ -1108,13 +1102,13 @@ static float mesh_remap_calc_loops_astar_f_cost( #define ASTAR_STEPS_MAX 64 -void BKE_mesh_remap_calc_loops_from_dm( +void BKE_mesh_remap_calc_loops_from_mesh( const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst, MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst, CustomData *ldata_dst, CustomData *pdata_dst, const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst, - DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src, + Mesh *me_src, MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map) { const float full_weight = 1.0f; @@ -1129,7 +1123,7 @@ void BKE_mesh_remap_calc_loops_from_dm( if (mode == MREMAP_MODE_TOPOLOGY) { /* In topology mapping, we assume meshes are identical, islands included! */ - BLI_assert(numloops_dst == dm_src->getNumLoops(dm_src)); + BLI_assert(numloops_dst == me_src->totloop); for (i = 0; i < numloops_dst; i++) { mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); } @@ -1172,19 +1166,15 @@ void BKE_mesh_remap_calc_loops_from_dm( /* Unlike above, those are one-to-one mappings, simpler! */ int *loop_to_poly_map_src = NULL; - bool verts_allocated_src; - MVert *verts_src = DM_get_vert_array(dm_src, &verts_allocated_src); - const int num_verts_src = dm_src->getNumVerts(dm_src); + MVert *verts_src = me_src->mvert; + const int num_verts_src = me_src->totvert; float (*vcos_src)[3] = NULL; - bool edges_allocated_src; - MEdge *edges_src = DM_get_edge_array(dm_src, &edges_allocated_src); - const int num_edges_src = dm_src->getNumEdges(dm_src); - bool loops_allocated_src; - MLoop *loops_src = DM_get_loop_array(dm_src, &loops_allocated_src); - const int num_loops_src = dm_src->getNumLoops(dm_src); - bool polys_allocated_src; - MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src); - const int num_polys_src = dm_src->getNumPolys(dm_src); + MEdge *edges_src = me_src->medge; + const int num_edges_src = me_src->totedge; + MLoop *loops_src = me_src->mloop; + const int num_loops_src = me_src->totloop; + MPoly *polys_src = me_src->mpoly; + const int num_polys_src = me_src->totpoly; const MLoopTri *looptri_src = NULL; int num_looptri_src = 0; @@ -1201,8 +1191,7 @@ void BKE_mesh_remap_calc_loops_from_dm( size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE; if (!use_from_vert) { - vcos_src = MEM_mallocN(sizeof(*vcos_src) * (size_t)num_verts_src, __func__); - dm_src->getVertCos(dm_src, vcos_src); + vcos_src = BKE_mesh_vertexCos_get(me_src, NULL); vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__); indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__); @@ -1218,11 +1207,12 @@ void BKE_mesh_remap_calc_loops_from_dm( if (need_pnors_dst) { /* Cache poly nors into a temp CDLayer. */ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL); + const bool do_poly_nors_dst = (poly_nors_dst == NULL); if (!poly_nors_dst) { poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst); CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } - if (dirty_nors_dst) { + if (dirty_nors_dst || do_poly_nors_dst) { BKE_mesh_calc_normals_poly( verts_dst, NULL, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst, poly_nors_dst, true); @@ -1233,11 +1223,12 @@ void BKE_mesh_remap_calc_loops_from_dm( /* Cache poly nors into a temp CDLayer. */ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); - if (dirty_nors_dst || !loop_nors_dst) { - if (!loop_nors_dst) { - loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); - CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); - } + const bool do_loop_nors_dst = (loop_nors_dst == NULL); + if (!loop_nors_dst) { + loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); + CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); + } + if (dirty_nors_dst || do_loop_nors_dst) { BKE_mesh_normals_loop_split( verts_dst, numverts_dst, edges_dst, numedges_dst, loops_dst, loop_nors_dst, numloops_dst, @@ -1247,13 +1238,17 @@ void BKE_mesh_remap_calc_loops_from_dm( } if (need_pnors_src || need_lnors_src) { /* Simpler for now, calcNormals never stores pnors :( */ - dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src); + if (!CustomData_has_layer(&me_src->pdata, CD_NORMAL)) { + CustomData_add_layer(&me_src->pdata, CD_NORMAL, CD_CALLOC, NULL, me_src->totpoly); + CustomData_set_layer_flag(&me_src->pdata, CD_NORMAL, CD_FLAG_TEMPORARY); + } + BKE_mesh_calc_normals_split(me_src); if (need_pnors_src) { - poly_nors_src = dm_src->getPolyDataArray(dm_src, CD_NORMAL); + poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL); } if (need_lnors_src) { - loop_nors_src = dm_src->getLoopDataArray(dm_src, CD_NORMAL); + loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL); } } } @@ -1352,38 +1347,25 @@ void BKE_mesh_remap_calc_loops_from_dm( } } } - /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */ bvhtree_from_mesh_verts_ex( - &treedata[tindex], verts_src, num_verts_src, verts_allocated_src, + &treedata[tindex], verts_src, num_verts_src, false, verts_active, num_verts_active, 0.0, 2, 6); - if (verts_allocated_src) { - verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */ - } } MEM_freeN(verts_active); } else { BLI_assert(num_trees == 1); - bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_VERTS, 2); + BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2); } } else { /* We use polygons. */ if (use_islands) { /* bvhtree here uses looptri faces... */ - const unsigned int dirty_tess_flag = dm_src->dirty & DM_DIRTY_TESS_CDLAYERS; BLI_bitmap *looptri_active; - /* We do not care about tessellated data here, only geometry itself is important. */ - if (dirty_tess_flag) { - dm_src->dirty &= ~dirty_tess_flag; - } - if (dirty_tess_flag) { - dm_src->dirty |= dirty_tess_flag; - } - - looptri_src = dm_src->getLoopTriArray(dm_src); - num_looptri_src = dm_src->getNumLoopTri(dm_src); + looptri_src = BKE_mesh_runtime_looptri_ensure(me_src); + num_looptri_src = me_src->runtime.looptris.len; looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__); for (tindex = 0; tindex < num_trees; tindex++) { @@ -1396,26 +1378,19 @@ void BKE_mesh_remap_calc_loops_from_dm( num_looptri_active++; } } - /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */ bvhtree_from_mesh_looptri_ex( &treedata[tindex], - verts_src, verts_allocated_src, - loops_src, loops_allocated_src, + verts_src, false, + loops_src, false, looptri_src, num_looptri_src, false, looptri_active, num_looptri_active, 0.0, 2, 6); - if (verts_allocated_src) { - verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */ - } - if (loops_allocated_src) { - loops_allocated_src = false; /* Only 'give' our loops once, to first tree! */ - } } MEM_freeN(looptri_active); } else { BLI_assert(num_trees == 1); - bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_LOOPTRI, 2); + BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2); } } @@ -1918,21 +1893,9 @@ void BKE_mesh_remap_calc_loops_from_dm( BLI_astar_solution_free(&as_solution); } - if (verts_allocated_src) { - MEM_freeN(verts_src); - } if (vcos_src) { MEM_freeN(vcos_src); } - if (edges_allocated_src) { - MEM_freeN(edges_src); - } - if (loops_allocated_src) { - MEM_freeN(loops_src); - } - if (polys_allocated_src) { - MEM_freeN(polys_src); - } if (vert_to_loop_map_src) { MEM_freeN(vert_to_loop_map_src); } @@ -1975,11 +1938,11 @@ void BKE_mesh_remap_calc_loops_from_dm( } } -void BKE_mesh_remap_calc_polys_from_dm( +void BKE_mesh_remap_calc_polys_from_mesh( const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius, MVert *verts_dst, const int numverts_dst, MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst, CustomData *pdata_dst, const bool dirty_nors_dst, - DerivedMesh *dm_src, MeshPairRemap *r_map) + Mesh *me_src, MeshPairRemap *r_map) { const float full_weight = 1.0f; const float max_dist_sq = max_dist * max_dist; @@ -2006,7 +1969,7 @@ void BKE_mesh_remap_calc_polys_from_dm( BKE_mesh_remap_init(r_map, numpolys_dst); if (mode == MREMAP_MODE_TOPOLOGY) { - BLI_assert(numpolys_dst == dm_src->getNumPolys(dm_src)); + BLI_assert(numpolys_dst == me_src->totpoly); for (i = 0; i < numpolys_dst; i++) { mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight); } @@ -2017,7 +1980,7 @@ void BKE_mesh_remap_calc_polys_from_dm( BVHTreeRayHit rayhit = {0}; float hit_dist; - bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2); + BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2); if (mode == MREMAP_MODE_POLY_NEAREST) { nearest.index = -1; @@ -2082,7 +2045,7 @@ void BKE_mesh_remap_calc_polys_from_dm( */ RNG *rng = BLI_rng_new(0); - const size_t numpolys_src = (size_t)dm_src->getNumPolys(dm_src); + const size_t numpolys_src = (size_t)me_src->totpoly; /* Here it's simpler to just allocate for all polys :/ */ int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__); diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c new file mode 100644 index 00000000000..0931318f17a --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -0,0 +1,380 @@ +/* + * ***** 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) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_runtime.c + * \ingroup bke + */ + +#include "atomic_ops.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BLI_math_geom.h" +#include "BLI_threads.h" + +#include "BKE_bvhutils.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_subdiv_ccg.h" +#include "BKE_shrinkwrap.h" + +/* -------------------------------------------------------------------- */ +/** \name Mesh Runtime Struct Utils + * \{ */ + +static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER; + +/** + * Default values defined at read time. + */ +void BKE_mesh_runtime_reset(Mesh *mesh) +{ + memset(&mesh->runtime, 0, sizeof(mesh->runtime)); +} + +void BKE_mesh_runtime_clear_cache(Mesh *mesh) +{ + BKE_mesh_runtime_clear_geometry(mesh); + BKE_mesh_batch_cache_free(mesh); + BKE_mesh_runtime_clear_edit_data(mesh); +} + +/* This is a ported copy of DM_ensure_looptri_data(dm) */ +/** + * Ensure the array is large enough + * + * /note This function must always be thread-protected by caller. It should only be used by internal code. + */ +static void mesh_ensure_looptri_data(Mesh *mesh) +{ + const unsigned int totpoly = mesh->totpoly; + const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop); + + BLI_assert(mesh->runtime.looptris.array_wip == NULL); + + SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip); + + if ((looptris_len > mesh->runtime.looptris.len_alloc) || + (looptris_len < mesh->runtime.looptris.len_alloc * 2) || + (totpoly == 0)) + { + MEM_SAFE_FREE(mesh->runtime.looptris.array_wip); + mesh->runtime.looptris.len_alloc = 0; + mesh->runtime.looptris.len = 0; + } + + if (totpoly) { + if (mesh->runtime.looptris.array_wip == NULL) { + mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__); + mesh->runtime.looptris.len_alloc = looptris_len; + } + + mesh->runtime.looptris.len = looptris_len; + } +} + +/* This is a ported copy of CDDM_recalc_looptri(dm). */ +void BKE_mesh_runtime_looptri_recalc(Mesh *mesh) +{ + mesh_ensure_looptri_data(mesh); + BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL); + + BKE_mesh_recalc_looptri( + mesh->mloop, mesh->mpoly, + mesh->mvert, + mesh->totloop, mesh->totpoly, + mesh->runtime.looptris.array_wip); + + BLI_assert(mesh->runtime.looptris.array == NULL); + atomic_cas_ptr((void **)&mesh->runtime.looptris.array, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip); + mesh->runtime.looptris.array_wip = NULL; +} + +/* This is a ported copy of dm_getNumLoopTri(dm). */ +int BKE_mesh_runtime_looptri_len(const Mesh *mesh) +{ + const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop); + BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len)); + return looptri_len; +} + +/* This is a ported copy of dm_getLoopTriArray(dm). */ +const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh) +{ + MLoopTri *looptri; + + BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ); + looptri = mesh->runtime.looptris.array; + BLI_rw_mutex_unlock(&loops_cache_lock); + + if (looptri != NULL) { + BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len); + } + else { + BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE); + /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already + * recomputed those looptris. */ + if (mesh->runtime.looptris.array == NULL) { + BKE_mesh_runtime_looptri_recalc(mesh); + } + looptri = mesh->runtime.looptris.array; + BLI_rw_mutex_unlock(&loops_cache_lock); + } + return looptri; +} + +/* This is a copy of DM_verttri_from_looptri(). */ +void BKE_mesh_runtime_verttri_from_looptri( + MVertTri *r_verttri, const MLoop *mloop, + const MLoopTri *looptri, int looptri_num) +{ + int i; + for (i = 0; i < looptri_num; i++) { + r_verttri[i].tri[0] = mloop[looptri[i].tri[0]].v; + r_verttri[i].tri[1] = mloop[looptri[i].tri[1]].v; + r_verttri[i].tri[2] = mloop[looptri[i].tri[2]].v; + } +} + + +bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh) +{ + if (mesh->runtime.edit_data != NULL) { + return false; + } + + mesh->runtime.edit_data = MEM_callocN(sizeof(EditMeshData), "EditMeshData"); + return true; +} + +bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh) +{ + if (mesh->runtime.edit_data == NULL) { + return false; + } + + if (mesh->runtime.edit_data->polyCos != NULL) + MEM_freeN((void *)mesh->runtime.edit_data->polyCos); + if (mesh->runtime.edit_data->polyNos != NULL) + MEM_freeN((void *)mesh->runtime.edit_data->polyNos); + if (mesh->runtime.edit_data->vertexCos != NULL) + MEM_freeN((void *)mesh->runtime.edit_data->vertexCos); + if (mesh->runtime.edit_data->vertexNos != NULL) + MEM_freeN((void *)mesh->runtime.edit_data->vertexNos); + + MEM_SAFE_FREE(mesh->runtime.edit_data); + return true; +} + +void BKE_mesh_runtime_clear_geometry(Mesh *mesh) +{ + bvhcache_free(&mesh->runtime.bvh_cache); + MEM_SAFE_FREE(mesh->runtime.looptris.array); + /* TODO(sergey): Does this really belong here? */ + if (mesh->runtime.subdiv_ccg != NULL) { + BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg); + mesh->runtime.subdiv_ccg = NULL; + } + BKE_shrinkwrap_discard_boundary_data(mesh); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Batch Cache Callbacks + * \{ */ + +/* Draw Engine */ +void (*BKE_mesh_batch_cache_dirty_tag_cb)(Mesh *me, int mode) = NULL; +void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL; + +void BKE_mesh_batch_cache_dirty_tag(Mesh *me, int mode) +{ + if (me->runtime.batch_cache) { + BKE_mesh_batch_cache_dirty_tag_cb(me, mode); + } +} +void BKE_mesh_batch_cache_free(Mesh *me) +{ + if (me->runtime.batch_cache) { + BKE_mesh_batch_cache_free_cb(me); + } +} + +/** \} */ + +/** \name Mesh runtime debug helpers. + * \{ */ +/* evaluated mesh info printing function, + * to help track down differences output */ + +#ifndef NDEBUG +#include "BLI_dynstr.h" + +static void mesh_runtime_debug_info_layers( + DynStr *dynstr, CustomData *cd) +{ + int type; + + for (type = 0; type < CD_NUMTYPES; type++) { + if (CustomData_has_layer(cd, type)) { + /* note: doesn't account for multiple layers */ + const char *name = CustomData_layertype_name(type); + const int size = CustomData_sizeof(type); + const void *pt = CustomData_get_layer(cd, type); + const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0; + const char *structname; + int structnum; + CustomData_file_write_info(type, &structname, &structnum); + BLI_dynstr_appendf( + dynstr, + " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", + name, structname, type, (const void *)pt, size, pt_size); + } + } +} + +char *BKE_mesh_runtime_debug_info(Mesh *me_eval) +{ + DynStr *dynstr = BLI_dynstr_new(); + char *ret; + + BLI_dynstr_appendf(dynstr, "{\n"); + BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval); +#if 0 + const char *tstr; + switch (me_eval->type) { + case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break; + case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break; + default: tstr = "UNKNOWN"; break; + } + BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr); +#endif + BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert); + BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge); + BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface); + BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly); + BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only); + + BLI_dynstr_appendf(dynstr, " 'vertexLayers': (\n"); + mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata); + BLI_dynstr_appendf(dynstr, " ),\n"); + + BLI_dynstr_appendf(dynstr, " 'edgeLayers': (\n"); + mesh_runtime_debug_info_layers(dynstr, &me_eval->edata); + BLI_dynstr_appendf(dynstr, " ),\n"); + + BLI_dynstr_appendf(dynstr, " 'loopLayers': (\n"); + mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata); + BLI_dynstr_appendf(dynstr, " ),\n"); + + BLI_dynstr_appendf(dynstr, " 'polyLayers': (\n"); + mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata); + BLI_dynstr_appendf(dynstr, " ),\n"); + + BLI_dynstr_appendf(dynstr, " 'tessFaceLayers': (\n"); + mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata); + BLI_dynstr_appendf(dynstr, " ),\n"); + + BLI_dynstr_appendf(dynstr, "}\n"); + + ret = BLI_dynstr_get_cstring(dynstr); + BLI_dynstr_free(dynstr); + return ret; +} + +void BKE_mesh_runtime_debug_print(Mesh *me_eval) +{ + char *str = BKE_mesh_runtime_debug_info(me_eval); + puts(str); + fflush(stdout); + MEM_freeN(str); +} + +/* XXX Should go in customdata file? */ +void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data) +{ + int i; + const CustomDataLayer *layer; + + printf("{\n"); + + for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) { + + const char *name = CustomData_layertype_name(layer->type); + const int size = CustomData_sizeof(layer->type); + const char *structname; + int structnum; + CustomData_file_write_info(layer->type, &structname, &structnum); + printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", + name, structname, layer->type, (const void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size)); + } + + printf("}\n"); +} + +bool BKE_mesh_runtime_is_valid(Mesh *me_eval) +{ + const bool do_verbose = true; + const bool do_fixes = false; + + bool is_valid = true; + bool changed = true; + + if (do_verbose) { + printf("MESH: %s\n", me_eval->id.name + 2); + } + + is_valid &= BKE_mesh_validate_all_customdata( + &me_eval->vdata, &me_eval->edata, &me_eval->ldata, &me_eval->pdata, + false, /* setting mask here isn't useful, gives false positives */ + do_verbose, do_fixes, + &changed); + + is_valid &= BKE_mesh_validate_arrays( + me_eval, + me_eval->mvert, me_eval->totvert, + me_eval->medge, me_eval->totedge, + me_eval->mface, me_eval->totface, + me_eval->mloop, me_eval->totloop, + me_eval->mpoly, me_eval->totpoly, + me_eval->dvert, + do_verbose, do_fixes, + &changed); + + BLI_assert(changed == false); + + return is_valid; +} + +#endif /* NDEBUG */ + +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c new file mode 100644 index 00000000000..b8d260e6922 --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -0,0 +1,716 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_tangent.c + * \ingroup bke + * + * Functions to evaluate mesh tangents. + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_stack.h" +#include "BLI_task.h" + +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_mesh_tangent.h" +#include "BKE_report.h" + +#include "BLI_strict_flags.h" + +#include "atomic_ops.h" +#include "mikktspace.h" + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Tangent Calculations (Single Layer) + * \{ */ + +/* Tangent space utils. */ + +/* User data. */ +typedef struct { + const MPoly *mpolys; /* faces */ + const MLoop *mloops; /* faces's vertices */ + const MVert *mverts; /* vertices */ + const MLoopUV *luvs; /* texture coordinates */ + float (*lnors)[3]; /* loops' normals */ + float (*tangents)[4]; /* output tangents */ + int num_polys; /* number of polygons */ +} BKEMeshToTangent; + +/* Mikktspace's API */ +static int get_num_faces(const SMikkTSpaceContext *pContext) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + return p_mesh->num_polys; +} + +static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + return p_mesh->mpolys[face_idx].totloop; +} + +static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx; + copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co); +} + +static void get_texture_coordinate( + const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx, + const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv); +} + +static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]); +} + +static void set_tspace( + const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign, + const int face_idx, const int vert_idx) +{ + BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData; + float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx]; + copy_v3_v3(p_res, fv_tangent); + p_res[3] = face_sign; +} + +/** + * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with + * split normals can be used to recreate the full tangent space. + * Note: * The mesh should be made of only tris and quads! + */ +void BKE_mesh_calc_loop_tangent_single_ex( + const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops, + float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs, + const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys, + ReportList *reports) +{ + BKEMeshToTangent mesh_to_tangent = {NULL}; + SMikkTSpaceContext s_context = {NULL}; + SMikkTSpaceInterface s_interface = {NULL}; + + const MPoly *mp; + int mp_index; + + /* First check we do have a tris/quads only mesh. */ + for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { + if (mp->totloop > 4) { + BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting"); + return; + } + } + + /* Compute Mikktspace's tangent normals. */ + mesh_to_tangent.mpolys = mpolys; + mesh_to_tangent.mloops = mloops; + mesh_to_tangent.mverts = mverts; + mesh_to_tangent.luvs = loopuvs; + mesh_to_tangent.lnors = loopnors; + mesh_to_tangent.tangents = r_looptangent; + mesh_to_tangent.num_polys = numPolys; + + s_context.m_pUserData = &mesh_to_tangent; + s_context.m_pInterface = &s_interface; + s_interface.m_getNumFaces = get_num_faces; + s_interface.m_getNumVerticesOfFace = get_num_verts_of_face; + s_interface.m_getPosition = get_position; + s_interface.m_getTexCoord = get_texture_coordinate; + s_interface.m_getNormal = get_normal; + s_interface.m_setTSpaceBasic = set_tspace; + + /* 0 if failed */ + if (genTangSpaceDefault(&s_context) == false) { + BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!"); + } +} + +/** + * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code. + * \note + * - There must be a valid loop's CD_NORMALS available. + * - The mesh should be made of only tris and quads! + */ +void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports) +{ + MLoopUV *loopuvs; + float (*loopnors)[3]; + + /* Check we have valid texture coordinates first! */ + if (uvmap) { + loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap); + } + else { + loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV); + } + if (!loopuvs) { + BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap); + return; + } + + loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + if (!loopnors) { + BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting"); + return; + } + + BKE_mesh_calc_loop_tangent_single_ex( + mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents, + loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Tangent Calculations (All Layers) + * \{ */ + + +/* Necessary complexity to handle looptri's as quads for correct tangents */ +#define USE_LOOPTRI_DETECT_QUADS + +typedef struct { + const float (*precomputedFaceNormals)[3]; + const float (*precomputedLoopNormals)[3]; + const MLoopTri *looptri; + MLoopUV *mloopuv; /* texture coordinates */ + const MPoly *mpoly; /* indices */ + const MLoop *mloop; /* indices */ + const MVert *mvert; /* vertices & normals */ + const float (*orco)[3]; + float (*tangent)[4]; /* destination */ + int numTessFaces; + +#ifdef USE_LOOPTRI_DETECT_QUADS + /* map from 'fake' face index to looptri, + * quads will point to the first looptri of the quad */ + const int *face_as_quad_map; + int num_face_as_quad_map; +#endif + +} SGLSLMeshToTangent; + +/* interface */ +static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext) +{ + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + +#ifdef USE_LOOPTRI_DETECT_QUADS + return pMesh->num_face_as_quad_map; +#else + return pMesh->numTessFaces; +#endif +} + +static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num) +{ +#ifdef USE_LOOPTRI_DETECT_QUADS + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + if (pMesh->face_as_quad_map) { + const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + return 4; + } + } + return 3; +#else + UNUSED_VARS(pContext, face_num); + return 3; +#endif +} + +static void dm_ts_GetPosition( + const SMikkTSpaceContext *pContext, float r_co[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + const float *co; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + +finally: + co = pMesh->mvert[pMesh->mloop[loop_index].v].co; + copy_v3_v3(r_co, co); +} + +static void dm_ts_GetTextureCoordinate( + const SMikkTSpaceContext *pContext, float r_uv[2], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + +finally: + if (pMesh->mloopuv != NULL) { + const float *uv = pMesh->mloopuv[loop_index].uv; + copy_v2_v2(r_uv, uv); + } + else { + const float *orco = pMesh->orco[pMesh->mloop[loop_index].v]; + map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]); + } +} + +static void dm_ts_GetNormal( + const SMikkTSpaceContext *pContext, float r_no[3], + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + +finally: + if (pMesh->precomputedLoopNormals) { + copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]); + } + else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */ + if (pMesh->precomputedFaceNormals) { + copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]); + } + else { +#ifdef USE_LOOPTRI_DETECT_QUADS + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + normal_quad_v3( + r_no, + pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co, + pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co, + pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co, + pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co); + } + else +#endif + { + normal_tri_v3( + r_no, + pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co, + pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co, + pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co); + } + } + } + else { + const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no; + normal_short_to_float_v3(r_no, no); + } +} + +static void dm_ts_SetTSpace( + const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, + const int face_num, const int vert_index) +{ + //assert(vert_index >= 0 && vert_index < 4); + SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData; + const MLoopTri *lt; + uint loop_index; + +#ifdef USE_LOOPTRI_DETECT_QUADS + if (pMesh->face_as_quad_map) { + lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]]; + const MPoly *mp = &pMesh->mpoly[lt->poly]; + if (mp->totloop == 4) { + loop_index = (uint)(mp->loopstart + vert_index); + goto finally; + } + /* fall through to regular triangle */ + } + else { + lt = &pMesh->looptri[face_num]; + } +#else + lt = &pMesh->looptri[face_num]; +#endif + loop_index = lt->tri[vert_index]; + + float *pRes; + +finally: + pRes = pMesh->tangent[loop_index]; + copy_v3_v3(pRes, fvTangent); + pRes[3] = fSign; +} + +static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +{ + struct SGLSLMeshToTangent *mesh2tangent = taskdata; + /* new computation method */ + { + SMikkTSpaceContext sContext = {NULL}; + SMikkTSpaceInterface sInterface = {NULL}; + + sContext.m_pUserData = mesh2tangent; + sContext.m_pInterface = &sInterface; + sInterface.m_getNumFaces = dm_ts_GetNumFaces; + sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace; + sInterface.m_getPosition = dm_ts_GetPosition; + sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate; + sInterface.m_getNormal = dm_ts_GetNormal; + sInterface.m_setTSpaceBasic = dm_ts_SetTSpace; + + /* 0 if failed */ + genTangSpaceDefault(&sContext); + } +} + +void BKE_mesh_add_loop_tangent_named_layer_for_uv( + CustomData *uv_data, CustomData *tan_data, int numLoopData, + const char *layer_name) +{ + if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && + CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) + { + CustomData_add_layer_named( + tan_data, CD_TANGENT, CD_CALLOC, NULL, + numLoopData, layer_name); + } +} + +/** + * Here we get some useful information such as active uv layer name and search if it is already in tangent_names. + * Also, we calculate tangent_mask that works as a descriptor of tangents state. + * If tangent_mask has changed, then recalculate tangents. + */ +void BKE_mesh_calc_loop_tangent_step_0( + const CustomData *loopData, bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_count, + bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n, + char *ract_uv_name, char *rren_uv_name, short *rtangent_mask) +{ + /* Active uv in viewport */ + int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV); + *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV); + ract_uv_name[0] = 0; + if (*ract_uv_n != -1) { + strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name); + } + + /* Active tangent in render */ + *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV); + rren_uv_name[0] = 0; + if (*rren_uv_n != -1) { + strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name); + } + + /* If active tangent not in tangent_names we take it into account */ + *rcalc_act = false; + *rcalc_ren = false; + for (int i = 0; i < tangent_names_count; i++) { + if (tangent_names[i][0] == 0) { + calc_active_tangent = true; + } + } + if (calc_active_tangent) { + *rcalc_act = true; + *rcalc_ren = true; + for (int i = 0; i < tangent_names_count; i++) { + if (STREQ(ract_uv_name, tangent_names[i])) + *rcalc_act = false; + if (STREQ(rren_uv_name, tangent_names[i])) + *rcalc_ren = false; + } + } + *rtangent_mask = 0; + + const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV); + for (int n = 0; n < uv_layer_num; n++) { + const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n); + bool add = false; + for (int i = 0; i < tangent_names_count; i++) { + if (tangent_names[i][0] && STREQ(tangent_names[i], name)) { + add = true; + break; + } + } + if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) || + (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))) + { + add = true; + } + if (add) + *rtangent_mask |= (short)(1 << n); + } + + if (uv_layer_num == 0) + *rtangent_mask |= DM_TANGENT_MASK_ORCO; +} + +/** + * See: #BKE_editmesh_loop_tangent_calc (matching logic). + */ +void BKE_mesh_calc_loop_tangent_ex( + const MVert *mvert, + const MPoly *mpoly, const uint mpoly_len, + const MLoop *mloop, + const MLoopTri *looptri, + const uint looptri_len, + + CustomData *loopdata, + bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_len, + const float (*poly_normals)[3], + const float (*loop_normals)[3], + const float (*vert_orco)[3], + /* result */ + CustomData *loopdata_out, + const uint loopdata_out_len, + short *tangent_mask_curr_p) +{ + int act_uv_n = -1; + int ren_uv_n = -1; + bool calc_act = false; + bool calc_ren = false; + char act_uv_name[MAX_NAME]; + char ren_uv_name[MAX_NAME]; + short tangent_mask = 0; + short tangent_mask_curr = *tangent_mask_curr_p; + + BKE_mesh_calc_loop_tangent_step_0( + loopdata, calc_active_tangent, tangent_names, tangent_names_len, + &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask); + if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) { + /* Check we have all the needed layers */ + /* Allocate needed tangent layers */ + for (int i = 0; i < tangent_names_len; i++) + if (tangent_names[i][0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]); + if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1) + CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + if (calc_act && act_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name); + if (calc_ren && ren_uv_name[0]) + BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name); + +#ifdef USE_LOOPTRI_DETECT_QUADS + int num_face_as_quad_map; + int *face_as_quad_map = NULL; + + /* map faces to quads */ + if (looptri_len != mpoly_len) { + /* over alloc, since we dont know how many ngon or quads we have */ + + /* map fake face index to looptri */ + face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__); + int k, j; + for (k = 0, j = 0; j < (int)looptri_len; k++, j++) { + face_as_quad_map[k] = j; + /* step over all quads */ + if (mpoly[looptri[j].poly].totloop == 4) { + j++; /* skips the nest looptri */ + } + } + num_face_as_quad_map = k; + } + else { + num_face_as_quad_map = (int)looptri_len; + } +#endif + + /* Calculation */ + if (looptri_len != 0) { + TaskScheduler *scheduler = BLI_task_scheduler_get(); + TaskPool *task_pool; + task_pool = BLI_task_pool_create(scheduler, NULL); + + tangent_mask_curr = 0; + /* Calculate tangent layers */ + SGLSLMeshToTangent data_array[MAX_MTFACE]; + const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT); + for (int n = 0; n < tangent_layer_num; n++) { + int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n); + BLI_assert(n < MAX_MTFACE); + SGLSLMeshToTangent *mesh2tangent = &data_array[n]; + mesh2tangent->numTessFaces = (int)looptri_len; +#ifdef USE_LOOPTRI_DETECT_QUADS + mesh2tangent->face_as_quad_map = face_as_quad_map; + mesh2tangent->num_face_as_quad_map = num_face_as_quad_map; +#endif + mesh2tangent->mvert = mvert; + mesh2tangent->mpoly = mpoly; + mesh2tangent->mloop = mloop; + mesh2tangent->looptri = looptri; + /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled), + * have to check this is valid... + */ + mesh2tangent->precomputedLoopNormals = loop_normals; + mesh2tangent->precomputedFaceNormals = poly_normals; + + mesh2tangent->orco = NULL; + mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name); + + /* Fill the resulting tangent_mask */ + if (!mesh2tangent->mloopuv) { + mesh2tangent->orco = vert_orco; + if (!mesh2tangent->orco) + continue; + + tangent_mask_curr |= DM_TANGENT_MASK_ORCO; + } + else { + int uv_ind = CustomData_get_named_layer_index(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name); + int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV); + BLI_assert(uv_ind != -1 && uv_start != -1); + BLI_assert(uv_ind - uv_start < MAX_MTFACE); + tangent_mask_curr |= (short)(1 << (uv_ind - uv_start)); + } + + mesh2tangent->tangent = loopdata_out->layers[index].data; + BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW); + } + + BLI_assert(tangent_mask_curr == tangent_mask); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + } + else { + tangent_mask_curr = tangent_mask; + } +#ifdef USE_LOOPTRI_DETECT_QUADS + if (face_as_quad_map) { + MEM_freeN(face_as_quad_map); + } +#undef USE_LOOPTRI_DETECT_QUADS + +#endif + + *tangent_mask_curr_p = tangent_mask_curr; + + /* Update active layer index */ + int act_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n); + if (act_uv_index != -1) { + int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name); + CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index); + }/* else tangent has been built from orco */ + + /* Update render layer index */ + int ren_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n); + if (ren_uv_index != -1) { + int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name); + CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index); + }/* else tangent has been built from orco */ + } +} + +void BKE_mesh_calc_loop_tangents( + Mesh *me_eval, bool calc_active_tangent, + const char (*tangent_names)[MAX_NAME], int tangent_names_len) +{ + /* TODO(campbell): store in Mesh.runtime to avoid recalculation. */ + short tangent_mask = 0; + BKE_mesh_calc_loop_tangent_ex( + me_eval->mvert, + me_eval->mpoly, (uint)me_eval->totpoly, + me_eval->mloop, + me_eval->runtime.looptris.array, (uint)me_eval->runtime.looptris.len, + &me_eval->ldata, + calc_active_tangent, + tangent_names, tangent_names_len, + CustomData_get_layer(&me_eval->pdata, CD_NORMAL), + CustomData_get_layer(&me_eval->ldata, CD_NORMAL), + CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */ + /* result */ + &me_eval->ldata, (uint)me_eval->totloop, + &tangent_mask); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 82b3edb5b49..af4d1265cfd 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -43,10 +43,10 @@ #include "BLI_math_vector.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" #include "BKE_mesh.h" +#include "DEG_depsgraph.h" + #include "MEM_guardedalloc.h" /* loop v/e are unsigned, so using max uint_32 value as invalid marker... */ @@ -618,62 +618,6 @@ bool BKE_mesh_validate_arrays( } /* Test same polys. */ -#if 0 - { - bool p1_sub = true, p2_sub = true; - - /* NOTE: This performs a sub-set test. */ - /* XXX This (and the sort of verts list) is better than systematic - * search of all verts of one list into the other if lists have - * a fair amount of elements. - * Not sure however it's worth it in this case? - * But as we also need sorted vert list to check verts multi-used - * (in first pass of checks)... */ - /* XXX If we consider only "equal" polys (i.e. using exactly same set of verts) - * as invalid, better to replace this by a simple memory cmp... */ - while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) { - if (*p1_v < *p2_v) { - if (p1_sub) - p1_sub = false; - p1_nv--; - p1_v++; - } - else if (*p2_v < *p1_v) { - if (p2_sub) - p2_sub = false; - p2_nv--; - p2_v++; - } - else { - /* Equality, both next verts. */ - p1_nv--; - p2_nv--; - p1_v++; - p2_v++; - } - } - if (p1_nv && p1_sub) - p1_sub = false; - else if (p2_nv && p2_sub) - p2_sub = false; - - if (p1_sub && p2_sub) { - PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n", - prev_sp->index, sp->index, sp->index); - sp->invalid = true; - } - /* XXX In fact, these might be valid? :/ */ - else if (p1_sub) { - PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index); - sp->invalid = true; - } - else if (p2_sub) { - PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index); - prev_sp->invalid = true; - prev_sp = sp; /* sp is new reference poly. */ - } - } -#else if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) { if (do_verbose) { PRINT_ERR("\tPolys %u and %u use same vertices (%d", @@ -687,7 +631,6 @@ bool BKE_mesh_validate_arrays( } sp->invalid = true; } -#endif else { prev_sp = sp; } @@ -939,7 +882,7 @@ bool BKE_mesh_validate_all_customdata( { bool is_valid = true; bool is_change_v, is_change_e, is_change_l, is_change_p; - int tot_texpoly, tot_uvloop, tot_vcolloop; + int tot_uvloop, tot_vcolloop; CustomDataMask mask = check_meshmask ? CD_MASK_MESH : 0; is_valid &= mesh_validate_customdata(vdata, mask, do_verbose, do_fixes, &is_change_v); @@ -947,17 +890,8 @@ bool BKE_mesh_validate_all_customdata( is_valid &= mesh_validate_customdata(ldata, mask, do_verbose, do_fixes, &is_change_l); is_valid &= mesh_validate_customdata(pdata, mask, do_verbose, do_fixes, &is_change_p); - tot_texpoly = CustomData_number_of_layers(pdata, CD_MTEXPOLY); tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV); tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL); - if (tot_texpoly != tot_uvloop) { - PRINT_ERR("\tCustomDataLayer mismatch, tot_texpoly(%d), tot_uvloop(%d)\n", - tot_texpoly, tot_uvloop); - } - if (tot_texpoly > MAX_MTFACE) { - PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MTFACE, tot_texpoly - MAX_MTFACE); - } if (tot_uvloop > MAX_MTFACE) { PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", MAX_MTFACE, tot_uvloop - MAX_MTFACE); @@ -968,18 +902,10 @@ bool BKE_mesh_validate_all_customdata( } /* check indices of clone/stencil */ - if (do_fixes && CustomData_get_clone_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) { - CustomData_set_layer_clone(pdata, CD_MTEXPOLY, 0); - is_change_p = true; - } if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) { CustomData_set_layer_clone(ldata, CD_MLOOPUV, 0); is_change_l = true; } - if (do_fixes && CustomData_get_stencil_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) { - CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, 0); - is_change_p = true; - } if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) { CustomData_set_layer_stencil(ldata, CD_MLOOPUV, 0); is_change_l = true; @@ -991,7 +917,7 @@ bool BKE_mesh_validate_all_customdata( } /** - * \see #DM_is_valid to call on derived meshes + * Validates and corrects a Mesh. * * \returns true if a change is made. */ @@ -1022,7 +948,7 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_ &changed); if (changed) { - DAG_id_tag_update(&me->id, OB_RECALC_DATA); + DEG_id_tag_update(&me->id, OB_RECALC_DATA); return true; } else { @@ -1031,61 +957,39 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_ } /** - * Duplicate of BM_mesh_cd_validate() for Mesh data. + * Checks if a Mesh is valid without any modification. This is always verbose. + * + * \see #DM_is_valid to call on derived meshes + * + * \returns is_valid. */ -void BKE_mesh_cd_validate(Mesh *me) +bool BKE_mesh_is_valid(Mesh *me) { - int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); - int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); - int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); - int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY); - int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV); - int i; + const bool do_verbose = true; + const bool do_fixes = false; - /* XXX For now, do not delete those, just warn they are not really usable. */ - if (UNLIKELY(totlayer_mtex > MAX_MTFACE)) { - printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MTFACE, totlayer_mtex - MAX_MTFACE); - } - if (UNLIKELY(totlayer_uv > MAX_MTFACE)) { - printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MTFACE, totlayer_uv - MAX_MTFACE); - } - if (UNLIKELY(totlayer_mcol > MAX_MCOL)) { - printf("WARNING! More VCol layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n", - MAX_MCOL, totlayer_mcol - MAX_MCOL); - } + bool is_valid = true; + bool changed = true; - if (LIKELY(totlayer_mtex == totlayer_uv)) { - /* pass */ - } - else if (totlayer_mtex < totlayer_uv) { - do { - const char *from_name = me->ldata.layers[uv_index + totlayer_mtex].name; - CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name); - CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex); - } while (totlayer_uv != ++totlayer_mtex); - mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY); - } - else if (totlayer_uv < totlayer_mtex) { - do { - const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name; - CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name); - CustomData_set_layer_unique_name(&me->ldata, totlayer_uv); - } while (totlayer_mtex != ++totlayer_uv); - uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV); - } + is_valid &= BKE_mesh_validate_all_customdata( + &me->vdata, &me->edata, &me->ldata, &me->pdata, + false, /* setting mask here isn't useful, gives false positives */ + do_verbose, do_fixes, &changed); - BLI_assert(totlayer_mtex == totlayer_uv); + is_valid &= BKE_mesh_validate_arrays( + me, + me->mvert, me->totvert, + me->medge, me->totedge, + me->mface, me->totface, + me->mloop, me->totloop, + me->mpoly, me->totpoly, + me->dvert, + do_verbose, do_fixes, + &changed); - /* Check uv/tex names match as well!!! */ - for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) { - const char *name_src = me->pdata.layers[mtex_index].name; - const char *name_dst = me->ldata.layers[uv_index].name; - if (!STREQ(name_src, name_dst)) { - BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false); - } - } + BLI_assert(changed == false); + + return is_valid; } /** @@ -1108,7 +1012,7 @@ bool BKE_mesh_validate_material_indices(Mesh *me) } if (!is_valid) { - DAG_id_tag_update(&me->id, OB_RECALC_DATA); + DEG_id_tag_update(&me->id, OB_RECALC_DATA); return true; } else { @@ -1540,4 +1444,78 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select) BLI_edgehash_free(eh, NULL); } + +void BKE_mesh_calc_edges_loose(Mesh *mesh) +{ + MEdge *med = mesh->medge; + for (int i = 0; i < mesh->totedge; i++, med++) { + med->flag |= ME_LOOSEEDGE; + } + MLoop *ml = mesh->mloop; + for (int i = 0; i < mesh->totloop; i++, ml++) { + mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE; + } +} + +/** + * Calculate/create edges from tessface data + * + * \param mesh The mesh to add edges into + */ + +void BKE_mesh_calc_edges_tessface(Mesh *mesh) +{ + CustomData edgeData; + EdgeSetIterator *ehi; + MFace *mf = mesh->mface; + MEdge *med; + EdgeSet *eh; + int i, *index, numEdges, numFaces = mesh->totface; + + eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces)); + + for (i = 0; i < numFaces; i++, mf++) { + BLI_edgeset_add(eh, mf->v1, mf->v2); + BLI_edgeset_add(eh, mf->v2, mf->v3); + + if (mf->v4) { + BLI_edgeset_add(eh, mf->v3, mf->v4); + BLI_edgeset_add(eh, mf->v4, mf->v1); + } + else { + BLI_edgeset_add(eh, mf->v3, mf->v1); + } + } + + numEdges = BLI_edgeset_len(eh); + + /* write new edges into a temporary CustomData */ + CustomData_reset(&edgeData); + CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); + CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges); + + med = CustomData_get_layer(&edgeData, CD_MEDGE); + index = CustomData_get_layer(&edgeData, CD_ORIGINDEX); + + for (ehi = BLI_edgesetIterator_new(eh), i = 0; + BLI_edgesetIterator_isDone(ehi) == false; + BLI_edgesetIterator_step(ehi), i++, med++, index++) + { + BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2); + + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + *index = ORIGINDEX_NONE; + } + BLI_edgesetIterator_free(ehi); + + /* free old CustomData and assign new one */ + CustomData_free(&mesh->edata, mesh->totedge); + mesh->edata = edgeData; + mesh->totedge = numEdges; + + mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE); + + BLI_edgeset_free(eh); +} + /** \} */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 723b4a5aa97..73a9d462687 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -46,6 +46,7 @@ #include "MEM_guardedalloc.h" #include "DNA_armature_types.h" +#include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "BLI_utildefines.h" @@ -58,17 +59,25 @@ #include "BLT_translation.h" #include "BKE_appdir.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_editmesh.h" #include "BKE_global.h" +#include "BKE_idcode.h" #include "BKE_key.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_mesh.h" #include "BKE_multires.h" +#include "BKE_object.h" #include "BKE_DerivedMesh.h" /* may move these, only for modifier_path_relbase */ #include "BKE_main.h" /* end */ +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "MOD_modifiertypes.h" static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL}; @@ -127,6 +136,7 @@ ModifierData *modifier_new(int type) md->type = type; md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded; + md->flag = eModifierFlag_StaticOverride_Local; if (mti->flags & eModifierTypeFlag_EnableInEditmode) md->mode |= eModifierMode_Editmode; @@ -283,7 +293,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData) /* callback's can use this * to avoid copying every member. */ -void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst) +void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst, const int UNUSED(flag)) { const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type); @@ -313,9 +323,10 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag const ModifierTypeInfo *mti = modifierType_getInfo(md->type); target->mode = md->mode; + target->flag = md->flag; if (mti->copyData) { - mti->copyData(md, target); + mti->copyData(md, target, flag); } if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { @@ -338,9 +349,7 @@ bool modifier_supportsCage(struct Scene *scene, ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - - return ((!mti->isDisabled || !mti->isDisabled(md, 0)) && + return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && (mti->flags & eModifierTypeFlag_SupportsEditmode) && modifier_supportsMapping(md)); } @@ -349,11 +358,9 @@ bool modifier_couldBeCage(struct Scene *scene, ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - return ((md->mode & eModifierMode_Realtime) && (md->mode & eModifierMode_Editmode) && - (!mti->isDisabled || !mti->isDisabled(md, 0)) && + (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && modifier_supportsMapping(md)); } @@ -410,9 +417,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC const ModifierTypeInfo *mti = modifierType_getInfo(md->type); bool supports_mapping; - md->scene = scene; - - if (mti->isDisabled && mti->isDisabled(md, 0)) continue; + if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue; if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue; if (md->mode & eModifierMode_DisableTemporary) continue; @@ -468,14 +473,12 @@ bool modifiers_isParticleEnabled(Object *ob) * * \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called. */ -bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode) +bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - md->scene = scene; - if ((md->mode & required_mode) != required_mode) return false; - if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false; + if (scene != NULL && mti->isDisabled && mti->isDisabled(scene, md, required_mode == eModifierMode_Render)) return false; if (md->mode & eModifierMode_DisableTemporary) return false; if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false; @@ -619,6 +622,27 @@ Object *modifiers_isDeformedByArmature(Object *ob) return NULL; } +Object *modifiers_isDeformedByMeshDeform(Object *ob) +{ + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + MeshDeformModifierData *mdmd = NULL; + + /* return the first selected armature, this lets us use multiple armatures */ + for (; md; md = md->next) { + if (md->type == eModifierType_MeshDeform) { + mdmd = (MeshDeformModifierData *) md; + if (mdmd->object && (mdmd->object->flag & SELECT)) + return mdmd->object; + } + } + + if (mdmd) /* if were still here then return the last armature */ + return mdmd->object; + + return NULL; +} + /* Takes an object and returns its first selected lattice, else just its lattice * This should work for multiple lattices per object */ @@ -686,7 +710,7 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm) bool modifier_isCorrectableDeformed(ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - return (mti->deformMatricesEM != NULL); + return mti->deformMatricesEM != NULL; } bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob) @@ -695,9 +719,9 @@ bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob) ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); int required_mode = eModifierMode_Realtime; - if (ob->mode == OB_MODE_EDIT) + if (ob->mode == OB_MODE_EDIT) { required_mode |= eModifierMode_Editmode; - + } for (; md; md = md->next) { if (!modifier_isEnabled(scene, md, required_mode)) { /* pass */ @@ -802,61 +826,104 @@ void modifier_path_init(char *path, int path_maxlen, const char *name) /* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */ -struct DerivedMesh *modwrap_applyModifier( - ModifierData *md, Object *ob, - struct DerivedMesh *dm, - ModifierApplyFlag flag) +struct Mesh *modwrap_applyModifier( + ModifierData *md, const ModifierEvalContext *ctx, + struct Mesh *me) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); + BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false); if (mti->dependsOnNormals && mti->dependsOnNormals(md)) { - DM_ensure_normals(dm); + BKE_mesh_calc_normals(me); } - return mti->applyModifier(md, ob, dm, flag); + return mti->applyModifier(md, ctx, me); } -struct DerivedMesh *modwrap_applyModifierEM( - ModifierData *md, Object *ob, - struct BMEditMesh *em, - DerivedMesh *dm, - ModifierApplyFlag flag) +void modwrap_deformVerts( + ModifierData *md, const ModifierEvalContext *ctx, + Mesh *me, float (*vertexCos)[3], int numVerts) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); + BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false); - if (mti->dependsOnNormals && mti->dependsOnNormals(md)) { - DM_ensure_normals(dm); + if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) { + BKE_mesh_calc_normals(me); } - return mti->applyModifierEM(md, ob, em, dm, flag); + mti->deformVerts(md, ctx, me, vertexCos, numVerts); } -void modwrap_deformVerts( - ModifierData *md, Object *ob, - DerivedMesh *dm, - float (*vertexCos)[3], int numVerts, - ModifierApplyFlag flag) +void modwrap_deformVertsEM( + ModifierData *md, const ModifierEvalContext *ctx, + struct BMEditMesh *em, Mesh *me, + float (*vertexCos)[3], int numVerts) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); + BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false); - if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - DM_ensure_normals(dm); + if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) { + BKE_mesh_calc_normals(me); } - mti->deformVerts(md, ob, dm, vertexCos, numVerts, flag); + mti->deformVertsEM(md, ctx, em, me, vertexCos, numVerts); } -void modwrap_deformVertsEM( - ModifierData *md, Object *ob, - struct BMEditMesh *em, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) +/* end modifier callback wrappers */ + + +/* wrappers for modifier callbacks that accept Mesh and select the proper implementation + * depending on if the modifier has been ported to Mesh or is still using DerivedMesh + */ + +/* deprecated variants of above that accept DerivedMesh */ + +struct DerivedMesh *modifier_applyModifier_DM_deprecated( + struct ModifierData *md, const ModifierEvalContext *ctx, + struct DerivedMesh *dm) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false); - if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - DM_ensure_normals(dm); + /* TODO(sybren): deduplicate all the copies of this code in this file. */ + Mesh *mesh = NULL; + if (dm != NULL) { + mesh = BKE_id_new_nomain(ID_ME, NULL); + DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false); } - mti->deformVertsEM(md, ob, em, dm, vertexCos, numVerts); + + struct Mesh *new_mesh = mti->applyModifier(md, ctx, mesh); + + /* Make a DM that doesn't reference new_mesh so we can free the latter. */ + DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING); + + if (new_mesh != mesh) { + BKE_id_free(NULL, new_mesh); + } + if (mesh != NULL) { + BKE_id_free(NULL, mesh); + } + + return ndm; + +} + +/** + * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier, + * e.g. second operand for boolean modifier. + * Note thqt modifiers in stack always get fully evaluated COW ID pointers, never original ones. Makes things simpler. + */ +Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, bool *r_free_mesh) +{ + Mesh *me; + + if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) { + /* Note: currently we have no equivalent to derived cagemesh or even final dm in BMEditMesh... + * This is TODO in core depsgraph/modifier stack code still. */ + BMEditMesh *em = BKE_editmesh_from_object(ob_eval); + me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0); + *r_free_mesh = true; + } + else { + me = ob_eval->runtime.mesh_eval; + *r_free_mesh = false; + } + + return me; } -/* end modifier callback wrappers */ diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c deleted file mode 100644 index 4de876f1060..00000000000 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * ***** 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) 2005 by the Blender Foundation. - * All rights reserved. - * - * Contributor(s): Joseph Eagar - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -/** \file blender/blenkernel/intern/modifiers_bmesh.c - * \ingroup bke - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" -#include "BLI_alloca.h" - -#include "BKE_DerivedMesh.h" -#include "BKE_editmesh.h" - -/* Static function for alloc */ -static BMFace *bm_face_create_from_mpoly( - MPoly *mp, MLoop *ml, - BMesh *bm, BMVert **vtable, BMEdge **etable) -{ - BMVert **verts = BLI_array_alloca(verts, mp->totloop); - BMEdge **edges = BLI_array_alloca(edges, mp->totloop); - int j; - - for (j = 0; j < mp->totloop; j++, ml++) { - verts[j] = vtable[ml->v]; - edges[j] = etable[ml->e]; - } - - return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD); -} - -/** - * The main function for copying DerivedMesh data into BMesh. - * - * \note The mesh may already have geometry. see 'is_init' - */ -void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal) -{ - MVert *mv, *mvert; - MEdge *me, *medge; - MPoly *mpoly, *mp; - MLoop *mloop; - BMVert *v, **vtable; - BMEdge *e, **etable; - float (*face_normals)[3]; - BMFace *f; - int i, j, totvert, totedge /* , totface */ /* UNUSED */ ; - bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0); - char has_orig_htype = 0; - - int cd_vert_bweight_offset; - int cd_edge_bweight_offset; - int cd_edge_crease_offset; - - if (is_init == false) { - /* check if we have an origflag */ - has_orig_htype |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0; - has_orig_htype |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0; - has_orig_htype |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0; - } - - /*merge custom data layout*/ - CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT); - CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE); - CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP); - CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE); - - if (is_init) { - BM_mesh_cd_flag_apply(bm, dm->cd_flag); - } - - cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); - cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); - cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - - totvert = dm->getNumVerts(dm); - totedge = dm->getNumEdges(dm); - /* totface = dm->getNumPolys(dm); */ /* UNUSED */ - - vtable = MEM_mallocN(sizeof(*vtable) * totvert, __func__); - etable = MEM_mallocN(sizeof(*etable) * totedge, __func__); - - /*do verts*/ - bool vert_allocated; - mv = mvert = DM_get_vert_array(dm, &vert_allocated); - for (i = 0; i < totvert; i++, mv++) { - v = BM_vert_create(bm, mv->co, NULL, BM_CREATE_SKIP_CD); - normal_short_to_float_v3(v->no, mv->no); - v->head.hflag = BM_vert_flag_from_mflag(mv->flag); - BM_elem_index_set(v, i); /* set_inline */ - - CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data, true); - vtable[i] = v; - - /* add bevel weight */ - if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mv->bweight / 255.0f); - - if (UNLIKELY(has_orig_htype & BM_VERT)) { - int *orig_index = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_ORIGINDEX); - *orig_index = ORIGINDEX_NONE; - } - } - if (vert_allocated) MEM_freeN(mvert); - if (is_init) bm->elem_index_dirty &= ~BM_VERT; - - /*do edges*/ - bool edge_allocated; - me = medge = DM_get_edge_array(dm, &edge_allocated); - for (i = 0; i < totedge; i++, me++) { - //BLI_assert(BM_edge_exists(vtable[me->v1], vtable[me->v2]) == NULL); - e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, BM_CREATE_SKIP_CD); - - e->head.hflag = BM_edge_flag_from_mflag(me->flag); - BM_elem_index_set(e, i); /* set_inline */ - - CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data, true); - etable[i] = e; - - if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)me->bweight / 255.0f); - if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)me->crease / 255.0f); - - if (UNLIKELY(has_orig_htype & BM_EDGE)) { - int *orig_index = CustomData_bmesh_get(&bm->edata, e->head.data, CD_ORIGINDEX); - *orig_index = ORIGINDEX_NONE; - } - } - if (edge_allocated) MEM_freeN(medge); - if (is_init) bm->elem_index_dirty &= ~BM_EDGE; - - /* do faces */ - /* note: i_alt is aligned with bmesh faces which may not always align with mpolys */ - bool poly_allocated, loop_allocated; - mpoly = mp = DM_get_poly_array(dm, &poly_allocated); - mloop = DM_get_loop_array(dm, &loop_allocated); - face_normals = (dm->dirty & DM_DIRTY_NORMALS) ? NULL : CustomData_get_layer(&dm->polyData, CD_NORMAL); - for (i = 0; i < dm->numPolyData; i++, mp++) { - BMLoop *l_iter; - BMLoop *l_first; - - f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, - bm, vtable, etable); - - if (UNLIKELY(f == NULL)) { - continue; - } - - f->head.hflag = BM_face_flag_from_mflag(mp->flag); - BM_elem_index_set(f, bm->totface - 1); /* set_inline */ - f->mat_nr = mp->mat_nr; - - j = mp->loopstart; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - /* Save index of correspsonding MLoop */ - CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, j, &l_iter->head.data, true); - BM_elem_index_set(l_iter, j++); /* set_inline */ - } while ((l_iter = l_iter->next) != l_first); - - CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data, true); - - if (calc_face_normal) { - if (face_normals) { - copy_v3_v3(f->no, face_normals[i]); - } - else { - BM_face_normal_update(f); - } - } - - if (UNLIKELY(has_orig_htype & BM_FACE)) { - int *orig_index = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_ORIGINDEX); - *orig_index = ORIGINDEX_NONE; - } - } - if (poly_allocated) MEM_freeN(mpoly); - if (loop_allocated) MEM_freeN(mloop); - if (is_init) bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); - - MEM_freeN(vtable); - MEM_freeN(etable); -} - -/* converts a cddm to a BMEditMesh. if existing is non-NULL, the - * new geometry will be put in there.*/ -BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do_tessellate) -{ - BMEditMesh *em = existing; - BMesh *bm; - - if (em) { - bm = em->bm; - } - else { - bm = BM_mesh_create( - &bm_mesh_allocsize_default, - &((struct BMeshCreateParams){.use_toolflags = false,})); - } - - DM_to_bmesh_ex(dm, bm, do_tessellate); - - if (!em) { - em = BKE_editmesh_create(bm, do_tessellate); - } - else { - if (do_tessellate) { - BKE_editmesh_tessface_calc(em); - } - } - - return em; -} - -BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal) -{ - BMesh *bm; - const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm); - - bm = BM_mesh_create( - &allocsize, - &((struct BMeshCreateParams){.use_toolflags = false,})); - - DM_to_bmesh_ex(dm, bm, calc_face_normal); - - return bm; -} diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index a11b0c62aa8..0117b36a16e 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1162,6 +1162,7 @@ void BKE_movieclip_get_size(MovieClip *clip, MovieClipUser *user, int *width, in * cache lookups and even unwanted non-proxied files loading when doing mask parenting, * so let's disable this for now and assume image sequence consists of images with * equal sizes (sergey) + * TODO(sergey): Support reading sequences of different resolution. */ if (user->framenr == clip->lastframe) { #endif @@ -1609,8 +1610,51 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip, return result; } -void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip) +static void movieclip_selection_synchronize(MovieClip *clip_dst, const MovieClip *clip_src) { - DEG_debug_print_eval(__func__, clip->id.name, clip); + BLI_assert(clip_dst != clip_src); + MovieTracking *tracking_dst = &clip_dst->tracking, tracking_src = clip_src->tracking; + /* Syncs the active object, track and plane track. */ + tracking_dst->objectnr = tracking_src.objectnr; + const int active_track_index = BLI_findindex(&tracking_src.tracks, tracking_src.act_track); + const int active_plane_track_index = BLI_findindex(&tracking_src.plane_tracks, tracking_src.act_plane_track); + tracking_dst->act_track = BLI_findlink(&tracking_dst->tracks, active_track_index); + tracking_dst->act_plane_track = BLI_findlink(&tracking_dst->plane_tracks, active_plane_track_index); + + /* Syncs the tracking selection flag. */ + MovieTrackingObject *tracking_object_dst, *tracking_object_src; + tracking_object_src = tracking_src.objects.first; + + for (tracking_object_dst = tracking_dst->objects.first; + tracking_object_dst != NULL; + tracking_object_dst = tracking_object_dst->next, + tracking_object_src = tracking_object_src->next) + { + ListBase *tracksbase_dst, *tracksbase_src; + tracksbase_dst = BKE_tracking_object_get_tracks(tracking_dst, tracking_object_dst); + tracksbase_src = BKE_tracking_object_get_tracks(&tracking_src, tracking_object_src); + + MovieTrackingTrack *track_dst, *track_src; + track_src = tracksbase_src->first; + for (track_dst = tracksbase_dst->first; + track_dst != NULL; + track_dst = track_dst->next, track_src = track_src->next) + { + track_dst->flag = track_src->flag; + track_dst->pat_flag = track_src->pat_flag; + track_dst->search_flag = track_src->search_flag; + } + } +} + +void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, MovieClip *clip) +{ + DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip); BKE_tracking_dopesheet_tag_update(&clip->tracking); } + +void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip *clip) +{ + DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip); + movieclip_selection_synchronize(clip, (MovieClip *)clip->id.orig_id); +} diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 279c6eb0c82..8f02b51fd5f 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -49,12 +49,15 @@ #include "BKE_pbvh.h" #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" +#include "BKE_library.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_scene.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" #include "BKE_editmesh.h" @@ -62,6 +65,8 @@ #include "CCGSubSurf.h" +#include "DEG_depsgraph_query.h" + #include <math.h> #include <string.h> @@ -277,14 +282,14 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level) return mdisps; } -DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob) +DerivedMesh *get_multires_dm(struct Depsgraph *depsgraph, Scene *scene, MultiresModifierData *mmd, Object *ob) { ModifierData *md = (ModifierData *)mmd; - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); + DerivedMesh *tdm = mesh_get_derived_deform(depsgraph, scene, ob, CD_MASK_BAREMESH); DerivedMesh *dm; + ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY}; - dm = mti->applyModifier(md, ob, tdm, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY); + dm = modifier_applyModifier_DM_deprecated(md, &mectx, tdm); if (dm == tdm) { dm = CDDM_copy(tdm); } @@ -292,6 +297,28 @@ DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob return dm; } +Mesh *BKE_multires_create_mesh( + struct Depsgraph *depsgraph, + Scene *scene, + MultiresModifierData *mmd, + Object *ob) +{ + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene, ob_eval, CD_MASK_BAREMESH); + ModifierEvalContext modifier_ctx = { + .depsgraph = depsgraph, + .object = ob_eval, + .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY}; + + const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type); + Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh); + + if (result == deformed_mesh) { + result = BKE_mesh_copy_for_eval(deformed_mesh, true); + } + return result; +} + MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd) { ModifierData *md; @@ -336,17 +363,17 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f return mmd; } -static int multires_get_level(Object *ob, MultiresModifierData *mmd, - bool render, bool ignore_simplify) +int multires_get_level(const Scene *scene, const Object *ob, const MultiresModifierData *mmd, + bool render, bool ignore_simplify) { if (render) - return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl; + return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) : mmd->renderlvl; else if (ob->mode == OB_MODE_SCULPT) return mmd->sculptlvl; else if (ignore_simplify) return mmd->lvl; else - return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl; + return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl; } void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl) @@ -366,21 +393,49 @@ static void multires_dm_mark_as_modified(DerivedMesh *dm, MultiresModifiedFlags ccgdm->multires.modified_flags |= flags; } +static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg, + MultiresModifiedFlags flags) +{ + if (flags & MULTIRES_COORDS_MODIFIED) { + subdiv_ccg->dirty.coords = true; + } + if (flags & MULTIRES_HIDDEN_MODIFIED) { + subdiv_ccg->dirty.hidden = true; + } +} + void multires_mark_as_modified(Object *ob, MultiresModifiedFlags flags) { - if (ob && ob->derivedFinal) - multires_dm_mark_as_modified(ob->derivedFinal, flags); + if (ob == NULL) { + return; + } + Mesh *mesh = ob->data; + SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg; + if (subdiv_ccg == NULL) { + return; + } + multires_ccg_mark_as_modified(subdiv_ccg, flags); } void multires_force_update(Object *ob) { - if (ob) { - BKE_object_free_derived_caches(ob); - - if (ob->sculpt && ob->sculpt->pbvh) { - BKE_pbvh_free(ob->sculpt->pbvh); - ob->sculpt->pbvh = NULL; + if (ob == NULL) { + return; + } + SculptSession *sculpt_session = ob->sculpt; + if (sculpt_session != NULL && sculpt_session->pbvh != NULL) { + PBVH *pbvh = sculpt_session->pbvh; + if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { + Mesh *mesh = ob->data; + multiresModifier_reshapeFromCCG( + sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); + } + else { + /* NOTE: Disabled for until OpenSubdiv is enabled by default. */ + // BLI_assert(!"multires_force_update is used on non-grids PBVH"); } + BKE_pbvh_free(pbvh); + ob->sculpt->pbvh = NULL; } } @@ -398,68 +453,6 @@ void multires_force_render_update(Object *ob) multires_force_update(ob); } -int multiresModifier_reshapeFromDM(Scene *scene, MultiresModifierData *mmd, - Object *ob, DerivedMesh *srcdm) -{ - DerivedMesh *mrdm = get_multires_dm(scene, mmd, ob); - - if (mrdm && srcdm && mrdm->getNumVerts(mrdm) == srcdm->getNumVerts(srcdm)) { - multires_mvert_to_ss(mrdm, srcdm->getVertArray(srcdm)); - - multires_dm_mark_as_modified(mrdm, MULTIRES_COORDS_MODIFIED); - multires_force_update(ob); - - mrdm->release(mrdm); - - return 1; - } - - if (mrdm) mrdm->release(mrdm); - - return 0; -} - -/* Returns 1 on success, 0 if the src's totvert doesn't match */ -int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *dst, Object *src) -{ - DerivedMesh *srcdm = mesh_get_derived_final(scene, src, CD_MASK_BAREMESH); - return multiresModifier_reshapeFromDM(scene, mmd, dst, srcdm); -} - -int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd, - Object *ob, ModifierData *md) -{ - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - DerivedMesh *dm, *ndm; - int numVerts, result; - float (*deformedVerts)[3]; - - if (multires_get_level(ob, mmd, false, true) == 0) - return 0; - - /* Create DerivedMesh for deformation modifier */ - dm = get_multires_dm(scene, mmd, ob); - numVerts = dm->getNumVerts(dm); - deformedVerts = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "multiresReshape_deformVerts"); - - dm->getVertCos(dm, deformedVerts); - mti->deformVerts(md, ob, dm, deformedVerts, numVerts, 0); - - ndm = CDDM_copy(dm); - CDDM_apply_vert_coords(ndm, deformedVerts); - - MEM_freeN(deformedVerts); - dm->release(dm); - - /* Reshaping */ - result = multiresModifier_reshapeFromDM(scene, mmd, ob, ndm); - - /* Cleanup */ - ndm->release(ndm); - - return result; -} - /* reset the multires levels to match the number of mdisps */ static int get_levels_from_disps(Object *ob) { @@ -680,10 +673,10 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) } /* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */ -void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction) +void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object *ob, int direction) { Mesh *me = BKE_mesh_from_object(ob); - int lvl = multires_get_level(ob, mmd, false, true); + int lvl = multires_get_level(scene, ob, mmd, false, true); int levels = mmd->totlvl - lvl; MDisps *mdisps; @@ -700,7 +693,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire multires_set_tot_level(ob, mmd, lvl); } -static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask) +static DerivedMesh *multires_dm_create_local(Scene *scene, Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask) { MultiresModifierData mmd = {{NULL}}; MultiresFlags flags = MULTIRES_USE_LOCAL_MMD; @@ -714,29 +707,44 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv if (alloc_paint_mask) flags |= MULTIRES_ALLOC_PAINT_MASK; - return multires_make_derived_from_derived(dm, &mmd, ob, flags); + return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags); } -static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv, int alloc_paint_mask) +static DerivedMesh *subsurf_dm_create_local( + Scene *scene, Object *ob, DerivedMesh *dm, + int lvl, + bool is_simple, bool is_optimal, bool is_plain_uv, bool alloc_paint_mask, + bool for_render) { SubsurfModifierData smd = {{NULL}}; SubsurfFlags flags = 0; smd.levels = smd.renderLevels = lvl; - if (!plain_uv) - smd.flags |= eSubsurfModifierFlag_SubsurfUv; - if (simple) + smd.quality = 3; + if (!is_plain_uv) { + smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + } + else { + smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; + } + if (is_simple) { smd.subdivType = ME_SIMPLE_SUBSURF; - if (optimal) + } + if (is_optimal) { smd.flags |= eSubsurfModifierFlag_ControlEdges; + } - if (ob->mode & OB_MODE_EDIT) + if (ob->mode & OB_MODE_EDIT) { flags |= SUBSURF_IN_EDIT_MODE; - - if (alloc_paint_mask) + } + if (alloc_paint_mask) { flags |= SUBSURF_ALLOC_PAINT_MASK; + } + if (for_render) { + flags |= SUBSURF_USE_RENDER_PARAMS; + } - return subsurf_make_derived_from_derived(dm, &smd, NULL, flags); + return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags); } @@ -750,7 +758,7 @@ static float v3_dist_from_plane(float v[3], float center[3], float no[3]) return dot_v3v3(s, no); } -void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) +void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object *ob) { DerivedMesh *cddm, *dispdm, *origdm; Mesh *me; @@ -772,7 +780,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) /* generate highest level with displacements */ cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - dispdm = multires_dm_create_local(ob, cddm, totlvl, totlvl, 0, 0); + dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0); cddm->release(cddm); /* copy the new locations of the base verts into the mesh */ @@ -868,7 +876,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) /* subdivide the mesh to highest level without displacements */ cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0); + origdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, 0, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, 0, false); cddm->release(cddm); /* calc disps */ @@ -878,7 +886,9 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) dispdm->release(dispdm); } -static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl, int updateblock, int simple) +static void multires_subdivide( + MultiresModifierData *mmd, Scene *scene, Object *ob, + int totlvl, int updateblock, int simple) { Mesh *me = ob->data; MDisps *mdisps; @@ -907,11 +917,11 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl /* create subsurf DM from original mesh at high level */ cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask); + highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false); ss = ((CCGDerivedMesh *)highdm)->ss; /* create multires DM from original mesh at low level */ - lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask); + lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask); BLI_assert(lowdm != cddm); cddm->release(cddm); @@ -961,9 +971,9 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl multires_set_tot_level(ob, mmd, totlvl); } -void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple) +void multiresModifier_subdivide(MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple) { - multires_subdivide(mmd, ob, mmd->totlvl + 1, updateblock, simple); + multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple); } static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3]) @@ -1196,7 +1206,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm } } -void multires_modifier_update_mdisps(struct DerivedMesh *dm) +void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; Object *ob; @@ -1228,11 +1238,11 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) else cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask); + highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false); ss = ((CCGDerivedMesh *)highdm)->ss; /* create multires DM from original mesh and displacements */ - lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple, has_mask); + lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask); cddm->release(cddm); /* gather grid data */ @@ -1290,7 +1300,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) else cddm = CDDM_from_mesh(me); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask); + subdm = subsurf_dm_create_local(scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false); cddm->release(cddm); multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl); @@ -1332,147 +1342,36 @@ void multires_modifier_update_hidden(DerivedMesh *dm) } } -void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to) +void multires_stitch_grids(Object *ob) { - DerivedMesh *ccgdm = NULL, *subsurf = NULL; - CCGElem **gridData, **subGridData = NULL; - CCGKey key; - MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); - MDisps *mdisps; - MultiresModifierData *mmd = get_multires_modifier(NULL, ob, 1); - int *gridOffset, totlvl; - int i, k, numGrids, gridSize, dGridSize, dSkip; - - if (!mmd) + if (ob == NULL) { return; - - mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS); - - if (!mdisps) { - goto cleanup; - } - - totlvl = mmd->totlvl; - ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple, false); - - subsurf = subsurf_dm_create_local(ob, dm, totlvl, - mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv, 0); - - numGrids = subsurf->getNumGrids(subsurf); - gridSize = subsurf->getGridSize(subsurf); - gridData = subsurf->getGridData(subsurf); - subsurf->getGridKey(subsurf, &key); - - subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); - - for (i = 0; i < numGrids; i++) { - subGridData[i] = MEM_calloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData"); - memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); - } - - /* numGrids = ccgdm->dm->getNumGrids((DerivedMesh *)ccgdm); */ /*UNUSED*/ - gridSize = ccgdm->getGridSize((DerivedMesh *)ccgdm); - gridData = ccgdm->getGridData((DerivedMesh *)ccgdm); - gridOffset = ccgdm->getGridOffset((DerivedMesh *)ccgdm); - - dGridSize = multires_side_tot[totlvl]; - dSkip = (dGridSize - 1) / (gridSize - 1); - - k = 0; /*current loop/mdisp index within the mloop array*/ - - /* TODO: Use BLI_task parallel range for that one too? */ - for (i = 0; i < dm->numPolyData; ++i) { - const int numVerts = mpoly[i].totloop; - int S, x, y, gIndex = gridOffset[i]; - - for (S = 0; S < numVerts; ++S, ++gIndex, ++k) { - MDisps *mdisp = &mdisps[mpoly[i].loopstart + S]; - /* CCGElem *grid = gridData[gIndex]; */ /* UNUSED */ - CCGElem *subgrid = subGridData[gIndex]; - float (*dispgrid)[3] = NULL; - - /* when adding new faces in edit mode, need to allocate disps */ - if (!mdisp->disps) { - mdisp->totdisp = gridSize * gridSize; - mdisp->level = totlvl; - mdisp->disps = MEM_calloc_arrayN(mdisp->totdisp, 3 * sizeof(float), "disp in multires_set_space"); - } - - dispgrid = mdisp->disps; - - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; - float *co = CCG_grid_elem_co(&key, subgrid, x, y); - float mat[3][3], dco[3]; - - /* construct tangent space matrix */ - grid_tangent_matrix(mat, &key, x, y, subgrid); - - /* convert to absolute coordinates in space */ - if (from == MULTIRES_SPACE_TANGENT) { - mul_v3_m3v3(dco, mat, data); - add_v3_v3(dco, co); - } - else if (from == MULTIRES_SPACE_OBJECT) { - add_v3_v3v3(dco, co, data); - } - else if (from == MULTIRES_SPACE_ABSOLUTE) { - copy_v3_v3(dco, data); - } - - /*now, convert to desired displacement type*/ - if (to == MULTIRES_SPACE_TANGENT) { - invert_m3(mat); - - sub_v3_v3(dco, co); - mul_v3_m3v3(data, mat, dco); - } - else if (to == MULTIRES_SPACE_OBJECT) { - sub_v3_v3(dco, co); - mul_v3_m3v3(data, mat, dco); - } - else if (to == MULTIRES_SPACE_ABSOLUTE) { - copy_v3_v3(data, dco); - } - } - } - } } - -cleanup: - if (subsurf) { - subsurf->needsFree = 1; - subsurf->release(subsurf); + SculptSession *sculpt_session = ob->sculpt; + if (sculpt_session == NULL) { + return; } - - if (ccgdm) { - ccgdm->needsFree = 1; - ccgdm->release(ccgdm); + PBVH *pbvh = sculpt_session->pbvh; + SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg; + if (pbvh == NULL || subdiv_ccg == NULL) { + return; } -} - -void multires_stitch_grids(Object *ob) -{ - /* utility for smooth brush */ - if (ob && ob->derivedFinal) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)ob->derivedFinal; - CCGFace **faces; - int totface; - - if (ccgdm->pbvh) { - BKE_pbvh_get_grid_updates(ccgdm->pbvh, false, (void ***)&faces, &totface); - - if (totface) { - ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface); - MEM_freeN(faces); - } - } + BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS); + /* NOTE: Currently CCG does not keep track of faces, making it impossible + * to use BKE_pbvh_get_grid_updates(). + */ + CCGFace **faces; + int num_faces; + BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces); + if (num_faces) { + BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces); + MEM_freeN(faces); } } DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, MultiresModifierData *mmd, + Scene *scene, Object *ob, MultiresFlags flags) { @@ -1483,16 +1382,17 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, CCGKey key; const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0; const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0; - int lvl = multires_get_level(ob, mmd, render, ignore_simplify); + int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify); int i, gridSize, numGrids; if (lvl == 0) return dm; - result = subsurf_dm_create_local(ob, dm, lvl, + result = subsurf_dm_create_local(scene, ob, dm, lvl, mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, - mmd->flags & eMultiresModifierFlag_PlainUv, - flags & MULTIRES_ALLOC_PAINT_MASK); + mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, + flags & MULTIRES_ALLOC_PAINT_MASK, + render); if (!(flags & MULTIRES_USE_LOCAL_MMD)) { ccgdm = (CCGDerivedMesh *)result; @@ -2168,7 +2068,7 @@ void multires_load_old(Object *ob, Mesh *me) BLI_insertlinkbefore(&ob->modifiers, md, mmd); for (i = 0; i < me->mr->level_count - 1; ++i) - multiresModifier_subdivide(mmd, ob, 1, 0); + multiresModifier_subdivide(mmd, NULL, ob, 1, 0); mmd->lvl = mmd->totlvl; orig = CDDM_from_mesh(me); @@ -2177,7 +2077,7 @@ void multires_load_old(Object *ob, Mesh *me) * reference subsurfed dm with this option, before calling multiresModifier_disp_run(), * which implicitly expects both subsurfs from its first dm and oldGridData parameters to * be of the same "format"! */ - dm = multires_make_derived_from_derived(orig, mmd, ob, 0); + dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0); multires_load_old_dm(dm, me, mmd->totlvl + 1); @@ -2192,14 +2092,14 @@ void multires_load_old(Object *ob, Mesh *me) /* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them * such that 'ob_dst' has the same total number of levels as 'ob_src'. */ -void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst) +void multiresModifier_sync_levels_ex(Scene *scene, Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst) { if (mmd_src->totlvl == mmd_dst->totlvl) { return; } if (mmd_src->totlvl > mmd_dst->totlvl) { - multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); + multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); } else { multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); @@ -2221,134 +2121,50 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) } if (mmd_src && mmd_dst) { - multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst); + multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst); } } -static void multires_apply_smat_cb( - void *__restrict userdata, - const int pidx, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void multires_apply_uniform_scale(Object *object, const float scale) { - MultiresThreadedData *tdata = userdata; - - CCGElem **gridData = tdata->gridData; - CCGElem **subGridData = tdata->subGridData; - CCGKey *dm_key = tdata->key; - CCGKey *subdm_key = tdata->sub_key; - MPoly *mpoly = tdata->mpoly; - MDisps *mdisps = tdata->mdisps; - int *gridOffset = tdata->gridOffset; - int gridSize = tdata->gridSize; - int dGridSize = tdata->dGridSize; - int dSkip = tdata->dSkip; - float (*smat)[3] = tdata->smat; - - const int numVerts = mpoly[pidx].totloop; - MDisps *mdisp = &mdisps[mpoly[pidx].loopstart]; - int S, x, y, gIndex = gridOffset[pidx]; - - for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) { - CCGElem *grid = gridData[gIndex]; - CCGElem *subgrid = subGridData[gIndex]; - float (*dispgrid)[3] = mdisp->disps; - - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *co = CCG_grid_elem_co(dm_key, grid, x, y); - float *sco = CCG_grid_elem_co(subdm_key, subgrid, x, y); - float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; - float mat[3][3], disp[3]; - - /* construct tangent space matrix */ - grid_tangent_matrix(mat, dm_key, x, y, grid); - - /* scale subgrid coord and calculate displacement */ - mul_m3_v3(smat, sco); - sub_v3_v3v3(disp, sco, co); - - /* convert difference to tangent space */ - invert_m3(mat); - mul_v3_m3v3(data, mat, disp); - } + Mesh *mesh = (Mesh *)object->data; + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + for (int i = 0; i < mesh->totloop; ++i) { + MDisps *grid = &mdisps[i]; + for (int j = 0; j < grid->totdisp; ++j) { + mul_v3_fl(grid->disps[j], scale); } } } -static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3]) +static void multires_apply_smat( + struct Depsgraph *UNUSED(depsgraph), + Scene *scene, + Object *object, + float smat[3][3]) { - DerivedMesh *dm = NULL, *cddm = NULL, *subdm = NULL; - CCGElem **gridData, **subGridData; - CCGKey dm_key, subdm_key; - Mesh *me = (Mesh *)ob->data; - MPoly *mpoly = me->mpoly; - /* MLoop *mloop = me->mloop; */ /* UNUSED */ - MDisps *mdisps; - int *gridOffset; - int i, /*numGrids, */ gridSize, dGridSize, dSkip, totvert; - float (*vertCos)[3] = NULL; - MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1); - MultiresModifierData high_mmd; - - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - - if (!mdisps || !mmd || !mmd->totlvl) return; - - /* we need derived mesh created from highest resolution */ - high_mmd = *mmd; - high_mmd.lvl = high_mmd.totlvl; - - /* unscaled multires with applied displacement */ - subdm = get_multires_dm(scene, &high_mmd, ob); - - /* prepare scaled CDDM to create ccgDN */ - cddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); - - totvert = cddm->getNumVerts(cddm); - vertCos = MEM_malloc_arrayN(totvert, sizeof(*vertCos), "multiresScale vertCos"); - cddm->getVertCos(cddm, vertCos); - for (i = 0; i < totvert; i++) - mul_m3_v3(smat, vertCos[i]); - CDDM_apply_vert_coords(cddm, vertCos); - MEM_freeN(vertCos); - - /* scaled ccgDM for tangent space of object with applied scale */ - dm = subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0); - cddm->release(cddm); - - gridSize = dm->getGridSize(dm); - gridData = dm->getGridData(dm); - gridOffset = dm->getGridOffset(dm); - dm->getGridKey(dm, &dm_key); - subGridData = subdm->getGridData(subdm); - subdm->getGridKey(subdm, &subdm_key); - - dGridSize = multires_side_tot[high_mmd.totlvl]; - dSkip = (dGridSize - 1) / (gridSize - 1); - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - - MultiresThreadedData data = { - .gridData = gridData, - .subGridData = subGridData, - .key = &dm_key, - .sub_key = &subdm_key, - .mpoly = mpoly, - .mdisps = mdisps, - .gridOffset = gridOffset, - .gridSize = gridSize, - .dGridSize = dGridSize, - .dSkip = dSkip, - .smat = smat - }; - - BLI_task_parallel_range(0, me->totpoly, &data, multires_apply_smat_cb, &settings); - - dm->release(dm); - subdm->release(subdm); + const MultiresModifierData *mmd = get_multires_modifier(scene, object, true); + if (mmd == NULL || mmd->totlvl == 0) { + return; + } + /* Make sure layer present. */ + Mesh *mesh = (Mesh *)object->data; + CustomData_external_read( + &mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); + if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) { + return; + } + if (is_uniform_scaled_m3(smat)) { + const float scale = mat3_to_scale(smat); + multires_apply_uniform_scale(object, scale); + } + else { + /* TODO(sergey): This branch of code actually requires more work to + * preserve all the details. + */ + const float scale = mat3_to_scale(smat); + multires_apply_uniform_scale(object, scale); + } } int multires_mdisp_corners(MDisps *s) @@ -2364,17 +2180,17 @@ int multires_mdisp_corners(MDisps *s) return 0; } -void multiresModifier_scale_disp(Scene *scene, Object *ob) +void multiresModifier_scale_disp(struct Depsgraph *depsgraph, Scene *scene, Object *ob) { float smat[3][3]; /* object's scale matrix */ BKE_object_scale_to_mat3(ob, smat); - multires_apply_smat(scene, ob, smat); + multires_apply_smat(depsgraph, scene, ob, smat); } -void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob) +void multiresModifier_prepare_join(struct Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob) { float smat[3][3], tmat[3][3], mat[3][3]; multires_sync_levels(scene, to_ob, ob); @@ -2385,7 +2201,7 @@ void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob) BKE_object_scale_to_mat3(ob, smat); mul_m3_m3m3(mat, smat, tmat); - multires_apply_smat(scene, ob, mat); + multires_apply_smat(depsgraph, scene, ob, mat); } /* update multires data after topology changing */ diff --git a/source/blender/blenkernel/intern/multires_inline.h b/source/blender/blenkernel/intern/multires_inline.h new file mode 100644 index 00000000000..99b4695fe46 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_inline.h @@ -0,0 +1,68 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/multires_inline.h + * \ingroup bke + */ + +#ifndef __MULTIRES_INLINE_H__ +#define __MULTIRES_INLINE_H__ + +#include "BKE_multires.h" +#include "BLI_math_vector.h" + +BLI_INLINE void BKE_multires_construct_tangent_matrix( + float tangent_matrix[3][3], + const float dPdu[3], + const float dPdv[3], + const int corner) +{ + if (corner == 0) { + copy_v3_v3(tangent_matrix[0], dPdv); + copy_v3_v3(tangent_matrix[1], dPdu); + mul_v3_fl(tangent_matrix[0], -1.0f); + mul_v3_fl(tangent_matrix[1], -1.0f); + } + else if (corner == 1) { + copy_v3_v3(tangent_matrix[0], dPdu); + copy_v3_v3(tangent_matrix[1], dPdv); + mul_v3_fl(tangent_matrix[1], -1.0f); + } + else if (corner == 2) { + copy_v3_v3(tangent_matrix[0], dPdv); + copy_v3_v3(tangent_matrix[1], dPdu); + } + else if (corner == 3) { + copy_v3_v3(tangent_matrix[0], dPdu); + copy_v3_v3(tangent_matrix[1], dPdv); + mul_v3_fl(tangent_matrix[0], -1.0f); + } + cross_v3_v3v3(tangent_matrix[2], dPdu, dPdv); + normalize_v3(tangent_matrix[0]); + normalize_v3(tangent_matrix[1]); + normalize_v3(tangent_matrix[2]); +} + +#endif /* __MULTIRES_INLINE_H__ */ diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c new file mode 100644 index 00000000000..fe4bc5ca3e0 --- /dev/null +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -0,0 +1,1206 @@ +/* + * ***** 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) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/multires_reshape.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_task.h" + +#include "BKE_ccg.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_ccg.h" +#include "BKE_subdiv_eval.h" +#include "BKE_subdiv_foreach.h" +#include "BKE_subdiv_mesh.h" + +#include "DEG_depsgraph_query.h" + +static void multires_reshape_init_mmd( + MultiresModifierData *reshape_mmd, + const MultiresModifierData *mmd) +{ + *reshape_mmd = *mmd; +} + +static void multires_reshape_init_mmd_top_level( + MultiresModifierData *reshape_mmd, + const MultiresModifierData *mmd) +{ + *reshape_mmd = *mmd; + reshape_mmd->lvl = reshape_mmd->totlvl; +} + +/* ============================================================================= + * General reshape implementation, reused by all particular cases. + */ + +typedef struct MultiresReshapeContext { + Subdiv *subdiv; + const Mesh *coarse_mesh; + MDisps *mdisps; + GridPaintMask *grid_paint_mask; + int top_grid_size; + int top_level; +} MultiresReshapeContext; + +static void multires_reshape_allocate_displacement_grid( + MDisps *displacement_grid, const int level) +{ + const int grid_size = BKE_subdiv_grid_size_from_level(level); + const int grid_area = grid_size * grid_size; + float (*disps)[3] = MEM_calloc_arrayN( + grid_area, 3 * sizeof(float), "multires disps"); + displacement_grid->disps = disps; + displacement_grid->totdisp = grid_area; + displacement_grid->level = level; +} + +static void multires_reshape_ensure_displacement_grid( + MDisps *displacement_grid, const int level) +{ + if (displacement_grid->disps != NULL) { + return; + } + multires_reshape_allocate_displacement_grid( + displacement_grid, level); +} + +static void multires_reshape_ensure_displacement_grids( + Mesh *mesh, + const int grid_level) +{ + const int num_grids = mesh->totloop; + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + multires_reshape_ensure_displacement_grid( + &mdisps[grid_index], grid_level); + } +} + +static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level) +{ + GridPaintMask *grid_paint_masks = + CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); + if (grid_paint_masks == NULL) { + return; + } + const int num_grids = mesh->totloop; + const int grid_size = BKE_subdiv_grid_size_from_level(grid_level); + const int grid_area = grid_size * grid_size; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index]; + if (grid_paint_mask->level == grid_level) { + continue; + } + grid_paint_mask->level = grid_level; + if (grid_paint_mask->data) { + MEM_freeN(grid_paint_mask->data); + } + grid_paint_mask->data = MEM_calloc_arrayN( + grid_area, sizeof(float), "gpm.data"); + } +} + +static void multires_reshape_ensure_grids(Mesh *mesh, const int grid_level) +{ + multires_reshape_ensure_displacement_grids(mesh, grid_level); + multires_reshape_ensure_mask_grids(mesh, grid_level); +} + +static void multires_reshape_vertex_copy_to_next( + MultiresReshapeContext *ctx, + const MPoly *coarse_poly, + const int current_corner, + const MDisps *current_displacement_grid, + const GridPaintMask *current_mask_grid, + const int current_grid_x, const int current_grid_y) +{ + const int grid_size = ctx->top_grid_size; + const int next_current_corner = (current_corner + 1) % coarse_poly->totloop; + const int next_grid_x = 0; + const int next_grid_y = current_grid_x; + const int current_index = current_grid_y * grid_size + current_grid_x; + const int next_index = next_grid_y * grid_size + next_grid_x; + /* Copy displacement. */ + MDisps *next_displacement_grid = &ctx->mdisps[ + coarse_poly->loopstart + next_current_corner]; + float *next_displacement = next_displacement_grid->disps[next_index]; + copy_v3_v3(next_displacement, + current_displacement_grid->disps[current_index]); + SWAP(float, next_displacement[0], next_displacement[1]); + next_displacement[0] = -next_displacement[0]; + /* Copy mask, if exists. */ + if (current_mask_grid != NULL) { + GridPaintMask *next_mask_grid = &ctx->grid_paint_mask[ + coarse_poly->loopstart + next_current_corner]; + next_mask_grid->data[next_index] = + current_mask_grid->data[current_index]; + } +} + +static void multires_reshape_vertex_copy_to_prev( + MultiresReshapeContext *ctx, + const MPoly *coarse_poly, + const int current_corner, + const MDisps *current_displacement_grid, + const GridPaintMask *current_mask_grid, + const int current_grid_x, const int current_grid_y) +{ + const int grid_size = ctx->top_grid_size; + const int prev_current_corner = + (current_corner - 1 + coarse_poly->totloop) % coarse_poly->totloop; + const int prev_grid_x = current_grid_y; + const int prev_grid_y = 0; + const int current_index = current_grid_y * grid_size + current_grid_x; + const int prev_index = prev_grid_y * grid_size + prev_grid_x; + /* Copy displacement. */ + MDisps *prev_displacement_grid = &ctx->mdisps[ + coarse_poly->loopstart + prev_current_corner]; + float *prev_displacement = prev_displacement_grid->disps[prev_index]; + copy_v3_v3(prev_displacement, + current_displacement_grid->disps[current_index]); + SWAP(float, prev_displacement[0], prev_displacement[1]); + prev_displacement[1] = -prev_displacement[1]; + /* Copy mask, if exists. */ + if (current_mask_grid != NULL) { + GridPaintMask *prev_mask_grid = &ctx->grid_paint_mask[ + coarse_poly->loopstart + prev_current_corner]; + prev_mask_grid->data[prev_index] = + current_mask_grid->data[current_index]; + } +} + +static void copy_boundary_displacement( + MultiresReshapeContext *ctx, + const MPoly *coarse_poly, + const int corner, + const int grid_x, const int grid_y, + const MDisps *displacement_grid, + const GridPaintMask *mask_grid) +{ + if (grid_x == 0 && grid_y == 0) { + for (int i = 0; i < coarse_poly->totloop; i++) { + const int current_face_corner = + (corner + i) % coarse_poly->totloop; + const int grid_index = coarse_poly->loopstart + current_face_corner; + MDisps *current_displacement_grid = &ctx->mdisps[grid_index]; + GridPaintMask *current_mask_grid = + mask_grid != NULL ? &ctx->grid_paint_mask[grid_index] + : NULL; + multires_reshape_vertex_copy_to_next( + ctx, + coarse_poly, + current_face_corner, + current_displacement_grid, + current_mask_grid, + 0, 0); + } + } + else if (grid_x == 0) { + multires_reshape_vertex_copy_to_prev( + ctx, + coarse_poly, + corner, + displacement_grid, + mask_grid, + grid_x, grid_y); + } + else if (grid_y == 0) { + multires_reshape_vertex_copy_to_next( + ctx, + coarse_poly, + corner, + displacement_grid, + mask_grid, + grid_x, grid_y); + } +} + +static void multires_reshape_vertex_from_final_data( + MultiresReshapeContext *ctx, + const int ptex_face_index, + const float u, const float v, + const int coarse_poly_index, + const int coarse_corner, + const float final_P[3], const float final_mask) +{ + Subdiv *subdiv = ctx->subdiv; + const int grid_size = ctx->top_grid_size; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; + const int loop_index = coarse_poly->loopstart + coarse_corner; + /* Evaluate limit surface. */ + float P[3], dPdu[3], dPdv[3]; + BKE_subdiv_eval_limit_point_and_derivatives( + subdiv, ptex_face_index, u, v, P, dPdu, dPdv); + /* Get coordinate and corner configuration. */ + float grid_u, grid_v; + MDisps *displacement_grid; + GridPaintMask *grid_paint_mask = NULL; + int face_corner = coarse_corner; + int grid_corner = 0; + int grid_index; + if (coarse_poly->totloop == 4) { + float corner_u, corner_v; + face_corner = BKE_subdiv_rotate_quad_to_corner( + u, v, &corner_u, &corner_v); + grid_corner = face_corner; + grid_index = loop_index + face_corner; + BKE_subdiv_ptex_face_uv_to_grid_uv( + corner_u, corner_v, &grid_u, &grid_v); + } + else { + grid_index = loop_index; + BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, &grid_u, &grid_v); + } + displacement_grid = &ctx->mdisps[grid_index]; + if (ctx->grid_paint_mask != NULL) { + grid_paint_mask = &ctx->grid_paint_mask[grid_index]; + BLI_assert(grid_paint_mask->level == displacement_grid->level); + } + /* Convert object coordinate to a tangent space of displacement grid. */ + float D[3]; + sub_v3_v3v3(D, final_P, P); + float tangent_matrix[3][3]; + BKE_multires_construct_tangent_matrix( + tangent_matrix, dPdu, dPdv, grid_corner); + float inv_tangent_matrix[3][3]; + invert_m3_m3(inv_tangent_matrix, tangent_matrix); + float tangent_D[3]; + mul_v3_m3v3(tangent_D, inv_tangent_matrix, D); + /* Write tangent displacement. */ + const int grid_x = (grid_u * (grid_size - 1) + 0.5f); + const int grid_y = (grid_v * (grid_size - 1) + 0.5f); + const int index = grid_y * grid_size + grid_x; + copy_v3_v3(displacement_grid->disps[index], tangent_D); + /* Write mask grid. */ + if (grid_paint_mask != NULL) { + grid_paint_mask->data[index] = final_mask; + } + /* Copy boundary to the next/previous grids */ + copy_boundary_displacement( + ctx, coarse_poly, face_corner, grid_x, grid_y, + displacement_grid, grid_paint_mask); +} + +/* ============================================================================= + * Helpers to propagate displacement to higher levels. + */ + +typedef struct MultiresPropagateData { + /* Number of displacement grids. */ + int num_grids; + /* Resolution level up to which displacement is known. */ + int reshape_level; + /* Resolution up to which propagation is happening, affecting all the + * levels in [reshape_level + 1, top_level]. + */ + int top_level; + /* Grid sizes at the corresponding levels. */ + int reshape_grid_size; + int top_grid_size; + /* Keys to access CCG at different levels. */ + CCGKey reshape_level_key; + CCGKey top_level_key; + /* Original grid data, before any updates for reshape. + * Contains data at the reshape_level resolution level. + */ + CCGElem **orig_grids_data; + /* Custom data layers from a coarse mesh. */ + MDisps *mdisps; + GridPaintMask *grid_paint_mask; +} MultiresPropagateData; + +static CCGElem **allocate_grids(CCGKey *key, int num_grids) +{ + CCGElem **grids = MEM_calloc_arrayN( + num_grids, sizeof(CCGElem *), "reshape grids*"); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + grids[grid_index] = MEM_calloc_arrayN( + key->elem_size, + key->grid_area, + "reshape orig_grids_data elems"); + } + return grids; +} + +static void free_grids(CCGElem **grids, int num_grids) +{ + if (grids == NULL) { + return; + } + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + MEM_freeN(grids[grid_index]); + } + MEM_freeN(grids); +} + +/* Initialize element sizes and offsets. */ +static void multires_reshape_init_key_layers( + CCGKey *key, + const MultiresPropagateData *data) +{ + key->elem_size = 3 * sizeof(float); + if (data->grid_paint_mask != NULL) { + key->mask_offset = 3 * sizeof(float); + key->elem_size += sizeof(float); + key->has_mask = true; + } + else { + key->mask_offset = -1; + key->has_mask = false; + } + /* We never have normals in original grids. */ + key->normal_offset = -1; + key->has_normals = false; +} + +/* Initialize key used to access reshape grids at given level. */ +static void multires_reshape_init_level_key( + CCGKey *key, + const MultiresPropagateData *data, + const int level) +{ + key->level = level; + /* Init layers. */ + multires_reshape_init_key_layers(key, data); + /* By default, only 3 floats for coordinate, */ + key->grid_size = BKE_subdiv_grid_size_from_level(key->level); + key->grid_area = key->grid_size * key->grid_size; + key->grid_bytes = key->elem_size * key->grid_area; +} + +static void multires_reshape_store_original_grids( + MultiresPropagateData *data) +{ + const int num_grids = data->num_grids; + /* Original data to be backed up. */ + const MDisps *mdisps = data->mdisps; + const GridPaintMask *grid_paint_mask = data->grid_paint_mask; + /* Allocate grids for backup. */ + CCGKey *orig_key = &data->reshape_level_key; + CCGElem **orig_grids_data = allocate_grids(orig_key, num_grids); + /* Fill in grids. */ + const int orig_grid_size = data->reshape_grid_size; + const int top_grid_size = data->top_grid_size; + const int skip = (top_grid_size - 1) / (orig_grid_size - 1); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + CCGElem *orig_grid = orig_grids_data[grid_index]; + for (int y = 0; y < orig_grid_size; y++) { + const int top_y = y * skip; + for (int x = 0; x < orig_grid_size; x++) { + const int top_x = x * skip; + const int top_index = top_y * top_grid_size + top_x; + memcpy(CCG_grid_elem_co(orig_key, orig_grid, x, y), + mdisps[grid_index].disps[top_index], + sizeof(float) * 3); + if (orig_key->has_mask) { + *CCG_grid_elem_mask(orig_key, orig_grid, x, y) = + grid_paint_mask[grid_index].data[top_index]; + } + } + } + } + /* Store in the context. */ + data->orig_grids_data = orig_grids_data; +} + +static void multires_reshape_propagate_prepare( + MultiresPropagateData *data, + Mesh *coarse_mesh, + const int reshape_level, + const int top_level) +{ + BLI_assert(reshape_level <= top_level); + memset(data, 0, sizeof(*data)); + data->num_grids = coarse_mesh->totloop; + data->reshape_level = reshape_level; + data->top_level = top_level; + if (reshape_level == top_level) { + /* Nothing to do, reshape will happen on the whole grid content. */ + return; + } + data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); + data->grid_paint_mask = + CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK); + data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level); + data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level); + /* Initialize keys to access CCG at different levels. */ + multires_reshape_init_level_key( + &data->reshape_level_key, data, data->reshape_level); + multires_reshape_init_level_key( + &data->top_level_key, data, data->top_level); + /* Make a copy of grids before reshaping, so we can calculate deltas + * later on. + */ + multires_reshape_store_original_grids(data); +} + +static void multires_reshape_propagate_prepare_from_mmd( + MultiresPropagateData *data, + struct Depsgraph *depsgraph, + Object *object, + const MultiresModifierData *mmd, + const int top_level, + const bool use_render_params) +{ + /* TODO(sergey): Find mode reliable way of getting current level. */ + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Mesh *mesh = object->data; + const int level = multires_get_level( + scene_eval, object, mmd, use_render_params, true); + multires_reshape_propagate_prepare(data, mesh, level, top_level); +} + +/* Calculate delta of changed reshape level data layers. Delta goes to a + * grids at top level (meaning, the result grids are only partially filled + * in). + */ +static void multires_reshape_calculate_delta( + MultiresPropagateData *data, + CCGElem **delta_grids_data) +{ + const int num_grids = data->num_grids; + /* At this point those custom data layers has updated data for the + * level we are propagating from. + */ + const MDisps *mdisps = data->mdisps; + const GridPaintMask *grid_paint_mask = data->grid_paint_mask; + CCGKey *reshape_key = &data->reshape_level_key; + CCGKey *delta_level_key = &data->top_level_key; + /* Calculate delta. */ + const int top_grid_size = data->top_grid_size; + const int reshape_grid_size = data->reshape_grid_size; + const int delta_grid_size = data->top_grid_size; + const int skip = (top_grid_size - 1) / (reshape_grid_size - 1); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + /*const*/ CCGElem *orig_grid = data->orig_grids_data[grid_index]; + CCGElem *delta_grid = delta_grids_data[grid_index]; + for (int y = 0; y < reshape_grid_size; y++) { + const int top_y = y * skip; + for (int x = 0; x < reshape_grid_size; x++) { + const int top_x = x * skip; + const int top_index = top_y * delta_grid_size + top_x; + sub_v3_v3v3( + CCG_grid_elem_co( + delta_level_key, delta_grid, top_x, top_y), + mdisps[grid_index].disps[top_index], + CCG_grid_elem_co(reshape_key, orig_grid, x, y)); + if (delta_level_key->has_mask) { + const float old_mask_value = *CCG_grid_elem_mask( + reshape_key, orig_grid, x, y); + const float new_mask_value = + grid_paint_mask[grid_index].data[top_index]; + *CCG_grid_elem_mask( + delta_level_key, delta_grid, top_x, top_y) = + new_mask_value - old_mask_value; + } + } + } + } +} + +/* Makes it so delta is propagated onto all the higher levels, but is also + * that this delta is smoothed in a way that it does not cause artifacts on + * boundaries. + */ + +typedef struct MultiresPropagateCornerData { + float coord_delta[3]; + float mask_delta; +} MultiresPropagateCornerData; + +BLI_INLINE void multires_reshape_propagate_init_patch_corners( + MultiresPropagateData *data, + CCGElem *delta_grid, + const int patch_x, const int patch_y, + MultiresPropagateCornerData r_corners[4]) +{ + CCGKey *delta_level_key = &data->top_level_key; + const int orig_grid_size = data->reshape_grid_size; + const int top_grid_size = data->top_grid_size; + const int skip = (top_grid_size - 1) / (orig_grid_size - 1); + const int x = patch_x * skip; + const int y = patch_y * skip; + /* Store coordinate deltas. */ + copy_v3_v3(r_corners[0].coord_delta, + CCG_grid_elem_co(delta_level_key, delta_grid, x, y)); + copy_v3_v3(r_corners[1].coord_delta, + CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y)); + copy_v3_v3(r_corners[2].coord_delta, + CCG_grid_elem_co(delta_level_key, delta_grid, x, y + skip)); + copy_v3_v3(r_corners[3].coord_delta, + CCG_grid_elem_co(delta_level_key, delta_grid, + x + skip, y + skip)); + if (delta_level_key->has_mask) { + r_corners[0].mask_delta = + *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y); + r_corners[1].mask_delta = + *CCG_grid_elem_mask(delta_level_key, delta_grid, + x + skip, y); + r_corners[2].mask_delta = + *CCG_grid_elem_mask(delta_level_key, delta_grid, + x, y + skip); + r_corners[3].mask_delta = + *CCG_grid_elem_mask(delta_level_key, delta_grid, + x + skip, y + skip); + } +} + +BLI_INLINE void multires_reshape_propagate_interpolate_coord( + float delta[3], + const MultiresPropagateCornerData corners[4], + const float weights[4]) +{ + interp_v3_v3v3v3v3( + delta, + corners[0].coord_delta, corners[1].coord_delta, + corners[2].coord_delta, corners[3].coord_delta, + weights); +} + +BLI_INLINE float multires_reshape_propagate_interpolate_mask( + const MultiresPropagateCornerData corners[4], + const float weights[4]) +{ + return corners[0].mask_delta * weights[0] + + corners[1].mask_delta * weights[1] + + corners[2].mask_delta * weights[2] + + corners[3].mask_delta * weights[3]; +} + +BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid_patch( + MultiresPropagateData *data, + CCGElem *delta_grid, + const int patch_x, const int patch_y) +{ + CCGKey *delta_level_key = &data->top_level_key; + const int orig_grid_size = data->reshape_grid_size; + const int top_grid_size = data->top_grid_size; + const int skip = (top_grid_size - 1) / (orig_grid_size - 1); + const float skip_inv = 1.0f / (float)skip; + MultiresPropagateCornerData corners[4]; + multires_reshape_propagate_init_patch_corners( + data, delta_grid, patch_x, patch_y, corners); + const int start_x = patch_x * skip; + const int start_y = patch_y * skip; + for (int y = 0; y <= skip; y++) { + const float v = (float)y * skip_inv; + const int final_y = start_y + y; + for (int x = 0; x <= skip; x++) { + const float u = (float)x * skip_inv; + const int final_x = start_x + x; + const float linear_weights[4] = {(1.0f - u) * (1.0f - v), + u * (1.0f - v), + (1.0f - u) * v, + u * v}; + multires_reshape_propagate_interpolate_coord( + CCG_grid_elem_co(delta_level_key, delta_grid, + final_x, final_y), + corners, + linear_weights); + if (delta_level_key->has_mask) { + float *mask = CCG_grid_elem_mask(delta_level_key, delta_grid, + final_x, final_y); + *mask = multires_reshape_propagate_interpolate_mask( + corners, linear_weights); + } + } + } +} + +BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid( + MultiresPropagateData *data, + CCGElem *delta_grid) +{ + const int orig_grid_size = data->reshape_grid_size; + for (int patch_y = 0; patch_y < orig_grid_size - 1; patch_y++) { + for (int patch_x = 0; patch_x < orig_grid_size - 1; patch_x++) { + multires_reshape_propagate_and_smooth_delta_grid_patch( + data, delta_grid, patch_x, patch_y); + } + } +} + +/* Entry point to propagate+smooth. */ +static void multires_reshape_propagate_and_smooth_delta( + MultiresPropagateData *data, + CCGElem **delta_grids_data) +{ + const int num_grids = data->num_grids; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + CCGElem *delta_grid = delta_grids_data[grid_index]; + multires_reshape_propagate_and_smooth_delta_grid(data, delta_grid); + } +} + +/* Apply smoothed deltas on the actual data layers. */ +static void multires_reshape_propagate_apply_delta( + MultiresPropagateData *data, + CCGElem **delta_grids_data) +{ + const int num_grids = data->num_grids; + /* At this point those custom data layers has updated data for the + * level we are propagating from. + */ + MDisps *mdisps = data->mdisps; + GridPaintMask *grid_paint_mask = data->grid_paint_mask; + CCGKey *orig_key = &data->reshape_level_key; + CCGKey *delta_level_key = &data->top_level_key; + CCGElem **orig_grids_data = data->orig_grids_data; + const int orig_grid_size = data->reshape_grid_size; + const int top_grid_size = data->top_grid_size; + const int skip = (top_grid_size - 1) / (orig_grid_size - 1); + /* Restore grid values at the reshape level. Those values are to be changed + * to the accommodate for the smooth delta. + */ + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + CCGElem *orig_grid = orig_grids_data[grid_index]; + for (int y = 0; y < orig_grid_size; y++) { + const int top_y = y * skip; + for (int x = 0; x < orig_grid_size; x++) { + const int top_x = x * skip; + const int top_index = top_y * top_grid_size + top_x; + copy_v3_v3(mdisps[grid_index].disps[top_index], + CCG_grid_elem_co(orig_key, orig_grid, x, y)); + if (grid_paint_mask != NULL) { + grid_paint_mask[grid_index].data[top_index] = + *CCG_grid_elem_mask(orig_key, orig_grid, x, y); + } + } + } + } + /* Add smoothed delta to all the levels. */ + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + CCGElem *delta_grid = delta_grids_data[grid_index]; + for (int y = 0; y < top_grid_size; y++) { + for (int x = 0; x < top_grid_size; x++) { + const int top_index = y * top_grid_size + x; + add_v3_v3(mdisps[grid_index].disps[top_index], + CCG_grid_elem_co(delta_level_key, delta_grid, x, y)); + if (delta_level_key->has_mask) { + grid_paint_mask[grid_index].data[top_index] += + *CCG_grid_elem_mask( + delta_level_key, delta_grid, x, y); + } + } + } + } +} + +static void multires_reshape_propagate(MultiresPropagateData *data) +{ + if (data->reshape_level == data->top_level) { + return; + } + const int num_grids = data->num_grids; + /* Calculate delta made at the reshape level. */ + CCGKey *delta_level_key = &data->top_level_key; + CCGElem **delta_grids_data = allocate_grids(delta_level_key, num_grids); + multires_reshape_calculate_delta(data, delta_grids_data); + /* Propagate deltas to the higher levels. */ + multires_reshape_propagate_and_smooth_delta(data, delta_grids_data); + /* Finally, apply smoothed deltas. */ + multires_reshape_propagate_apply_delta(data, delta_grids_data); + /* Cleanup. */ + free_grids(delta_grids_data, num_grids); +} + +static void multires_reshape_propagate_free(MultiresPropagateData *data) +{ + free_grids(data->orig_grids_data, data->num_grids); +} + +/* ============================================================================= + * Reshape from deformed vertex coordinates. + */ + +typedef struct MultiresReshapeFromDeformedVertsContext { + MultiresReshapeContext reshape_ctx; + const float (*deformed_verts)[3]; + int num_deformed_verts; +} MultiresReshapeFromDeformedVertsContext; + +static bool multires_reshape_topology_info( + const SubdivForeachContext *foreach_context, + const int num_vertices, + const int UNUSED(num_edges), + const int UNUSED(num_loops), + const int UNUSED(num_polygons)) +{ + MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; + if (num_vertices != ctx->num_deformed_verts) { + return false; + } + return true; +} + +static void multires_reshape_vertex( + MultiresReshapeFromDeformedVertsContext *ctx, + const int ptex_face_index, + const float u, const float v, + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index) +{ + const float *final_P = ctx->deformed_verts[subdiv_vertex_index]; + multires_reshape_vertex_from_final_data( + &ctx->reshape_ctx, + ptex_face_index, u, v, + coarse_poly_index, + coarse_corner, + final_P, 0.0f); +} + +static void multires_reshape_vertex_inner( + const SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float u, const float v, + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index) +{ + MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; + multires_reshape_vertex( + ctx, + ptex_face_index, u, v, + coarse_poly_index, + coarse_corner, + subdiv_vertex_index); +} + +static void multires_reshape_vertex_every_corner( + const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float u, const float v, + const int UNUSED(coarse_vertex_index), + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index) +{ + MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; + multires_reshape_vertex( + ctx, + ptex_face_index, u, v, + coarse_poly_index, + coarse_corner, + subdiv_vertex_index); +} + +static void multires_reshape_vertex_every_edge( + const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float u, const float v, + const int UNUSED(coarse_edge_index), + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index) +{ + MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data; + multires_reshape_vertex( + ctx, + ptex_face_index, u, v, + coarse_poly_index, + coarse_corner, + subdiv_vertex_index); +} + +static Subdiv *multires_create_subdiv_for_reshape( + struct Depsgraph *depsgraph, + /*const*/ Object *object, + const MultiresModifierData *mmd) +{ + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *object_eval = DEG_get_evaluated_object(depsgraph, object); + Mesh *deformed_mesh = mesh_get_eval_deform( + depsgraph, scene_eval, object_eval, CD_MASK_BAREMESH); + SubdivSettings subdiv_settings; + BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); + Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh); + if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) { + BKE_subdiv_free(subdiv); + return NULL; + } + return subdiv; +} + +static bool multires_reshape_from_vertcos( + struct Depsgraph *depsgraph, + Object *object, + const MultiresModifierData *mmd, + const float (*deformed_verts)[3], + const int num_deformed_verts, + const bool use_render_params) +{ + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Mesh *coarse_mesh = object->data; + MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); + /* Make sure displacement grids are ready. */ + multires_reshape_ensure_grids(coarse_mesh, mmd->totlvl); + /* Pick maximum between multires level and dispalcement level. + * This is because mesh can be used by objects with multires at different + * levels. + * + * TODO(sergey): At this point it should be possible to always use + * mdisps->level. + */ + const int top_level = max_ii(mmd->totlvl, mdisps->level); + /* Construct context. */ + MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = { + .reshape_ctx = { + .coarse_mesh = coarse_mesh, + .mdisps = mdisps, + .grid_paint_mask = NULL, + .top_grid_size = BKE_subdiv_grid_size_from_level(top_level), + .top_level = top_level, + }, + .deformed_verts = deformed_verts, + .num_deformed_verts = num_deformed_verts, + }; + SubdivForeachContext foreach_context = { + .topology_info = multires_reshape_topology_info, + .vertex_inner = multires_reshape_vertex_inner, + .vertex_every_edge = multires_reshape_vertex_every_edge, + .vertex_every_corner = multires_reshape_vertex_every_corner, + .user_data = &reshape_deformed_verts_ctx, + }; + /* Initialize subdivision surface. */ + Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd); + if (subdiv == NULL) { + return false; + } + reshape_deformed_verts_ctx.reshape_ctx.subdiv = subdiv; + /* Initialize mesh rasterization settings. */ + SubdivToMeshSettings mesh_settings; + BKE_multires_subdiv_mesh_settings_init( + &mesh_settings, scene_eval, object, mmd, use_render_params, true); + /* Initialize propagation to higher levels. */ + MultiresPropagateData propagate_data; + multires_reshape_propagate_prepare_from_mmd( + &propagate_data, depsgraph, object, mmd, top_level, use_render_params); + /* Run all the callbacks. */ + BKE_subdiv_foreach_subdiv_geometry( + subdiv, + &foreach_context, + &mesh_settings, + coarse_mesh); + BKE_subdiv_free(subdiv); + /* Update higher levels if needed. */ + multires_reshape_propagate(&propagate_data); + multires_reshape_propagate_free(&propagate_data); + return true; +} + +/* ============================================================================= + * Reshape from object. + */ + +/* Returns truth on success, false otherwise. + * + * This function might fail in cases like source and destination not having + * matched amount of vertices. + */ +bool multiresModifier_reshapeFromObject( + struct Depsgraph *depsgraph, + MultiresModifierData *mmd, + Object *dst, + Object *src) +{ + /* Would be cool to support this eventually, but it is very tricky to match + * vertices order even for meshes, when mixing meshes and other objects it's + * even more tricky. + */ + if (src->type != OB_MESH) { + return false; + } + MultiresModifierData reshape_mmd; + multires_reshape_init_mmd(&reshape_mmd, mmd); + /* Get evaluated vertices locations to reshape to. */ + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *src_eval = DEG_get_evaluated_object(depsgraph, src); + Mesh *src_mesh_eval = mesh_get_eval_final( + depsgraph, scene_eval, src_eval, CD_MASK_BAREMESH); + int num_deformed_verts; + float (*deformed_verts)[3] = BKE_mesh_vertexCos_get( + src_mesh_eval, &num_deformed_verts); + bool result = multires_reshape_from_vertcos( + depsgraph, + dst, + &reshape_mmd, + deformed_verts, + num_deformed_verts, + false); + MEM_freeN(deformed_verts); + return result; +} + +/* ============================================================================= + * Reshape from modifier. + */ + +bool multiresModifier_reshapeFromDeformModifier( + struct Depsgraph *depsgraph, + MultiresModifierData *mmd, + Object *object, + ModifierData *md) +{ + MultiresModifierData highest_mmd; + /* It is possible that the current subdivision level of multires is lower + * that it's maximum possible one (i.e., viewport is set to a lower level + * for the performance purposes). But even then, we want all the multires + * levels to be reshaped. Most accurate way to do so is to ignore all + * simplifications and calculate deformation modifier for the highest + * possible multires level. + * Alternative would be propagate displacement from current level to a + * higher ones, but that is likely to cause artifacts. + */ + multires_reshape_init_mmd_top_level(&highest_mmd, mmd); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + /* Perform sanity checks and early output. */ + if (multires_get_level( + scene_eval, object, &highest_mmd, false, true) == 0) + { + return false; + } + /* Create mesh for the multires, ignoring any further modifiers (leading + * deformation modifiers will be applied though). + */ + Mesh *multires_mesh = BKE_multires_create_mesh( + depsgraph, scene_eval, &highest_mmd, object); + int num_deformed_verts; + float (*deformed_verts)[3] = BKE_mesh_vertexCos_get( + multires_mesh, &num_deformed_verts); + /* Apply deformation modifier on the multires, */ + const ModifierEvalContext modifier_ctx = { + .depsgraph = depsgraph, + .object = object, + .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY}; + modwrap_deformVerts( + md, &modifier_ctx, multires_mesh, deformed_verts, + multires_mesh->totvert); + BKE_id_free(NULL, multires_mesh); + /* Reshaping */ + bool result = multires_reshape_from_vertcos( + depsgraph, + object, + &highest_mmd, + deformed_verts, + num_deformed_verts, + false); + /* Cleanup */ + MEM_freeN(deformed_verts); + return result; +} + +/* ============================================================================= + * Reshape from grids. + */ + +typedef struct ReshapeFromCCGTaskData { + MultiresReshapeContext reshape_ctx; + int *face_ptex_offset; + const CCGKey *key; + /*const*/ CCGElem **grids; +} ReshapeFromCCGTaskData; + +static void reshape_from_ccg_regular_face(ReshapeFromCCGTaskData *data, + const MPoly *coarse_poly) +{ + const CCGKey *key = data->key; + /*const*/ CCGElem **grids = data->grids; + const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int key_grid_size = key->grid_size; + const int key_grid_size_1 = key_grid_size - 1; + const int resolution = 2 * key_grid_size - 1; + const float resolution_1_inv = 1.0f / (float)(resolution - 1); + const int coarse_poly_index = coarse_poly - coarse_mpoly; + const int ptex_face_index = data->face_ptex_offset[coarse_poly_index]; + for (int y = 0; y < resolution; y++) { + const float v = y * resolution_1_inv; + for (int x = 0; x < resolution; x++) { + const float u = x * resolution_1_inv; + float corner_u, corner_v; + float grid_u, grid_v; + const int face_corner = BKE_subdiv_rotate_quad_to_corner( + u, v, &corner_u, &corner_v); + BKE_subdiv_ptex_face_uv_to_grid_uv( + corner_u, corner_v, &grid_u, &grid_v); + /*const*/ CCGElem *grid = + grids[coarse_poly->loopstart + face_corner]; + /*const*/ CCGElem *grid_element = CCG_grid_elem( + key, + grid, + key_grid_size_1 * grid_u, + key_grid_size_1 * grid_v); + const float *final_P = CCG_elem_co(key, grid_element); + float final_mask = 0.0f; + if (key->has_mask) { + final_mask = *CCG_elem_mask(key, grid_element); + } + multires_reshape_vertex_from_final_data( + &data->reshape_ctx, + ptex_face_index, + u, v, + coarse_poly_index, + 0, + final_P, final_mask); + } + } +} + +static void reshape_from_ccg_special_face(ReshapeFromCCGTaskData *data, + const MPoly *coarse_poly) +{ + const CCGKey *key = data->key; + /*const*/ CCGElem **grids = data->grids; + const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int key_grid_size = key->grid_size; + const int key_grid_size_1 = key_grid_size - 1; + const int resolution = key_grid_size; + const float resolution_1_inv = 1.0f / (float)(resolution - 1); + const int coarse_poly_index = coarse_poly - coarse_mpoly; + const int ptex_face_index = data->face_ptex_offset[coarse_poly_index]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + for (int y = 0; y < resolution; y++) { + const float v = y * resolution_1_inv; + for (int x = 0; x < resolution; x++) { + const float u = x * resolution_1_inv; + float grid_u, grid_v; + BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, &grid_u, &grid_v); + /*const*/ CCGElem *grid = + grids[coarse_poly->loopstart + corner]; + /*const*/ CCGElem *grid_element = CCG_grid_elem( + key, + grid, + key_grid_size_1 * grid_u, + key_grid_size_1 * grid_v); + const float *final_P = CCG_elem_co(key, grid_element); + float final_mask = 0.0f; + if (key->has_mask) { + final_mask = *CCG_elem_mask(key, grid_element); + } + multires_reshape_vertex_from_final_data( + &data->reshape_ctx, + ptex_face_index + corner, + u, v, + coarse_poly_index, + corner, + final_P, final_mask); + } + } + } +} + +static void reshape_from_ccg_task( + void *__restrict userdata, + const int coarse_poly_index, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + ReshapeFromCCGTaskData *data = userdata; + const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; + if (coarse_poly->totloop == 4) { + reshape_from_ccg_regular_face(data, coarse_poly); + } + else { + reshape_from_ccg_special_face(data, coarse_poly); + } +} + +bool multiresModifier_reshapeFromCCG( + const int tot_level, + Mesh *coarse_mesh, + SubdivCCG *subdiv_ccg) +{ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + /* Sanity checks. */ + if (coarse_mesh->totloop != subdiv_ccg->num_grids) { + /* Grids are supposed to eb created for each face-cornder (aka loop). */ + return false; + } + MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS); + GridPaintMask *grid_paint_mask = + CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK); + Subdiv *subdiv = subdiv_ccg->subdiv; + /* Make sure displacement grids are ready. */ + multires_reshape_ensure_grids(coarse_mesh, tot_level); + /* Pick maximum between multires level and dispalcement level. + * This is because mesh can be used by objects with multires at different + * levels. + * + * TODO(sergey): At this point it should be possible to always use + * mdisps->level. + */ + const int top_level = max_ii(tot_level, mdisps->level); + /* Construct context. */ + ReshapeFromCCGTaskData data = { + .reshape_ctx = { + .subdiv = subdiv, + .coarse_mesh = coarse_mesh, + .mdisps = mdisps, + .grid_paint_mask = grid_paint_mask, + .top_grid_size = BKE_subdiv_grid_size_from_level(top_level), + .top_level = top_level}, + .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv), + .key = &key, + .grids = subdiv_ccg->grids}; + /* Initialize propagation to higher levels. */ + MultiresPropagateData propagate_data; + multires_reshape_propagate_prepare( + &propagate_data, coarse_mesh, key.level, top_level); + /* Threaded grids iteration. */ + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + BLI_task_parallel_range(0, coarse_mesh->totpoly, + &data, + reshape_from_ccg_task, + ¶llel_range_settings); + /* Update higher levels if needed. */ + multires_reshape_propagate(&propagate_data); + multires_reshape_propagate_free(&propagate_data); + return true; +} diff --git a/source/blender/blenkernel/intern/multires_subdiv.c b/source/blender/blenkernel/intern/multires_subdiv.c new file mode 100644 index 00000000000..e0b316d49de --- /dev/null +++ b/source/blender/blenkernel/intern/multires_subdiv.c @@ -0,0 +1,67 @@ +/* + * ***** 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) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/multires_subdiv.c + * \ingroup bke + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" + +#include "BLI_utildefines.h" + +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_mesh.h" + +void BKE_multires_subdiv_settings_init( + SubdivSettings *settings, + const MultiresModifierData *mmd) +{ + settings->is_simple = (mmd->simple != 0); + settings->is_adaptive = !settings->is_simple; + settings->level = mmd->quality; + settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY; + settings->fvar_linear_interpolation = + BKE_subdiv_fvar_interpolation_from_uv_smooth(mmd->uv_smooth); +} + +void BKE_multires_subdiv_mesh_settings_init( + SubdivToMeshSettings *mesh_settings, + const Scene *scene, + const Object *object, + const MultiresModifierData *mmd, + const bool use_render_params, + const bool ignore_simplify) +{ + const int level = multires_get_level( + scene, object, mmd, use_render_params, ignore_simplify); + mesh_settings->resolution = (1 << level) + 1; +} diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c deleted file mode 100644 index 35bcca52f63..00000000000 --- a/source/blender/blenkernel/intern/navmesh_conversion.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/navmesh_conversion.c - * \ingroup bke - */ - -#include <math.h> -#include <stdlib.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_meshdata_types.h" - -#include "BLI_utildefines.h" -#include "BLI_math.h" -#include "BLI_sort.h" - -#include "BKE_navmesh_conversion.h" -#include "BKE_cdderivedmesh.h" - -#include "recast-capi.h" - -BLI_INLINE float area2(const float *a, const float *b, const float *c) -{ - return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]); -} - -BLI_INLINE int left(const float *a, const float *b, const float *c) -{ - return area2(a, b, c) < 0; -} - -int polyNumVerts(const unsigned short *p, const int vertsPerPoly) -{ - int i, nv = 0; - for (i = 0; i < vertsPerPoly; i++) { - if (p[i] == 0xffff) - break; - nv++; - } - return nv; -} - -int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts) -{ - int j, nv = polyNumVerts(p, vertsPerPoly); - if (nv < 3) - return 0; - for (j = 0; j < nv; j++) { - const float *v = &verts[3 * p[j]]; - const float *v_next = &verts[3 * p[(j + 1) % nv]]; - const float *v_prev = &verts[3 * p[(nv + j - 1) % nv]]; - if (!left(v_prev, v, v_next)) - return 0; - - } - return 1; -} - -/* XXX, could replace with #dist_to_line_segment_v3(), or add a squared version */ -float distPointToSegmentSq(const float point[3], const float a[3], const float b[3]) -{ - float abx[3], dx[3]; - float d, t; - - sub_v3_v3v3(abx, b, a); - sub_v3_v3v3(dx, point, a); - - d = abx[0] * abx[0] + abx[2] * abx[2]; - t = abx[0] * dx[0] + abx[2] * dx[2]; - - if (d > 0.0f) - t /= d; - if (t < 0.0f) - t = 0.0f; - else if (t > 1.0f) - t = 1.0f; - dx[0] = a[0] + t * abx[0] - point[0]; - dx[2] = a[2] + t * abx[2] - point[2]; - - return dx[0] * dx[0] + dx[2] * dx[2]; -} - -int buildRawVertIndicesData(DerivedMesh *dm, int *nverts_r, float **verts_r, - int *ntris_r, unsigned short **tris_r, int **trisToFacesMap_r, - int **recastData) -{ - int vi, fi, triIdx; - int nverts, ntris; - int *trisToFacesMap; - float *verts; - unsigned short *tris, *tri; - int nfaces; - MFace *faces; - - nverts = dm->getNumVerts(dm); - if (nverts >= 0xffff) { - printf("Converting navmesh: Error! Too many vertices. Max number of vertices %d\n", 0xffff); - return 0; - } - if (nverts == 0) { - printf("Converting navmesh: Error! There are no vertices!\n"); - return 0; - } - - verts = MEM_mallocN(sizeof(float[3]) * nverts, "buildRawVertIndicesData verts"); - dm->getVertCos(dm, (float(*)[3])verts); - - /* flip coordinates */ - for (vi = 0; vi < nverts; vi++) { - SWAP(float, verts[3 * vi + 1], verts[3 * vi + 2]); - } - - /* calculate number of tris */ - dm->recalcTessellation(dm); - nfaces = dm->getNumTessFaces(dm); - if (nfaces == 0) { - printf("Converting navmesh: Error! There are %i vertices, but no faces!\n", nverts); - return 0; - } - - faces = dm->getTessFaceArray(dm); - ntris = nfaces; - for (fi = 0; fi < nfaces; fi++) { - MFace *face = &faces[fi]; - if (face->v4) - ntris++; - } - - /* copy and transform to triangles (reorder on the run) */ - trisToFacesMap = MEM_callocN(sizeof(int) * ntris, "buildRawVertIndicesData trisToFacesMap"); - tris = MEM_callocN(sizeof(unsigned short) * 3 * ntris, "buildRawVertIndicesData tris"); - tri = tris; - triIdx = 0; - for (fi = 0; fi < nfaces; fi++) { - MFace *face = &faces[fi]; - tri[3 * triIdx + 0] = (unsigned short) face->v1; - tri[3 * triIdx + 1] = (unsigned short) face->v3; - tri[3 * triIdx + 2] = (unsigned short) face->v2; - trisToFacesMap[triIdx++] = fi; - if (face->v4) { - tri[3 * triIdx + 0] = (unsigned short) face->v1; - tri[3 * triIdx + 1] = (unsigned short) face->v4; - tri[3 * triIdx + 2] = (unsigned short) face->v3; - trisToFacesMap[triIdx++] = fi; - } - } - - /* carefully, recast data is just reference to data in derived mesh */ - *recastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST); - - *nverts_r = nverts; - *verts_r = verts; - *ntris_r = ntris; - *tris_r = tris; - *trisToFacesMap_r = trisToFacesMap; - - return 1; -} - -int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys, - unsigned short *polys, const unsigned short *dmeshes, - const float *verts, const unsigned short *dtris, - const int *dtrisToPolysMap) -{ - int polyidx; - int capacity = vertsPerPoly; - unsigned short *newPoly = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPoly"); - memset(newPoly, 0xff, sizeof(unsigned short) * capacity); - - for (polyidx = 0; polyidx < npolys; polyidx++) { - size_t i; - int j, k; - int nv = 0; - /* search border */ - int tri, btri = -1; - int edge, bedge = -1; - int dtrisNum = dmeshes[polyidx * 4 + 3]; - int dtrisBase = dmeshes[polyidx * 4 + 2]; - unsigned char *traversedTris = MEM_callocN(sizeof(unsigned char) * dtrisNum, "buildPolygonsByDetailedMeshes traversedTris"); - unsigned short *adjustedPoly; - int adjustedNv; - int allBorderTraversed; - - for (j = 0; j < dtrisNum && btri == -1; j++) { - int curpolytri = dtrisBase + j; - for (k = 0; k < 3; k++) { - unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k]; - if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) { - btri = curpolytri; - bedge = k; - break; - } - } - } - if (btri == -1 || bedge == -1) { - /* can't find triangle with border edge */ - MEM_freeN(traversedTris); - MEM_freeN(newPoly); - - return 0; - } - - newPoly[nv++] = dtris[btri * 3 * 2 + bedge]; - tri = btri; - edge = (bedge + 1) % 3; - traversedTris[tri - dtrisBase] = 1; - while (tri != btri || edge != bedge) { - int neighbortri = dtris[tri * 3 * 2 + 3 + edge]; - if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) { - if (nv == capacity) { - unsigned short *newPolyBig; - capacity += vertsPerPoly; - newPolyBig = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPolyBig"); - memset(newPolyBig, 0xff, sizeof(unsigned short) * capacity); - memcpy(newPolyBig, newPoly, sizeof(unsigned short) * nv); - MEM_freeN(newPoly); - newPoly = newPolyBig; - } - newPoly[nv++] = dtris[tri * 3 * 2 + edge]; - /* move to next edge */ - edge = (edge + 1) % 3; - } - else { - /* move to next tri */ - int twinedge = -1; - for (k = 0; k < 3; k++) { - if (dtris[neighbortri * 3 * 2 + 3 + k] == tri) { - twinedge = k; - break; - } - } - if (twinedge == -1) { - printf("Converting navmesh: Error! Can't find neighbor edge - invalid adjacency info\n"); - MEM_freeN(traversedTris); - goto returnLabel; - } - tri = neighbortri; - edge = (twinedge + 1) % 3; - traversedTris[tri - dtrisBase] = 1; - } - } - - adjustedPoly = MEM_callocN(sizeof(unsigned short) * nv, "buildPolygonsByDetailedMeshes adjustedPoly"); - adjustedNv = 0; - for (i = 0; i < nv; i++) { - unsigned short prev = newPoly[(nv + i - 1) % nv]; - unsigned short cur = newPoly[i]; - unsigned short next = newPoly[(i + 1) % nv]; - float distSq = distPointToSegmentSq(&verts[3 * cur], &verts[3 * prev], &verts[3 * next]); - static const float tolerance = 0.001f; - if (distSq > tolerance) - adjustedPoly[adjustedNv++] = cur; - } - memcpy(newPoly, adjustedPoly, adjustedNv * sizeof(unsigned short)); - MEM_freeN(adjustedPoly); - nv = adjustedNv; - - allBorderTraversed = 1; - for (i = 0; i < dtrisNum; i++) { - if (traversedTris[i] == 0) { - /* check whether it has border edges */ - int curpolytri = dtrisBase + i; - for (k = 0; k < 3; k++) { - unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k]; - if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) { - allBorderTraversed = 0; - break; - } - } - } - } - - if (nv <= vertsPerPoly && allBorderTraversed) { - for (i = 0; i < nv; i++) { - polys[polyidx * vertsPerPoly * 2 + i] = newPoly[i]; - } - } - - MEM_freeN(traversedTris); - } - -returnLabel: - MEM_freeN(newPoly); - - return 1; -} - -struct SortContext { - const int *recastData; - const int *trisToFacesMap; -}; - -static int compareByData(const void *a, const void *b, void *ctx) -{ - return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)a]] - - ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)b]]); -} - -int buildNavMeshData(const int nverts, const float *verts, - const int ntris, const unsigned short *tris, - const int *recastData, const int *trisToFacesMap, - int *ndtris_r, unsigned short **dtris_r, - int *npolys_r, unsigned short **dmeshes_r, unsigned short **polys_r, - int *vertsPerPoly_r, int **dtrisToPolysMap_r, int **dtrisToTrisMap_r) - -{ - int *trisMapping; - int i; - struct SortContext context; - int validTriStart, prevPolyIdx, curPolyIdx, newPolyIdx, prevpolyidx; - unsigned short *dmesh; - - int ndtris, npolys, vertsPerPoly; - unsigned short *dtris, *dmeshes, *polys; - int *dtrisToPolysMap, *dtrisToTrisMap; - - if (!recastData) { - printf("Converting navmesh: Error! Can't find recast custom data\n"); - return 0; - } - - trisMapping = MEM_callocN(sizeof(int) * ntris, "buildNavMeshData trisMapping"); - - /* sort the triangles by polygon idx */ - for (i = 0; i < ntris; i++) - trisMapping[i] = i; - context.recastData = recastData; - context.trisToFacesMap = trisToFacesMap; - BLI_qsort_r(trisMapping, ntris, sizeof(int), compareByData, &context); - - /* search first valid triangle - triangle of convex polygon */ - validTriStart = -1; - for (i = 0; i < ntris; i++) { - if (recastData[trisToFacesMap[trisMapping[i]]] > 0) { - validTriStart = i; - break; - } - } - - if (validTriStart < 0) { - printf("Converting navmesh: Error! No valid polygons in mesh\n"); - MEM_freeN(trisMapping); - return 0; - } - - ndtris = ntris - validTriStart; - /* fill dtris to faces mapping */ - dtrisToTrisMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToTrisMap"); - memcpy(dtrisToTrisMap, &trisMapping[validTriStart], ndtris * sizeof(int)); - MEM_freeN(trisMapping); - - /* create detailed mesh triangles - copy only valid triangles - * and reserve memory for adjacency info */ - dtris = MEM_callocN(sizeof(unsigned short) * 3 * 2 * ndtris, "buildNavMeshData dtris"); - memset(dtris, 0xff, sizeof(unsigned short) * 3 * 2 * ndtris); - for (i = 0; i < ndtris; i++) { - memcpy(dtris + 3 * 2 * i, tris + 3 * dtrisToTrisMap[i], sizeof(unsigned short) * 3); - } - - /* create new recast data corresponded to dtris and renumber for continuous indices */ - prevPolyIdx = -1; - newPolyIdx = 0; - dtrisToPolysMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToPolysMap"); - for (i = 0; i < ndtris; i++) { - curPolyIdx = recastData[trisToFacesMap[dtrisToTrisMap[i]]]; - if (curPolyIdx != prevPolyIdx) { - newPolyIdx++; - prevPolyIdx = curPolyIdx; - } - dtrisToPolysMap[i] = newPolyIdx; - } - - - /* build adjacency info for detailed mesh triangles */ - if (!recast_buildMeshAdjacency(dtris, ndtris, nverts, 3)) { - printf("Converting navmesh: Error! Unable to build mesh adjacency information\n"); - MEM_freeN(trisMapping); - MEM_freeN(dtrisToPolysMap); - return 0; - } - - /* create detailed mesh description for each navigation polygon */ - npolys = dtrisToPolysMap[ndtris - 1]; - dmeshes = MEM_callocN(sizeof(unsigned short) * npolys * 4, "buildNavMeshData dmeshes"); - memset(dmeshes, 0, npolys * 4 * sizeof(unsigned short)); - dmesh = NULL; - prevpolyidx = 0; - for (i = 0; i < ndtris; i++) { - int curpolyidx = dtrisToPolysMap[i]; - if (curpolyidx != prevpolyidx) { - if (curpolyidx != prevpolyidx + 1) { - printf("Converting navmesh: Error! Wrong order of detailed mesh faces\n"); - goto fail; - } - dmesh = dmesh == NULL ? dmeshes : dmesh + 4; - dmesh[2] = (unsigned short)i; /* tbase */ - dmesh[3] = 0; /* tnum */ - prevpolyidx = curpolyidx; - } - dmesh[3]++; - } - - /* create navigation polygons */ - vertsPerPoly = 6; - polys = MEM_callocN(sizeof(unsigned short) * npolys * vertsPerPoly * 2, "buildNavMeshData polys"); - memset(polys, 0xff, sizeof(unsigned short) * vertsPerPoly * 2 * npolys); - - if (!buildPolygonsByDetailedMeshes(vertsPerPoly, npolys, polys, dmeshes, verts, dtris, dtrisToPolysMap)) { - printf("Converting navmesh: Error! Unable to build polygons from detailed mesh\n"); - goto fail; - } - - *ndtris_r = ndtris; - *npolys_r = npolys; - *vertsPerPoly_r = vertsPerPoly; - *dtris_r = dtris; - *dmeshes_r = dmeshes; - *polys_r = polys; - *dtrisToPolysMap_r = dtrisToPolysMap; - *dtrisToTrisMap_r = dtrisToTrisMap; - - return 1; - -fail: - MEM_freeN(dmeshes); - MEM_freeN(dtrisToPolysMap); - MEM_freeN(dtrisToTrisMap); - return 0; -} - - -int buildNavMeshDataByDerivedMesh(DerivedMesh *dm, int *vertsPerPoly, - int *nverts, float **verts, - int *ndtris, unsigned short **dtris, - int *npolys, unsigned short **dmeshes, - unsigned short **polys, int **dtrisToPolysMap, - int **dtrisToTrisMap, int **trisToFacesMap) -{ - int res; - int ntris = 0, *recastData = NULL; - unsigned short *tris = NULL; - - res = buildRawVertIndicesData(dm, nverts, verts, &ntris, &tris, trisToFacesMap, &recastData); - if (!res) { - printf("Converting navmesh: Error! Can't get raw vertices and indices from mesh\n"); - goto exit; - } - - res = buildNavMeshData(*nverts, *verts, ntris, tris, recastData, *trisToFacesMap, - ndtris, dtris, npolys, dmeshes, polys, vertsPerPoly, - dtrisToPolysMap, dtrisToTrisMap); - if (!res) { - printf("Converting navmesh: Error! Can't build navmesh data from mesh\n"); - goto exit; - } - -exit: - if (tris) - MEM_freeN(tris); - - return res; -} - -int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx) -{ - int i, res = -1; - for (i = 0; i < vertsPerPoly; i++) { - if (p[i] == 0xffff) - break; - if (p[i] == vertexIdx) { - res = i; - break; - } - } - return res; -} diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 2f0af028abd..76671e0775d 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -60,7 +60,7 @@ #include "BKE_nla.h" #ifdef WITH_AUDASPACE -# include AUD_SPECIAL_H +# include <AUD_Special.h> #endif #include "RNA_access.h" @@ -76,7 +76,7 @@ /* Remove the given NLA strip from the NLA track it occupies, free the strip's data, * and the strip itself. */ -void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip) +void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user) { NlaStrip *cs, *csn; @@ -87,12 +87,13 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip) /* free child-strips */ for (cs = strip->strips.first; cs; cs = csn) { csn = cs->next; - BKE_nlastrip_free(&strip->strips, cs); + BKE_nlastrip_free(&strip->strips, cs, do_id_user); } /* remove reference to action */ - if (strip->act) + if (strip->act != NULL && do_id_user) { id_us_min(&strip->act->id); + } /* free remapping info */ //if (strip->remap) @@ -114,7 +115,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip) /* Remove the given NLA track from the set of NLA tracks, free the track's data, * and the track itself. */ -void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt) +void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user) { NlaStrip *strip, *stripn; @@ -125,7 +126,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt) /* free strips */ for (strip = nlt->strips.first; strip; strip = stripn) { stripn = strip->next; - BKE_nlastrip_free(&nlt->strips, strip); + BKE_nlastrip_free(&nlt->strips, strip, do_id_user); } /* free NLA track itself now */ @@ -138,7 +139,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt) /* Free the elements of type NLA Tracks provided in the given list, but do not free * the list itself since that is not free-standing */ -void BKE_nla_tracks_free(ListBase *tracks) +void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user) { NlaTrack *nlt, *nltn; @@ -149,7 +150,7 @@ void BKE_nla_tracks_free(ListBase *tracks) /* free tracks one by one */ for (nlt = tracks->first; nlt; nlt = nltn) { nltn = nlt->next; - BKE_nlatrack_free(tracks, nlt); + BKE_nlatrack_free(tracks, nlt, do_id_user); } /* clear the list's pointers to be safe */ @@ -162,12 +163,15 @@ void BKE_nla_tracks_free(ListBase *tracks) * Copy NLA strip * * \param use_same_action When true, the existing action is used (instead of being duplicated) + * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h */ -NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_action) +NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_action, const int flag) { NlaStrip *strip_d; NlaStrip *cs, *cs_d; + const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0; + /* sanity check */ if (strip == NULL) return NULL; @@ -179,12 +183,14 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac /* handle action */ if (strip_d->act) { if (use_same_action) { - /* increase user-count of action */ - id_us_plus(&strip_d->act->id); + if (do_id_user) { + /* increase user-count of action */ + id_us_plus(&strip_d->act->id); + } } else { /* use a copy of the action instead (user count shouldn't have changed yet) */ - strip_d->act = BKE_action_copy(bmain, strip_d->act); + BKE_id_copy_ex(bmain, &strip_d->act->id, (ID **)&strip_d->act, flag, false); } } @@ -196,7 +202,7 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac BLI_listbase_clear(&strip_d->strips); for (cs = strip->strips.first; cs; cs = cs->next) { - cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action); + cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action, flag); BLI_addtail(&strip_d->strips, cs_d); } @@ -204,8 +210,11 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac return strip_d; } -/* Copy NLA Track */ -NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_actions) +/** + * Copy a single NLA Track. + * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h + */ +NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_actions, const int flag) { NlaStrip *strip, *strip_d; NlaTrack *nlt_d; @@ -222,7 +231,7 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_acti BLI_listbase_clear(&nlt_d->strips); for (strip = nlt->strips.first; strip; strip = strip->next) { - strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions); + strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions, flag); BLI_addtail(&nlt_d->strips, strip_d); } @@ -230,8 +239,11 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_acti return nlt_d; } -/* Copy all NLA data */ -void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src) +/** + * Copy all NLA data. + * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h + */ +void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int flag) { NlaTrack *nlt, *nlt_d; @@ -246,7 +258,7 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src) for (nlt = src->first; nlt; nlt = nlt->next) { /* make a copy, and add the copy to the destination list */ // XXX: we need to fix this sometime - nlt_d = BKE_nlatrack_copy(bmain, nlt, true); + nlt_d = BKE_nlatrack_copy(bmain, nlt, true, flag); BLI_addtail(dst, nlt_d); } } @@ -752,7 +764,7 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip) } /* free the meta-strip now */ - BKE_nlastrip_free(strips, strip); + BKE_nlastrip_free(strips, strip, true); } /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips @@ -2013,30 +2025,3 @@ void BKE_nla_tweakmode_exit(AnimData *adt) adt->actstrip = NULL; adt->flag &= ~ADT_NLA_EDIT_ON; } - -/* Baking Tools ------------------------------------------- */ - -static void UNUSED_FUNCTION(BKE_nla_bake) (Scene *scene, ID *UNUSED(id), AnimData *adt, int UNUSED(flag)) -{ - - /* verify that data is valid - * 1) Scene and AnimData must be provided - * 2) there must be tracks to merge... - */ - if (ELEM(NULL, scene, adt, adt->nla_tracks.first)) - return; - - /* if animdata currently has an action, 'push down' this onto the stack first */ - if (adt->action) - BKE_nla_action_pushdown(adt); - - /* get range of motion to bake, and the channels involved... */ - - /* temporarily mute the action, and start keying to it */ - - /* start keying... */ - - /* unmute the action */ -} - -/* *************************************************** */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index b3f210dfba5..869e2849be5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -75,6 +75,8 @@ #include "NOD_shader.h" #include "NOD_texture.h" +#include "DEG_depsgraph.h" + #define NODE_DEFAULT_MAX_WIDTH 700 /* Fallback types for undefined tree, nodes, sockets */ @@ -1211,6 +1213,56 @@ void nodeDetachNode(struct bNode *node) } } +void nodePositionRelative(bNode *from_node, bNode *to_node, bNodeSocket *from_sock, bNodeSocket *to_sock) +{ + float offset_x; + int tot_sock_idx; + + /* Socket to plug into. */ + if (SOCK_IN == to_sock->in_out) { + offset_x = - (from_node->typeinfo->width + 50); + tot_sock_idx = BLI_listbase_count(&to_node->outputs); + tot_sock_idx += BLI_findindex(&to_node->inputs, to_sock); + } + else { + offset_x = to_node->typeinfo->width + 50; + tot_sock_idx = BLI_findindex(&to_node->outputs, to_sock); + } + + BLI_assert(tot_sock_idx != -1); + + float offset_y = U.widget_unit * tot_sock_idx; + + /* Output socket. */ + if (from_sock) { + if (SOCK_IN == from_sock->in_out) { + tot_sock_idx = BLI_listbase_count(&from_node->outputs); + tot_sock_idx += BLI_findindex(&from_node->inputs, from_sock); + } + else { + tot_sock_idx = BLI_findindex(&from_node->outputs, from_sock); + } + } + + BLI_assert(tot_sock_idx != -1); + + offset_y -= U.widget_unit * tot_sock_idx; + + from_node->locx = to_node->locx + offset_x; + from_node->locy = to_node->locy - offset_y; +} + +void nodePositionPropagate(bNode *node) +{ + for (bNodeSocket *nsock = node->inputs.first; nsock; nsock = nsock->next) { + if (nsock->link != NULL) { + bNodeLink *link = nsock->link; + nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock); + nodePositionPropagate(link->fromnode); + } + } +} + void ntreeInitDefault(bNodeTree *ntree) { ntree_set_typeinfo(ntree, NULL); @@ -1592,54 +1644,6 @@ void BKE_node_preview_set_pixel(bNodePreview *preview, const float col[4], int x } } -#if 0 -static void nodeClearPreview(bNode *node) -{ - if (node->preview && node->preview->rect) - memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect)); -} - -/* use it to enforce clear */ -void ntreeClearPreview(bNodeTree *ntree) -{ - bNode *node; - - if (ntree == NULL) - return; - - for (node = ntree->nodes.first; node; node = node->next) { - if (node->typeinfo->flag & NODE_PREVIEW) - nodeClearPreview(node); - if (node->type == NODE_GROUP) - ntreeClearPreview((bNodeTree *)node->id); - } -} - -/* hack warning! this function is only used for shader previews, and - * since it gets called multiple times per pixel for Ztransp we only - * add the color once. Preview gets cleared before it starts render though */ -void nodeAddToPreview(bNode *node, const float col[4], int x, int y, int do_manage) -{ - bNodePreview *preview = node->preview; - if (preview) { - if (x >= 0 && y >= 0) { - if (x < preview->xsize && y < preview->ysize) { - unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x); - - if (do_manage) { - linearrgb_to_srgb_uchar4(tar, col); - } - else { - rgba_float_to_uchar(tar, col); - } - } - //else printf("prv out bound x y %d %d\n", x, y); - } - //else printf("prv out bound x y %d %d\n", x, y); - } -} -#endif - /* ************** Free stuff ********** */ /* goes over entire tree */ @@ -1939,15 +1943,15 @@ void ntreeSetOutput(bNodeTree *ntree) * might be different for editor or for "real" use... */ } -bNodeTree *ntreeFromID(ID *id) +bNodeTree *ntreeFromID(const ID *id) { switch (GS(id->name)) { - case ID_MA: return ((Material *)id)->nodetree; - case ID_LA: return ((Lamp *)id)->nodetree; - case ID_WO: return ((World *)id)->nodetree; - case ID_TE: return ((Tex *)id)->nodetree; - case ID_SCE: return ((Scene *)id)->nodetree; - case ID_LS: return ((FreestyleLineStyle *)id)->nodetree; + case ID_MA: return ((const Material *)id)->nodetree; + case ID_LA: return ((const Lamp *)id)->nodetree; + case ID_WO: return ((const World *)id)->nodetree; + case ID_TE: return ((const Tex *)id)->nodetree; + case ID_SCE: return ((const Scene *)id)->nodetree; + case ID_LS: return ((const FreestyleLineStyle *)id)->nodetree; default: return NULL; } } @@ -1995,9 +1999,6 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) if (ntree) { bNodeTree *ltree; bNode *node; - AnimData *adt; - - bAction *action_backup = NULL, *tmpact_backup = NULL; BLI_spin_lock(&spin); if (!ntree->duplilock) { @@ -2007,23 +2008,16 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) BLI_mutex_lock(ntree->duplilock); - /* Workaround for copying an action on each render! - * set action to NULL so animdata actions don't get copied */ - adt = BKE_animdata_from_id(&ntree->id); - - if (adt) { - action_backup = adt->action; - tmpact_backup = adt->tmpact; - - adt->action = NULL; - adt->tmpact = NULL; - } - /* Make full copy outside of Main database. * Note: previews are not copied here. */ - BKE_id_copy_ex(NULL, (ID *)ntree, (ID **)<ree, - LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false); + BKE_id_copy_ex( + NULL, &ntree->id, (ID **)<ree, + (LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_COPY_NO_PREVIEW | + LIB_ID_COPY_NO_ANIMDATA), + false); ltree->flag |= NTREE_IS_LOCALIZED; for (node = ltree->nodes.first; node; node = node->next) { @@ -2032,31 +2026,19 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) } } - if (adt) { - AnimData *ladt = BKE_animdata_from_id(<ree->id); - - adt->action = ladt->action = action_backup; - adt->tmpact = ladt->tmpact = tmpact_backup; - - if (action_backup) - id_us_plus(&action_backup->id); - if (tmpact_backup) - id_us_plus(&tmpact_backup->id); - - } - /* end animdata uglyness */ - /* ensures only a single output node is enabled */ ntreeSetOutput(ntree); for (node = ntree->nodes.first; node; node = node->next) { /* store new_node pointer to original */ - node->new_node->new_node = node; + node->new_node->original = node; } if (ntree->typeinfo->localize) ntree->typeinfo->localize(ltree, ntree); + ltree->id.tag |= LIB_TAG_LOCALIZED; + BLI_mutex_unlock(ntree->duplilock); return ltree; @@ -3127,77 +3109,6 @@ void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node) } -/* nodes that use ID data get synced with local data */ -void nodeSynchronizeID(bNode *node, bool copy_to_id) -{ - if (node->id == NULL) return; - - if (ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) { - bNodeSocket *sock; - Material *ma = (Material *)node->id; - int a; - short check_flags = SOCK_UNAVAIL; - - if (!copy_to_id) - check_flags |= SOCK_HIDDEN; - - /* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */ - for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) { - if (!(sock->flag & check_flags)) { - if (copy_to_id) { - switch (a) { - case MAT_IN_COLOR: - copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; - case MAT_IN_SPEC: - copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; - case MAT_IN_REFL: - ma->ref = ((bNodeSocketValueFloat *)sock->default_value)->value; break; - case MAT_IN_MIR: - copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break; - case MAT_IN_AMB: - ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break; - case MAT_IN_EMIT: - ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break; - case MAT_IN_SPECTRA: - ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break; - case MAT_IN_RAY_MIRROR: - ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break; - case MAT_IN_ALPHA: - ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break; - case MAT_IN_TRANSLUCENCY: - ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break; - } - } - else { - switch (a) { - case MAT_IN_COLOR: - copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break; - case MAT_IN_SPEC: - copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break; - case MAT_IN_REFL: - ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ref; break; - case MAT_IN_MIR: - copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break; - case MAT_IN_AMB: - ((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break; - case MAT_IN_EMIT: - ((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break; - case MAT_IN_SPECTRA: - ((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break; - case MAT_IN_RAY_MIRROR: - ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break; - case MAT_IN_ALPHA: - ((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break; - case MAT_IN_TRANSLUCENCY: - ((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break; - } - } - } - } - } -} - - /* ************* node type access ********** */ void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen) @@ -3424,11 +3335,6 @@ void node_type_internal_links(bNodeType *ntype, void (*update_internal_links)(bN ntype->update_internal_links = update_internal_links; } -void node_type_compatibility(struct bNodeType *ntype, short compatibility) -{ - ntype->compatibility = compatibility; -} - /* callbacks for undefined types */ static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(nodetree)) @@ -3563,10 +3469,7 @@ static void registerShaderNodes(void) { register_node_type_sh_group(); - register_node_type_sh_output(); - register_node_type_sh_material(); register_node_type_sh_camera(); - register_node_type_sh_lamp(); register_node_type_sh_gamma(); register_node_type_sh_brightcontrast(); register_node_type_sh_value(); @@ -3577,9 +3480,8 @@ static void registerShaderNodes(void) register_node_type_sh_mix_rgb(); register_node_type_sh_valtorgb(); register_node_type_sh_rgbtobw(); - register_node_type_sh_texture(); + register_node_type_sh_shadertorgb(); register_node_type_sh_normal(); - register_node_type_sh_geom(); register_node_type_sh_mapping(); register_node_type_sh_curve_vec(); register_node_type_sh_curve_rgb(); @@ -3587,7 +3489,6 @@ static void registerShaderNodes(void) register_node_type_sh_vect_math(); register_node_type_sh_vect_transform(); register_node_type_sh_squeeze(); - register_node_type_sh_material_ext(); register_node_type_sh_invert(); register_node_type_sh_seprgb(); register_node_type_sh_combrgb(); @@ -3633,6 +3534,7 @@ static void registerShaderNodes(void) register_node_type_sh_add_shader(); register_node_type_sh_uvmap(); register_node_type_sh_uvalongstroke(); + register_node_type_sh_eevee_specular(); register_node_type_sh_output_lamp(); register_node_type_sh_output_material(); @@ -3826,3 +3728,28 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, return true; } + +/* -------------------------------------------------------------------- */ +/* NodeTree kernel functions */ + +void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index) +{ + BLI_assert(layer_index != -1); + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { + if (node->custom1 == layer_index) { + node->custom1 = 0; + } + else if (node->custom1 > layer_index) { + node->custom1--; + } + } + } +} + +void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph, + bNodeTree *ntree_dst, + const bNodeTree *ntree_src) +{ + DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst); +} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index add7c1fd992..d36a5838630 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -39,9 +39,10 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_camera_types.h" +#include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" -#include "DNA_group_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_key_types.h" #include "DNA_lamp_types.h" #include "DNA_lattice_types.h" @@ -53,12 +54,13 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_smoke_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" #include "DNA_object_types.h" -#include "DNA_property_types.h" +#include "DNA_lightprobe_types.h" #include "DNA_rigidbody_types.h" #include "BLI_blenlib.h" @@ -76,21 +78,21 @@ #include "BKE_idprop.h" #include "BKE_armature.h" #include "BKE_action.h" -#include "BKE_bullet.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_animsys.h" #include "BKE_anim.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_fcurve.h" -#include "BKE_group.h" +#include "BKE_gpencil_modifier.h" #include "BKE_icons.h" #include "BKE_key.h" #include "BKE_lamp.h" +#include "BKE_layer.h" #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -103,20 +105,28 @@ #include "BKE_multires.h" #include "BKE_node.h" #include "BKE_object.h" +#include "BKE_object_facemap.h" #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_pointcache.h" -#include "BKE_property.h" +#include "BKE_lightprobe.h" #include "BKE_rigidbody.h" -#include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_shader_fx.h" #include "BKE_speaker.h" #include "BKE_softbody.h" #include "BKE_subsurf.h" +#include "BKE_subdiv_ccg.h" #include "BKE_material.h" #include "BKE_camera.h" #include "BKE_image.h" +#include "BKE_gpencil.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "DRW_engine.h" #ifdef WITH_MOD_FLUID #include "LBM_fluidsim.h" @@ -129,8 +139,6 @@ #include "CCGSubSurf.h" #include "atomic_ops.h" -#include "GPU_material.h" - /* Vertex parent modifies original BMesh which is not safe for threading. * Ideally such a modification should be handled as a separate DAG update * callback for mesh datablock, but for until it is actually supported use @@ -152,16 +160,6 @@ void BKE_object_workob_clear(Object *workob) workob->rotmode = ROT_MODE_EUL; } -void BKE_object_update_base_layer(struct Scene *scene, Object *ob) -{ - Base *base = scene->base.first; - - while (base) { - if (base->object == ob) base->lay = ob->lay; - base = base->next; - } -} - void BKE_object_free_particlesystems(Object *ob) { ParticleSystem *psys; @@ -173,42 +171,35 @@ void BKE_object_free_particlesystems(Object *ob) void BKE_object_free_softbody(Object *ob) { - if (ob->soft) { - sbFree(ob->soft); - ob->soft = NULL; - } -} - -void BKE_object_free_bulletsoftbody(Object *ob) -{ - if (ob->bsoft) { - bsbFree(ob->bsoft); - ob->bsoft = NULL; - } + sbFree(ob); } void BKE_object_free_curve_cache(Object *ob) { - if (ob->curve_cache) { - BKE_displist_free(&ob->curve_cache->disp); - BKE_curve_bevelList_free(&ob->curve_cache->bev); - if (ob->curve_cache->path) { - free_path(ob->curve_cache->path); + if (ob->runtime.curve_cache) { + BKE_displist_free(&ob->runtime.curve_cache->disp); + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); + if (ob->runtime.curve_cache->path) { + free_path(ob->runtime.curve_cache->path); } - BKE_nurbList_free(&ob->curve_cache->deformed_nurbs); - MEM_freeN(ob->curve_cache); - ob->curve_cache = NULL; + BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs); + MEM_freeN(ob->runtime.curve_cache); + ob->runtime.curve_cache = NULL; } } void BKE_object_free_modifiers(Object *ob, const int flag) { ModifierData *md; + GpencilModifierData *gp_md; while ((md = BLI_pophead(&ob->modifiers))) { modifier_free_ex(md, flag); } + while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) { + BKE_gpencil_modifier_free_ex(gp_md, flag); + } /* particle modifiers were freed, so free the particlesystems as well */ BKE_object_free_particlesystems(ob); @@ -219,6 +210,15 @@ void BKE_object_free_modifiers(Object *ob, const int flag) BKE_object_free_derived_caches(ob); } +void BKE_object_free_shaderfx(Object *ob, const int flag) +{ + ShaderFxData *fx; + + while ((fx = BLI_pophead(&ob->shader_fx))) { + BKE_shaderfx_free_ex(fx, flag); + } +} + void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) { /* reset functionality */ @@ -241,6 +241,29 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) } } +void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd) +{ + if (hmd->object == NULL) { + return; + } + /* reset functionality */ + bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget); + + if (hmd->subtarget[0] && pchan) { + float imat[4][4], mat[4][4]; + + /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */ + mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat); + + invert_m4_m4(imat, mat); + mul_m4_m4m4(hmd->parentinv, imat, ob->obmat); + } + else { + invert_m4_m4(hmd->object->imat, hmd->object->obmat); + mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat); + } +} + bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) { const ModifierTypeInfo *mti; @@ -265,7 +288,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) return true; } -void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) +void BKE_object_link_modifiers(Scene *scene, struct Object *ob_dst, const struct Object *ob_src) { ModifierData *md; BKE_object_free_modifiers(ob_dst, 0); @@ -291,7 +314,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr switch (md->type) { case eModifierType_Softbody: - BKE_object_copy_softbody(ob_dst, ob_src); + BKE_object_copy_softbody(ob_dst, ob_src, 0); break; case eModifierType_Skin: /* ensure skin-node customdata exists */ @@ -304,7 +327,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr if (md->type == eModifierType_Multires) { /* Has to be done after mod creation, but *before* we actually copy its settings! */ - multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); + multiresModifier_sync_levels_ex(scene, ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); } modifier_copyData(md, nmd); @@ -317,6 +340,93 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr /* TODO: smoke?, cloth? */ } +/* Copy CCG related data. Used to sync copy of mesh with reshaped original + * mesh. + */ +static void copy_ccg_data(Mesh *mesh_destination, + Mesh *mesh_source, + int layer_type) +{ + BLI_assert(mesh_destination->totloop == mesh_source->totloop); + CustomData *data_destination = &mesh_destination->ldata; + CustomData *data_source = &mesh_source->ldata; + const int num_elements = mesh_source->totloop; + if (!CustomData_has_layer(data_source, layer_type)) { + return; + } + const int layer_index = CustomData_get_layer_index( + data_destination, layer_type); + CustomData_free_layer( + data_destination, layer_type, num_elements, layer_index); + BLI_assert(!CustomData_has_layer(data_destination, layer_type)); + CustomData_add_layer( + data_destination, layer_type, CD_CALLOC, NULL, num_elements); + BLI_assert(CustomData_has_layer(data_destination, layer_type)); + CustomData_copy_layer_type_data(data_source, data_destination, + layer_type, 0, 0, num_elements); +} + +static void object_update_from_subsurf_ccg(Object *object) +{ + /* Currently CCG is only created for Mesh objects. */ + if (object->type != OB_MESH) { + return; + } + /* Object was never evaluated, so can not have CCG subdivision surface. */ + Mesh *mesh_eval = object->runtime.mesh_eval; + if (mesh_eval == NULL) { + return; + } + SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; + if (subdiv_ccg == NULL) { + return; + } + /* Check whether there is anything to be reshaped. */ + if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) { + return; + } + const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level; + Object *object_orig = DEG_get_original_object(object); + Mesh *mesh_orig = (Mesh *)object_orig->data; + multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg); + /* NOTE: we need to reshape into an original mesh from main database, + * allowing: + * + * - Update copies of that mesh at any moment. + * - Save the file without doing extra reshape. + * - All the users of the mesh have updated displacement. + * + * However, the tricky part here is that we only know about sculpted + * state of a mesh on an object level, and object is being updated after + * mesh datablock is updated. This forces us to: + * + * - Update mesh datablock from object evaluation, which is technically + * forbidden, but there is no other place for this yet. + * - Reshape to the original mesh from main database, and then copy updated + * layer to copy of that mesh (since copy of the mesh has decoupled + * custom data layers). + * + * All this is defeating all the designs we need to follow to allow safe + * threaded evaluation, but this is as good as we can make it within the + * current sculpt//evaluated mesh design. This is also how we've survived + * with old DerivedMesh based solutions. So, while this is all wrong and + * needs reconsideration, doesn't seem to be a big stopper for real + * production artists. + */ + /* TODO(sergey): Solve this somehow, to be fully stable for threaded + * evaluation environment. + */ + /* NOTE: runtime.mesh_orig is what was before assigning mesh_eval, + * it is orig as in what was in object_eval->data before evaluating + * modifier stack. + * + * mesh_cow is a copy-on-written version od object_orig->data. + */ + Mesh *mesh_cow = object->runtime.mesh_orig; + copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS); + copy_ccg_data(mesh_cow, mesh_orig, CD_GRID_PAINT_MASK); +} + /* free data derived from mesh, called when mesh changes or is freed */ void BKE_object_free_derived_caches(Object *ob) { @@ -346,6 +456,38 @@ void BKE_object_free_derived_caches(Object *ob) ob->bb = NULL; } + object_update_from_subsurf_ccg(ob); + BKE_object_free_derived_mesh_caches(ob); + + if (ob->runtime.mesh_eval != NULL) { + Mesh *mesh_eval = ob->runtime.mesh_eval; + /* Restore initial pointer. */ + if (ob->data == mesh_eval) { + ob->data = ob->runtime.mesh_orig; + } + /* Evaluated mesh points to edit mesh, but does not own it. */ + mesh_eval->edit_btmesh = NULL; + BKE_mesh_free(mesh_eval); + BKE_libblock_free_data(&mesh_eval->id, false); + MEM_freeN(mesh_eval); + ob->runtime.mesh_eval = NULL; + } + if (ob->runtime.mesh_deform_eval != NULL) { + Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval; + BKE_mesh_free(mesh_deform_eval); + BKE_libblock_free_data(&mesh_deform_eval->id, false); + MEM_freeN(mesh_deform_eval); + ob->runtime.mesh_deform_eval = NULL; + } + + BKE_object_free_curve_cache(ob); + + /* clear grease pencil data */ + DRW_gpencil_freecache(ob); +} + +void BKE_object_free_derived_mesh_caches(struct Object *ob) +{ if (ob->derivedFinal) { ob->derivedFinal->needsFree = 1; ob->derivedFinal->release(ob->derivedFinal); @@ -356,8 +498,6 @@ void BKE_object_free_derived_caches(Object *ob) ob->derivedDeform->release(ob->derivedDeform); ob->derivedDeform = NULL; } - - BKE_object_free_curve_cache(ob); } void BKE_object_free_caches(Object *object) @@ -381,14 +521,12 @@ void BKE_object_free_caches(Object *object) for (md = object->modifiers.first; md != NULL; md = md->next) { if (md->type == eModifierType_ParticleSystem) { ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md; - if (psmd->dm_final != NULL) { - psmd->dm_final->needsFree = 1; - psmd->dm_final->release(psmd->dm_final); - psmd->dm_final = NULL; - if (psmd->dm_deformed != NULL) { - psmd->dm_deformed->needsFree = 1; - psmd->dm_deformed->release(psmd->dm_deformed); - psmd->dm_deformed = NULL; + if (psmd->mesh_final) { + BKE_id_free(NULL, psmd->mesh_final); + psmd->mesh_final = NULL; + if (psmd->mesh_original) { + BKE_id_free(NULL, psmd->mesh_original); + psmd->mesh_original = NULL; } psmd->flag |= eParticleSystemFlag_file_loaded; update_flag |= OB_RECALC_DATA; @@ -396,12 +534,21 @@ void BKE_object_free_caches(Object *object) } } + /* NOTE: If object is coming from a duplicator, it might be a temporary + * object created by dependency graph, which shares pointers with original + * object. In this case we can not free anything. + */ + if ((object->base_flag & BASE_FROMDUPLI) == 0) { + BKE_object_free_derived_caches(object); + update_flag |= OB_RECALC_DATA; + } + /* Tag object for update, so once memory critical operation is over and * scene update routines are back to it's business the object will be * guaranteed to be in a known state. */ if (update_flag != 0) { - DAG_id_tag_update(&object->id, update_flag); + DEG_id_tag_update(&object->id, update_flag); } } @@ -410,8 +557,11 @@ void BKE_object_free(Object *ob) { BKE_animdata_free((ID *)ob, false); + DRW_drawdata_free((ID *)ob); + /* BKE_<id>_free shall never touch to ID->us. Never ever. */ BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT); + BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT); MEM_SAFE_FREE(ob->mat); MEM_SAFE_FREE(ob->matbits); @@ -419,6 +569,7 @@ void BKE_object_free(Object *ob) MEM_SAFE_FREE(ob->bb); BLI_freelistN(&ob->defbase); + BLI_freelistN(&ob->fmaps); if (ob->pose) { BKE_pose_free_ex(ob->pose, false); ob->pose = NULL; @@ -427,27 +578,14 @@ void BKE_object_free(Object *ob) animviz_free_motionpath(ob->mpath); ob->mpath = NULL; } - BKE_bproperty_free_list(&ob->prop); - - free_sensors(&ob->sensors); - free_controllers(&ob->controllers); - free_actuators(&ob->actuators); BKE_constraints_free_ex(&ob->constraints, false); free_partdeflect(ob->pd); - BKE_rigidbody_free_object(ob); + BKE_rigidbody_free_object(ob, NULL); BKE_rigidbody_free_constraint(ob); - if (ob->soft) { - sbFree(ob->soft); - ob->soft = NULL; - } - if (ob->bsoft) { - bsbFree(ob->bsoft); - ob->bsoft = NULL; - } - GPU_lamp_free(ob); + sbFree(ob); BKE_sculptsession_free(ob); @@ -456,12 +594,12 @@ void BKE_object_free(Object *ob) BLI_freelistN(&ob->lodlevels); /* Free runtime curves data. */ - if (ob->curve_cache) { - BKE_curve_bevelList_free(&ob->curve_cache->bev); - if (ob->curve_cache->path) - free_path(ob->curve_cache->path); - MEM_freeN(ob->curve_cache); - ob->curve_cache = NULL; + if (ob->runtime.curve_cache) { + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); + if (ob->runtime.curve_cache->path) + free_path(ob->runtime.curve_cache->path); + MEM_freeN(ob->runtime.curve_cache); + ob->runtime.curve_cache = NULL; } BKE_previewimg_free(&ob->preview); @@ -470,63 +608,135 @@ void BKE_object_free(Object *ob) /* actual check for internal data, not context or flags */ bool BKE_object_is_in_editmode(const Object *ob) { - if (ob->data == NULL) + if (ob->data == NULL) { return false; + } + switch (ob->type) { + case OB_MESH: + return ((Mesh *)ob->data)->edit_btmesh != NULL; + case OB_ARMATURE: + return ((bArmature *)ob->data)->edbo != NULL; + case OB_FONT: + return ((Curve *)ob->data)->editfont != NULL; + case OB_MBALL: + return ((MetaBall *)ob->data)->editelems != NULL; + case OB_LATTICE: + return ((Lattice *)ob->data)->editlatt != NULL; + case OB_SURF: + case OB_CURVE: + return ((Curve *)ob->data)->editnurb != NULL; + default: + return false; + } +} + +bool BKE_object_is_in_editmode_vgroup(const Object *ob) +{ + return (OB_TYPE_SUPPORT_VGROUP(ob->type) && + BKE_object_is_in_editmode(ob)); +} + +bool BKE_object_data_is_in_editmode(const ID *id) +{ + const short type = GS(id->name); + BLI_assert(OB_DATA_SUPPORT_EDITMODE(type)); + switch (type) { + case ID_ME: + return ((const Mesh *)id)->edit_btmesh != NULL; + case ID_CU: + return ( + (((const Curve *)id)->editnurb != NULL) || + (((const Curve *)id)->editfont != NULL) + ); + case ID_MB: + return ((const MetaBall *)id)->editelems != NULL; + case ID_LT: + return ((const Lattice *)id)->editlatt != NULL; + case ID_AR: + return ((const bArmature *)id)->edbo != NULL; + default: + BLI_assert(0); + return false; + } +} + +bool BKE_object_is_in_wpaint_select_vert(const Object *ob) +{ if (ob->type == OB_MESH) { Mesh *me = ob->data; - if (me->edit_btmesh) - return true; + return ((ob->mode & OB_MODE_WEIGHT_PAINT) && + (me->edit_btmesh == NULL) && + (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX)); } - else if (ob->type == OB_ARMATURE) { - bArmature *arm = ob->data; - if (arm->edbo) + return false; +} + +bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode) +{ + if (object_mode & OB_MODE_EDIT) { + if (BKE_object_is_in_editmode(ob)) { return true; + } } - else if (ob->type == OB_FONT) { - Curve *cu = ob->data; - - if (cu->editfont) + else if (object_mode & OB_MODE_VERTEX_PAINT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) { return true; + } } - else if (ob->type == OB_MBALL) { - MetaBall *mb = ob->data; - - if (mb->editelems) + else if (object_mode & OB_MODE_WEIGHT_PAINT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) { return true; + } } - else if (ob->type == OB_LATTICE) { - Lattice *lt = ob->data; - - if (lt->editlatt) + else if (object_mode & OB_MODE_SCULPT) { + if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) { return true; + } } - else if (ob->type == OB_SURF || ob->type == OB_CURVE) { - Curve *cu = ob->data; - - if (cu->editnurb) + else if (object_mode & OB_MODE_POSE) { + if (ob->pose != NULL) { return true; + } } return false; } -bool BKE_object_is_in_editmode_vgroup(const Object *ob) +bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode) { - return (OB_TYPE_SUPPORT_VGROUP(ob->type) && - BKE_object_is_in_editmode(ob)); + return ((ob->mode == object_mode) || + (ob->mode & object_mode) != 0); } -bool BKE_object_is_in_wpaint_select_vert(const Object *ob) +/** + * Return if the object is visible, as evaluated by depsgraph + */ +bool BKE_object_is_visible(const Object *ob, const eObjectVisibilityCheck mode) { - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - return ((ob->mode & OB_MODE_WEIGHT_PAINT) && - (me->edit_btmesh == NULL) && - (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX)); + if ((ob->base_flag & BASE_VISIBLE) == 0) { + return false; } - return false; + if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) { + return true; + } + + if (((ob->transflag & OB_DUPLI) == 0) && + (ob->particlesystem.first == NULL)) + { + return true; + } + + switch (mode) { + case OB_VISIBILITY_CHECK_FOR_VIEWPORT: + return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0); + case OB_VISIBILITY_CHECK_FOR_RENDER: + return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0); + default: + BLI_assert(!"Object visible test mode not supported."); + return false; + } } bool BKE_object_exists_check(Main *bmain, const Object *obtest) @@ -554,11 +764,12 @@ static const char *get_obdata_defname(int type) case OB_FONT: return DATA_("Text"); case OB_MBALL: return DATA_("Mball"); case OB_CAMERA: return DATA_("Camera"); - case OB_LAMP: return DATA_("Lamp"); + case OB_LAMP: return DATA_("Light"); case OB_LATTICE: return DATA_("Lattice"); case OB_ARMATURE: return DATA_("Armature"); case OB_SPEAKER: return DATA_("Speaker"); case OB_EMPTY: return DATA_("Empty"); + case OB_GPENCIL: return DATA_("GPencil"); default: printf("get_obdata_defname: Internal error, bad type: %d\n", type); return DATA_("Empty"); @@ -582,6 +793,8 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) case OB_LATTICE: return BKE_lattice_add(bmain, name); case OB_ARMATURE: return BKE_armature_add(bmain, name); case OB_SPEAKER: return BKE_speaker_add(bmain, name); + case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name); + case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name); case OB_EMPTY: return NULL; default: printf("%s: Internal error, bad type: %d\n", __func__, type); @@ -619,6 +832,10 @@ void BKE_object_init(Object *ob) ob->dt = OB_TEXTURE; ob->empty_drawtype = OB_PLAINAXES; ob->empty_drawsize = 1.0; + ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT; + ob->empty_image_visibility_flag = ( + OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE | + OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC); if (ob->type == OB_EMPTY) { copy_v2_fl(ob->ima_ofs, -0.5f); } @@ -636,26 +853,10 @@ void BKE_object_init(Object *ob) ob->dupsta = 1; ob->dupend = 100; ob->dupfacesca = 1.0; - /* Game engine defaults*/ - ob->mass = ob->inertia = 1.0f; - ob->formfactor = 0.4f; - ob->damping = 0.04f; - ob->rdamping = 0.1f; - ob->anisotropicFriction[0] = 1.0f; - ob->anisotropicFriction[1] = 1.0f; - ob->anisotropicFriction[2] = 1.0f; - ob->gameflag = OB_PROP | OB_COLLISION; - ob->margin = 0.04f; - ob->init_state = 1; - ob->state = 1; - ob->obstacleRad = 1.0f; - ob->step_height = 0.15f; - ob->jump_speed = 10.0f; - ob->fall_speed = 55.0f; - ob->max_jumps = 1; ob->col_group = 0x01; ob->col_mask = 0xffff; ob->preview = NULL; + ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER; /* NT fluid sim defaults */ ob->fluidsimSettings = NULL; @@ -664,6 +865,8 @@ void BKE_object_init(Object *ob) /* Animation Visualization defaults */ animviz_settings_init(&ob->avs); + + ob->display.flag = OB_SHOW_SHADOW; } /* more general add: creates minimum required data, but without vertices etc. */ @@ -676,6 +879,9 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob = BKE_libblock_alloc(bmain, ID_OB, name, 0); + /* We increase object user count when linking to Collections. */ + id_us_min(&ob->id); + /* default object vars */ ob->type = type; @@ -684,168 +890,112 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) return ob; } -/* general add: to scene, with layer from area and default name */ -/* creates minimum required data, but without vertices etc. */ -Object *BKE_object_add( - Main *bmain, Scene *scene, - int type, const char *name) + +static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, const char *name) { Object *ob; - Base *base; ob = BKE_object_add_only_object(bmain, type, name); - ob->data = BKE_object_obdata_add_from_type(bmain, type, name); + BKE_view_layer_base_deselect_all(view_layer); - ob->lay = scene->lay; - - base = BKE_scene_base_add(scene, ob); - BKE_scene_base_deselect_all(scene); - BKE_scene_base_select(scene, base); - DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - + DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); return ob; } - -#ifdef WITH_GAMEENGINE - -void BKE_object_lod_add(Object *ob) -{ - LodLevel *lod = MEM_callocN(sizeof(LodLevel), "LoD Level"); - LodLevel *last = ob->lodlevels.last; - - /* If the lod list is empty, initialize it with the base lod level */ - if (!last) { - LodLevel *base = MEM_callocN(sizeof(LodLevel), "Base LoD Level"); - BLI_addtail(&ob->lodlevels, base); - base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT; - base->source = ob; - base->obhysteresis = 10; - last = ob->currentlod = base; - } - - lod->distance = last->distance + 25.0f; - lod->obhysteresis = 10; - lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT; - - BLI_addtail(&ob->lodlevels, lod); -} - -static int lod_cmp(const void *a, const void *b) -{ - const LodLevel *loda = a; - const LodLevel *lodb = b; - - if (loda->distance < lodb->distance) return -1; - return loda->distance > lodb->distance; -} - -void BKE_object_lod_sort(Object *ob) -{ - BLI_listbase_sort(&ob->lodlevels, lod_cmp); -} - -bool BKE_object_lod_remove(Object *ob, int level) +/** + * General add: to scene, with layer from area and default name + * + * Object is added to the active Collection. + * If there is no linked collection to the active ViewLayer we create a new one. + */ +/* creates minimum required data, but without vertices etc. */ +Object *BKE_object_add( + Main *bmain, Scene *UNUSED(scene), ViewLayer *view_layer, + int type, const char *name) { - LodLevel *rem; - - if (level < 1 || level > BLI_listbase_count(&ob->lodlevels) - 1) - return false; - - rem = BLI_findlink(&ob->lodlevels, level); + Object *ob; + Base *base; + LayerCollection *layer_collection; - if (rem == ob->currentlod) { - ob->currentlod = rem->prev; - } + ob = object_add_common(bmain, view_layer, type, name); - BLI_remlink(&ob->lodlevels, rem); - MEM_freeN(rem); + layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, ob); - /* If there are no user defined lods, remove the base lod as well */ - if (BLI_listbase_is_single(&ob->lodlevels)) { - LodLevel *base = ob->lodlevels.first; - BLI_remlink(&ob->lodlevels, base); - MEM_freeN(base); - ob->currentlod = NULL; - } + base = BKE_view_layer_base_find(view_layer, ob); + BKE_view_layer_base_select_and_set_active(view_layer, base); - return true; + return ob; } -static LodLevel *lod_level_select(Object *ob, const float camera_position[3]) +/** + * Add a new object, using another one as a reference + * + * \param ob_src object to use to determine the collections of the new object. + */ +Object *BKE_object_add_from( + Main *bmain, Scene *scene, ViewLayer *view_layer, + int type, const char *name, Object *ob_src) { - LodLevel *current = ob->currentlod; - float dist_sq; - - if (!current) return NULL; - - dist_sq = len_squared_v3v3(ob->obmat[3], camera_position); - - if (dist_sq < SQUARE(current->distance)) { - /* check for higher LoD */ - while (current->prev && dist_sq < SQUARE(current->distance)) { - current = current->prev; - } - } - else { - /* check for lower LoD */ - while (current->next && dist_sq > SQUARE(current->next->distance)) { - current = current->next; - } - } + Object *ob; + Base *base; - return current; -} + ob = object_add_common(bmain, view_layer, type, name); + BKE_collection_object_add_from(bmain, scene, ob_src, ob); -bool BKE_object_lod_is_usable(Object *ob, Scene *scene) -{ - bool active = (scene) ? ob == OBACT : false; - return (ob->mode == OB_MODE_OBJECT || !active); -} - -void BKE_object_lod_update(Object *ob, const float camera_position[3]) -{ - LodLevel *cur_level = ob->currentlod; - LodLevel *new_level = lod_level_select(ob, camera_position); + base = BKE_view_layer_base_find(view_layer, ob); + BKE_view_layer_base_select_and_set_active(view_layer, base); - if (new_level != cur_level) { - ob->currentlod = new_level; - } + return ob; } -static Object *lod_ob_get(Object *ob, Scene *scene, int flag) +/** + * Add a new object, but assign the given datablock as the ob->data + * for the newly created object. + * + * \param data The datablock to assign as ob->data for the new object. + * This is assumed to be of the correct type. + * \param do_id_user If true, id_us_plus() will be called on data when + * assigning it to the object. + */ +Object *BKE_object_add_for_data( + Main *bmain, ViewLayer *view_layer, + int type, const char *name, ID *data, bool do_id_user) { - LodLevel *current = ob->currentlod; + Object *ob; + Base *base; + LayerCollection *layer_collection; - if (!current || !BKE_object_lod_is_usable(ob, scene)) - return ob; + /* same as object_add_common, except we don't create new ob->data */ + ob = BKE_object_add_only_object(bmain, type, name); + ob->data = data; + if (do_id_user) id_us_plus(data); - while (current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) { - current = current->prev; - } + BKE_view_layer_base_deselect_all(view_layer); + DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - return current->source; -} + layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, ob); -struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene) -{ - return lod_ob_get(ob, scene, OB_LOD_USE_MESH); -} + base = BKE_view_layer_base_find(view_layer, ob); + BKE_view_layer_base_select_and_set_active(view_layer, base); -struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene) -{ - return lod_ob_get(ob, scene, OB_LOD_USE_MAT); + return ob; } -#endif /* WITH_GAMEENGINE */ - -SoftBody *copy_softbody(const SoftBody *sb, const int flag) +void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag) { + SoftBody *sb = ob_src->soft; SoftBody *sbn; + bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN; - if (sb == NULL) return(NULL); + ob_dst->softflag = ob_src->softflag; + if (sb == NULL) { + ob_dst->soft = NULL; + return; + } sbn = MEM_dupallocN(sb); @@ -878,64 +1028,27 @@ SoftBody *copy_softbody(const SoftBody *sb, const int flag) sbn->scratch = NULL; - sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, flag); + if (tagged_no_main == 0) { + sbn->shared = MEM_dupallocN(sb->shared); + sbn->shared->pointcache = BKE_ptcache_copy_list(&sbn->shared->ptcaches, &sb->shared->ptcaches, flag); + } if (sb->effector_weights) sbn->effector_weights = MEM_dupallocN(sb->effector_weights); - return sbn; -} - -BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb, const int UNUSED(flag)) -{ - BulletSoftBody *bsbn; - - if (bsb == NULL) - return NULL; - bsbn = MEM_dupallocN(bsb); - /* no pointer in this structure yet */ - return bsbn; + ob_dst->soft = sbn; } ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag) { - ParticleSystem *psysn; - ParticleData *pa; - int p; - - psysn = MEM_dupallocN(psys); - psysn->particles = MEM_dupallocN(psys->particles); - psysn->child = MEM_dupallocN(psys->child); - - if (psys->part->type == PART_HAIR) { - for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++) - pa->hair = MEM_dupallocN(pa->hair); - } + ParticleSystem *psysn = MEM_dupallocN(psys); - if (psysn->particles && (psysn->particles->keys || psysn->particles->boid)) { - ParticleKey *key = psysn->particles->keys; - BoidParticle *boid = psysn->particles->boid; - - if (key) - key = MEM_dupallocN(key); - - if (boid) - boid = MEM_dupallocN(boid); - - for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++) { - if (boid) - pa->boid = boid++; - if (key) { - pa->keys = key; - key += pa->totkey; - } - } - } + psys_copy_particles(psysn, psys); if (psys->clmd) { psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth); modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag); - psys->hair_in_dm = psys->hair_out_dm = NULL; + psys->hair_in_mesh = psys->hair_out_mesh = NULL; } BLI_duplicatelist(&psysn->targets, &psys->targets); @@ -947,13 +1060,19 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f psysn->effectors = NULL; psysn->tree = NULL; psysn->bvhtree = NULL; + psysn->batch_cache = NULL; BLI_listbase_clear(&psysn->pathcachebufs); BLI_listbase_clear(&psysn->childcachebufs); - psysn->renderdata = NULL; - /* XXX Never copy caches here? */ - psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES); + if (flag & LIB_ID_CREATE_NO_MAIN) { + BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0); + psysn->flag |= PSYS_SHARED_CACHES; + BLI_assert(psysn->pointcache != NULL); + } + else { + psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag); + } /* XXX - from reading existing code this seems correct but intended usage of * pointcache should /w cloth should be added in 'ParticleSystem' - campbell */ @@ -1013,14 +1132,6 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const } } -void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src) -{ - if (ob_src->soft) { - ob_dst->softflag = ob_src->softflag; - ob_dst->soft = copy_softbody(ob_src->soft, 0); - } -} - static void copy_object_pose(Object *obn, const Object *ob, const int flag) { bPoseChannel *chan; @@ -1087,12 +1198,103 @@ Object *BKE_object_pose_armature_get(Object *ob) ob = modifiers_isDeformedByArmature(ob); + /* Only use selected check when non-active. */ if (BKE_object_pose_context_check(ob)) return ob; return NULL; } +Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer) +{ + Object *ob_armature = BKE_object_pose_armature_get(ob); + if (ob_armature) { + Base *base = BKE_view_layer_base_find(view_layer, ob_armature); + if (base) { + if (BASE_VISIBLE(base)) { + return ob_armature; + } + } + } + return NULL; +} + +/** + * Access pose array with special check to get pose object when in weight paint mode. + */ +Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, uint *r_objects_len, bool unique) +{ + Object *ob_active = OBACT(view_layer); + Object *ob_pose = BKE_object_pose_armature_get(ob_active); + Object **objects = NULL; + if (ob_pose == ob_active) { + objects = BKE_view_layer_array_from_objects_in_mode( + view_layer, r_objects_len, { + .object_mode = OB_MODE_POSE, + .no_dup_data = unique}); + } + else if (ob_pose != NULL) { + *r_objects_len = 1; + objects = MEM_mallocN(sizeof(*objects), __func__); + objects[0] = ob_pose; + } + else { + *r_objects_len = 0; + objects = MEM_mallocN(0, __func__); + } + return objects; +} +Object **BKE_object_pose_array_get_unique(ViewLayer *view_layer, uint *r_objects_len) +{ + return BKE_object_pose_array_get_ex(view_layer, r_objects_len, true); +} +Object **BKE_object_pose_array_get(ViewLayer *view_layer, uint *r_objects_len) +{ + return BKE_object_pose_array_get_ex(view_layer, r_objects_len, false); +} + +Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, uint *r_bases_len, bool unique) +{ + Base *base_active = BASACT(view_layer); + Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : NULL; + Base *base_pose = NULL; + Base **bases = NULL; + + if (base_active) { + if (ob_pose == base_active->object) { + base_pose = base_active; + } + else { + base_pose = BKE_view_layer_base_find(view_layer, ob_pose); + } + } + + if (base_active && (base_pose == base_active)) { + bases = BKE_view_layer_array_from_bases_in_mode( + view_layer, r_bases_len, { + .object_mode = OB_MODE_POSE, + .no_dup_data = unique}); + } + else if (base_pose != NULL) { + *r_bases_len = 1; + bases = MEM_mallocN(sizeof(*bases), __func__); + bases[0] = base_pose; + } + else { + *r_bases_len = 0; + bases = MEM_mallocN(0, __func__); + } + return bases; +} +Base **BKE_object_pose_base_array_get_unique(ViewLayer *view_layer, uint *r_bases_len) +{ + return BKE_object_pose_base_array_get_ex(view_layer, r_bases_len, true); +} +Base **BKE_object_pose_base_array_get(ViewLayer *view_layer, uint *r_bases_len) +{ + return BKE_object_pose_base_array_get_ex(view_layer, r_bases_len, false); +} + void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) { copy_v3_v3(ob_tar->loc, ob_src->loc); @@ -1112,9 +1314,14 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) * * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more). */ -void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_src, const int flag) +void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag) { ModifierData *md; + GpencilModifierData *gmd; + ShaderFxData *fx; + + /* Do not copy runtime data. */ + BKE_object_runtime_reset(ob_dst); /* We never handle usercount here for own data. */ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; @@ -1134,7 +1341,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_ if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser); if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb); - ob_dst->flag &= ~OB_FROMGROUP; BLI_listbase_clear(&ob_dst->modifiers); @@ -1145,21 +1351,37 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_ BLI_addtail(&ob_dst->modifiers, nmd); } - BLI_listbase_clear(&ob_dst->prop); - BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop); + BLI_listbase_clear(&ob_dst->greasepencil_modifiers); - BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata); + for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) { + GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type); + BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name)); + BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata); + BLI_addtail(&ob_dst->greasepencil_modifiers, nmd); + } + + BLI_listbase_clear(&ob_dst->shader_fx); + + for (fx = ob_src->shader_fx.first; fx; fx = fx->next) { + ShaderFxData *nfx = BKE_shaderfx_new(fx->type); + BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name)); + BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata); + BLI_addtail(&ob_dst->shader_fx, nfx); + } if (ob_src->pose) { copy_object_pose(ob_dst, ob_src, flag_subdata); /* backwards compat... non-armatures can get poses in older files? */ - if (ob_src->type == OB_ARMATURE) - BKE_pose_rebuild(ob_dst, ob_dst->data); + if (ob_src->type == OB_ARMATURE) { + const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0; + BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user); + } } defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase); + BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps); BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true); - ob_dst->mode = OB_MODE_OBJECT; + ob_dst->mode = ob_dst->type != OB_GPENCIL ? OB_MODE_OBJECT : ob_dst->mode; ob_dst->sculpt = NULL; if (ob_src->pd) { @@ -1168,8 +1390,7 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_ ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng); } } - ob_dst->soft = copy_softbody(ob_src->soft, flag_subdata); - ob_dst->bsoft = copy_bulletsoftbody(ob_src->bsoft, flag_subdata); + BKE_object_copy_softbody(ob_dst, ob_src, flag_subdata); ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata); ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata); @@ -1178,16 +1399,14 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_ ob_dst->derivedDeform = NULL; ob_dst->derivedFinal = NULL; - BLI_listbase_clear(&ob_dst->gpulamp); + BLI_listbase_clear((ListBase *)&ob_dst->drawdata); BLI_listbase_clear(&ob_dst->pc_ids); - ob_dst->mpath = NULL; + ob_dst->avs = ob_src->avs; + ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath); copy_object_lod(ob_dst, ob_src, flag_subdata); - /* Do not copy runtime curve data. */ - ob_dst->curve_cache = NULL; - /* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id); @@ -1202,6 +1421,10 @@ Object *BKE_object_copy(Main *bmain, const Object *ob) { Object *ob_copy; BKE_id_copy_ex(bmain, &ob->id, (ID **)&ob_copy, 0, false); + + /* We increase object user count when linking to Collections. */ + id_us_min(&ob_copy->id); + return ob_copy; } @@ -1325,9 +1548,9 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */ /* local_object->proxy == pointer to library object, saved in files and read */ -/* local_object->proxy_group == pointer to group dupli-object, saved in files and read */ +/* local_object->proxy_group == pointer to collection dupli-object, saved in files and read */ -void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) +void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob) { /* paranoia checks */ if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) { @@ -1336,24 +1559,24 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) } ob->proxy = target; - ob->proxy_group = gob; + ob->proxy_group = cob; id_lib_extern(&target->id); - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - DAG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* copy transform - * - gob means this proxy comes from a group, just apply the matrix + * - cob means this proxy comes from a collection, just apply the matrix * so the object wont move from its dupli-transform. * - * - no gob means this is being made from a linked object, + * - no cob means this is being made from a linked object, * this is closer to making a copy of the object - in-place. */ - if (gob) { + if (cob) { ob->rotmode = target->rotmode; - mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat); - if (gob->dup_group) { /* should always be true */ + mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat); + if (cob->dup_group) { /* should always be true */ float tvec[3]; - mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs); + mul_v3_mat3_m4v3(tvec, ob->obmat, cob->dup_group->dupli_ofs); sub_v3_v3(ob->obmat[3], tvec); } BKE_object_apply_mat4(ob, ob->obmat, false, true); @@ -1402,7 +1625,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) if (target->type == OB_ARMATURE) { copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */ BKE_pose_rest(ob->pose); /* clear all transforms in channels */ - BKE_pose_rebuild(ob, ob->data); /* set all internal links */ + BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */ armature_set_id_extern(ob); } @@ -1438,6 +1661,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size) ob->empty_drawsize *= size; break; } + case OB_GPENCIL: + { + ob->empty_drawsize *= size; + break; + } case OB_FONT: { Curve *cu = ob->data; @@ -1662,7 +1890,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]) if (ob->parent) { float par_imat[4][4]; - BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat); + BKE_object_get_parent_matrix(NULL, NULL, ob, ob->parent, par_imat); invert_m4(par_imat); mul_m4_m4m4(mat, par_imat, ob->obmat); } @@ -1675,23 +1903,31 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]) int enable_cu_speed = 1; /** - * \param scene: Used when curve cache needs to be calculated, or for dupli-frame time. + * \param depsgraph: Used for dupli-frame time. * \return success if \a mat is set. */ -static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) +static bool ob_parcurve(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Object *par, float mat[4][4]) { Curve *cu = par->data; float vec[4], dir[3], quat[4], radius, ctime; + /* TODO: Make sure this doesn't crash. */ +#if 0 /* only happens on reload file, but violates depsgraph still... fix! */ if (par->curve_cache == NULL) { if (scene == NULL) { return false; } - BKE_displist_make_curveTypes(scene, par, 0); + BKE_displist_make_curveTypes(depsgraph, scene, par, 0); + } +#else + /* See: T56619 */ + if (par->runtime.curve_cache == NULL) { + return false; } +#endif - if (par->curve_cache->path == NULL) { + if (par->runtime.curve_cache->path == NULL) { return false; } @@ -1714,11 +1950,11 @@ static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) } else { /* For dupli-frames only */ - if (scene == NULL) { + if (depsgraph == NULL) { return false; } - ctime = BKE_scene_frame_get(scene); + ctime = DEG_get_ctime(depsgraph); if (cu->pathlen) { ctime /= cu->pathlen; } @@ -1732,21 +1968,7 @@ static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) { if (cu->flag & CU_FOLLOW) { -#if 0 - float si, q[4]; - vec_to_quat(quat, dir, ob->trackflag, ob->upflag); - - /* the tilt */ - normalize_v3(dir); - q[0] = cosf(0.5 * vec[3]); - si = sinf(0.5 * vec[3]); - q[1] = -si * dir[0]; - q[2] = -si * dir[1]; - q[3] = -si * dir[2]; - mul_qt_qtqt(quat, q, quat); -#else quat_apply_track(quat, ob->trackflag, ob->upflag); -#endif normalize_qt(quat); quat_to_mat4(mat, quat); } @@ -1806,18 +2028,23 @@ static void give_parvert(Object *par, int nr, float vec[3]) if (par->type == OB_MESH) { Mesh *me = par->data; BMEditMesh *em = me->edit_btmesh; - DerivedMesh *dm; + DerivedMesh *dm = NULL; + Mesh *me_eval = (em) ? em->mesh_eval_final : par->runtime.mesh_eval; - dm = (em) ? em->derivedFinal : par->derivedFinal; + /* Keep this until subsurf code ported away from derived mesh - campbell. */ + dm = par->derivedFinal; + if (dm && dm->type != DM_TYPE_CCGDM) { + dm = NULL; + } - if (dm) { + if (me_eval) { int count = 0; - int numVerts = dm->getNumVerts(dm); + const int numVerts = me_eval->totvert; if (nr < numVerts) { bool use_special_ss_case = false; - if (dm->type == DM_TYPE_CCGDM) { + if (dm && dm->type == DM_TYPE_CCGDM) { ModifierData *md; VirtualModifierData virtualModifierData; use_special_ss_case = true; @@ -1836,7 +2063,7 @@ static void give_parvert(Object *par, int nr, float vec[3]) if (!use_special_ss_case) { /* avoid dm->getVertDataArray() since it allocates arrays in the dm (not thread safe) */ - if (em && dm->type == DM_TYPE_EDITBMESH) { + if (em && me_eval->runtime.is_original) { if (em->bm->elem_table_dirty & BM_VERT) { #ifdef VPARENT_THREADING_HACK BLI_mutex_lock(&vparent_lock); @@ -1863,27 +2090,21 @@ static void give_parvert(Object *par, int nr, float vec[3]) count++; } } - else if (CustomData_has_layer(&dm->vertData, CD_ORIGINDEX) && - !(em && dm->type == DM_TYPE_EDITBMESH)) + else if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) && + !(em && me_eval->runtime.is_original)) { - int i; - + const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX); /* Get the average of all verts with (original index == nr). */ - for (i = 0; i < numVerts; i++) { - const int *index = dm->getVertData(dm, i, CD_ORIGINDEX); - if (*index == nr) { - float co[3]; - dm->getVertCo(dm, i, co); - add_v3_v3(vec, co); + for (int i = 0; i < numVerts; i++) { + if (index[i] == nr) { + add_v3_v3(vec, me_eval->mvert[i].co); count++; } } } else { if (nr < numVerts) { - float co[3]; - dm->getVertCo(dm, nr, co); - add_v3_v3(vec, co); + add_v3_v3(vec, me_eval->mvert[nr].co); count++; } } @@ -1897,7 +2118,9 @@ static void give_parvert(Object *par, int nr, float vec[3]) } else { /* use first index if its out of range */ - dm->getVertCo(dm, 0, vec); + if (me_eval->totvert) { + copy_v3_v3(vec, me_eval->mvert[0].co); + } } } else { @@ -1910,10 +2133,10 @@ static void give_parvert(Object *par, int nr, float vec[3]) ListBase *nurb; /* Unless there's some weird depsgraph failure the cache should exist. */ - BLI_assert(par->curve_cache != NULL); + BLI_assert(par->runtime.curve_cache != NULL); - if (par->curve_cache->deformed_nurbs.first != NULL) { - nurb = &par->curve_cache->deformed_nurbs; + if (par->runtime.curve_cache->deformed_nurbs.first != NULL) { + nurb = &par->runtime.curve_cache->deformed_nurbs; } else { Curve *cu = par->data; @@ -1924,7 +2147,7 @@ static void give_parvert(Object *par, int nr, float vec[3]) } else if (par->type == OB_LATTICE) { Lattice *latt = par->data; - DispList *dl = par->curve_cache ? BKE_displist_find(&par->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = par->runtime.curve_cache ? BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) : NULL; float (*co)[3] = dl ? (float (*)[3])dl->verts : NULL; int tot; @@ -1969,7 +2192,7 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4]) } -void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4]) +void BKE_object_get_parent_matrix(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, float parentmat[4][4]) { float tmat[4][4]; float vec[3]; @@ -1980,7 +2203,7 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p ok = 0; if (par->type == OB_CURVE) { if ((((Curve *)par->data)->flag & CU_PATH) && - (ob_parcurve(scene, ob, par, tmat))) + (ob_parcurve(depsgraph, scene, ob, par, tmat))) { ok = 1; } @@ -2016,7 +2239,8 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p /** * \param r_originmat Optional matrix that stores the space the object is in (without its own matrix applied) */ -static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4], +static void solve_parenting(Depsgraph *depsgraph, + Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4], float r_originmat[3][3], const bool set_origin) { float totmat[4][4]; @@ -2027,7 +2251,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4 if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat); - BKE_object_get_parent_matrix(scene, ob, par, totmat); + BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat); /* total */ mul_m4_m4m4(tmat, totmat, ob->parentinv); @@ -2070,20 +2294,21 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat } /* note, scene is the active scene while actual_scene is the scene the object resides in */ -void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime, - RigidBodyWorld *rbw, float r_originmat[3][3]) +void BKE_object_where_is_calc_time_ex( + Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime, + RigidBodyWorld *rbw, float r_originmat[3][3]) { if (ob == NULL) return; /* execute drivers only, as animation has already been done */ - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS); if (ob->parent) { Object *par = ob->parent; float slowmat[4][4]; /* calculate parent matrix */ - solve_parenting(scene, ob, par, ob->obmat, slowmat, r_originmat, true); + solve_parenting(depsgraph, scene, ob, par, ob->obmat, slowmat, r_originmat, true); /* "slow parent" is definitely not threadsafe, and may also give bad results jumping around * An old-fashioned hack which probably doesn't really cut it anymore @@ -2105,8 +2330,8 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime, /* solve constraints */ if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) { bConstraintOb *cob; - cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - BKE_constraints_solve(&ob->constraints, cob, ctime); + cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime); BKE_constraints_clear_evalob(cob); } @@ -2115,16 +2340,16 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime, else ob->transflag &= ~OB_NEG_SCALE; } -void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime) +void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime) { - BKE_object_where_is_calc_time_ex(scene, ob, ctime, NULL, NULL); + BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, ctime, NULL, NULL); } /* get object transformation matrix without recalculating dependencies and * constraints -- assume dependencies are already solved by depsgraph. * no changes to object and it's parent would be done. * used for bundles orientation in 3d space relative to parented blender camera */ -void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4]) +void BKE_object_where_is_calc_mat4(Depsgraph *depsgraph, Scene *scene, Object *ob, float obmat[4][4]) { if (ob->parent) { @@ -2132,7 +2357,7 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4]) Object *par = ob->parent; - solve_parenting(scene, ob, par, obmat, slowmat, NULL, false); + solve_parenting(depsgraph, scene, ob, par, obmat, slowmat, NULL, false); if (ob->partype & PARSLOW) where_is_object_parslow(ob, obmat, slowmat); @@ -2142,52 +2367,69 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4]) } } -void BKE_object_where_is_calc_ex(Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3]) +void BKE_object_where_is_calc_ex(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3]) { - BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), rbw, r_originmat); + BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), rbw, r_originmat); } -void BKE_object_where_is_calc(Scene *scene, Object *ob) +void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob) { - BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), NULL, NULL); + BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), NULL, NULL); } -/* for calculation of the inverse parent transform, only used for editor */ -void BKE_object_workob_calc_parent(Scene *scene, Object *ob, Object *workob) +/** + * For calculation of the inverse parent transform, only used for editor. + * + * It assumes the object parent is already in the depsgraph. + * Otherwise, after changing ob->parent you need to call: + * - #DEG_relations_tag_update(bmain); + * - #BKE_scene_graph_update_tagged(depsgraph, bmain); + */ +void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob) { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); BKE_object_workob_clear(workob); unit_m4(workob->obmat); unit_m4(workob->parentinv); unit_m4(workob->constinv); - workob->parent = ob->parent; - workob->trackflag = ob->trackflag; - workob->upflag = ob->upflag; + /* Since this is used while calculating parenting, at this moment ob_eval->parent is still NULL. */ + workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent); - workob->partype = ob->partype; - workob->par1 = ob->par1; - workob->par2 = ob->par2; - workob->par3 = ob->par3; + workob->trackflag = ob_eval->trackflag; + workob->upflag = ob_eval->upflag; - workob->constraints.first = ob->constraints.first; - workob->constraints.last = ob->constraints.last; + workob->partype = ob_eval->partype; + workob->par1 = ob_eval->par1; + workob->par2 = ob_eval->par2; + workob->par3 = ob_eval->par3; - BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr)); + workob->constraints = ob_eval->constraints; - BKE_object_where_is_calc(scene, workob); + BLI_strncpy(workob->parsubstr, ob_eval->parsubstr, sizeof(workob->parsubstr)); + + BKE_object_where_is_calc(depsgraph, scene, workob); } -/* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */ -void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent) +/** + * Applies the global transformation \a mat to the \a ob using a relative parent space if supplied. + * + * \param mat the global transformation mat that the object should be set object to. + * \param parent the parent space in which this object will be set relative to (should probably always be parent_eval). + * \param use_compat true to ensure that rotations are set using the min difference between the old and new orientation. + */ +void BKE_object_apply_mat4_ex(Object *ob, float mat[4][4], Object *parent, float parentinv[4][4], const bool use_compat) { + /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */ + float rot[3][3]; - if (use_parent && ob->parent) { + if (parent != NULL) { float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4]; - BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat); + BKE_object_get_parent_matrix(NULL, NULL, ob, parent, parent_mat); - mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv); + mul_m4_m4m4(diff_mat, parent_mat, parentinv); invert_m4_m4(imat, diff_mat); mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */ @@ -2209,10 +2451,16 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c /* BKE_object_mat3_to_rot handles delta rotations */ } +/* XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly */ +void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent) +{ + BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat); +} + BoundBox *BKE_boundbox_alloc_unit(void) { BoundBox *bb; - const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {-1.0f, -1.0f, -1.0f}; + const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox"); BKE_boundbox_init_from_minmax(bb, min, max); @@ -2260,20 +2508,29 @@ BoundBox *BKE_object_boundbox_get(Object *ob) { BoundBox *bb = NULL; - if (ob->type == OB_MESH) { - bb = BKE_mesh_boundbox_get(ob); - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - bb = BKE_curve_boundbox_get(ob); - } - else if (ob->type == OB_MBALL) { - bb = ob->bb; - } - else if (ob->type == OB_LATTICE) { - bb = BKE_lattice_boundbox_get(ob); - } - else if (ob->type == OB_ARMATURE) { - bb = BKE_armature_boundbox_get(ob); + switch (ob->type) { + case OB_MESH: + bb = BKE_mesh_boundbox_get(ob); + break; + case OB_CURVE: + case OB_SURF: + case OB_FONT: + bb = BKE_curve_boundbox_get(ob); + break; + case OB_MBALL: + bb = BKE_mball_boundbox_get(ob); + break; + case OB_LATTICE: + bb = BKE_lattice_boundbox_get(ob); + break; + case OB_ARMATURE: + bb = BKE_armature_boundbox_get(ob); + break; + case OB_GPENCIL: + bb = BKE_gpencil_boundbox_get(ob); + break; + default: + break; } return bb; } @@ -2288,6 +2545,23 @@ void BKE_object_boundbox_flag(Object *ob, int flag, const bool set) } } +void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval) +{ + float min[3], max[3]; + + INIT_MINMAX(min, max); + + BKE_mesh_minmax(me_eval, min, max); + + if (ob->bb == NULL) { + ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox"); + } + + BKE_boundbox_init_from_minmax(ob->bb, min, max); + + ob->bb->flag &= ~BOUNDBOX_DIRTY; +} + void BKE_object_dimensions_get(Object *ob, float vec[3]) { BoundBox *bb = NULL; @@ -2393,7 +2667,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us float size[3]; copy_v3_v3(size, ob->size); - if (ob->type == OB_EMPTY) { + if ((ob->type == OB_EMPTY) || (ob->type == OB_GPENCIL)) { mul_v3_fl(size, ob->empty_drawsize); } @@ -2417,9 +2691,9 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value) if (!ob->iuser) { ob->iuser = MEM_callocN(sizeof(ImageUser), "image user"); ob->iuser->ok = 1; + ob->iuser->flag |= IMA_ANIM_ALWAYS; ob->iuser->frames = 100; ob->iuser->sfra = 1; - ob->iuser->fie_ima = 2; } } else { @@ -2430,9 +2704,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value) } } -bool BKE_object_minmax_dupli( - Main *bmain, Scene *scene, - Object *ob, float r_min[3], float r_max[3], const bool use_hidden) +bool BKE_object_minmax_dupli(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_min[3], float r_max[3], const bool use_hidden) { bool ok = false; if ((ob->transflag & OB_DUPLI) == 0) { @@ -2441,7 +2713,7 @@ bool BKE_object_minmax_dupli( else { ListBase *lb; DupliObject *dob; - lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob); + lb = object_duplilist(depsgraph, scene, ob); for (dob = lb->first; dob; dob = dob->next) { if ((use_hidden == false) && (dob->no_draw != 0)) { /* pass */ @@ -2473,21 +2745,19 @@ void BKE_object_foreach_display_point( { float co[3]; - if (ob->derivedFinal) { - DerivedMesh *dm = ob->derivedFinal; - MVert *mv = dm->getVertArray(dm); - int totvert = dm->getNumVerts(dm); - int i; - - for (i = 0; i < totvert; i++, mv++) { + if (ob->runtime.mesh_eval) { + const Mesh *me = ob->runtime.mesh_eval; + const MVert *mv = me->mvert; + const int totvert = me->totvert; + for (int i = 0; i < totvert; i++, mv++) { mul_v3_m4v3(co, obmat, mv->co); func_cb(co, user_data); } } - else if (ob->curve_cache && ob->curve_cache->disp.first) { + else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) { DispList *dl; - for (dl = ob->curve_cache->disp.first; dl; dl = dl->next) { + for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) { const float *v3 = dl->verts; int totvert = dl->nr; int i; @@ -2501,33 +2771,20 @@ void BKE_object_foreach_display_point( } void BKE_scene_foreach_display_point( - Main *bmain, Scene *scene, View3D *v3d, const short flag, + Depsgraph *depsgraph, void (*func_cb)(const float[3], void *), void *user_data) { - Base *base; - Object *ob; - - for (base = FIRSTBASE; base; base = base->next) { - if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag & flag) == flag) { - ob = base->object; - - if ((ob->transflag & OB_DUPLI) == 0) { - BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data); - } - else { - ListBase *lb; - DupliObject *dob; - - lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob); - for (dob = lb->first; dob; dob = dob->next) { - if (dob->no_draw == 0) { - BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data); - } - } - free_object_duplilist(lb); /* does restore */ - } + DEG_OBJECT_ITER_BEGIN( + depsgraph, ob, + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI) + { + if ((ob->base_flag & BASE_SELECTED) != 0) { + BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data); } } + DEG_OBJECT_ITER_END; } /* copied from DNA_object_types.h */ @@ -2541,7 +2798,7 @@ typedef struct ObTfmBack { float obmat[4][4]; /* final worldspace matrix with constraints & animsys applied */ float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */ float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */ - float imat[4][4]; /* inverse matrix of 'obmat' for during render, old game engine, temporally: ipokeys of transform */ + float imat[4][4]; /* inverse matrix of 'obmat' for during render, temporally: ipokeys of transform */ } ObTfmBack; void *BKE_object_tfm_backup(Object *ob) @@ -2598,25 +2855,24 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob) return BKE_object_parent_loop_check(par->parent, ob); } -static void object_handle_update_proxy(Main *bmain, - EvaluationContext *eval_ctx, +static void object_handle_update_proxy(Depsgraph *depsgraph, Scene *scene, Object *object, const bool do_proxy_update) { - /* The case when this is a group proxy, object_update is called in group.c */ + /* The case when this is a collection proxy, object_update is called in collection.c */ if (object->proxy == NULL) { return; } /* set pointer in library proxy target, for copying, but restore it */ object->proxy->proxy_from = object; - // printf("set proxy pointer for later group stuff %s\n", ob->id.name); + // printf("set proxy pointer for later collection stuff %s\n", ob->id.name); /* the no-group proxy case, we call update */ if (object->proxy_group == NULL) { if (do_proxy_update) { // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); - BKE_object_handle_update(bmain, eval_ctx, scene, object->proxy); + BKE_object_handle_update(depsgraph, scene, object->proxy); } } } @@ -2629,14 +2885,18 @@ static void object_handle_update_proxy(Main *bmain, /* the main object update call, for object matrix, constraints, keys and displist (modifiers) */ /* requires flags to be set! */ /* Ideally we shouldn't have to pass the rigid body world, but need bigger restructuring to avoid id */ -void BKE_object_handle_update_ex(Main *bmain, - EvaluationContext *eval_ctx, +void BKE_object_handle_update_ex(Depsgraph *depsgraph, Scene *scene, Object *ob, RigidBodyWorld *rbw, const bool do_proxy_update) { - if ((ob->recalc & OB_RECALC_ALL) == 0) { - object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update); + const ID *object_data = ob->data; + const bool recalc_object = (ob->id.recalc & ID_RECALC) != 0; + const bool recalc_data = + (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0) + : 0; + if (!recalc_object && ! recalc_data) { + object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update); return; } /* Speed optimization for animation lookups. */ @@ -2646,46 +2906,48 @@ void BKE_object_handle_update_ex(Main *bmain, BKE_pose_update_constraint_flags(ob->pose); } } - if (ob->recalc & OB_RECALC_DATA) { + if (recalc_data) { if (ob->type == OB_ARMATURE) { /* this happens for reading old files and to match library armatures * with poses we do it ahead of BKE_object_where_is_calc to ensure animation * is evaluated on the rebuilt pose, otherwise we get incorrect poses * on file load */ - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) - BKE_pose_rebuild(ob, ob->data); + if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { + /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */ + BKE_pose_rebuild(NULL, ob, ob->data, true); + } } } /* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers, * which is only in BKE_object_where_is_calc now */ /* XXX: should this case be OB_RECALC_OB instead? */ - if (ob->recalc & OB_RECALC_ALL) { + if (recalc_object || recalc_data) { if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { printf("recalcob %s\n", ob->id.name + 2); } /* Handle proxy copy for target. */ - if (!BKE_object_eval_proxy_copy(eval_ctx, ob)) { - BKE_object_where_is_calc_ex(scene, rbw, ob, NULL); + if (!BKE_object_eval_proxy_copy(depsgraph, ob)) { + BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, NULL); } } - if (ob->recalc & OB_RECALC_DATA) { - BKE_object_handle_data_update(bmain, eval_ctx, scene, ob); + if (recalc_data) { + BKE_object_handle_data_update(depsgraph, scene, ob); } - ob->recalc &= ~OB_RECALC_ALL; + ob->id.recalc &= ID_RECALC_ALL; - object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update); + object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update); } /* WARNING: "scene" here may not be the scene object actually resides in. * When dealing with background-sets, "scene" is actually the active scene. * e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n - * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the corrent rigid body world + * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the current rigid body world */ -void BKE_object_handle_update(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob) +void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob) { - BKE_object_handle_update_ex(bmain, eval_ctx, scene, ob, NULL, true); + BKE_object_handle_update_ex(depsgraph, scene, ob, NULL, true); } void BKE_object_sculpt_modifiers_changed(Object *ob) @@ -2730,14 +2992,7 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, switch (GS(((ID *)ob->data)->name)) { case ID_ME: { - Mesh *me = ob->data; - if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { - BKE_mesh_texspace_calc(me); - } - if (r_texflag) *r_texflag = &me->texflag; - if (r_loc) *r_loc = me->loc; - if (r_size) *r_size = me->size; - if (r_rot) *r_rot = me->rot; + BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size); break; } case ID_CU: @@ -2767,6 +3022,68 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, return 1; } +/** Get evaluated mesh for given (main, original) object and depsgraph. */ +Mesh *BKE_object_get_evaluated_mesh(const Depsgraph *depsgraph, Object *ob) +{ + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + return ob_eval->runtime.mesh_eval; +} + +/* Get object's mesh with all modifiers applied. */ +Mesh *BKE_object_get_final_mesh(Object *object) +{ + if (object->runtime.mesh_eval != NULL) { + BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); + BLI_assert(object->runtime.mesh_eval == object->data); + BLI_assert((object->runtime.mesh_eval->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) != 0); + return object->runtime.mesh_eval; + } + /* Wasn't evaluated yet. */ + return object->data; +} + +/* Get mesh which is not affected by modifiers: + * - For original objects it will be same as object->data, and it is a mesh + * which is in the corresponding bmain. + * - For copied-on-write objects it will give pointer to a copied-on-write + * mesh which corresponds to original object's mesh. + */ +Mesh *BKE_object_get_pre_modified_mesh(Object *object) +{ + if (object->runtime.mesh_orig != NULL) { + BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE); + BLI_assert(object->id.orig_id != NULL); + BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data); + Mesh *result = object->runtime.mesh_orig; + BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); + BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); + return result; + } + BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0); + return object->data; +} + +/* Get a mesh which corresponds to very very original mesh from bmain. + * - For original objects it will be object->data. + * - For evaluated objects it will be same mesh as corresponding original + * object uses as data. + */ +Mesh *BKE_object_get_original_mesh(Object *object) +{ + Mesh *result = NULL; + if (object->id.orig_id == NULL) { + BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0); + result = object->data; + } + else { + BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0); + result = ((Object *)object->id.orig_id)->data; + } + BLI_assert(result != NULL); + BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) == 0); + return result; +} + static int pc_cmp(const void *a, const void *b) { const LinkData *ad = a, *bd = b; @@ -2841,7 +3158,7 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const if (newkey || from_mix == false) { /* create from mesh */ kb = BKE_keyblock_add_ctime(key, name, false); - BKE_keyblock_convert_from_mesh(me, kb); + BKE_keyblock_convert_from_mesh(me, key, kb); } else { /* copy from current values */ @@ -3269,6 +3586,10 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default) return clip; } +void BKE_object_runtime_reset(Object *object) +{ + memset(&object->runtime, 0, sizeof(object->runtime)); +} /* * Find an associated Armature object @@ -3304,33 +3625,33 @@ static void obrel_list_add(LinkNode **links, Object *ob) } /* - * Iterates over all objects of the given scene. + * Iterates over all objects of the given scene layer. * Depending on the eObjectSet flag: * collect either OB_SET_ALL, OB_SET_VISIBLE or OB_SET_SELECTED objects. * If OB_SET_VISIBLE or OB_SET_SELECTED are collected, * then also add related objects according to the given includeFilters. */ -LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter) +LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter) { LinkNode *links = NULL; Base *base; /* Remove markers from all objects */ - for (base = scene->base.first; base; base = base->next) { + for (base = view_layer->object_bases.first; base; base = base->next) { base->object->id.tag &= ~LIB_TAG_DOIT; } /* iterate over all selected and visible objects */ - for (base = scene->base.first; base; base = base->next) { + for (base = view_layer->object_bases.first; base; base = base->next) { if (objectSet == OB_SET_ALL) { /* as we get all anyways just add it */ Object *ob = base->object; obrel_list_add(&links, ob); } else { - if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), scene, base)) || - (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, base))) + if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(base)) || + (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(base))) { Object *ob = base->object; @@ -3359,8 +3680,8 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS /* child relationship */ if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) { Base *local_base; - for (local_base = scene->base.first; local_base; local_base = local_base->next) { - if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) { + for (local_base = view_layer->object_bases.first; local_base; local_base = local_base->next) { + if (BASE_EDITABLE_BGMODE(local_base)) { Object *child = local_base->object; if (obrel_list_test(child)) { @@ -3395,27 +3716,21 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS */ struct LinkNode *BKE_object_groups(Main *bmain, Object *ob) { - LinkNode *group_linknode = NULL; - Group *group = NULL; - while ((group = BKE_group_object_find(bmain, group, ob))) { - BLI_linklist_prepend(&group_linknode, group); + LinkNode *collection_linknode = NULL; + Collection *collection = NULL; + while ((collection = BKE_collection_object_find(bmain, collection, ob))) { + BLI_linklist_prepend(&collection_linknode, collection); } - return group_linknode; + return collection_linknode; } -void BKE_object_groups_clear(Main *bmain, Scene *scene, Base *base, Object *object) +void BKE_object_groups_clear(Main *bmain, Object *ob) { - Group *group = NULL; - - BLI_assert((base == NULL) || (base->object == object)); - - if (scene && base == NULL) { - base = BKE_scene_base_find(scene, object); - } - - while ((group = BKE_group_object_find(bmain, group, base->object))) { - BKE_group_object_unlink(bmain, group, object, scene, base); + Collection *collection = NULL; + while ((collection = BKE_collection_object_find(bmain, collection, ob))) { + BKE_collection_object_remove(bmain, collection, ob, false); + DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE); } } @@ -3439,12 +3754,12 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot) Mesh *me = ob->data; unsigned int i; - DerivedMesh *dm = ob->derivedDeform ? ob->derivedDeform : ob->derivedFinal; + Mesh *me_eval = ob->runtime.mesh_deform_eval ? ob->runtime.mesh_deform_eval : ob->runtime.mesh_deform_eval; const int *index; - if (dm && (index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))) { - MVert *mvert = dm->getVertArray(dm); - unsigned int totvert = dm->getNumVerts(dm); + if (me_eval && (index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) { + MVert *mvert = me_eval->mvert; + uint totvert = me_eval->totvert; /* tree over-allocs in case where some verts have ORIGINDEX_NONE */ tot = 0; @@ -3594,12 +3909,80 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) return false; } +bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md) +{ + if (BKE_gpencil_modifier_dependsOnTime(md)) { + return true; + } + + /* Check whether modifier is animated. */ + /* TODO (Aligorith): this should be handled as part of build_animdata() */ + if (ob->adt) { + AnimData *adt = ob->adt; + FCurve *fcu; + + char pattern[MAX_NAME + 32]; + BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name); + + /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */ + if (adt->action) { + for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) { + return true; + } + } + } + + /* This here allows modifier properties to get driven and still update properly */ + for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) { + return true; + } + } + } + + return false; +} + +bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx) +{ + if (BKE_shaderfx_dependsOnTime(fx)) { + return true; + } + + /* Check whether effect is animated. */ + /* TODO (Aligorith): this should be handled as part of build_animdata() */ + if (ob->adt) { + AnimData *adt = ob->adt; + FCurve *fcu; + + char pattern[MAX_NAME + 32]; + BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name); + + /* action - check for F-Curves with paths containing string[' */ + if (adt->action) { + for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + /* This here allows properties to get driven and still update properly */ + for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + return false; +} + /* set "ignore cache" flag for all caches on this object */ -static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state) +static void object_cacheIgnoreClear(Object *ob, int state) { ListBase pidlist; PTCacheID *pid; - BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0); + BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0); for (pid = pidlist.first; pid; pid = pid->next) { if (pid->cache) { @@ -3617,10 +4000,8 @@ static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state) * Avoid calling this in new code unless there is a very good reason for it! */ bool BKE_object_modifier_update_subframe( - Main *bmain, EvaluationContext *eval_ctx, - Scene *scene, Object *ob, bool update_mesh, - int parent_recursion, float frame, - int type) + Depsgraph *depsgraph, Scene *scene, Object *ob, bool update_mesh, + int parent_recursion, float frame, int type) { ModifierData *md = modifiers_findByType(ob, (ModifierType)type); bConstraint *con; @@ -3643,8 +4024,8 @@ bool BKE_object_modifier_update_subframe( if (parent_recursion) { int recursion = parent_recursion - 1; bool no_update = false; - if (ob->parent) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->parent, 0, recursion, frame, type); - if (ob->track) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->track, 0, recursion, frame, type); + if (ob->parent) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->parent, 0, recursion, frame, type); + if (ob->track) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->track, 0, recursion, frame, type); /* skip subframe if object is parented * to vertex of a dynamic paint canvas */ @@ -3661,7 +4042,7 @@ bool BKE_object_modifier_update_subframe( cti->get_constraint_targets(con, &targets); for (ct = targets.first; ct; ct = ct->next) { if (ct->tar) - BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ct->tar, 0, recursion, frame, type); + BKE_object_modifier_update_subframe(depsgraph, scene, ct->tar, 0, recursion, frame, type); } /* free temp targets */ if (cti->flush_constraint_targets) @@ -3671,28 +4052,29 @@ bool BKE_object_modifier_update_subframe( } /* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */ - ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM); + /* TODO(sergey): What about animation? */ + ob->id.recalc |= ID_RECALC_ALL; + BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM); if (update_mesh) { /* ignore cache clear during subframe updates - * to not mess up cache validity */ - object_cacheIgnoreClear(bmain, ob, 1); - BKE_object_handle_update(bmain, eval_ctx, scene, ob); - object_cacheIgnoreClear(bmain, ob, 0); + * to not mess up cache validity */ + object_cacheIgnoreClear(ob, 1); + BKE_object_handle_update(depsgraph, scene, ob); + object_cacheIgnoreClear(ob, 0); } else - BKE_object_where_is_calc_time(scene, ob, frame); + BKE_object_where_is_calc_time(depsgraph, scene, ob, frame); /* for curve following objects, parented curve has to be updated too */ if (ob->type == OB_CURVE) { Curve *cu = ob->data; - BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(depsgraph, scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM); } /* and armatures... */ if (ob->type == OB_ARMATURE) { bArmature *arm = ob->data; - BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM); - BKE_pose_where_is(scene, ob); + BKE_animsys_evaluate_animdata(depsgraph, scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM); + BKE_pose_where_is(depsgraph, scene, ob); } return false; diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 47f86c28dfc..70569bfd51b 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -51,7 +51,9 @@ #include "BKE_editmesh.h" #include "BKE_object_deform.h" /* own include */ #include "BKE_object.h" +#include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_gpencil.h" /** \name Misc helpers * \{ */ @@ -401,10 +403,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg) */ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) { - if (BKE_object_is_in_editmode_vgroup(ob)) - object_defgroup_remove_edit_mode(ob, defgroup); - else - object_defgroup_remove_object_mode(ob, defgroup); + if (ob->type == OB_GPENCIL) { + BKE_gpencil_vgroup_remove(ob, defgroup); + } + else { + if (BKE_object_is_in_editmode_vgroup(ob)) + object_defgroup_remove_edit_mode(ob, defgroup); + else + object_defgroup_remove_object_mode(ob, defgroup); + + BKE_object_batch_cache_dirty_tag(ob); + } } /** diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 1406a7dd66b..882ec07f56a 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -42,26 +42,30 @@ #include "BLI_rand.h" #include "DNA_anim_types.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "DNA_vfont_types.h" #include "BKE_animsys.h" -#include "BKE_DerivedMesh.h" -#include "BKE_depsgraph.h" +#include "BKE_collection.h" #include "BKE_font.h" -#include "BKE_group.h" #include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_iterators.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" #include "BKE_editmesh.h" #include "BKE_anim.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "BLI_strict_flags.h" #include "BLI_hash.h" @@ -69,16 +73,14 @@ /* Dupli-Geometry */ typedef struct DupliContext { - EvaluationContext *eval_ctx; - bool do_update; - bool animated; - Group *group; /* XXX child objects are selected from this group if set, could be nicer */ + Depsgraph *depsgraph; + Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */ + Object *obedit; /* Only to check if the object is in edit-mode. */ - Main *bmain; Scene *scene; + ViewLayer *view_layer; Object *object; float space_mat[4][4]; - unsigned int lay; int persistent_id[MAX_DUPLI_RECUR]; int level; @@ -98,23 +100,20 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx); /* create initial context for root object */ static void init_context( - DupliContext *r_ctx, Main *bmain, EvaluationContext *eval_ctx, - Scene *scene, Object *ob, float space_mat[4][4], bool update) + DupliContext *r_ctx, Depsgraph *depsgraph, + Scene *scene, Object *ob, float space_mat[4][4]) { - r_ctx->eval_ctx = eval_ctx; - r_ctx->bmain = bmain; + r_ctx->depsgraph = depsgraph; r_ctx->scene = scene; - /* don't allow BKE_object_handle_update for viewport during render, can crash */ - r_ctx->do_update = update && !(G.is_rendering && eval_ctx->mode != DAG_EVAL_RENDER); - r_ctx->animated = false; - r_ctx->group = NULL; + r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph); + r_ctx->collection = NULL; r_ctx->object = ob; + r_ctx->obedit = OBEDIT_FROM_OBACT(ob); if (space_mat) copy_m4_m4(r_ctx->space_mat, space_mat); else unit_m4(r_ctx->space_mat); - r_ctx->lay = ob->lay; r_ctx->level = 0; r_ctx->gen = get_dupli_generator(r_ctx); @@ -123,15 +122,13 @@ static void init_context( } /* create sub-context for recursive duplis */ -static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated) +static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index) { *r_ctx = *ctx; - r_ctx->animated |= animated; /* object animation makes all children animated */ - /* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */ - if (ctx->gen->type == OB_DUPLIGROUP) - r_ctx->group = ctx->object->dup_group; + if (ctx->gen->type == OB_DUPLICOLLECTION) + r_ctx->collection = ctx->object->dup_group; r_ctx->object = ob; if (mat) @@ -146,8 +143,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj * mat is transform of the object relative to current context (including object obmat) */ static DupliObject *make_dupli(const DupliContext *ctx, - Object *ob, float mat[4][4], int index, - bool animated, bool hide) + Object *ob, float mat[4][4], int index) { DupliObject *dob; int i; @@ -164,7 +160,6 @@ static DupliObject *make_dupli(const DupliContext *ctx, dob->ob = ob; mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat); dob->type = ctx->gen->type; - dob->animated = animated || ctx->animated; /* object itself or some parent is animated */ /* set persistent id, which is an array with a persistent index for each level * (particle number, vertex number, ..). by comparing this we can find the same @@ -177,8 +172,6 @@ static DupliObject *make_dupli(const DupliContext *ctx, for (; i < MAX_DUPLI_RECUR; i++) dob->persistent_id[i] = INT_MAX; - if (hide) - dob->no_draw = true; /* metaballs never draw in duplis, they are instead merged into one by the basis * mball outside of the group. this does mean that if that mball is not in the * scene, they will not show up at all, limitation that should be solved once. */ @@ -208,12 +201,12 @@ static DupliObject *make_dupli(const DupliContext *ctx, /* recursive dupli objects * space_mat is the local dupli space (excluding dupli object obmat!) */ -static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated) +static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index) { - /* simple preventing of too deep nested groups with MAX_DUPLI_RECUR */ + /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */ if (ctx->level < MAX_DUPLI_RECUR) { DupliContext rctx; - copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated); + copy_dupli_context(&rctx, ctx, ob, space_mat, index); if (rctx.gen) { rctx.gen->make_duplis(&rctx); } @@ -235,45 +228,40 @@ static bool is_child(const Object *ob, const Object *parent) return false; } -/* create duplis from every child in scene or group */ +/* create duplis from every child in scene or collection */ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb) { Object *parent = ctx->object; - Object *obedit = ctx->scene->obedit; - - if (ctx->group) { - unsigned int lay = ctx->group->layer; - int groupid = 0; - GroupObject *go; - for (go = ctx->group->gobject.first; go; go = go->next, groupid++) { - Object *ob = go->ob; - if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) { + if (ctx->collection) { + eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(ctx->collection, ob, mode) + { + if ((ob != ctx->obedit) && is_child(ob, parent)) { DupliContext pctx; - copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false); + copy_dupli_context(&pctx, ctx, ctx->object, NULL, _base_id); /* mballs have a different dupli handling */ - if (ob->type != OB_MBALL) + if (ob->type != OB_MBALL) { ob->flag |= OB_DONE; /* doesn't render */ - + } make_child_duplis_cb(&pctx, userdata, ob); } } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; } else { - unsigned int lay = ctx->scene->lay; int baseid = 0; - Base *base; - for (base = ctx->scene->base.first; base; base = base->next, baseid++) { + ViewLayer *view_layer = ctx->view_layer; + for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) { Object *ob = base->object; - - if ((base->lay & lay) && ob != obedit && is_child(ob, parent)) { + if ((ob != ctx->obedit) && is_child(ob, parent)) { DupliContext pctx; - copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false); + copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid); /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) - ob->flag |= OB_DONE; /* doesnt render */ + ob->flag |= OB_DONE; /* doesn't render */ make_child_duplis_cb(&pctx, userdata, ob); } @@ -284,77 +272,49 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild /*---- Implementations ----*/ -/* OB_DUPLIGROUP */ -static void make_duplis_group(const DupliContext *ctx) +/* OB_DUPLICOLLECTION */ +static void make_duplis_collection(const DupliContext *ctx) { - bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER); Object *ob = ctx->object; - Group *group; - GroupObject *go; - float group_mat[4][4]; - int id; - bool animated, hide; + Collection *collection; + float collection_mat[4][4]; if (ob->dup_group == NULL) return; - group = ob->dup_group; + collection = ob->dup_group; - /* combine group offset and obmat */ - unit_m4(group_mat); - sub_v3_v3(group_mat[3], group->dupli_ofs); - mul_m4_m4m4(group_mat, ob->obmat, group_mat); + /* combine collection offset and obmat */ + unit_m4(collection_mat); + sub_v3_v3(collection_mat[3], collection->dupli_ofs); + mul_m4_m4m4(collection_mat, ob->obmat, collection_mat); /* don't access 'ob->obmat' from now on. */ - /* handles animated groups */ - - /* we need to check update for objects that are not in scene... */ - if (ctx->do_update) { - /* note: update is optional because we don't always need object - * transformations to be correct. Also fixes bug [#29616]. */ - BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, ctx->scene, ob, group); - } - - animated = BKE_group_is_animated(group, ob); - - for (go = group->gobject.first, id = 0; go; go = go->next, id++) { - /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ - if (go->ob != ob) { + eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, cob, mode) + { + if (cob != ob) { float mat[4][4]; - /* Special case for instancing dupli-groups, see: T40051 - * this object may be instanced via dupli-verts/faces, in this case we don't want to render - * (blender convention), but _do_ show in the viewport. - * - * Regular objects work fine but not if we're instancing dupli-groups, - * because the rules for rendering aren't applied to objects they instance. - * We could recursively pass down the 'hide' flag instead, but that seems unnecessary. - */ - if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) { - continue; - } - - /* group dupli offset, should apply after everything else */ - mul_m4_m4m4(mat, group_mat, go->ob->obmat); - - /* check the group instance and object layers match, also that the object visible flags are ok. */ - hide = (go->ob->lay & group->layer) == 0 || - (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW); + /* collection dupli offset, should apply after everything else */ + mul_m4_m4m4(mat, collection_mat, cob->obmat); - make_dupli(ctx, go->ob, mat, id, animated, hide); + make_dupli(ctx, cob, mat, _base_id); /* recursion */ - make_recursive_duplis(ctx, go->ob, group_mat, id, animated); + make_recursive_duplis(ctx, cob, collection_mat, _base_id); } } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; } -static const DupliGenerator gen_dupli_group = { - OB_DUPLIGROUP, /* type */ - make_duplis_group /* make_duplis */ +static const DupliGenerator gen_dupli_collection = { + OB_DUPLICOLLECTION, /* type */ + make_duplis_collection /* make_duplis */ }; /* OB_DUPLIFRAMES */ static void make_duplis_frames(const DupliContext *ctx) { + Depsgraph *depsgraph = ctx->depsgraph; Scene *scene = ctx->scene; Object *ob = ctx->object; extern int enable_cu_speed; /* object.c */ @@ -362,8 +322,8 @@ static void make_duplis_frames(const DupliContext *ctx) int cfrao = scene->r.cfra; int dupend = ob->dupend; - /* dupliframes not supported inside groups */ - if (ctx->group) + /* dupliframes not supported inside collections */ + if (ctx->collection) return; /* if we don't have any data/settings which will lead to object movement, * don't waste time trying, as it will all look the same... @@ -381,10 +341,6 @@ static void make_duplis_frames(const DupliContext *ctx) /* duplicate over the required range */ if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0; - /* special flag to avoid setting recalc flags to notify the depsgraph of - * updates, as this is not a permanent change to the object */ - ob->id.recalc |= ID_RECALC_SKIP_ANIM_TAG; - for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) { int ok = 1; @@ -402,10 +358,11 @@ static void make_duplis_frames(const DupliContext *ctx) * and/or other objects which may affect this object's transforms are not updated either. * However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine! */ - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ - BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); + /* ob-eval will do drivers, so we don't need to do them */ + BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); + BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra); - make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false); + make_dupli(ctx, ob, ob->obmat, scene->r.cfra); } } @@ -416,8 +373,9 @@ static void make_duplis_frames(const DupliContext *ctx) */ scene->r.cfra = cfrao; - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ - BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); + /* ob-eval will do drivers, so we don't need to do them */ + BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); + BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra); /* but, to make sure unkeyed object transforms are still sane, * let's copy object's original data back over @@ -432,7 +390,7 @@ static const DupliGenerator gen_dupli_frames = { /* OB_DUPLIVERTS */ typedef struct VertexDupliData { - DerivedMesh *dm; + Mesh *me_eval; BMEditMesh *edit_btmesh; int totvert; float (*orco)[3]; @@ -490,56 +448,34 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); - dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false); + dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index); if (vdd->orco) copy_v3_v3(dob->orco, vdd->orco[index]); /* recursion */ - make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false); + make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index); } static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child) { VertexDupliData *vdd = userdata; - DerivedMesh *dm = vdd->dm; + Mesh *me_eval = vdd->me_eval; vdd->inst_ob = child; invert_m4_m4(child->imat, child->obmat); /* relative transform from parent to child space */ mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat); - if (vdd->edit_btmesh) { - dm->foreachMappedVert(dm, vertex_dupli__mapFunc, vdd, - vdd->use_rotation ? DM_FOREACH_USE_NORMAL : 0); - } - else { - int a, totvert = vdd->totvert; - float vec[3], no[3]; - - if (vdd->use_rotation) { - for (a = 0; a < totvert; a++) { - dm->getVertCo(dm, a, vec); - dm->getVertNo(dm, a, no); - - vertex_dupli__mapFunc(vdd, a, vec, no, NULL); - } - } - else { - for (a = 0; a < totvert; a++) { - dm->getVertCo(dm, a, vec); - - vertex_dupli__mapFunc(vdd, a, vec, NULL, NULL); - } - } - } + BKE_mesh_foreach_mapped_vert(me_eval, vertex_dupli__mapFunc, vdd, + vdd->use_rotation ? MESH_FOREACH_USE_NORMAL : 0); } static void make_duplis_verts(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *parent = ctx->object; - bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); + bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER); VertexDupliData vdd; vdd.ctx = ctx; @@ -547,32 +483,31 @@ static void make_duplis_verts(const DupliContext *ctx) /* gather mesh info */ { - Mesh *me = parent->data; - BMEditMesh *em = BKE_editmesh_from_object(parent); CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH); + vdd.edit_btmesh = BKE_editmesh_from_object(parent); - if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) { - vdd.dm = mesh_create_derived_render(scene, parent, dm_mask); - } - else if (em) { - vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask); + /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */ + if (vdd.edit_btmesh != NULL) { + /* XXX TODO replace with equivalent of editbmesh_get_eval_cage when available. */ + vdd.me_eval = mesh_get_eval_deform(ctx->depsgraph, scene, parent, dm_mask); } else { - vdd.dm = mesh_get_derived_final(scene, parent, dm_mask); + vdd.me_eval = mesh_get_eval_final(ctx->depsgraph, scene, parent, dm_mask); } - vdd.edit_btmesh = me->edit_btmesh; - if (use_texcoords) - vdd.orco = vdd.dm->getVertDataArray(vdd.dm, CD_ORCO); - else + if (use_texcoords) { + vdd.orco = CustomData_get_layer(&vdd.me_eval->vdata, CD_ORCO); + } + else { vdd.orco = NULL; + } - vdd.totvert = vdd.dm->getNumVerts(vdd.dm); + vdd.totvert = vdd.me_eval->totvert; } make_child_duplis(ctx, &vdd, make_child_duplis_verts); - vdd.dm->release(vdd.dm); + vdd.me_eval = NULL; } static const DupliGenerator gen_dupli_verts = { @@ -626,8 +561,8 @@ static void make_duplis_font(const DupliContext *ctx) const wchar_t *text = NULL; bool text_free = false; - /* font dupliverts not supported inside groups */ - if (ctx->group) + /* font dupliverts not supported inside collections */ + if (ctx->collection) return; copy_m4_m4(pmat, par->obmat); @@ -655,7 +590,9 @@ static void make_duplis_font(const DupliContext *ctx) /* advance matching BLI_strncpy_wchar_from_utf8 */ for (a = 0; a < text_len; a++, ct++) { - ob = find_family_object(ctx->bmain, cu->family, family_len, (unsigned int)text[a], family_gh); + /* XXX That G.main is *really* ugly, but not sure what to do here... + * Definitively don't think it would be safe to put back Main *bmain pointer in DupliContext as done in 2.7x? */ + ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh); if (ob) { vec[0] = fsize * (ct->xof - xof); vec[1] = fsize * (ct->yof - yof); @@ -675,7 +612,7 @@ static void make_duplis_font(const DupliContext *ctx) copy_v3_v3(obmat[3], vec); - make_dupli(ctx, ob, obmat, a, false, false); + make_dupli(ctx, ob, obmat, a); } } @@ -695,7 +632,7 @@ static const DupliGenerator gen_dupli_verts_font = { /* OB_DUPLIFACES */ typedef struct FaceDupliData { - DerivedMesh *dm; + Mesh *me_eval; int totface; MPoly *mpoly; MLoop *mloop; @@ -743,7 +680,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj float (*orco)[3] = fdd->orco; MLoopUV *mloopuv = fdd->mloopuv; int a, totface = fdd->totface; - bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); + bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER); float child_imat[4][4]; DupliObject *dob; @@ -781,7 +718,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj */ mul_m4_m4m4(space_mat, obmat, inst_ob->imat); - dob = make_dupli(ctx, inst_ob, obmat, a, false, false); + dob = make_dupli(ctx, inst_ob, obmat, a); if (use_texcoords) { float w = 1.0f / (float)mp->totloop; @@ -801,7 +738,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj } /* recursion */ - make_recursive_duplis(ctx, inst_ob, space_mat, a, false); + make_recursive_duplis(ctx, inst_ob, space_mat, a); } } @@ -809,7 +746,7 @@ static void make_duplis_faces(const DupliContext *ctx) { Scene *scene = ctx->scene; Object *parent = ctx->object; - bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); + bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER); FaceDupliData fdd; fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0); @@ -819,36 +756,34 @@ static void make_duplis_faces(const DupliContext *ctx) BMEditMesh *em = BKE_editmesh_from_object(parent); CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH); - if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) { - fdd.dm = mesh_create_derived_render(scene, parent, dm_mask); - } - else if (em) { - fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask); + /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */ + if (em != NULL) { + /* XXX TODO replace with equivalent of editbmesh_get_eval_cage when available. */ + fdd.me_eval = mesh_get_eval_deform(ctx->depsgraph, scene, parent, dm_mask); } else { - fdd.dm = mesh_get_derived_final(scene, parent, dm_mask); + fdd.me_eval = mesh_get_eval_final(ctx->depsgraph, scene, parent, dm_mask); } if (use_texcoords) { - CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm); - const int uv_idx = CustomData_get_render_layer(ml_data, CD_MLOOPUV); - fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO); - fdd.mloopuv = CustomData_get_layer_n(ml_data, CD_MLOOPUV, uv_idx); + fdd.orco = CustomData_get_layer(&fdd.me_eval->vdata, CD_ORCO); + const int uv_idx = CustomData_get_render_layer(&fdd.me_eval->ldata, CD_MLOOPUV); + fdd.mloopuv = CustomData_get_layer_n(&fdd.me_eval->ldata, CD_MLOOPUV, uv_idx); } else { fdd.orco = NULL; fdd.mloopuv = NULL; } - fdd.totface = fdd.dm->getNumPolys(fdd.dm); - fdd.mpoly = fdd.dm->getPolyArray(fdd.dm); - fdd.mloop = fdd.dm->getLoopArray(fdd.dm); - fdd.mvert = fdd.dm->getVertArray(fdd.dm); + fdd.totface = fdd.me_eval->totpoly; + fdd.mpoly = fdd.me_eval->mpoly; + fdd.mloop = fdd.me_eval->mloop; + fdd.mvert = fdd.me_eval->mvert; } make_child_duplis(ctx, &fdd, make_child_duplis_faces); - fdd.dm->release(fdd.dm); + fdd.me_eval = NULL; } static const DupliGenerator gen_dupli_faces = { @@ -861,10 +796,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem { Scene *scene = ctx->scene; Object *par = ctx->object; - bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER; - bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW); + eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); + bool for_render = mode == DAG_EVAL_RENDER; + bool use_texcoords = for_render; - GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; @@ -877,8 +812,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4]; int a, b, hair = 0; - int totpart, totchild, totgroup = 0 /*, pa_num */; - const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene); + int totpart, totchild; int no_draw_flag = PARS_UNEXIST; @@ -889,21 +823,20 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part == NULL) return; - if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER))) + if (!psys_check_enabled(par, psys, for_render)) return; if (!for_render) no_draw_flag |= PARS_NO_DISP; - ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ + ctime = DEG_get_ctime(ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; - BLI_srandom((unsigned int)(31415926 + psys->seed)); - - if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { + if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; + sim.depsgraph = ctx->depsgraph; sim.scene = scene; sim.ob = par; sim.psys = psys; @@ -917,10 +850,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem return; } else { /*PART_DRAW_GR */ - if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject)) + if (part->dup_group == NULL) + return; + + const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->dup_group); + if (BLI_listbase_is_empty(&dup_collection_objects)) return; - if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) { + if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) { return; } } @@ -937,46 +874,67 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem totpart = psys->totcached; } - psys_check_group_weights(part); + RNG *rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed); psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* gather list of objects or single object */ - if (part->ren_as == PART_DRAW_GR) { - if (ctx->do_update) { - BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, scene, par, part->dup_group); - } + int totcollection = 0; + if (part->ren_as == PART_DRAW_GR) { if (part->draw & PART_DRAW_COUNT_GR) { - for (dw = part->dupliweights.first; dw; dw = dw->next) - totgroup += dw->count; + psys_find_group_weights(part); + + for (dw = part->dupliweights.first; dw; dw = dw->next) { + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) + { + if (dw->ob == object) { + totcollection += dw->count; + break; + } + } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; + } } else { - for (go = part->dup_group->gobject.first; go; go = go->next) - totgroup++; + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) + { + (void) object; + totcollection++; + } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ - oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list"); - obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list"); - - if (part->draw & PART_DRAW_COUNT_GR && totgroup) { - dw = part->dupliweights.first; + oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list"); + obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list"); - for (a = 0; a < totgroup; dw = dw->next) { - for (b = 0; b < dw->count; b++, a++) { - oblist[a] = dw->ob; - obcopylist[a] = *dw->ob; + if (part->draw & PART_DRAW_COUNT_GR) { + a = 0; + for (dw = part->dupliweights.first; dw; dw = dw->next) { + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) + { + if (dw->ob == object) { + for (b = 0; b < dw->count; b++, a++) { + oblist[a] = dw->ob; + obcopylist[a] = *dw->ob; + } + break; + } } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; } } else { - go = part->dup_group->gobject.first; - for (a = 0; a < totgroup; a++, go = go->next) { - oblist[a] = go->ob; - obcopylist[a] = *go->ob; + a = 0; + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) + { + oblist[a] = object; + obcopylist[a] = *object; + a++; } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; } } else { @@ -1018,14 +976,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ - if (totgroup == 0) + if (totcollection == 0) continue; - /* for groups, pick the object based on settings */ + /* for collections, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) - b = BLI_rand() % totgroup; + b = BLI_rng_get_int(rng) % totcollection; else - b = a % totgroup; + b = a % totcollection; ob = oblist[b]; obmat = oblist[b]->obmat; @@ -1065,27 +1023,37 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { - for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { - + b = 0; + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode) + { copy_m4_m4(tmat, oblist[b]->obmat); + /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); - /* group dupli offset, should apply after everything else */ - if (!is_zero_v3(part->dup_group->dupli_ofs)) + + /* collection dupli offset, should apply after everything else */ + if (!is_zero_v3(part->dup_group->dupli_ofs)) { sub_v3_v3(tmat[3], part->dup_group->dupli_ofs); + } + /* individual particle transform */ mul_m4_m4m4(mat, pamat, tmat); - dob = make_dupli(ctx, go->ob, mat, a, false, false); + dob = make_dupli(ctx, object, mat, a); dob->particle_system = psys; - if (use_texcoords) + + if (use_texcoords) { psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); + } + + b++; } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; } else { /* to give ipos in object correct offset */ - BKE_object_where_is_calc_time(scene, ob, ctime - pa_time); + BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; @@ -1126,24 +1094,22 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); - dob = make_dupli(ctx, ob, mat, a, false, false); + dob = make_dupli(ctx, ob, mat, a); dob->particle_system = psys; if (use_texcoords) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); - /* XXX blender internal needs this to be set to dupligroup to render - * groups correctly, but we don't want this hack for cycles */ - if (dupli_type_hack && ctx->group) - dob->type = OB_DUPLIGROUP; } } /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { - for (a = 0; a < totgroup; a++) + for (a = 0; a < totcollection; a++) *(oblist[a]) = obcopylist[a]; } else *ob = obcopy; + + BLI_rng_free(rng); } /* clean up */ @@ -1167,7 +1133,7 @@ static void make_duplis_particles(const DupliContext *ctx) for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) { /* particles create one more level for persistent psys index */ DupliContext pctx; - copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid, false); + copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid); make_duplis_particle_system(&pctx, psys); } } @@ -1189,7 +1155,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) return NULL; /* Should the dupli's be generated for this object? - Respect restrict flags */ - if (ctx->eval_ctx->mode == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW)) + if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW)) return NULL; if (transflag & OB_DUPLIPARTS) { @@ -1210,8 +1176,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) else if (transflag & OB_DUPLIFRAMES) { return &gen_dupli_frames; } - else if (transflag & OB_DUPLIGROUP) { - return &gen_dupli_group; + else if (transflag & OB_DUPLICOLLECTION) { + return &gen_dupli_collection; } return NULL; @@ -1221,11 +1187,11 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) /* ---- ListBase dupli container implementation ---- */ /* Returns a list of DupliObject */ -ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update) +ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) { ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist"); DupliContext ctx; - init_context(&ctx, bmain, eval_ctx, scene, ob, NULL, update); + init_context(&ctx, depsgraph, sce, ob, NULL); if (ctx.gen) { ctx.duplilist = duplilist; ctx.gen->make_duplis(&ctx); @@ -1234,13 +1200,6 @@ ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *s return duplilist; } -/* note: previously updating was always done, this is why it defaults to be on - * but there are likely places it can be called without updating */ -ListBase *object_duplilist(Main *bmain, EvaluationContext *eval_ctx, Scene *sce, Object *ob) -{ - return object_duplilist_ex(bmain, eval_ctx, sce, ob, true); -} - void free_object_duplilist(ListBase *lb) { BLI_freelistN(lb); @@ -1276,59 +1235,3 @@ int count_duplilist(Object *ob) } return 1; } - -DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist) -{ - DupliApplyData *apply_data = NULL; - int num_objects = BLI_listbase_count(duplilist); - - if (num_objects > 0) { - DupliObject *dob; - int i; - apply_data = MEM_mallocN(sizeof(DupliApplyData), "DupliObject apply data"); - apply_data->num_objects = num_objects; - apply_data->extra = MEM_mallocN(sizeof(DupliExtraData) * (size_t) num_objects, - "DupliObject apply extra data"); - - for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) { - /* make sure derivedmesh is calculated once, before drawing */ - if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) { - mesh_get_derived_final(scene, dob->ob, scene->customdata_mask); - dob->ob->transflag |= OB_DUPLICALCDERIVED; - } - } - - for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) { - /* copy obmat from duplis */ - copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat); - copy_m4_m4(dob->ob->obmat, dob->mat); - - /* copy layers from the main duplicator object */ - apply_data->extra[i].lay = dob->ob->lay; - dob->ob->lay = ob->lay; - } - } - return apply_data; -} - -void duplilist_restore(ListBase *duplilist, DupliApplyData *apply_data) -{ - DupliObject *dob; - int i; - /* Restore object matrices. - * NOTE: this has to happen in reverse order, since nested - * dupli objects can repeatedly override the obmat. - */ - for (dob = duplilist->last, i = apply_data->num_objects - 1; dob; dob = dob->prev, --i) { - copy_m4_m4(dob->ob->obmat, apply_data->extra[i].obmat); - dob->ob->transflag &= ~OB_DUPLICALCDERIVED; - - dob->ob->lay = apply_data->extra[i].lay; - } -} - -void duplilist_free_apply_data(DupliApplyData *apply_data) -{ - MEM_freeN(apply_data->extra); - MEM_freeN(apply_data); -} diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c new file mode 100644 index 00000000000..ef254864d2e --- /dev/null +++ b/source/blender/blenkernel/intern/object_facemap.c @@ -0,0 +1,257 @@ + +/* + * ***** 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) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/object_facemap.c + * \ingroup bke + */ + +#include <string.h> + +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" + +#include "BLI_utildefines.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" +#include "BLI_listbase.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_object.h" +#include "BKE_object_facemap.h" /* own include */ +#include "BKE_object_deform.h" + +#include "BLT_translation.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +static bool fmap_unique_check(void *arg, const char *name) +{ + struct {Object *ob; void *fm; } *data = arg; + + bFaceMap *fmap; + + for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) { + if (data->fm != fmap) { + if (!strcmp(fmap->name, name)) { + return true; + } + } + } + + return false; +} + +static bFaceMap *fmap_duplicate(bFaceMap *infmap) +{ + bFaceMap *outfmap; + + if (!infmap) + return NULL; + + outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap"); + + /* For now, just copy everything over. */ + memcpy(outfmap, infmap, sizeof(bFaceMap)); + + outfmap->next = outfmap->prev = NULL; + + return outfmap; +} + +void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase) +{ + bFaceMap *fmap, *fmapn; + + BLI_listbase_clear(outbase); + + for (fmap = inbase->first; fmap; fmap = fmap->next) { + fmapn = fmap_duplicate(fmap); + BLI_addtail(outbase, fmapn); + } +} + +void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap) +{ + struct {Object *ob; void *fmap; } data; + data.ob = ob; + data.fmap = fmap; + + BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name)); +} + +bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name) +{ + bFaceMap *fmap; + + if (!ob || ob->type != OB_MESH) + return NULL; + + fmap = MEM_callocN(sizeof(bFaceMap), __func__); + + BLI_strncpy(fmap->name, name, sizeof(fmap->name)); + + BLI_addtail(&ob->fmaps, fmap); + + ob->actfmap = BLI_listbase_count(&ob->fmaps); + + BKE_object_facemap_unique_name(ob, fmap); + + return fmap; +} + +bFaceMap *BKE_object_facemap_add(Object *ob) +{ + return BKE_object_facemap_add_name(ob, DATA_("FaceMap")); +} + + +static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge) +{ + const int fmap_nr = BLI_findindex(&ob->fmaps, fmap); + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP); + + if (cd_fmap_offset != -1) { + BMFace *efa; + BMIter iter; + int *map; + + if (purge) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (map) { + if (*map == fmap_nr) + *map = -1; + else if (*map > fmap_nr) + *map -= 1; + } + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset); + + if (map && *map == fmap_nr && (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) { + *map = -1; + } + } + } + } + + if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) + ob->actfmap--; + + BLI_remlink(&ob->fmaps, fmap); + MEM_freeN(fmap); + } + } +} + +static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge) +{ + const int fmap_nr = BLI_findindex(&ob->fmaps, fmap); + + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + + if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) { + int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP); + int i; + + if (map) { + for (i = 0; i < me->totpoly; i++) { + if (map[i] == fmap_nr) + map[i] = -1; + else if (purge && map[i] > fmap_nr) + map[i]--; + } + } + } + + if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) + ob->actfmap--; + + BLI_remlink(&ob->fmaps, fmap); + MEM_freeN(fmap); + } +} + +static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge) +{ + if (is_edit_mode) + object_fmap_remove_edit_mode(ob, fmap, false, purge); + else + object_fmap_remove_object_mode(ob, fmap, purge); +} + +void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap) +{ + fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true); +} + +void BKE_object_facemap_clear(Object *ob) +{ + bFaceMap *fmap = (bFaceMap *)ob->fmaps.first; + + if (fmap) { + const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob); + + while (fmap) { + bFaceMap *next_fmap = fmap->next; + fmap_remove_exec(ob, fmap, edit_mode, false); + fmap = next_fmap; + } + } + /* remove all face-maps */ + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0); + } + ob->actfmap = 0; +} + +int BKE_object_facemap_name_index(Object *ob, const char *name) +{ + return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1; +} + +bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name) +{ + return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name)); +} diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index bb738033f02..902237d7ac8 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -28,22 +28,22 @@ */ #include "DNA_anim_types.h" +#include "DNA_collection_types.h" #include "DNA_constraint_types.h" -#include "DNA_group_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" +#include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math.h" -#include "BLI_threads.h" #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_action.h" #include "BKE_constraint.h" -#include "BKE_depsgraph.h" +#include "BKE_curve.h" #include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_editmesh.h" @@ -53,21 +53,26 @@ #include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_scene.h" +#include "BKE_gpencil.h" + +#include "MEM_guardedalloc.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" -static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER; -void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx), - Object *ob) +void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob) { - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* calculate local matrix */ BKE_object_to_mat4(ob, ob->obmat); @@ -75,7 +80,7 @@ void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx), /* Evaluate parent */ /* NOTE: based on solve_parenting(), but with the cruft stripped out */ -void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx), +void BKE_object_eval_parent(Depsgraph *depsgraph, Scene *scene, Object *ob) { @@ -85,14 +90,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx), float tmat[4][4]; float locmat[4][4]; - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* get local matrix (but don't calculate it, as that was done already!) */ // XXX: redundant? copy_m4_m4(locmat, ob->obmat); /* get parent effect matrix */ - BKE_object_get_parent_matrix(scene, ob, par, totmat); + BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat); /* total */ mul_m4_m4m4(tmat, totmat, ob->parentinv); @@ -107,14 +112,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx), } } -void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx), +void BKE_object_eval_constraints(Depsgraph *depsgraph, Scene *scene, Object *ob) { bConstraintOb *cob; float ctime = BKE_scene_frame_get(scene); - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* evaluate constraints stack */ /* TODO: split this into: @@ -125,23 +130,38 @@ void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx), * Not sure why, this is from Joshua - sergey * */ - cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - BKE_constraints_solve(&ob->constraints, cob, ctime); + cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime); BKE_constraints_clear_evalob(cob); } -void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob) +void BKE_object_eval_done(Depsgraph *depsgraph, Object *ob) { - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* Set negative scale flag in object. */ if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE; else ob->transflag &= ~OB_NEG_SCALE; + + if (DEG_is_active(depsgraph)) { + Object *ob_orig = DEG_get_original_object(ob); + copy_m4_m4(ob_orig->obmat, ob->obmat); + copy_m4_m4(ob_orig->constinv, ob->constinv); + ob_orig->transflag = ob->transflag; + ob_orig->flag = ob->flag; + + BoundBox *bb = BKE_object_boundbox_get(ob); + if (bb != NULL) { + if (ob_orig->bb == NULL) { + ob_orig->bb = MEM_mallocN(sizeof(*ob_orig->bb), __func__); + } + *ob_orig->bb = *bb; + } + } } void BKE_object_handle_data_update( - Main *bmain, - EvaluationContext *eval_ctx, + Depsgraph *depsgraph, Scene *scene, Object *ob) { @@ -150,40 +170,47 @@ void BKE_object_handle_data_update( Key *key; float ctime = BKE_scene_frame_get(scene); - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) - printf("recalcdata %s\n", ob->id.name + 2); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); /* TODO(sergey): Only used by legacy depsgraph. */ if (adt) { /* evaluate drivers - datalevel */ - /* XXX: for mesh types, should we push this to derivedmesh instead? */ - BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); + /* XXX: for mesh types, should we push this to evaluated mesh instead? */ + BKE_animsys_evaluate_animdata(depsgraph, scene, data_id, adt, ctime, ADT_RECALC_DRIVERS); } /* TODO(sergey): Only used by legacy depsgraph. */ key = BKE_key_from_object(ob); if (key && key->block.first) { if (!(ob->shapeflag & OB_SHAPE_LOCK)) - BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(depsgraph, scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS); } /* includes all keys and modifiers */ switch (ob->type) { case OB_MESH: { - BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL; +#if 0 + BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL; +#else + BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_btmesh : NULL; + if (em && em->ob != ob) { + em = NULL; + } +#endif + uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH; #ifdef WITH_FREESTYLE /* make sure Freestyle edge/face marks appear in DM for render (see T40315) */ - if (eval_ctx->mode != DAG_EVAL_VIEWPORT) { + if (DEG_get_mode(depsgraph) != DAG_EVAL_VIEWPORT) { data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; } #endif if (em) { - makeDerivedMesh(scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */ + makeDerivedMesh(depsgraph, scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */ } else { - makeDerivedMesh(scene, ob, NULL, data_mask, false); + makeDerivedMesh(depsgraph, scene, ob, NULL, data_mask, false); } break; } @@ -195,75 +222,48 @@ void BKE_object_handle_data_update( } } else { - BKE_pose_where_is(scene, ob); + BKE_pose_where_is(depsgraph, scene, ob); } break; case OB_MBALL: - BKE_displist_make_mball(bmain, eval_ctx, scene, ob); + BKE_displist_make_mball(depsgraph, scene, ob); break; case OB_CURVE: case OB_SURF: case OB_FONT: - BKE_displist_make_curveTypes(scene, ob, 0); + BKE_displist_make_curveTypes(depsgraph, scene, ob, 0); break; case OB_LATTICE: - BKE_lattice_modifiers_calc(scene, ob); + BKE_lattice_modifiers_calc(depsgraph, scene, ob); break; case OB_EMPTY: if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data) if (BKE_image_is_animated(ob->data)) - BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0); + BKE_image_user_check_frame_calc(ob->iuser, (int)ctime); break; } - /* related materials */ - /* XXX: without depsgraph tagging, this will always need to be run, which will be slow! - * However, not doing anything (or trying to hack around this lack) is not an option - * anymore, especially due to Cycles [#31834] - */ - if (ob->totcol) { - int a; - if (ob->totcol != 0) { - BLI_mutex_lock(&material_lock); - for (a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - if (ma) { - /* recursively update drivers for this material */ - material_drivers_update(scene, ma, ctime); - } - } - BLI_mutex_unlock(&material_lock); - } - } - else if (ob->type == OB_LAMP) - lamp_drivers_update(scene, ob->data, ctime); - /* particles */ - if (ob != scene->obedit && ob->particlesystem.first) { + if (!(ob->mode & OB_MODE_EDIT) && ob->particlesystem.first) { + const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); ParticleSystem *tpsys, *psys; - DerivedMesh *dm; ob->transflag &= ~OB_DUPLIPARTS; psys = ob->particlesystem.first; while (psys) { - /* ensure this update always happens even if psys is disabled */ - if (psys->recalc & PSYS_RECALC_TYPE) { - psys_changed_type(ob, psys); - } - - if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) { + if (psys_check_enabled(ob, psys, use_render_params)) { /* check use of dupli objects here */ - if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && + if (psys->part && (psys->part->draw_as == PART_DRAW_REND || use_render_params) && ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) { ob->transflag |= OB_DUPLIPARTS; } - particle_system_update(bmain, scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER)); + particle_system_update(depsgraph, scene, ob, psys, use_render_params); psys = psys->next; } else if (psys->flag & PSYS_DELETE) { @@ -275,28 +275,17 @@ void BKE_object_handle_data_update( else psys = psys->next; } - - if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) { - /* this is to make sure we get render level duplis in groups: - * the derivedmesh must be created before init_render_mesh, - * since object_duplilist does dupliparticles before that */ - CustomDataMask data_mask = CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL; - dm = mesh_create_derived_render(scene, ob, data_mask); - dm->release(dm); - - for (psys = ob->particlesystem.first; psys; psys = psys->next) - psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; - } } /* quick cache removed */ } -bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), +bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph, Object *object) { /* Handle proxy copy for target, */ if (ID_IS_LINKED(object) && object->proxy_from) { + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); if (object->proxy_from->proxy_group) { /* Transform proxy into group space. */ Object *obg = object->proxy_from->proxy_group; @@ -316,46 +305,136 @@ bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), return false; } -void BKE_object_eval_uber_transform(EvaluationContext *eval_ctx, Object *object) +void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object) +{ + BKE_object_eval_proxy_copy(depsgraph, object); +} + +void BKE_object_batch_cache_dirty_tag(Object *ob) { - BKE_object_eval_proxy_copy(eval_ctx, object); - object->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME); - if (object->data == NULL) { - object->recalc &= ~OB_RECALC_DATA; + switch (ob->type) { + case OB_MESH: + BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + break; + case OB_LATTICE: + BKE_lattice_batch_cache_dirty_tag(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL); + break; + case OB_CURVE: + case OB_FONT: + case OB_SURF: + BKE_curve_batch_cache_dirty_tag(ob->data, BKE_CURVE_BATCH_DIRTY_ALL); + break; + case OB_MBALL: + BKE_mball_batch_cache_dirty_tag(ob->data, BKE_MBALL_BATCH_DIRTY_ALL); + break; + case OB_GPENCIL: + BKE_gpencil_batch_cache_dirty_tag(ob->data); + break; } } -void BKE_object_eval_uber_data(Main *bmain, EvaluationContext *eval_ctx, +void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob) { - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); BLI_assert(ob->type != OB_ARMATURE); - BKE_object_handle_data_update(bmain, eval_ctx, scene, ob); - - ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); + BKE_object_handle_data_update(depsgraph, scene, ob); + BKE_object_batch_cache_dirty_tag(ob); } -void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx), +void BKE_object_eval_cloth(Depsgraph *depsgraph, Scene *scene, Object *object) { - DEG_debug_print_eval(__func__, object->id.name, object); + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH); } -void BKE_object_eval_transform_all(EvaluationContext *eval_ctx, +void BKE_object_eval_transform_all(Depsgraph *depsgraph, Scene *scene, Object *object) { /* This mimics full transform update chain from new depsgraph. */ - BKE_object_eval_local_transform(eval_ctx, object); + BKE_object_eval_local_transform(depsgraph, object); if (object->parent != NULL) { - BKE_object_eval_parent(eval_ctx, scene, object); + BKE_object_eval_parent(depsgraph, scene, object); } if (!BLI_listbase_is_empty(&object->constraints)) { - BKE_object_eval_constraints(eval_ctx, scene, object); + BKE_object_eval_constraints(depsgraph, scene, object); + } + BKE_object_eval_uber_transform(depsgraph, object); + BKE_object_eval_done(depsgraph, object); +} + +void BKE_object_eval_update_shading(Depsgraph *depsgraph, Object *object) +{ + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + if (object->type == OB_MESH) { + BKE_mesh_batch_cache_dirty_tag(object->data, BKE_MESH_BATCH_DIRTY_SHADING); + } +} + +void BKE_object_data_select_update(Depsgraph *depsgraph, ID *object_data) +{ + DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data); + switch (GS(object_data->name)) { + case ID_ME: + BKE_mesh_batch_cache_dirty_tag( + (Mesh *)object_data, + BKE_MESH_BATCH_DIRTY_SELECT); + break; + case ID_CU: + BKE_curve_batch_cache_dirty_tag( + (Curve *)object_data, + BKE_CURVE_BATCH_DIRTY_SELECT); + break; + case ID_LT: + BKE_lattice_batch_cache_dirty_tag( + (struct Lattice *)object_data, + BKE_LATTICE_BATCH_DIRTY_SELECT); + break; + default: + break; + } +} + +void BKE_object_eval_flush_base_flags(Depsgraph *depsgraph, + Scene *scene, const int view_layer_index, + Object *object, int base_index, + const bool is_from_set) +{ + /* TODO(sergey): Avoid list lookup. */ + BLI_assert(view_layer_index >= 0); + ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index); + BLI_assert(view_layer != NULL); + BLI_assert(view_layer->object_bases_array != NULL); + BLI_assert(base_index >= 0); + BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *)); + Base *base = view_layer->object_bases_array[base_index]; + BLI_assert(base->object == object); + + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + + /* Copy flags and settings from base. */ + object->base_flag = base->flag; + if (is_from_set) { + object->base_flag |= BASE_FROM_SET; + object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE); + } + + /* Copy to original object datablock if needed. */ + if (DEG_is_active(depsgraph)) { + Object *object_orig = DEG_get_original_object(object); + object_orig->base_flag = object->base_flag; + } + + if (object->mode == OB_MODE_PARTICLE_EDIT) { + for (ParticleSystem *psys = object->particlesystem.first; + psys != NULL; + psys = psys->next) + { + BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); + } } - BKE_object_eval_uber_transform(eval_ctx, object); - BKE_object_eval_done(eval_ctx, object); } diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 7f3f916964a..adbe1a7f889 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_modifier_types.h" #include "DNA_scene_types.h" #include "BLI_math.h" @@ -241,14 +242,6 @@ static void init_complex(fftw_complex cmpl, float real, float image) cmpl[1] = image; } -#if 0 /* unused */ -static void add_complex_f(fftw_complex res, fftw_complex cmpl, float f) -{ - res[0] = cmpl[0] + f; - res[1] = cmpl[1]; -} -#endif - static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2) { res[0] = cmpl1[0] + cmpl2[0]; @@ -774,15 +767,6 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount if (o->_do_normals) { BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH); BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH); - -#if 0 - for (i = 0; i < o->_M; ++i) { - for (j = 0; j < o->_N; ++j) { - o->_N_y[i * o->_N + j] = 1.0f / scale; - } - } - (MEM01) -#endif o->_N_y = 1.0f / scale; } @@ -835,6 +819,35 @@ struct Ocean *BKE_ocean_add(void) return oc; } +bool BKE_ocean_ensure(struct OceanModifierData *omd) +{ + if (omd->ocean) { + return false; + } + + omd->ocean = BKE_ocean_add(); + BKE_ocean_init_from_modifier(omd->ocean, omd); + return true; +} + +void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData const *omd) +{ + short do_heightfield, do_chop, do_normals, do_jacobian; + + do_heightfield = true; + do_chop = (omd->chop_amount > 0); + do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS); + do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM); + + BKE_ocean_free_data(ocean); + BKE_ocean_init(ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution, + omd->spatial_size, omd->spatial_size, + omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment, + omd->depth, omd->time, + do_heightfield, do_chop, do_normals, do_jacobian, + omd->seed); +} + void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed) @@ -1227,30 +1240,12 @@ void BKE_ocean_simulate_cache(struct OceanCache *och, int frame) cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE); och->ibufs_disp[f] = IMB_loadiffname(string, 0, NULL); -#if 0 - if (och->ibufs_disp[f] == NULL) - printf("error loading %s\n", string); - else - printf("loaded cache %s\n", string); -#endif cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM); och->ibufs_foam[f] = IMB_loadiffname(string, 0, NULL); -#if 0 - if (och->ibufs_foam[f] == NULL) - printf("error loading %s\n", string); - else - printf("loaded cache %s\n", string); -#endif cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL); och->ibufs_norm[f] = IMB_loadiffname(string, 0, NULL); -#if 0 - if (och->ibufs_norm[f] == NULL) - printf("error loading %s\n", string); - else - printf("loaded cache %s\n", string); -#endif } @@ -1325,13 +1320,6 @@ void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v * break up the foam where height (Y) is low (wave valley), and X and Z displacement is greatest */ -#if 0 - vec[0] = ocr.disp[0]; - vec[1] = ocr.disp[2]; - hor_stretch = len_v2(vec); - CLAMP(hor_stretch, 0.0, 1.0); -#endif - neg_disp = ocr.disp[1] < 0.0f ? 1.0f + ocr.disp[1] : 1.0f; neg_disp = neg_disp < 0.0f ? 0.0f : neg_disp; @@ -1339,15 +1327,6 @@ void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f; neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus; -#if 0 - if (ocr.disp[1] < 0.0 || r > och->foam_fade) - pr *= och->foam_fade; - - - pr = pr * (1.0 - hor_stretch) * ocr.disp[1]; - pr = pr * neg_disp * neg_eplus; -#endif - if (pr < 1.0f) pr *= pr; @@ -1511,4 +1490,16 @@ void BKE_ocean_bake(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), /* unused */ (void)update_cb; } + +void BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean), struct OceanModifierData const *UNUSED(omd)) +{ +} + #endif /* WITH_OCEANSIM */ + +void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd) +{ + BKE_ocean_free_cache(omd->oceancache); + omd->oceancache = NULL; + omd->cached = false; +} diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index 9db9b2ddf54..fb62645ef43 100644 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -27,6 +27,7 @@ */ #include <stdlib.h> +#include <string.h> #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -40,6 +41,7 @@ typedef struct TseGroup { TreeStoreElem **elems; + int lastused; int size; int allocated; } TseGroup; @@ -53,10 +55,11 @@ static TseGroup *tse_group_create(void) tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems"); tse_group->size = 0; tse_group->allocated = 1; + tse_group->lastused = 0; return tse_group; } -static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem) +static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem) { if (UNLIKELY(tse_group->size == tse_group->allocated)) { tse_group->allocated *= 2; @@ -66,6 +69,26 @@ static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem) tse_group->size++; } +static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem) +{ + int min_allocated = MAX2(1, tse_group->allocated / 2); + BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0); + + tse_group->size--; + BLI_assert(tse_group->size >= 0); + for (int i = 0; i < tse_group->size; i++) { + if (tse_group->elems[i] == elem) { + memcpy(tse_group->elems[i], tse_group->elems[i + 1], (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *)); + break; + } + } + + if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) { + tse_group->allocated = min_allocated; + tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated); + } +} + static void tse_group_free(TseGroup *tse_group) { MEM_freeN(tse_group->elems); @@ -122,6 +145,16 @@ static void free_treehash_group(void *key) tse_group_free(key); } +void BKE_outliner_treehash_clear_used(void *treehash) +{ + GHashIterator gh_iter; + + GHASH_ITER(gh_iter, treehash) { + TseGroup *group = BLI_ghashIterator_getValue(&gh_iter); + group->lastused = 0; + } +} + void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore) { BLI_assert(treehash); @@ -140,7 +173,22 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem) *val_p = tse_group_create(); } group = *val_p; - tse_group_add(group, elem); + group->lastused = 0; + tse_group_add_element(group, elem); +} + +void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem) +{ + TseGroup *group = BLI_ghash_lookup(treehash, elem); + + BLI_assert(group != NULL); + if (group->size <= 1) { + /* one element -> remove group completely */ + BLI_ghash_remove(treehash, elem, NULL, free_treehash_group); + } + else { + tse_group_remove_element(group, elem); + } } static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id) @@ -163,10 +211,19 @@ TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, s group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); if (group) { - int i; - for (i = 0; i < group->size; i++) { - if (!group->elems[i]->used) { - return group->elems[i]; + /* Find unused element, with optimization to start from previously + * found element assuming we do repeated lookups. */ + int size = group->size; + int offset = group->lastused; + + for (int i = 0; i < size; i++, offset++) { + if (offset >= size) { + offset = 0; + } + + if (!group->elems[offset]->used) { + group->lastused = offset; + return group->elems[offset]; } } } diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 0637fc4f00c..0446b697c68 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -54,6 +54,7 @@ #include "BKE_font.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_packedFile.h" #include "BKE_report.h" @@ -264,33 +265,6 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) BKE_report(reports, RPT_INFO, "No new files have been packed"); } - -#if 0 - -// attempt to create a function that generates an unique filename -// this will work when all functions in fileops.c understand relative filenames... - -static char *find_new_name(char *name) -{ - char tempname[FILE_MAX]; - char *newname; - size_t len; - - if (fop_exists(name)) { - for (number = 1; number <= 999; number++) { - BLI_snprintf(tempname, sizeof(tempname), "%s.%03d", name, number); - if (!fop_exists(tempname)) { - break; - } - } - } - len = strlen(tempname) + 1; - newname = MEM_mallocN(len, "find_new_name"); - memcpy(newname, tempname, len * sizeof(char)); - return newname; -} -#endif - int writePackedFile( ReportList *reports, const char *ref_file_name, const char *filename, PackedFile *pf, const bool guimode) { diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index dd5d801d2ac..24782af4d22 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -41,30 +41,46 @@ #include "DNA_scene_types.h" #include "DNA_brush_types.h" #include "DNA_space_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_workspace_types.h" #include "BLI_bitmap.h" +#include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_string_utils.h" #include "BLI_math_vector.h" #include "BLI_listbase.h" +#include "BLT_translation.h" + +#include "BKE_animsys.h" #include "BKE_brush.h" +#include "BKE_ccg.h" #include "BKE_colortools.h" #include "BKE_deform.h" #include "BKE_main.h" #include "BKE_context.h" #include "BKE_crazyspace.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" +#include "BKE_gpencil.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "RNA_enum_types.h" + #include "bmesh.h" const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; @@ -74,9 +90,9 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; static eOverlayControlFlags overlay_flags = 0; -void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex) +void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex) { - Paint *p = BKE_paint_get_active(scene); + Paint *p = BKE_paint_get_active(scene, view_layer); Brush *br = p->brush; if (!br) @@ -88,9 +104,9 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex) overlay_flags |= PAINT_OVERLAY_INVALID_TEXTURE_SECONDARY; } -void BKE_paint_invalidate_cursor_overlay(Scene *scene, CurveMapping *curve) +void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve) { - Paint *p = BKE_paint_get_active(scene); + Paint *p = BKE_paint_get_active(scene, view_layer); Brush *br = p->brush; if (br && br->curve == curve) @@ -146,6 +162,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode) return &ts->imapaint.paint; case PAINT_MODE_SCULPT_UV: return &ts->uvsculpt->paint; + case PAINT_MODE_GPENCIL: + return &ts->gp_paint->paint; case PAINT_MODE_INVALID: return NULL; default: @@ -156,13 +174,50 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode) return NULL; } -Paint *BKE_paint_get_active(Scene *sce) +const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) { - if (sce) { + switch (mode) { + case PAINT_MODE_SCULPT: + return rna_enum_brush_sculpt_tool_items; + case PAINT_MODE_VERTEX: + return rna_enum_brush_vertex_tool_items; + case PAINT_MODE_WEIGHT: + return rna_enum_brush_weight_tool_items; + case PAINT_MODE_TEXTURE_2D: + case PAINT_MODE_TEXTURE_3D: + return rna_enum_brush_image_tool_items; + case PAINT_MODE_SCULPT_UV: + return NULL; + case PAINT_MODE_GPENCIL: + return rna_enum_brush_gpencil_types_items; + case PAINT_MODE_INVALID: + break; + } + return NULL; +} + +const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode) +{ + switch (mode) { + case PAINT_MODE_SCULPT: return "sculpt_tool"; + case PAINT_MODE_VERTEX: return "vertex_tool"; + case PAINT_MODE_WEIGHT: return "weight_tool"; + case PAINT_MODE_TEXTURE_2D: + case PAINT_MODE_TEXTURE_3D: return "image_tool"; + case PAINT_MODE_GPENCIL: return "gpencil_tool"; + default: + /* invalid paint mode */ + return NULL; + } +} + +Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) +{ + if (sce && view_layer) { ToolSettings *ts = sce->toolsettings; - if (sce->basact && sce->basact->object) { - switch (sce->basact->object->mode) { + if (view_layer->basact && view_layer->basact->object) { + switch (view_layer->basact->object->mode) { case OB_MODE_SCULPT: return &ts->sculpt->paint; case OB_MODE_VERTEX_PAINT: @@ -171,10 +226,14 @@ Paint *BKE_paint_get_active(Scene *sce) return &ts->wpaint->paint; case OB_MODE_TEXTURE_PAINT: return &ts->imapaint.paint; + case OB_MODE_GPENCIL_PAINT: + return &ts->gp_paint->paint; case OB_MODE_EDIT: if (ts->use_uv_sculpt) return &ts->uvsculpt->paint; return &ts->imapaint.paint; + default: + break; } } @@ -188,14 +247,15 @@ Paint *BKE_paint_get_active(Scene *sce) Paint *BKE_paint_get_active_from_context(const bContext *C) { Scene *sce = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima; - if (sce) { + if (sce && view_layer) { ToolSettings *ts = sce->toolsettings; Object *obact = NULL; - if (sce->basact && sce->basact->object) - obact = sce->basact->object; + if (view_layer->basact && view_layer->basact->object) + obact = view_layer->basact->object; if ((sima = CTX_wm_space_image(C)) != NULL) { if (obact && obact->mode == OB_MODE_EDIT) { @@ -209,7 +269,7 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) } } else { - return BKE_paint_get_active(sce); + return BKE_paint_get_active(sce, view_layer); } } @@ -219,14 +279,15 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) { Scene *sce = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); SpaceImage *sima; - if (sce) { + if (sce && view_layer) { ToolSettings *ts = sce->toolsettings; Object *obact = NULL; - if (sce->basact && sce->basact->object) - obact = sce->basact->object; + if (view_layer->basact && view_layer->basact->object) + obact = view_layer->basact->object; if ((sima = CTX_wm_space_image(C)) != NULL) { if (obact && obact->mode == OB_MODE_EDIT) { @@ -266,6 +327,32 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) return PAINT_MODE_INVALID; } +ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref) +{ + if (tref->space_type == SPACE_VIEW3D) { + switch (tref->mode) { + case CTX_MODE_SCULPT: + return PAINT_MODE_SCULPT; + case CTX_MODE_PAINT_VERTEX: + return PAINT_MODE_VERTEX; + case CTX_MODE_PAINT_WEIGHT: + return PAINT_MODE_WEIGHT; + case CTX_MODE_GPENCIL_PAINT: + return PAINT_MODE_GPENCIL; + case CTX_MODE_PAINT_TEXTURE: + return PAINT_MODE_TEXTURE_3D; + } + } + else if (tref->space_type == SPACE_IMAGE) { + switch (tref->mode) { + case SI_MODE_PAINT: + return PAINT_MODE_TEXTURE_2D; + } + } + + return PAINT_MODE_INVALID; +} + Brush *BKE_paint_brush(Paint *p) { return p ? p->brush : NULL; @@ -277,9 +364,64 @@ void BKE_paint_brush_set(Paint *p, Brush *br) id_us_min((ID *)p->brush); id_us_plus((ID *)br); p->brush = br; + + BKE_paint_toolslots_brush_update(p); + } +} + +void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint) +{ + if (paint == &ts->imapaint.paint) { + paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool); + paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT; + } + else if (paint == &ts->sculpt->paint) { + paint->runtime.tool_offset = offsetof(Brush, sculpt_tool); + paint->runtime.ob_mode = OB_MODE_SCULPT; + } + else if (paint == &ts->vpaint->paint) { + paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool); + paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT; + } + else if (paint == &ts->wpaint->paint) { + paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool); + paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT; + } + else if (paint == &ts->gp_paint->paint) { + paint->runtime.tool_offset = offsetof(Brush, gpencil_tool); + paint->runtime.ob_mode = OB_MODE_GPENCIL_PAINT; + } + else if (paint == &ts->uvsculpt->paint) { + /* We don't use these yet. */ + paint->runtime.tool_offset = 0; + paint->runtime.ob_mode = 0; + } + else { + BLI_assert(0); } } +uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode) +{ + switch (mode) { + case PAINT_MODE_TEXTURE_2D: + case PAINT_MODE_TEXTURE_3D: + return offsetof(Brush, imagepaint_tool); + case PAINT_MODE_SCULPT: + return offsetof(Brush, sculpt_tool); + case PAINT_MODE_VERTEX: + return offsetof(Brush, vertexpaint_tool); + case PAINT_MODE_WEIGHT: + return offsetof(Brush, weightpaint_tool); + case PAINT_MODE_GPENCIL: + return offsetof(Brush, gpencil_tool); + case PAINT_MODE_SCULPT_UV: + case PAINT_MODE_INVALID: + break; /* We don't use these yet. */ + } + return 0; +} + /** Free (or release) any data used by this paint curve (does not free the pcurve itself). */ void BKE_paint_curve_free(PaintCurve *pc) { @@ -332,8 +474,8 @@ void BKE_paint_palette_set(Paint *p, Palette *palette) { if (p) { id_us_min((ID *)p->palette); - id_us_plus((ID *)palette); p->palette = palette; + id_us_plus((ID *)p->palette); } } @@ -341,8 +483,8 @@ void BKE_paint_curve_set(Brush *br, PaintCurve *pc) { if (br) { id_us_min((ID *)br->paint_curve); - id_us_plus((ID *)pc); br->paint_curve = pc; + id_us_plus((ID *)br->paint_curve); } } @@ -375,13 +517,7 @@ void BKE_palette_clear(Palette *palette) Palette *BKE_palette_add(Main *bmain, const char *name) { - Palette *palette; - - palette = BKE_libblock_alloc(bmain, ID_PAL, name, 0); - - /* enable fake user by default */ - id_fake_user_set(&palette->id); - + Palette *palette = BKE_id_new(bmain, ID_PAL, name); return palette; } @@ -410,6 +546,12 @@ void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local) BKE_id_make_local_generic(bmain, &palette->id, true, lib_local); } +void BKE_palette_init(Palette *palette) +{ + /* Enable fake user by default. */ + id_fake_user_set(&palette->id); +} + /** Free (or release) any data used by this palette (does not free the palette itself). */ void BKE_palette_free(Palette *palette) { @@ -418,19 +560,17 @@ void BKE_palette_free(Palette *palette) PaletteColor *BKE_palette_color_add(Palette *palette) { - PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color"); + PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color"); BLI_addtail(&palette->colors, color); return color; } - bool BKE_palette_is_empty(const struct Palette *palette) { return BLI_listbase_is_empty(&palette->colors); } - -/* are we in vertex paint or weight pain face select mode? */ +/* are we in vertex paint or weight paint face select mode? */ bool BKE_paint_select_face_test(Object *ob) { return ( (ob != NULL) && @@ -477,7 +617,7 @@ void BKE_paint_cavity_curve_preset(Paint *p, int preset) curvemapping_changed(p->cavity_curve, false); } -eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode) +eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode) { switch (mode) { case PAINT_MODE_SCULPT: @@ -486,9 +626,8 @@ eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode) return OB_MODE_VERTEX_PAINT; case PAINT_MODE_WEIGHT: return OB_MODE_WEIGHT_PAINT; - case PAINT_MODE_TEXTURE_3D: - return OB_MODE_TEXTURE_PAINT; case PAINT_MODE_TEXTURE_2D: + case PAINT_MODE_TEXTURE_3D: return OB_MODE_TEXTURE_PAINT; case PAINT_MODE_SCULPT_UV: return OB_MODE_EDIT; @@ -498,6 +637,64 @@ eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode) } } +/** + * Call when entering each respective paint mode. + */ +bool BKE_paint_ensure(const ToolSettings *ts, struct Paint **r_paint) +{ + Paint *paint = NULL; + if (*r_paint) { + /* Note: 'ts->imapaint' is ignored, it's not allocated. */ + BLI_assert( + ELEM(*r_paint, + &ts->gp_paint->paint, + &ts->sculpt->paint, + &ts->vpaint->paint, + &ts->wpaint->paint, + &ts->uvsculpt->paint)); + +#ifdef DEBUG + struct Paint paint_test = **r_paint; + BKE_paint_runtime_init(ts, *r_paint); + /* Swap so debug doesn't hide errors when release fails. */ + SWAP(Paint, **r_paint, paint_test); + BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode); + BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset); +#endif + return true; + } + + if (ELEM(*r_paint, &ts->vpaint->paint, &ts->wpaint->paint)) { + VPaint *data = MEM_callocN(sizeof(*data), __func__); + paint = &data->paint; + } + else if (*r_paint == &ts->sculpt->paint) { + Sculpt *data = MEM_callocN(sizeof(*data), __func__); + paint = &data->paint; + + /* Turn on X plane mirror symmetry by default */ + paint->symmetry_flags |= PAINT_SYMM_X; + + /* Make sure at least dyntopo subdivision is enabled */ + data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; + } + else if (*r_paint == &ts->gp_paint->paint) { + GpPaint *data = MEM_callocN(sizeof(*data), __func__); + paint = &data->paint; + } + else if (*r_paint == &ts->uvsculpt->paint) { + UvSculpt *data = MEM_callocN(sizeof(*data), __func__); + paint = &data->paint; + } + + paint->flags |= PAINT_SHOW_BRUSH; + + BKE_paint_runtime_init(ts, paint); + + *r_paint = paint; + return false; +} + void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) { UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings; @@ -507,7 +704,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) /* If there's no brush, create one */ brush = BKE_paint_brush(paint); if (brush == NULL) { - eObjectMode ob_mode = BKE_paint_object_mode_from_paint_mode(mode); + eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode); brush = BKE_brush_first_search(bmain, ob_mode); if (!brush) { @@ -529,6 +726,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) void BKE_paint_free(Paint *paint) { curvemapping_free(paint->cavity_curve); + MEM_SAFE_FREE(paint->tool_slots); } /* called when copying scene settings, so even if 'src' and 'tar' are the same @@ -539,10 +737,16 @@ void BKE_paint_copy(Paint *src, Paint *tar, const int flag) { tar->brush = src->brush; tar->cavity_curve = curvemapping_copy(src->cavity_curve); + tar->tool_slots = MEM_dupallocN(src->tool_slots); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)tar->brush); id_us_plus((ID *)tar->palette); + if (src->tool_slots != NULL) { + for (int i = 0; i < tar->tool_slots_len; i++) { + id_us_plus((ID *)tar->tool_slots[i].brush); + } + } } } @@ -713,8 +917,8 @@ void BKE_sculptsession_bm_to_me(Object *ob, bool reorder) if (ob && ob->sculpt) { sculptsession_bm_to_me_update_data_only(ob, reorder); - /* ensure the objects DerivedMesh mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + /* ensure the objects evaluated mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */ + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } } @@ -724,7 +928,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object) if (object->sculpt->bm) { /* Ensure no points to old arrays are stored in DM * - * Apparently, we could not use DAG_id_tag_update + * Apparently, we could not use DEG_id_tag_update * here because this will lead to the while object * surface to disappear, so we'll release DM in place. */ @@ -749,7 +953,6 @@ void BKE_sculptsession_free(Object *ob) { if (ob && ob->sculpt) { SculptSession *ss = ob->sculpt; - DerivedMesh *dm = ob->derivedFinal; if (ss->bm) { BKE_sculptsession_bm_to_me(ob, true); @@ -758,12 +961,11 @@ void BKE_sculptsession_free(Object *ob) if (ss->pbvh) BKE_pbvh_free(ss->pbvh); + MEM_SAFE_FREE(ss->pmap); + MEM_SAFE_FREE(ss->pmap_mem); if (ss->bm_log) BM_log_free(ss->bm_log); - if (dm && dm->getPBVH) - dm->getPBVH(NULL, dm); /* signal to clear */ - if (ss->texcache) MEM_freeN(ss->texcache); @@ -853,14 +1055,25 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) } /** - * \param need_mask So the DerivedMesh thats returned has mask data + * \param need_mask So that the evaluated mesh that is returned has mask data. */ -void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, - bool need_pmap, bool need_mask) +void BKE_sculpt_update_mesh_elements( + Depsgraph *depsgraph, Scene *scene, Sculpt *sd, Object *ob, + bool need_pmap, bool need_mask) { - DerivedMesh *dm; + /* TODO(sergey): Make sure ob points to an original object. This is what it + * is supposed to be pointing to. The issue is, currently draw code takes + * care of PBVH creation, even though this is something up to dependency + * graph. + * Probably, we need to being back logic which was checking for sculpt mode + * and (re)create PBVH if needed in that case, similar to how DerivedMesh + * was handling this. + */ + ob = DEG_get_original_object(ob); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + SculptSession *ss = ob->sculpt; - Mesh *me = ob->data; + Mesh *me = BKE_object_get_original_mesh(ob); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); @@ -895,13 +1108,13 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, CD_MASK_BAREMESH); /* VWPaint require mesh info for loop lookup, so require sculpt mode here */ if (mmd && ob->mode & OB_MODE_SCULPT) { ss->multires = mmd; - ss->totvert = dm->getNumVerts(dm); - ss->totpoly = dm->getNumPolys(dm); + ss->totvert = me_eval->totvert; + ss->totpoly = me_eval->totpoly; ss->mvert = NULL; ss->mpoly = NULL; ss->mloop = NULL; @@ -916,22 +1129,34 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); } - ss->pbvh = dm->getPBVH(ob, dm); - ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL; + ss->subdiv_ccg = me_eval->runtime.subdiv_ccg; + + PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob); + BLI_assert(pbvh == ss->pbvh); + UNUSED_VARS_NDEBUG(pbvh); + MEM_SAFE_FREE(ss->pmap); + MEM_SAFE_FREE(ss->pmap_mem); + if (need_pmap && ob->type == OB_MESH) { + BKE_mesh_vert_poly_map_create( + &ss->pmap, &ss->pmap_mem, + me->mpoly, me->mloop, + me->totvert, me->totpoly, me->totloop); + } pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color); pbvh_show_mask_set(ss->pbvh, ss->show_mask); if (ss->modifiers_active) { if (!ss->orig_cos) { + Object *object_orig = DEG_get_original_object(ob); int a; BKE_sculptsession_free_deformMats(ss); ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL); - BKE_crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos); - BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos); + BKE_crazyspace_build_sculpt(depsgraph, scene, object_orig, &ss->deform_imats, &ss->deform_cos); + BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert); for (a = 0; a < me->totvert; ++a) { invert_m3(ss->deform_imats[a]); @@ -955,7 +1180,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, if (vertCos) { if (!pbvh_deformed) { /* apply shape keys coordinates to PBVH */ - BKE_pbvh_apply_vertCos(ss->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert); } if (ss->deform_cos == NULL) { ss->deform_cos = vertCos; @@ -966,6 +1191,9 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, } } } + + /* 2.8x - avoid full mesh update! */ + BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS); } int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) @@ -1041,18 +1269,9 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene) { - Sculpt *sd = scene->toolsettings->sculpt; - if (sd == NULL) { - sd = scene->toolsettings->sculpt = MEM_callocN(sizeof(Sculpt), __func__); - - /* Turn on X plane mirror symmetry by default */ - sd->paint.symmetry_flags |= PAINT_SYMM_X; - sd->paint.flags |= PAINT_SHOW_BRUSH; - - /* Make sure at least dyntopo subdivision is enabled */ - sd->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; - } + BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->sculpt); + Sculpt *sd = scene->toolsettings->sculpt; if (!sd->detail_size) { sd->detail_size = 12; } @@ -1074,3 +1293,123 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene) sd->paint.tile_offset[2] = 1.0f; } } + +static bool check_sculpt_object_deformed(Object *object, const bool for_construction) +{ + bool deformed = false; + + /* Active modifiers means extra deformation, which can't be handled correct + * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush + * stuff and show final evaluated mesh so user would see actual object shape. + */ + deformed |= object->sculpt->modifiers_active; + + if (for_construction) { + deformed |= object->sculpt->kb != NULL; + } + else { + /* As in case with modifiers, we can't synchronize deformation made against + * PBVH and non-locked keyblock, so also use PBVH only for brushes and + * final DM to give final result to user. + */ + deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0; + } + + return deformed; +} + +static PBVH *build_pbvh_for_dynamic_topology(Object *ob) +{ + PBVH *pbvh = BKE_pbvh_new(); + BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm, + ob->sculpt->bm_smooth_shading, + ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset, + ob->sculpt->cd_face_node_offset); + pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); + return pbvh; +} + +static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform) +{ + Mesh *me = BKE_object_get_original_mesh(ob); + const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); + PBVH *pbvh = BKE_pbvh_new(); + + MLoopTri *looptri = MEM_malloc_arrayN( + looptris_num, sizeof(*looptri), __func__); + + BKE_mesh_recalc_looptri( + me->mloop, me->mpoly, + me->mvert, + me->totloop, me->totpoly, + looptri); + + BKE_pbvh_build_mesh( + pbvh, + me->mpoly, me->mloop, + me->mvert, me->totvert, &me->vdata, + looptri, looptris_num); + + pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); + + const bool is_deformed = check_sculpt_object_deformed(ob, true); + if (is_deformed && me_eval_deform != NULL) { + int totvert; + float (*v_cos)[3] = BKE_mesh_vertexCos_get(me_eval_deform, &totvert); + BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert); + MEM_freeN(v_cos); + } + + return pbvh; +} + +static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg) +{ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + PBVH *pbvh = BKE_pbvh_new(); + BKE_pbvh_build_grids( + pbvh, + subdiv_ccg->grids, subdiv_ccg->num_grids, + &key, + (void **)subdiv_ccg->grid_faces, + subdiv_ccg->grid_flag_mats, + subdiv_ccg->grid_hidden); + pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color); + pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); + return pbvh; +} + +PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) +{ + if (ob == NULL || ob->sculpt == NULL) { + return NULL; + } + PBVH *pbvh = ob->sculpt->pbvh; + if (pbvh != NULL) { + /* Nothing to do, PBVH is already up to date. */ + return pbvh; + } + + if (ob->sculpt->bm != NULL) { + /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */ + pbvh = build_pbvh_for_dynamic_topology(ob); + } + else { + Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); + Mesh *mesh_eval = object_eval->data; + if (mesh_eval->runtime.subdiv_ccg != NULL) { + pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg); + } + else if (ob->type == OB_MESH) { + Mesh *me_eval_deform = mesh_get_eval_deform( + depsgraph, DEG_get_evaluated_scene(depsgraph), ob, CD_MASK_BAREMESH); + pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform); + } + } + + ob->sculpt->pbvh = pbvh; + return pbvh; +} diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c new file mode 100644 index 00000000000..92e42a0a468 --- /dev/null +++ b/source/blender/blenkernel/intern/paint_toolslots.c @@ -0,0 +1,140 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/paint_toolslots.c + * \ingroup bke + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" +#include "DNA_brush_types.h" + +#include "BLI_utildefines.h" + +#include "BKE_main.h" +#include "BKE_library.h" +#include "BKE_brush.h" +#include "BKE_paint.h" + +void BKE_paint_toolslots_len_ensure(Paint *paint, int len) +{ + /* Tool slots are 'uchar'. */ + BLI_assert(len <= UCHAR_MAX); + if (paint->tool_slots_len < len) { + paint->tool_slots = MEM_recallocN(paint->tool_slots, sizeof(*paint->tool_slots) * len); + paint->tool_slots_len = len; + } +} + +static void paint_toolslots_init(Main *bmain, Paint *paint) +{ + if (paint == NULL) { + return; + } + const eObjectMode ob_mode = paint->runtime.ob_mode; + BLI_assert(paint->runtime.tool_offset && ob_mode); + for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) { + if (brush->ob_mode & ob_mode) { + const int slot_index = BKE_brush_tool_get(brush, paint); + BKE_paint_toolslots_len_ensure(paint, slot_index + 1); + if (paint->tool_slots[slot_index].brush == NULL) { + paint->tool_slots[slot_index].brush = brush; + id_us_plus(&brush->id); + } + } + } +} + +void BKE_paint_toolslots_init_from_main(struct Main *bmain) +{ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + ToolSettings *ts = scene->toolsettings; + paint_toolslots_init(bmain, &ts->imapaint.paint); + paint_toolslots_init(bmain, &ts->sculpt->paint); + paint_toolslots_init(bmain, &ts->vpaint->paint); + paint_toolslots_init(bmain, &ts->wpaint->paint); + paint_toolslots_init(bmain, &ts->gp_paint->paint); + } +} + + +void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush) +{ + const uint tool_offset = paint->runtime.tool_offset; + UNUSED_VARS_NDEBUG(tool_offset); + BLI_assert(tool_offset != 0); + const int slot_index = BKE_brush_tool_get(brush, paint); + BKE_paint_toolslots_len_ensure(paint, slot_index + 1); + PaintToolSlot *tslot = &paint->tool_slots[slot_index]; + id_us_plus(&brush->id); + id_us_min(&tslot->brush->id); + tslot->brush = brush; +} + +void BKE_paint_toolslots_brush_update(Paint *paint) +{ + if (paint->brush == NULL) { + return; + } + BKE_paint_toolslots_brush_update_ex(paint, paint->brush); +} + +/** + * Run this to ensure brush types are set for each slot on entering modes + * (for new scenes for example). + */ +void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint) +{ + /* Clear slots with invalid slots or mode (unlikely but possible). */ + const uint tool_offset = paint->runtime.tool_offset; + UNUSED_VARS_NDEBUG(tool_offset); + const eObjectMode ob_mode = paint->runtime.ob_mode; + BLI_assert(tool_offset && ob_mode); + for (int i = 0; i < paint->tool_slots_len; i++) { + PaintToolSlot *tslot = &paint->tool_slots[i]; + if (tslot->brush) { + if ((i != BKE_brush_tool_get(tslot->brush, paint)) || + (tslot->brush->ob_mode & ob_mode) == 0) + { + id_us_min(&tslot->brush->id); + tslot->brush = NULL; + } + } + } + + /* Unlikely but possible the active brush is not currently using a slot. */ + BKE_paint_toolslots_brush_update(paint); + + /* Fill slots from brushes. */ + paint_toolslots_init(bmain, paint); +} + +Brush *BKE_paint_toolslots_brush_get(Paint *paint, int slot_index) +{ + if (slot_index < paint->tool_slots_len) { + PaintToolSlot *tslot = &paint->tool_slots[slot_index]; + return tslot->brush; + } + return NULL; +} diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 40c0e1f8184..360dcd7b26a 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -36,8 +36,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_group_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -51,6 +51,7 @@ #include "BLI_noise.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_kdopbvh.h" #include "BLI_kdtree.h" #include "BLI_rand.h" #include "BLI_task.h" @@ -64,10 +65,10 @@ #include "BKE_boids.h" #include "BKE_cloth.h" +#include "BKE_collection.h" #include "BKE_colortools.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_group.h" #include "BKE_main.h" #include "BKE_lattice.h" @@ -78,14 +79,17 @@ #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" -#include "BKE_depsgraph.h" #include "BKE_modifier.h" #include "BKE_mesh.h" -#include "BKE_cdderivedmesh.h" +#include "BKE_cdderivedmesh.h" /* for weight_to_rgb() */ #include "BKE_pointcache.h" #include "BKE_scene.h" #include "BKE_deform.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + #include "RE_render_ext.h" #include "particle_private.h" @@ -96,19 +100,19 @@ float PSYS_FRAND_BASE[PSYS_FRAND_COUNT]; void psys_init_rng(void) { - int i; - BLI_srandom(5831); /* arbitrary */ - for (i = 0; i < PSYS_FRAND_COUNT; ++i) { - PSYS_FRAND_BASE[i] = BLI_frand(); - PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rand(); - PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rand(); + RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */ + for (int i = 0; i < PSYS_FRAND_COUNT; ++i) { + PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng); + PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng); + PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng); } + BLI_rng_free(rng); } static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex); -static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, - int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra); +static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, + int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra); /* few helpers for countall etc. */ int count_particles(ParticleSystem *psys) @@ -228,31 +232,15 @@ void psys_set_current_num(Object *ob, int index) } } -#if 0 /* UNUSED */ -Object *psys_find_object(Scene *scene, ParticleSystem *psys) -{ - Base *base; - ParticleSystem *tpsys; - - for (base = scene->base.first; base; base = base->next) { - for (tpsys = base->object->particlesystem.first; psys; psys = psys->next) { - if (tpsys == psys) - return base->object; - } - } - - return NULL; -} -#endif - struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData *sim) { struct LatticeDeformData *lattice_deform_data = NULL; - if (psys_in_edit_mode(sim->scene, sim->psys) == 0) { + if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) { Object *lattice = NULL; ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys); - int mode = G.is_rendering ? eModifierMode_Render : eModifierMode_Realtime; + bool for_render = DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER; + int mode = for_render ? eModifierMode_Render : eModifierMode_Realtime; for (; md; md = md->next) { if (md->type == eModifierType_Lattice) { @@ -285,10 +273,40 @@ void psys_enable_all(Object *ob) for (; psys; psys = psys->next) psys->flag &= ~PSYS_DISABLED; } -bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys) + +ParticleSystem *psys_orig_get(ParticleSystem *psys) { - return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata); + if (psys->orig_psys == NULL) { + return psys; + } + return psys->orig_psys; } + +static PTCacheEdit *psys_orig_edit_get(ParticleSystem *psys) +{ + if (psys->orig_psys == NULL) { + return psys->edit; + } + return psys->orig_psys->edit; +} + +bool psys_in_edit_mode(Depsgraph *depsgraph, const ParticleSystem *psys) +{ + const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + if (view_layer->basact == NULL) { + /* TODO(sergey): Needs double-check with multi-object edit. */ + return false; + } + const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const Object *object = view_layer->basact->object; + if (object->mode != OB_MODE_PARTICLE_EDIT) { + return false; + } + const ParticleSystem *psys_orig = psys_orig_get((ParticleSystem *)psys); + return (psys_orig->edit || psys->pointcache->edit) && + (use_render_params == false); +} + bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params) { ParticleSystemModifierData *psmd; @@ -297,7 +315,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_ return 0; psmd = psys_get_modifier(ob, psys); - if (psys->renderdata || use_render_params) { + if (use_render_params) { if (!(psmd->modifier.mode & eModifierMode_Render)) return 0; } @@ -315,68 +333,84 @@ bool psys_check_edited(ParticleSystem *psys) return (psys->pointcache->edit && psys->pointcache->edit->edited); } +void psys_find_group_weights(ParticleSettings *part) +{ + /* Find object pointers based on index. If the collection is linked from + * another library linking may not have the object pointers available on + * file load, so we have to retrieve them later. See T49273. */ + const ListBase dup_group_objects = BKE_collection_object_cache_get(part->dup_group); + + for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) { + if (dw->ob == NULL) { + Base *base = BLI_findlink(&dup_group_objects, dw->index); + if (base != NULL) { + dw->ob = base->object; + } + } + } +} + void psys_check_group_weights(ParticleSettings *part) { ParticleDupliWeight *dw, *tdw; - GroupObject *go; - int current = 0; - if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) { - /* First try to find NULL objects from their index, - * and remove all weights that don't have an object in the group. */ - dw = part->dupliweights.first; - while (dw) { - if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) { - go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index); - if (go) { - dw->ob = go->ob; - } - else { - tdw = dw->next; - BLI_freelinkN(&part->dupliweights, dw); - dw = tdw; - } - } - else { - dw = dw->next; - } - } + if (part->ren_as != PART_DRAW_GR || !part->dup_group) { + BLI_freelistN(&part->dupliweights); + return; + } - /* then add objects in the group to new list */ - go = part->dup_group->gobject.first; - while (go) { - dw = part->dupliweights.first; - while (dw && dw->ob != go->ob) - dw = dw->next; - - if (!dw) { - dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight"); - dw->ob = go->ob; - dw->count = 1; - BLI_addtail(&part->dupliweights, dw); - } + /* Find object pointers. */ + psys_find_group_weights(part); - go = go->next; + /* Remove NULL objects, that were removed from the collection. */ + dw = part->dupliweights.first; + while (dw) { + if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->dup_group, dw->ob)) { + tdw = dw->next; + BLI_freelinkN(&part->dupliweights, dw); + dw = tdw; + } + else { + dw = dw->next; } + } + /* Add new objects in the collection. */ + int index = 0; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object) + { dw = part->dupliweights.first; - for (; dw; dw = dw->next) { - if (dw->flag & PART_DUPLIW_CURRENT) { - current = 1; - break; - } + while (dw && dw->ob != object) { + dw = dw->next; } - if (!current) { - dw = part->dupliweights.first; - if (dw) - dw->flag |= PART_DUPLIW_CURRENT; + if (!dw) { + dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight"); + dw->ob = object; + dw->count = 1; + BLI_addtail(&part->dupliweights, dw); } + + dw->index = index++; } - else { - BLI_freelistN(&part->dupliweights); + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + /* Ensure there is an element marked as current. */ + int current = 0; + for (dw = part->dupliweights.first; dw; dw = dw->next) { + if (dw->flag & PART_DUPLIW_CURRENT) { + current = 1; + break; + } + } + + if (!current) { + dw = part->dupliweights.first; + if (dw) + dw->flag |= PART_DUPLIW_CURRENT; } } + int psys_uses_gravity(ParticleSimulationData *sim) { return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part && sim->psys->part->effector_weights->global_gravity != 0.0f; @@ -419,7 +453,7 @@ void BKE_particlesettings_free(ParticleSettings *part) fluid_free_settings(part->fluid); } -void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics) +void free_hair(Object *object, ParticleSystem *psys, int dynamics) { PARTICLE_P; @@ -434,26 +468,23 @@ void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics) if (psys->clmd) { if (dynamics) { - BKE_ptcache_free_list(&psys->ptcaches); - psys->pointcache = NULL; - modifier_free((ModifierData *)psys->clmd); - - psys->clmd = NULL; - psys->pointcache = BKE_ptcache_add(&psys->ptcaches); + PTCacheID pid; + BKE_ptcache_id_from_particles(&pid, object, psys); + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); } else { cloth_free_modifier(psys->clmd); } } - if (psys->hair_in_dm) - psys->hair_in_dm->release(psys->hair_in_dm); - psys->hair_in_dm = NULL; + if (psys->hair_in_mesh) + BKE_id_free(NULL, psys->hair_in_mesh); + psys->hair_in_mesh = NULL; - if (psys->hair_out_dm) - psys->hair_out_dm->release(psys->hair_out_dm); - psys->hair_out_dm = NULL; + if (psys->hair_out_mesh) + BKE_id_free(NULL, psys->hair_out_mesh); + psys->hair_out_mesh = NULL; } void free_keyed_keys(ParticleSystem *psys) { @@ -562,7 +593,21 @@ void psys_free(Object *ob, ParticleSystem *psys) psys_free_path_cache(psys, NULL); - free_hair(ob, psys, 1); + /* NOTE: We pass dynamics=0 to free_hair() to prevent it from doing an + * unneeded clear of the cache. But for historical reason that code path + * was only clearing cloth part of modifier data. + * + * Part of the story there is that particle evaluation is trying to not + * re-allocate thew ModifierData itself, and limits all allocations to + * the cloth part of it. + * + * Why evaluation is relying on hair_free() and in some specific code + * paths there is beyond me. + */ + free_hair(ob, psys, 0); + if (psys->clmd != NULL) { + modifier_free((ModifierData *)psys->clmd); + } psys_free_particles(psys); @@ -590,7 +635,9 @@ void psys_free(Object *ob, ParticleSystem *psys) psys->part = NULL; - BKE_ptcache_free_list(&psys->ptcaches); + if ((psys->flag & PSYS_SHARED_CACHES) == 0) { + BKE_ptcache_free_list(&psys->ptcaches); + } psys->pointcache = NULL; BLI_freelistN(&psys->targets); @@ -601,213 +648,62 @@ void psys_free(Object *ob, ParticleSystem *psys) if (psys->fluid_springs) MEM_freeN(psys->fluid_springs); - pdEndEffectors(&psys->effectors); + BKE_effectors_free(psys->effectors); if (psys->pdd) { psys_free_pdd(psys); MEM_freeN(psys->pdd); } - MEM_freeN(psys); - } -} - -/************************************************/ -/* Rendering */ -/************************************************/ -/* these functions move away particle data and bring it back after - * rendering, to make different render settings possible without - * removing the previous data. this should be solved properly once */ - -void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset) -{ - ParticleRenderData *data; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - - if (psys->renderdata) - return; - - data = MEM_callocN(sizeof(ParticleRenderData), "ParticleRenderData"); - - data->child = psys->child; - data->totchild = psys->totchild; - data->pathcache = psys->pathcache; - data->pathcachebufs.first = psys->pathcachebufs.first; - data->pathcachebufs.last = psys->pathcachebufs.last; - data->totcached = psys->totcached; - data->childcache = psys->childcache; - data->childcachebufs.first = psys->childcachebufs.first; - data->childcachebufs.last = psys->childcachebufs.last; - data->totchildcache = psys->totchildcache; - - if (psmd->dm_final) { - data->dm = CDDM_copy_with_tessface(psmd->dm_final); - } - data->totdmvert = psmd->totdmvert; - data->totdmedge = psmd->totdmedge; - data->totdmface = psmd->totdmface; - - psys->child = NULL; - psys->pathcache = NULL; - psys->childcache = NULL; - psys->totchild = psys->totcached = psys->totchildcache = 0; - BLI_listbase_clear(&psys->pathcachebufs); - BLI_listbase_clear(&psys->childcachebufs); + BKE_particle_batch_cache_free(psys); - copy_m4_m4(data->winmat, winmat); - mul_m4_m4m4(data->viewmat, viewmat, ob->obmat); - mul_m4_m4m4(data->mat, winmat, data->viewmat); - data->winx = winx; - data->winy = winy; - - data->timeoffset = timeoffset; - - psys->renderdata = data; - - /* Hair can and has to be recalculated if everything isn't displayed. */ - if (psys->part->disp != 100 && ELEM(psys->part->type, PART_HAIR, PART_FLUID)) { - psys->recalc |= PSYS_RECALC_RESET; + MEM_freeN(psys); } } -void psys_render_restore(Object *ob, ParticleSystem *psys) +void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src) { - ParticleRenderData *data; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - float render_disp = psys_get_current_display_percentage(psys); - float disp; - - data = psys->renderdata; - if (!data) - return; - - if (data->elems) - MEM_freeN(data->elems); - - if (psmd->dm_final) { - psmd->dm_final->needsFree = 1; - psmd->dm_final->release(psmd->dm_final); - } - if (psmd->dm_deformed) { - psmd->dm_deformed->needsFree = 1; - psmd->dm_deformed->release(psmd->dm_deformed); - psmd->dm_deformed = NULL; - } - - psys_free_path_cache(psys, NULL); - - if (psys->child) { - MEM_freeN(psys->child); - psys->child = 0; - psys->totchild = 0; - } - - psys->child = data->child; - psys->totchild = data->totchild; - psys->pathcache = data->pathcache; - psys->pathcachebufs.first = data->pathcachebufs.first; - psys->pathcachebufs.last = data->pathcachebufs.last; - psys->totcached = data->totcached; - psys->childcache = data->childcache; - psys->childcachebufs.first = data->childcachebufs.first; - psys->childcachebufs.last = data->childcachebufs.last; - psys->totchildcache = data->totchildcache; - - psmd->dm_final = data->dm; - psmd->totdmvert = data->totdmvert; - psmd->totdmedge = data->totdmedge; - psmd->totdmface = data->totdmface; - psmd->flag &= ~eParticleSystemFlag_psys_updated; - - if (psmd->dm_final) { - if (!psmd->dm_final->deformedOnly) { - if (ob->derivedDeform) { - psmd->dm_deformed = CDDM_copy(ob->derivedDeform); - } - else { - psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data); - } - DM_ensure_tessface(psmd->dm_deformed); - } - psys_calc_dmcache(ob, psmd->dm_final, psmd->dm_deformed, psys); - } - - MEM_freeN(data); - psys->renderdata = NULL; - - /* restore particle display percentage */ - disp = psys_get_current_display_percentage(psys); - - if (disp != render_disp) { - /* Hair can and has to be recalculated if everything isn't displayed. */ - if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) { - psys->recalc |= PSYS_RECALC_RESET; - } - else { - PARTICLE_P; - - LOOP_PARTICLES { - if (psys_frand(psys, p) > disp) - pa->flag |= PARS_NO_DISP; - else - pa->flag &= ~PARS_NO_DISP; - } + /* Free existing particles. */ + if (psys_dst->particles != psys_src->particles) { + psys_free_particles(psys_dst); + } + if (psys_dst->child != psys_src->child) { + psys_free_children(psys_dst); + } + /* Restore counters. */ + psys_dst->totpart = psys_src->totpart; + psys_dst->totchild = psys_src->totchild; + /* Copy particles and children. */ + psys_dst->particles = MEM_dupallocN(psys_src->particles); + psys_dst->child = MEM_dupallocN(psys_src->child); + if (psys_dst->part->type == PART_HAIR) { + ParticleData *pa; + int p; + for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) { + pa->hair = MEM_dupallocN(pa->hair); } } -} - -bool psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float *params) -{ - ParticleRenderData *data; - ParticleRenderElem *elem; - float x, w, scale, alpha, lambda, t, scalemin, scalemax; - int b; - - if (!(psys->renderdata && (psys->part->simplify_flag & PART_SIMPLIFY_ENABLE))) - return false; - - data = psys->renderdata; - if (!data->do_simplify) - return false; - b = (data->index_mf_to_mpoly) ? DM_origindex_mface_mpoly(data->index_mf_to_mpoly, data->index_mp_to_orig, cpa->num) : cpa->num; - if (b == ORIGINDEX_NONE) { - return false; - } - - elem = &data->elems[b]; - - lambda = elem->lambda; - t = elem->t; - scalemin = elem->scalemin; - scalemax = elem->scalemax; - - if (!elem->reduce) { - scale = scalemin; - alpha = 1.0f; - } - else { - x = (elem->curchild + 0.5f) / elem->totchild; - if (x < lambda - t) { - scale = scalemax; - alpha = 1.0f; + if (psys_dst->particles && (psys_dst->particles->keys || psys_dst->particles->boid)) { + ParticleKey *key = psys_dst->particles->keys; + BoidParticle *boid = psys_dst->particles->boid; + ParticleData *pa; + int p; + if (key != NULL) { + key = MEM_dupallocN(key); } - else if (x >= lambda + t) { - scale = scalemin; - alpha = 0.0f; + if (boid != NULL) { + boid = MEM_dupallocN(boid); } - else { - w = (lambda + t - x) / (2.0f * t); - scale = scalemin + (scalemax - scalemin) * w; - alpha = w; + for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) { + if (boid != NULL) { + pa->boid = boid++; + } + if (key != NULL) { + pa->keys = key; + key += pa->totkey; + } } } - - params[0] = scale; - params[1] = alpha; - - elem->curchild++; - - return 1; } /************************************************/ @@ -859,7 +755,7 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic typedef struct ParticleInterpolationData { HairKey *hkey[2]; - DerivedMesh *dm; + Mesh *mesh; MVert *mvert[2]; int keyed; @@ -993,8 +889,8 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic pind->birthtime = key->time; pind->dietime = (key + pa->totkey - 1)->time; - if (pind->dm) { - pind->mvert[0] = CDDM_get_vert(pind->dm, pa->hair_index); + if (pind->mesh) { + pind->mvert[0] = &pind->mesh->mvert[pa->hair_index]; pind->mvert[1] = pind->mvert[0] + 1; } } @@ -1103,7 +999,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData edit_to_particle(keys + 1, pind->ekey[0]); edit_to_particle(keys + 2, pind->ekey[1]); } - else if (pind->dm) { + else if (pind->mesh) { pind->mvert[0] = pind->mvert[1] - 1; mvert_to_particle(keys + 1, pind->mvert[0], pind->hkey[0]); mvert_to_particle(keys + 2, pind->mvert[1], pind->hkey[1]); @@ -1128,7 +1024,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData else edit_to_particle(keys, pind->ekey[0]); } - else if (pind->dm) { + else if (pind->mesh) { if (pind->hkey[0] != pa->hair) mvert_to_particle(keys, pind->mvert[0] - 1, pind->hkey[0] - 1); else @@ -1147,7 +1043,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData else edit_to_particle(keys + 3, pind->ekey[1]); } - else if (pind->dm) { + else if (pind->mesh) { if (pind->hkey[1] != pa->hair + pa->totkey - 1) mvert_to_particle(keys + 3, pind->mvert[1] + 1, pind->hkey[1] + 1); else @@ -1216,7 +1112,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach /* interpolate a location on a face based on face coordinates */ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*orcodata)[3], float w[4], float vec[3], float nor[3], float utan[3], float vtan[3], - float orco[3], float ornor[3]) + float orco[3]) { float *v1 = 0, *v2 = 0, *v3 = 0, *v4 = 0; float e1[3], e2[3], s1, s2, t1, t2; @@ -1314,21 +1210,13 @@ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*or o4 = orcodata[mface->v4]; interp_v3_v3v3v3v3(orco, o1, o2, o3, o4, w); - - if (ornor) - normal_quad_v3(ornor, o1, o2, o3, o4); } else { interp_v3_v3v3v3(orco, o1, o2, o3, w); - - if (ornor) - normal_tri_v3(ornor, o1, o2, o3); } } else { copy_v3_v3(orco, vec); - if (ornor && nor) - copy_v3_v3(ornor, nor); } } } @@ -1381,7 +1269,7 @@ void psys_interpolate_mcol(const MCol *mcol, int quad, const float w[4], MCol *m } } -static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, const float fw[4], const float *values) +static float psys_interpolate_value_from_verts(Mesh *mesh, short from, int index, const float fw[4], const float *values) { if (values == 0 || index == -1) return 0.0; @@ -1392,7 +1280,7 @@ static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int case PART_FROM_FACE: case PART_FROM_VOLUME: { - MFace *mf = dm->getTessFaceData(dm, index, CD_MFACE); + MFace *mf = &mesh->mface[index]; return interpolate_particle_value(values[mf->v1], values[mf->v2], values[mf->v3], values[mf->v4], fw, mf->v4); } @@ -1442,7 +1330,7 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4 * \return the DM tessface index. */ int psys_particle_dm_face_lookup( - DerivedMesh *dm_final, DerivedMesh *dm_deformed, + Mesh *mesh_final, Mesh *mesh_original, int findex_orig, const float fw[4], struct LinkNode **poly_nodes) { MFace *mtessface_final; @@ -1454,36 +1342,36 @@ int psys_particle_dm_face_lookup( const int *index_mf_to_mpoly = NULL; const int *index_mp_to_orig = NULL; - const int totface_final = dm_final->getNumTessFaces(dm_final); - const int totface_deformed = dm_deformed ? dm_deformed->getNumTessFaces(dm_deformed) : totface_final; + const int totface_final = mesh_final->totface; + const int totface_deformed = mesh_original ? mesh_original->totface : totface_final; if (ELEM(0, totface_final, totface_deformed)) { return DMCACHE_NOTFOUND; } - index_mf_to_mpoly = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX); - index_mp_to_orig = dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX); + index_mf_to_mpoly = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX); + index_mp_to_orig = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX); BLI_assert(index_mf_to_mpoly); - if (dm_deformed) { - index_mf_to_mpoly_deformed = dm_deformed->getTessFaceDataArray(dm_deformed, CD_ORIGINDEX); + if (mesh_original) { + index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX); } else { - BLI_assert(dm_final->deformedOnly); + BLI_assert(mesh_final->runtime.deformed_only); index_mf_to_mpoly_deformed = index_mf_to_mpoly; } BLI_assert(index_mf_to_mpoly_deformed); pindex_orig = index_mf_to_mpoly_deformed[findex_orig]; - if (dm_deformed == NULL) { - dm_deformed = dm_final; + if (mesh_original == NULL) { + mesh_original = mesh_final; } index_mf_to_mpoly_deformed = NULL; - mtessface_final = dm_final->getTessFaceArray(dm_final); - osface_final = dm_final->getTessFaceDataArray(dm_final, CD_ORIGSPACE); + mtessface_final = mesh_final->mface; + osface_final = CustomData_get_layer(&mesh_final->fdata, CD_ORIGSPACE); if (osface_final == NULL) { /* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */ @@ -1496,7 +1384,7 @@ int psys_particle_dm_face_lookup( return DMCACHE_NOTFOUND; } } - else if (findex_orig >= dm_deformed->getNumTessFaces(dm_deformed)) { + else if (findex_orig >= mesh_original->totface) { return DMCACHE_NOTFOUND; /* index not in the original mesh */ } @@ -1525,7 +1413,7 @@ int psys_particle_dm_face_lookup( else { /* if we have no node, try every face */ for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) { /* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */ - if (DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) { + if (BKE_mesh_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) { faceuv = osface_final[findex_dst].uv; /* check that this intersects - Its possible this misses :/ - @@ -1545,22 +1433,22 @@ int psys_particle_dm_face_lookup( return DMCACHE_NOTFOUND; } -static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4]) +static int psys_map_index_on_dm(Mesh *mesh, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4]) { if (index < 0) return 0; - if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) { + if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) { /* for meshes that are either only deformed or for child particles, the * index and fw do not require any mapping, so we can directly use it */ if (from == PART_FROM_VERT) { - if (index >= dm->getNumVerts(dm)) + if (index >= mesh->totvert) return 0; *mapindex = index; } else { /* FROM_FACE/FROM_VOLUME */ - if (index >= dm->getNumTessFaces(dm)) + if (index >= mesh->totface) return 0; *mapindex = index; @@ -1572,7 +1460,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_ * to their new location, which means a different index, and for faces * also a new face interpolation weights */ if (from == PART_FROM_VERT) { - if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > dm->getNumVerts(dm)) + if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > mesh->totvert) return 0; *mapindex = index_dmcache; @@ -1585,15 +1473,15 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_ i = index_dmcache; - if (i == DMCACHE_NOTFOUND || i >= dm->getNumTessFaces(dm)) + if (i == DMCACHE_NOTFOUND || i >= mesh->totface) return 0; *mapindex = i; /* modify the original weights to become * weights for the derived mesh face */ - osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE); - mface = dm->getTessFaceData(dm, i, CD_MFACE); + osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE); + mface = &mesh->mface[i]; if (osface == NULL) mapfw[0] = mapfw[1] = mapfw[2] = mapfw[3] = 0.0f; @@ -1606,32 +1494,31 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_ } /* interprets particle data to get a point on a mesh in object space */ -void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_dmcache, +void psys_particle_on_dm(Mesh *mesh_final, int from, int index, int index_dmcache, const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3], - float orco[3], float ornor[3]) + float orco[3]) { float tmpnor[3], mapfw[4]; float (*orcodata)[3]; int mapindex; - if (!psys_map_index_on_dm(dm_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) { + if (!psys_map_index_on_dm(mesh_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) { if (vec) { vec[0] = vec[1] = vec[2] = 0.0; } if (nor) { nor[0] = nor[1] = 0.0; nor[2] = 1.0; } if (orco) { orco[0] = orco[1] = orco[2] = 0.0; } - if (ornor) { ornor[0] = ornor[1] = 0.0; ornor[2] = 1.0; } if (utan) { utan[0] = utan[1] = utan[2] = 0.0; } if (vtan) { vtan[0] = vtan[1] = vtan[2] = 0.0; } return; } - orcodata = dm_final->getVertDataArray(dm_final, CD_ORCO); + orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO); if (from == PART_FROM_VERT) { - dm_final->getVertCo(dm_final, mapindex, vec); + copy_v3_v3(vec, mesh_final->mvert[mapindex].co); if (nor) { - dm_final->getVertNo(dm_final, mapindex, nor); + normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no); normalize_v3(nor); } @@ -1644,11 +1531,6 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d } } - if (ornor) { - dm_final->getVertNo(dm_final, mapindex, ornor); - normalize_v3(ornor); - } - if (utan && vtan) { utan[0] = utan[1] = utan[2] = 0.0f; vtan[0] = vtan[1] = vtan[2] = 0.0f; @@ -1659,15 +1541,15 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d MTFace *mtface; MVert *mvert; - mface = dm_final->getTessFaceData(dm_final, mapindex, CD_MFACE); - mvert = dm_final->getVertDataArray(dm_final, CD_MVERT); - mtface = CustomData_get_layer(&dm_final->faceData, CD_MTFACE); + mface = &mesh_final->mface[mapindex]; + mvert = mesh_final->mvert; + mtface = mesh_final->mtface; if (mtface) mtface += mapindex; if (from == PART_FROM_VOLUME) { - psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco, ornor); + psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco); if (nor) copy_v3_v3(nor, tmpnor); @@ -1676,19 +1558,19 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d add_v3_v3(vec, tmpnor); } else - psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco, ornor); + psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco); } } -float psys_particle_value_from_verts(DerivedMesh *dm, short from, ParticleData *pa, float *values) +float psys_particle_value_from_verts(Mesh *mesh, short from, ParticleData *pa, float *values) { float mapfw[4]; int mapindex; - if (!psys_map_index_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw)) + if (!psys_map_index_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw)) return 0.0f; - return psys_interpolate_value_from_verts(dm, from, mapindex, mapfw, values); + return psys_interpolate_value_from_verts(mesh, from, mapindex, mapfw, values); } ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys) @@ -1712,7 +1594,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys) /* ready for future use */ static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index), float *UNUSED(fuv), float vec[3], float nor[3], float utan[3], float vtan[3], - float orco[3], float ornor[3]) + float orco[3]) { /* TODO */ float zerovec[3] = {0.0f, 0.0f, 0.0f}; @@ -1731,9 +1613,6 @@ static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index), if (orco) { copy_v3_v3(orco, zerovec); } - if (ornor) { - copy_v3_v3(ornor, zerovec); - } } /************************************************/ /* Particles on emitter */ @@ -1776,9 +1655,9 @@ CustomDataMask psys_emitter_customdata_mask(ParticleSystem *psys) void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int index, int index_dmcache, float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3], - float orco[3], float ornor[3]) + float orco[3]) { - if (psmd && psmd->dm_final) { + if (psmd && psmd->mesh_final) { if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) { if (vec) copy_v3_v3(vec, fuv); @@ -1788,10 +1667,10 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in return; } /* we cant use the num_dmcache */ - psys_particle_on_dm(psmd->dm_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor); + psys_particle_on_dm(psmd->mesh_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco); } else - psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco, ornor); + psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco); } /************************************************/ @@ -1813,7 +1692,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors) return; LOOP_PARTICLES { - psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0, 0); + psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0); mul_m4_v3(sim->ob->obmat, state.co); mul_mat3_m4_v3(sim->ob->obmat, state.vel); @@ -1839,7 +1718,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors) } } -int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time) +int do_guides(Depsgraph *depsgraph, ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time) { CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL; CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL; @@ -1902,7 +1781,7 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i /* curve taper */ if (cu->taperobj) - mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100)); + mul_v3_fl(vec_to_point, BKE_displist_calc_taper(depsgraph, eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100)); else { /* curve size*/ if (cu->flag & CU_PATH_RADIUS) { @@ -1970,7 +1849,7 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK copy_qt_qt(eff_key.rot, (ca - 1)->rot); pd_point_from_particle(sim, sim->psys->particles + i, &eff_key, &epoint); - pdDoEffectors(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL); + BKE_effectors_apply(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL); mul_v3_fl(force, effector * powf((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps); @@ -2004,7 +1883,7 @@ static void offset_child(ChildParticle *cpa, ParticleKey *par, float *par_rot, P add_v3_v3(child->co, par->co); } -float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup) +float *psys_cache_vgroup(Mesh *mesh, ParticleSystem *psys, int vgroup) { float *vg = 0; @@ -2013,9 +1892,9 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup) } else if (psys->vgroup[vgroup]) { - MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + MDeformVert *dvert = mesh->dvert; if (dvert) { - int totvert = dm->getNumVerts(dm), i; + int totvert = mesh->totvert, i; vg = MEM_callocN(sizeof(float) * totvert, "vg_cache"); if (psys->vg_neg & (1 << vgroup)) { for (i = 0; i < totvert; i++) @@ -2041,7 +1920,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params int from = PART_FROM_FACE; totparent = (int)(totchild * part->parents * 0.3f); - if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) + if (use_render_params && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* hard limit, workaround for it being ignored above */ @@ -2052,10 +1931,10 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params tree = BLI_kdtree_new(totparent); for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) { - psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0); + psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco); /* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */ - get_cpa_texture(sim->psmd->dm_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra); + get_cpa_texture(sim->psmd->mesh_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra); if (ptex.exist >= psys_frand(psys, p + 24)) { BLI_kdtree_insert(tree, p, orco); @@ -2065,7 +1944,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params BLI_kdtree_balance(tree); for (; p < totchild; p++, cpa++) { - psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0); + psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco); cpa->parent = BLI_kdtree_find_nearest(tree, orco, NULL); } @@ -2085,10 +1964,10 @@ static bool psys_thread_context_init_path( psys_thread_context_init(ctx, sim); /*---start figuring out what is actually wanted---*/ - if (psys_in_edit_mode(scene, psys)) { + if (psys_in_edit_mode(sim->depsgraph, psys)) { ParticleEditSettings *pset = &scene->toolsettings->particle; - if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) + if ((use_render_params == 0) && (psys_orig_edit_get(psys) == NULL || pset->flag & PE_DRAW_PART) == 0) totchild = 0; segments = 1 << pset->draw_step; @@ -2097,14 +1976,14 @@ static bool psys_thread_context_init_path( if (totchild && part->childtype == PART_CHILD_FACES) { totparent = (int)(totchild * part->parents * 0.3f); - if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) + if (use_render_params && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* part->parents could still be 0 so we can't test with totparent */ between = 1; } - if (psys->renderdata || use_render_params) + if (use_render_params) segments = 1 << part->ren_step; else { totchild = (int)((float)totchild * (float)part->disp / 100.0f); @@ -2130,15 +2009,15 @@ static bool psys_thread_context_init_path( psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim); /* cache all relevant vertex groups if they exist */ - ctx->vg_length = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_LENGTH); - ctx->vg_clump = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_CLUMP); - ctx->vg_kink = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_KINK); - ctx->vg_rough1 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH1); - ctx->vg_rough2 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH2); - ctx->vg_roughe = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGHE); - ctx->vg_twist = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_TWIST); + ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH); + ctx->vg_clump = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_CLUMP); + ctx->vg_kink = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_KINK); + ctx->vg_rough1 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH1); + ctx->vg_rough2 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH2); + ctx->vg_roughe = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGHE); + ctx->vg_twist = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_TWIST); if (psys->part->flag & PART_CHILD_EFFECT) - ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR); + ctx->vg_effector = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_EFFECTOR); /* prepare curvemapping tables */ if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) { @@ -2182,11 +2061,12 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp ParticleSystem *psys = ctx->sim.psys; ParticleSettings *part = psys->part; ParticleCacheKey **cache = psys->childcache; - ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache; + PTCacheEdit *edit = psys_orig_edit_get(psys); + ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.depsgraph, psys) && edit ? edit->pathcache : psys->pathcache; ParticleCacheKey *child, *key[4]; ParticleTexture ptex; float *cpa_fuv = 0, *par_rot = 0, rot[4]; - float orco[3], ornor[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3]; + float orco[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3]; float eff_length, eff_vec[3], weight[4]; int k, cpa_num; short cpa_from; @@ -2208,7 +2088,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp needupdate = 0; w = 0; while (w < 4 && cpa->pa[w] >= 0) { - if (psys->edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) { + if (edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) { needupdate = 1; break; } @@ -2282,20 +2162,20 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; - psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, ornor, 0, 0, orco, 0); + psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco); mul_m4_v3(ob->obmat, co); for (w = 0; w < 4; w++) sub_v3_v3v3(off1[w], co, key[w]->co); - psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat); } else { ParticleData *pa = psys->particles + cpa->parent; float co[3]; if (ctx->editupdate) { - if (!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC)) + if (!(edit->points[cpa->parent].flag & PEP_EDIT_RECALC)) return; memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1)); @@ -2320,13 +2200,13 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp : pa->num_dmcache; /* XXX hack to avoid messed up particle num and subsequent crash (#40733) */ - if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final)) + if (cpa_num > ctx->sim.psmd->mesh_final->totface) cpa_num = 0; cpa_fuv = pa->fuv; - psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, ornor, 0, 0, orco, 0); + psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco); - psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat); } child_keys->segments = ctx->segments; @@ -2432,9 +2312,9 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp BLI_listbase_clear(&modifiers); psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, - par_co, NULL, NULL, NULL, par_orco, NULL); + par_co, NULL, NULL, NULL, par_orco); - psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco); + psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, hairmat, child_keys, par, par_orco); } else zero_v3(par_orco); @@ -2576,7 +2456,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re ParticleSettings *part = psys->part; ParticleCacheKey *ca, **cache; - DerivedMesh *hair_dm = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_dm : NULL; + Mesh *hair_mesh = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_mesh : NULL; ParticleKey result; @@ -2592,7 +2472,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4]; float rotmat[3][3]; int k; - int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step)); + int segments = (int)pow(2.0, (double)((use_render_params) ? part->ren_step : part->draw_step)); int totpart = psys->totpart; float length, vec[3]; float *vg_effector = NULL; @@ -2603,8 +2483,8 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re if ((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache) == 0) return; - if (psys_in_edit_mode(sim->scene, psys)) - if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) + if (psys_in_edit_mode(sim->depsgraph, psys)) + if ((psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) return; keyed = psys->flag & PSYS_KEYED; @@ -2621,15 +2501,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) { if ((psys->part->flag & PART_CHILD_EFFECT) == 0) - vg_effector = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_EFFECTOR); + vg_effector = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_EFFECTOR); if (!psys->totchild) - vg_length = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_LENGTH); + vg_length = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_LENGTH); } /* ensure we have tessfaces to be used for mapping */ if (part->from != PART_FROM_VERT) { - DM_ensure_tessface(psmd->dm_final); + BKE_mesh_tessface_ensure(psmd->mesh_final); } /*---first main loop: create all actual particles' paths---*/ @@ -2638,14 +2518,14 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f); pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p)); if (vg_length) - pa_length *= psys_particle_value_from_verts(psmd->dm_final, part->from, pa, vg_length); + pa_length *= psys_particle_value_from_verts(psmd->mesh_final, part->from, pa, vg_length); } pind.keyed = keyed; pind.cache = baked ? psys->pointcache : NULL; pind.epoint = NULL; pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); - pind.dm = hair_dm; + pind.mesh = hair_mesh; memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1)); @@ -2655,7 +2535,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re init_particle_interpolation(sim->ob, sim->psys, pa, &pind); /* hairmat is needed for for non-hair particle too so we get proper rotations */ - psys_mat_hair_to_global(sim->ob, psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(sim->ob, psmd->mesh_final, psys->part->from, pa, hairmat); copy_v3_v3(rotmat[0], hairmat[2]); copy_v3_v3(rotmat[1], hairmat[1]); copy_v3_v3(rotmat[2], hairmat[0]); @@ -2687,7 +2567,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re /* dynamic hair is in object space */ /* keyed and baked are already in global space */ - if (hair_dm) + if (hair_mesh) mul_m4_v3(sim->ob->obmat, ca->co); else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR)) mul_m4_v3(hairmat, ca->co); @@ -2710,7 +2590,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re if ((psys->part->flag & PART_CHILD_EFFECT) == 0) { float effector = 1.0f; if (vg_effector) - effector *= psys_particle_value_from_verts(psmd->dm_final, psys->part->from, pa, vg_effector); + effector *= psys_particle_value_from_verts(psmd->mesh_final, psys->part->from, pa, vg_effector); sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co); length = len_v3(vec); @@ -2723,7 +2603,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) { for (k = 0, ca = cache[p]; k <= segments; k++, ca++) /* ca is safe to cast, since only co and vel are used */ - do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments); + do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments); } /* lattices have to be calculated separately to avoid mixups between effector calculations */ @@ -2771,219 +2651,255 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re if (vg_length) MEM_freeN(vg_length); } -void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params) -{ - ParticleCacheKey *ca, **cache = edit->pathcache; - ParticleEditSettings *pset = &scene->toolsettings->particle; - - PTCacheEditPoint *point = NULL; - PTCacheEditKey *ekey = NULL; - - ParticleSystem *psys = edit->psys; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - ParticleData *pa = psys ? psys->particles : NULL; - - ParticleInterpolationData pind; - ParticleKey result; - float birthtime = 0.0f, dietime = 0.0f; - float t, time = 0.0f, keytime = 0.0f /*, frs_sec */; - float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f}; - int k, i; - int segments = 1 << pset->draw_step; - int totpart = edit->totpoint, recalc_set = 0; +typedef struct CacheEditrPathsIterData { + Object *object; + PTCacheEdit *edit; + ParticleSystemModifierData *psmd; + ParticleData *pa; + int segments; + bool use_weight; float sel_col[3]; float nosel_col[3]; +} CacheEditrPathsIterData; - segments = MAX2(segments, 4); - - if (!cache || edit->totpoint != edit->totcached) { - /* clear out old and create new empty path cache */ - psys_free_path_cache(edit->psys, edit); - cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1); - - /* set flag for update (child particles check this too) */ - for (i = 0, point = edit->points; i < totpart; i++, point++) - point->flag |= PEP_EDIT_RECALC; - recalc_set = 1; +static void psys_cache_edit_paths_iter( + void *__restrict iter_data_v, + const int iter, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + CacheEditrPathsIterData *iter_data = (CacheEditrPathsIterData *)iter_data_v; + PTCacheEdit *edit = iter_data->edit; + PTCacheEditPoint *point = &edit->points[iter]; + if (edit->totcached && !(point->flag & PEP_EDIT_RECALC)) { + return; } + if (point->totkey == 0) { + return; + } + Object *ob = iter_data->object; + ParticleSystem *psys = edit->psys; + ParticleCacheKey **cache = edit->pathcache; + ParticleSystemModifierData *psmd = iter_data->psmd; + ParticleData *pa = iter_data->pa ? iter_data->pa + iter : NULL; + PTCacheEditKey *ekey = point->keys; + const int segments = iter_data->segments; + const bool use_weight = iter_data->use_weight; - /* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */ + float birthtime = 0.0f, dietime = 0.0f; + float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f}; - const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL); + ParticleInterpolationData pind; + pind.keyed = 0; + pind.cache = NULL; + pind.epoint = point; + pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0; + pind.mesh = NULL; + /* should init_particle_interpolation set this ? */ if (use_weight) { - ; /* use weight painting colors now... */ - } - else { - sel_col[0] = (float)edit->sel_col[0] / 255.0f; - sel_col[1] = (float)edit->sel_col[1] / 255.0f; - sel_col[2] = (float)edit->sel_col[2] / 255.0f; - nosel_col[0] = (float)edit->nosel_col[0] / 255.0f; - nosel_col[1] = (float)edit->nosel_col[1] / 255.0f; - nosel_col[2] = (float)edit->nosel_col[2] / 255.0f; + pind.hkey[0] = NULL; + /* pa != NULL since the weight brush is only available for hair */ + pind.hkey[0] = pa->hair; + pind.hkey[1] = pa->hair + 1; } - /*---first main loop: create all actual particles' paths---*/ - for (i = 0, point = edit->points; i < totpart; i++, pa += pa ? 1 : 0, point++) { - if (edit->totcached && !(point->flag & PEP_EDIT_RECALC)) - continue; + memset(cache[iter], 0, sizeof(*cache[iter]) * (segments + 1)); - if (point->totkey == 0) - continue; + cache[iter]->segments = segments; - ekey = point->keys; + /*--get the first data points--*/ + init_particle_interpolation(ob, psys, pa, &pind); - pind.keyed = 0; - pind.cache = NULL; - pind.epoint = point; - pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0; - pind.dm = NULL; + if (psys) { + psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat); + copy_v3_v3(rotmat[0], hairmat[2]); + copy_v3_v3(rotmat[1], hairmat[1]); + copy_v3_v3(rotmat[2], hairmat[0]); + } + birthtime = pind.birthtime; + dietime = pind.dietime; - /* should init_particle_interpolation set this ? */ - if (use_weight) { - pind.hkey[0] = NULL; - /* pa != NULL since the weight brush is only available for hair */ - pind.hkey[0] = pa->hair; - pind.hkey[1] = pa->hair + 1; - } + if (birthtime >= dietime) { + cache[iter]->segments = -1; + return; + } + /*--interpolate actual path from data points--*/ + ParticleCacheKey *ca; + int k; + float t, time = 0.0f, keytime = 0.0f; + for (k = 0, ca = cache[iter]; k <= segments; k++, ca++) { + time = (float)k / (float)segments; + t = birthtime + time * (dietime - birthtime); + ParticleKey result; + result.time = -t; + do_particle_interpolation(psys, iter, pa, t, &pind, &result); + copy_v3_v3(ca->co, result.co); + + /* non-hair points are already in global space */ + if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { + mul_m4_v3(hairmat, ca->co); - memset(cache[i], 0, sizeof(*cache[i]) * (segments + 1)); + if (k) { + cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k); - cache[i]->segments = segments; + if (k == segments) + copy_qt_qt(ca->rot, (ca - 1)->rot); - /*--get the first data points--*/ - init_particle_interpolation(ob, psys, pa, &pind); + /* set velocity */ + sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co); - if (psys) { - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat); - copy_v3_v3(rotmat[0], hairmat[2]); - copy_v3_v3(rotmat[1], hairmat[1]); - copy_v3_v3(rotmat[2], hairmat[0]); + if (k == 1) + copy_v3_v3((ca - 1)->vel, ca->vel); + } } - - birthtime = pind.birthtime; - dietime = pind.dietime; - - if (birthtime >= dietime) { - cache[i]->segments = -1; - continue; + else { + ca->vel[0] = ca->vel[1] = 0.0f; + ca->vel[2] = 1.0f; } - /*--interpolate actual path from data points--*/ - for (k = 0, ca = cache[i]; k <= segments; k++, ca++) { - time = (float)k / (float)segments; - t = birthtime + time * (dietime - birthtime); - result.time = -t; - do_particle_interpolation(psys, i, pa, t, &pind, &result); - copy_v3_v3(ca->co, result.co); - - /* non-hair points are already in global space */ - if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { - mul_m4_v3(hairmat, ca->co); - - if (k) { - cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k); - - if (k == segments) - copy_qt_qt(ca->rot, (ca - 1)->rot); - - /* set velocity */ - sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co); - - if (k == 1) - copy_v3_v3((ca - 1)->vel, ca->vel); - } + /* selection coloring in edit mode */ + if (use_weight) { + if (k == 0) { + BKE_defvert_weight_to_rgb(ca->col, pind.hkey[1]->weight); } else { - ca->vel[0] = ca->vel[1] = 0.0f; - ca->vel[2] = 1.0f; - } - - /* selection coloring in edit mode */ - if (use_weight) { - if (k == 0) { - weight_to_rgb(ca->col, pind.hkey[1]->weight); + /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */ + float real_t; + if (result.time < 0.0f) { + real_t = -result.time; } else { - /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */ - float real_t; - if (result.time < 0.0f) { - real_t = -result.time; - } - else { - real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time); - } + real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time); + } - while (pind.hkey[1]->time < real_t) { - pind.hkey[1]++; - } - pind.hkey[0] = pind.hkey[1] - 1; - /* end copy */ + while (pind.hkey[1]->time < real_t) { + pind.hkey[1]++; + } + pind.hkey[0] = pind.hkey[1] - 1; + /* end copy */ - float w1[3], w2[3]; - keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); + float w1[3], w2[3]; + keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); - weight_to_rgb(w1, pind.hkey[0]->weight); - weight_to_rgb(w2, pind.hkey[1]->weight); + BKE_defvert_weight_to_rgb(w1, pind.hkey[0]->weight); + BKE_defvert_weight_to_rgb(w2, pind.hkey[1]->weight); - interp_v3_v3v3(ca->col, w1, w2, keytime); + interp_v3_v3v3(ca->col, w1, w2, keytime); + } + } + else { + if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) { + if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) { + copy_v3_v3(ca->col, iter_data->sel_col); + } + else { + keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); + interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime); } } else { - if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) { - if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) { - copy_v3_v3(ca->col, sel_col); - } - else { - keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); - interp_v3_v3v3(ca->col, sel_col, nosel_col, keytime); - } + if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) { + keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); + interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime); } else { - if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) { - keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time)); - interp_v3_v3v3(ca->col, nosel_col, sel_col, keytime); - } - else { - copy_v3_v3(ca->col, nosel_col); - } + copy_v3_v3(ca->col, iter_data->nosel_col); } } - - ca->time = t; } - if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { - /* First rotation is based on emitting face orientation. - * This is way better than having flipping rotations resulting - * from using a global axis as a rotation pole (vec_to_quat()). - * It's not an ideal solution though since it disregards the - * initial tangent, but taking that in to account will allow - * the possibility of flipping again. -jahka - */ - mat3_to_quat_is_ok(cache[i]->rot, rotmat); + + ca->time = t; + } + if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { + /* First rotation is based on emitting face orientation. + * This is way better than having flipping rotations resulting + * from using a global axis as a rotation pole (vec_to_quat()). + * It's not an ideal solution though since it disregards the + * initial tangent, but taking that in to account will allow + * the possibility of flipping again. -jahka + */ + mat3_to_quat_is_ok(cache[iter]->rot, rotmat); + } +} + +void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params) +{ + ParticleCacheKey **cache = edit->pathcache; + ParticleEditSettings *pset = &scene->toolsettings->particle; + + ParticleSystem *psys = edit->psys; + + ParticleData *pa = psys ? psys->particles : NULL; + + int segments = 1 << pset->draw_step; + int totpart = edit->totpoint, recalc_set = 0; + + segments = MAX2(segments, 4); + + if (!cache || edit->totpoint != edit->totcached) { + /* Clear out old and create new empty path cache. */ + psys_free_path_cache(edit->psys, edit); + cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1); + /* Set flag for update (child particles check this too). */ + int i; + PTCacheEditPoint *point; + for (i = 0, point = edit->points; i < totpart; i++, point++) { + point->flag |= PEP_EDIT_RECALC; } + recalc_set = 1; } + const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL); + + CacheEditrPathsIterData iter_data; + iter_data.object = ob; + iter_data.edit = edit; + iter_data.psmd = edit->psmd_eval; + iter_data.pa = pa; + iter_data.segments = segments; + iter_data.use_weight = use_weight; + + if (use_weight) { + ; /* use weight painting colors now... */ + } + else { + iter_data.sel_col[0] = (float)edit->sel_col[0] / 255.0f; + iter_data.sel_col[1] = (float)edit->sel_col[1] / 255.0f; + iter_data.sel_col[2] = (float)edit->sel_col[2] / 255.0f; + iter_data.nosel_col[0] = (float)edit->nosel_col[0] / 255.0f; + iter_data.nosel_col[1] = (float)edit->nosel_col[1] / 255.0f; + iter_data.nosel_col[2] = (float)edit->nosel_col[2] / 255.0f; + } + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; + BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings); + edit->totcached = totpart; if (psys) { ParticleSimulationData sim = {0}; + sim.depsgraph = depsgraph; sim.scene = scene; sim.ob = ob; sim.psys = psys; - sim.psmd = psys_get_modifier(ob, psys); + sim.psmd = edit->psmd_eval; psys_cache_child_paths(&sim, cfra, true, use_render_params); } /* clear recalc flag if set here */ if (recalc_set) { - for (i = 0, point = edit->points; i < totpart; i++, point++) + PTCacheEditPoint *point; + int i; + for (i = 0, point = edit->points; i < totpart; i++, point++) { point->flag &= ~PEP_EDIT_RECALC; + } } } /************************************************/ @@ -3007,22 +2923,6 @@ void psys_get_from_key(ParticleKey *key, float loc[3], float vel[3], float rot[4 if (rot) copy_qt_qt(rot, key->rot); if (time) *time = key->time; } -/*-------changing particle keys from space to another-------*/ -#if 0 -static void key_from_object(Object *ob, ParticleKey *key) -{ - float q[4]; - - add_v3_v3(key->vel, key->co); - - mul_m4_v3(ob->obmat, key->co); - mul_m4_v3(ob->obmat, key->vel); - mat4_to_quat(q, ob->obmat); - - sub_v3_v3v3(key->vel, key->vel, key->co); - mul_qt_qtqt(key->rot, q, key->rot); -} -#endif static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[4][4]) { @@ -3065,7 +2965,7 @@ static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat cross_v3_v3v3(mat[0], mat[1], mat[2]); } -static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float mat[4][4], int orco) +static void psys_face_mat(Object *ob, Mesh *mesh, ParticleData *pa, float mat[4][4], int orco) { float v[3][3]; MFace *mface; @@ -3073,72 +2973,72 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m float (*orcodata)[3]; int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache; - if (i == -1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; } + if (i == -1 || i >= mesh->totface) { unit_m4(mat); return; } - mface = dm->getTessFaceData(dm, i, CD_MFACE); - osface = dm->getTessFaceData(dm, i, CD_ORIGSPACE); + mface = &mesh->mface[i]; + osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE); - if (orco && (orcodata = dm->getVertDataArray(dm, CD_ORCO))) { + if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) { copy_v3_v3(v[0], orcodata[mface->v1]); copy_v3_v3(v[1], orcodata[mface->v2]); copy_v3_v3(v[2], orcodata[mface->v3]); /* ugly hack to use non-transformed orcos, since only those * give symmetric results for mirroring in particle mode */ - if (DM_get_vert_data_layer(dm, CD_ORIGINDEX)) + if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)) BKE_mesh_orco_verts_transform(ob->data, v, 3, 1); } else { - dm->getVertCo(dm, mface->v1, v[0]); - dm->getVertCo(dm, mface->v2, v[1]); - dm->getVertCo(dm, mface->v3, v[2]); + copy_v3_v3(v[0], mesh->mvert[mface->v1].co); + copy_v3_v3(v[1], mesh->mvert[mface->v2].co); + copy_v3_v3(v[2], mesh->mvert[mface->v3].co); } triatomat(v[0], v[1], v[2], (osface) ? osface->uv : NULL, mat); } -void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4]) +void psys_mat_hair_to_object(Object *UNUSED(ob), Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4]) { float vec[3]; /* can happen when called from a different object's modifier */ - if (!dm) { + if (!mesh) { unit_m4(hairmat); return; } - psys_face_mat(0, dm, pa, hairmat, 0); - psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0); + psys_face_mat(0, mesh, pa, hairmat, 0); + psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0); copy_v3_v3(hairmat[3], vec); } -void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4]) +void psys_mat_hair_to_orco(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4]) { float vec[3], orco[3]; - psys_face_mat(ob, dm, pa, hairmat, 1); - psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco, 0); + psys_face_mat(ob, mesh, pa, hairmat, 1); + psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco); /* see psys_face_mat for why this function is called */ - if (DM_get_vert_data_layer(dm, CD_ORIGINDEX)) + if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)) BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1); copy_v3_v3(hairmat[3], orco); } -void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float vec[3]) +void psys_vec_rot_to_face(Mesh *mesh, ParticleData *pa, float vec[3]) { float mat[4][4]; - psys_face_mat(0, dm, pa, mat, 0); + psys_face_mat(0, mesh, pa, mat, 0); transpose_m4(mat); /* cheap inverse for rotation matrix */ mul_mat3_m4_v3(mat, vec); } -void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4]) +void psys_mat_hair_to_global(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4]) { float facemat[4][4]; - psys_mat_hair_to_object(ob, dm, from, pa, facemat); + psys_mat_hair_to_object(ob, mesh, from, pa, facemat); mul_m4_m4m4(hairmat, ob->obmat, facemat); } @@ -3186,8 +3086,8 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob, psys->flag = PSYS_CURRENT; psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1); - DAG_relations_tag_update(bmain); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); return md; } @@ -3232,8 +3132,11 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob else ob->mode &= ~OB_MODE_PARTICLE_EDIT; - DAG_relations_tag_update(bmain); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } static void default_particle_settings(ParticleSettings *part) @@ -3296,7 +3199,7 @@ static void default_particle_settings(ParticleSettings *part) part->clength = 1.0f; part->clength_thres = 0.0f; - part->draw = PART_DRAW_EMITTER; + part->draw = 0; part->draw_line[0] = 0.5; part->path_start = 0.0f; part->path_end = 1.0f; @@ -3308,16 +3211,18 @@ static void default_particle_settings(ParticleSettings *part) part->color_vec_max = 1.f; part->draw_col = PART_DRAW_COL_MAT; - part->simplify_refsize = 1920; - part->simplify_rate = 1.0f; - part->simplify_transition = 0.1f; - part->simplify_viewport = 0.8; - if (!part->effector_weights) part->effector_weights = BKE_add_effector_weights(NULL); part->omat = 1; part->use_modifier_stack = false; + part->draw_size = 0.1f; + + part->shape_flag = PART_SHAPE_CLOSE_TIP; + part->shape = 0.0f; + part->rad_root = 1.0f; + part->rad_tip = 0.0f; + part->rad_scale = 0.01f; } @@ -3421,25 +3326,25 @@ void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const /* Textures */ /************************************************/ -static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const float fuv[4], +static int get_particle_uv(Mesh *mesh, ParticleData *pa, int index, const float fuv[4], char *name, float *texco, bool from_vert) { MFace *mf; MTFace *tf; int i; - tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, name); + tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name); if (tf == NULL) - tf = CustomData_get_layer(&dm->faceData, CD_MTFACE); + tf = mesh->mtface; if (tf == NULL) return 0; if (pa) { i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache; - if ((!from_vert && i >= dm->getNumTessFaces(dm)) || - (from_vert && i >= dm->getNumVerts(dm))) + if ((!from_vert && i >= mesh->totface) || + (from_vert && i >= mesh->totvert)) { i = -1; } @@ -3455,12 +3360,12 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f } else { if (from_vert) { - mf = dm->getTessFaceDataArray(dm, CD_MFACE); + mf = mesh->mface; /* This finds the first face to contain the emitting vertex, * this is not ideal, but is mostly fine as UV seams generally * map to equal-colored parts of a texture */ - for (int j = 0; j < dm->getNumTessFaces(dm); j++, mf++) { + for (int j = 0; j < mesh->totface; j++, mf++) { if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) { i = j; break; @@ -3468,7 +3373,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f } } else { - mf = dm->getTessFaceData(dm, i, CD_MFACE); + mf = &mesh->mface[i]; } psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco); @@ -3503,7 +3408,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f CLAMP(pvalue, -1.0f, 1.0f); \ } (void)0 -static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra) +static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra) { MTex *mtex, **mtexp = part->mtex; int m; @@ -3537,7 +3442,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti mul_m4_v3(mtex->object->imat, texvec); break; case TEXCO_UV: - if (fw && get_particle_uv(dm, NULL, face_index, fw, mtex->uvname, + if (fw && get_particle_uv(mesh, NULL, face_index, fw, mtex->uvname, texvec, (part->from == PART_FROM_VERT))) { break; @@ -3615,7 +3520,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex mul_m4_v3(mtex->object->imat, texvec); break; case TEXCO_UV: - if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname, + if (get_particle_uv(sim->psmd->mesh_final, pa, 0, pa->fuv, mtex->uvname, texvec, (part->from == PART_FROM_VERT))) { break; @@ -3623,7 +3528,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex /* no break, failed to get uv's, so let's try orco's */ ATTR_FALLTHROUGH; case TEXCO_ORCO: - psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec, 0); + psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec); if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { BKE_mesh_texspace_calc(me); @@ -3745,28 +3650,28 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread ParticleSystem *psys = ctx->sim.psys; int i = cpa - psys->child; - get_cpa_texture(ctx->dm, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra); + get_cpa_texture(ctx->mesh, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra); if (ptex->exist < psys_frand(psys, i + 24)) return; if (ctx->vg_length) - ptex->length *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_length); + ptex->length *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_length); if (ctx->vg_clump) - ptex->clump *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump); + ptex->clump *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump); if (ctx->vg_kink) - ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink); + ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink); if (ctx->vg_rough1) - ptex->rough1 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1); + ptex->rough1 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1); if (ctx->vg_rough2) - ptex->rough2 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2); + ptex->rough2 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2); if (ctx->vg_roughe) - ptex->roughe *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe); + ptex->roughe *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe); if (ctx->vg_effector) - ptex->effector *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector); + ptex->effector *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector); if (ctx->vg_twist) - ptex->twist *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist); + ptex->twist *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist); } /* get's hair (or keyed) particles state at the "path time" specified in state->time */ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel) @@ -3819,22 +3724,22 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE); /* pind.dm disabled in editmode means we don't get effectors taken into * account when subdividing for instance */ - pind.dm = psys_in_edit_mode(sim->scene, psys) ? NULL : psys->hair_out_dm; + pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ? NULL : psys->hair_out_mesh; /* XXX Sybren EEK */ init_particle_interpolation(sim->ob, psys, pa, &pind); do_particle_interpolation(psys, p, pa, t, &pind, state); - if (pind.dm) { + if (pind.mesh) { mul_m4_v3(sim->ob->obmat, state->co); mul_mat3_m4_v3(sim->ob->obmat, state->vel); } else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) { if ((pa->flag & PARS_REKEY) == 0) { - psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, part->from, pa, hairmat); + psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, part->from, pa, hairmat); mul_m4_v3(hairmat, state->co); mul_mat3_m4_v3(hairmat, state->vel); if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) { - do_guides(sim->psys->part, sim->psys->effectors, state, p, state->time); + do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, state, p, state->time); /* TODO: proper velocity handling */ } @@ -3885,7 +3790,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; - psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco, 0); + psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco); /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ //copy_v3_v3(cpa_1st, co); @@ -3894,9 +3799,9 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * pa = psys->particles + cpa->parent; - psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0); + psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco); if (part->type == PART_HAIR) - psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat); else unit_m4(hairmat); @@ -3914,10 +3819,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * cpa_num = pa->num; cpa_fuv = pa->fuv; - psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0); + psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco); if (part->type == PART_HAIR) { - psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0); - psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); + psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco); + psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat); } else { copy_v3_v3(orco, cpa->fuv); @@ -3925,18 +3830,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * } } - /* correct child ipo timing */ -#if 0 // XXX old animation system - if ((part->flag & PART_ABS_TIME) == 0 && part->ipo) { - calc_ipo(part->ipo, 100.0f * t); - execute_ipo((ID *)part, part->ipo); - } -#endif // XXX old animation system - /* get different child parameters from textures & vgroups */ memset(&ctx, 0, sizeof(ParticleThreadContext)); ctx.sim = *sim; - ctx.dm = psmd->dm_final; + ctx.mesh = psmd->mesh_final; ctx.ma = ma; /* TODO: assign vertex groups */ get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); @@ -4020,7 +3917,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta float timestep = psys_get_timestep(sim); /* negative time means "use current time" */ - cfra = state->time > 0 ? state->time : BKE_scene_frame_get(sim->scene); + cfra = state->time > 0 ? state->time : DEG_get_ctime(sim->depsgraph); if (p >= totpart) { if (!psys->totchild) @@ -4190,18 +4087,18 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, bool is_grid = (part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT); if (cpa) { - if ((part->childtype == PART_CHILD_FACES) && (psmd->dm_final != NULL)) { - CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final); + if ((part->childtype == PART_CHILD_FACES) && (psmd->mesh_final != NULL)) { + CustomData *mtf_data = &psmd->mesh_final->fdata; const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE); mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx); if (mtface && !is_grid) { - mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE); + mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE); mtface += cpa->num; psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv); } - psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco, 0); + psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco); return; } else { @@ -4209,8 +4106,8 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, } } - if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL) && !is_grid) { - CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final); + if ((part->from == PART_FROM_FACE) && (psmd->mesh_final != NULL) && !is_grid) { + CustomData *mtf_data = &psmd->mesh_final->fdata; const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE); mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx); @@ -4219,20 +4116,20 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part, if (num == DMCACHE_NOTFOUND) num = pa->num; - if (num >= psmd->dm_final->getNumTessFaces(psmd->dm_final)) { + if (num >= psmd->mesh_final->totface) { /* happens when simplify is enabled * gives invalid coords but would crash otherwise */ num = DMCACHE_NOTFOUND; } if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) { - mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE); + mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE); mtface += num; psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv); } } - psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco, 0); + psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco); } void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[4][4], float *scale) @@ -4250,9 +4147,9 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa pa = psys->particles + cpa->pa[0]; if (pa) - psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0, 0); + psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0); else - psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0, 0); + psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0); if (psys->part->rotmode == PART_ROT_VEL) { transpose_m3_m4(nmat, ob->imat); @@ -4384,9 +4281,10 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3] madd_v3_v3fl(center, yvec, bb->offset[1]); } -void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) +void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSimulationData sim = {0}; + sim.depsgraph = depsgraph; sim.scene = scene; sim.ob = ob; sim.psys = psys; @@ -4401,7 +4299,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) float hairmat[4][4], imat[4][4]; for (p = 0; p < psys->totpart; p++, pa++) { - psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, psys->part->from, pa, hairmat); invert_m4_m4(imat, hairmat); hkey = pa->hair; @@ -4419,3 +4317,22 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) psys->flag |= PSYS_EDITED; } } + + + +/* Draw Engine */ +void (*BKE_particle_batch_cache_dirty_tag_cb)(ParticleSystem *psys, int mode) = NULL; +void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL; + +void BKE_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode) +{ + if (psys->batch_cache) { + BKE_particle_batch_cache_dirty_tag_cb(psys, mode); + } +} +void BKE_particle_batch_cache_free(ParticleSystem *psys) +{ + if (psys->batch_cache) { + BKE_particle_batch_cache_free_cb(psys); + } +} diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index 79c3f247232..0cba5f5a2fc 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -39,40 +39,6 @@ #include "particle_private.h" -struct Material; - -static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3]) -{ - float cross[3], nstrand[3], vnor[3], blend; - - if (!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f))) - return; - - if (ma->mode & MA_STR_SURFDIFF) { - cross_v3_v3v3(cross, surfnor, nor); - cross_v3_v3v3(nstrand, nor, cross); - - blend = dot_v3v3(nstrand, surfnor); - CLAMP(blend, 0.0f, 1.0f); - - interp_v3_v3v3(vnor, nstrand, surfnor, blend); - normalize_v3(vnor); - } - else { - copy_v3_v3(vnor, nor); - } - - if (ma->strand_surfnor > 0.0f) { - if (ma->strand_surfnor > surfdist) { - blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor; - interp_v3_v3v3(vnor, vnor, surfnor, blend); - normalize_v3(vnor); - } - } - - copy_v3_v3(nor, vnor); -} - /* ------------------------------------------------------------------------- */ typedef struct ParticlePathIterator { @@ -320,7 +286,7 @@ static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *k } void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers, - ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4], + ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], float hairmat[4][4], ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3]) { struct ParticleSettings *part = ctx->sim.psys->part; @@ -333,11 +299,8 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod int totkeys, k; float max_length; -#if 0 /* TODO for the future: use true particle modifiers that work on the whole curve */ - for (mod = modifiers->first; mod; mod = mod->next) { - mod->apply(keys, totkeys, parent_keys); - } -#else + /* TODO for the future: use true particle modifiers that work on the whole curve */ + (void)modifiers; (void)mod; @@ -389,9 +352,6 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod if (k >= 2) { sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co); mul_v3_fl((key-1)->vel, 0.5); - - if (ma && draw_col_ma) - get_strand_normal(ma, ornor, cur_length, (key-1)->vel); } if (use_length_check && k > 0) { @@ -413,11 +373,9 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod if (ma && draw_col_ma) { copy_v3_v3(key->col, &ma->r); - get_strand_normal(ma, ornor, cur_length, key->vel); } } } -#endif } /* ------------------------------------------------------------------------- */ @@ -820,7 +778,7 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx, if (part->flag & PART_CHILD_EFFECT) /* state is safe to cast, since only co and vel are used */ - guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t); + guided = do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t); if (guided == 0) { float orco_offset[3]; diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 8a3b1312590..6c5a9085e71 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -50,14 +50,13 @@ #include "DNA_particle_types.h" #include "DNA_scene_types.h" -#include "BKE_cdderivedmesh.h" -#include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_particle.h" -static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot); +#include "DEG_depsgraph_query.h" static void alloc_child_particles(ParticleSystem *psys, int tot) { @@ -80,12 +79,13 @@ static void alloc_child_particles(ParticleSystem *psys, int tot) } } -static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys) +static void distribute_simple_children(Scene *scene, Object *ob, Mesh *final_mesh, Mesh *deform_mesh, ParticleSystem *psys, const bool use_render_params) { ChildParticle *cpa = NULL; int i, p; - int child_nbr= psys_get_child_number(scene, psys); - int totpart= psys_get_tot_child(scene, psys); + int child_nbr= psys_get_child_number(scene, psys, use_render_params); + int totpart= psys_get_tot_child(scene, psys, use_render_params); + RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed); alloc_child_particles(psys, totpart); @@ -97,9 +97,9 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi /* create even spherical distribution inside unit sphere */ while (length>=1.0f) { - cpa->fuv[0]=2.0f*BLI_frand()-1.0f; - cpa->fuv[1]=2.0f*BLI_frand()-1.0f; - cpa->fuv[2]=2.0f*BLI_frand()-1.0f; + cpa->fuv[0]=2.0f*BLI_rng_get_float(rng)-1.0f; + cpa->fuv[1]=2.0f*BLI_rng_get_float(rng)-1.0f; + cpa->fuv[2]=2.0f*BLI_rng_get_float(rng)-1.0f; length=len_v3(cpa->fuv); } @@ -107,14 +107,16 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi } } /* dmcache must be updated for parent particles if children from faces is used */ - psys_calc_dmcache(ob, finaldm, deformdm, psys); + psys_calc_dmcache(ob, final_mesh, deform_mesh, psys); + + BLI_rng_free(rng); } -static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) +static void distribute_grid(Mesh *mesh, ParticleSystem *psys) { ParticleData *pa=NULL; float min[3], max[3], delta[3], d; - MVert *mv, *mvert = dm->getVertDataArray(dm,0); - int totvert=dm->getNumVerts(dm), from=psys->part->from; + MVert *mv, *mvert = mesh->mvert; + int totvert=mesh->totvert, from=psys->part->from; int i, j, k, p, res=psys->part->grid_res, size[3], axis; /* find bounding box of dm */ @@ -196,8 +198,8 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) int a, a1, a2, a0mul, a1mul, a2mul, totface; int amax= from==PART_FROM_FACE ? 3 : 1; - totface=dm->getNumTessFaces(dm); - mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE); + totface = mesh->totface; + mface = mface_array = mesh->mface; for (a=0; a<amax; a++) { if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; } @@ -314,19 +316,16 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) static void hammersley_create(float *out, int n, int seed, float amount) { RNG *rng; - double p, t, offs[2]; - int k, kk; + + double offs[2], t; rng = BLI_rng_new(31415926 + n + seed); offs[0] = BLI_rng_get_double(rng) + (double)amount; offs[1] = BLI_rng_get_double(rng) + (double)amount; BLI_rng_free(rng); - for (k = 0; k < n; k++) { - t = 0; - for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) - if (kk & 1) /* kk mod 2 = 1 */ - t += p; + for (int k = 0; k < n; k++) { + BLI_hammersley_1D(k, &t); out[2*k + 0] = fmod((double)k/(double)n + offs[0], 1.0); out[2*k + 1] = fmod(t + offs[1], 1.0); @@ -434,7 +433,7 @@ static int distribute_binary_search(float *sum, int n, float value) /* the max number if calls to rng_* funcs within psys_thread_distribute_particle * be sure to keep up to date if this changes */ -#define PSYS_RND_DIST_SKIP 2 +#define PSYS_RND_DIST_SKIP 3 /* note: this function must be thread safe, for from == PART_FROM_CHILD */ #define ONLY_WORKING_WITH_PA_VERTS 0 @@ -443,7 +442,7 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i ParticleThreadContext *ctx= thread->ctx; MFace *mface; - mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE); + mface = ctx->mesh->mface; int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */ @@ -452,12 +451,12 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i zero_v4(pa->fuv); - if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->dm->getNumVerts(ctx->dm)) { + if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->mesh->totvert) { /* This finds the first face to contain the emitting vertex, * this is not ideal, but is mostly fine as UV seams generally * map to equal-colored parts of a texture */ - for (int i = 0; i < ctx->dm->getNumTessFaces(ctx->dm); i++, mface++) { + for (int i = 0; i < ctx->mesh->totface; i++, mface++) { if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) { unsigned int *vert = &mface->v1; @@ -478,8 +477,8 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i KDTreeNearest ptn[3]; int w, maxw; - psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1); + psys_particle_on_dm(ctx->mesh,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0); + BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1); maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3); for (w=0; w<maxw; w++) { @@ -488,13 +487,15 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i } #endif - if (rng_skip_tot > 0) /* should never be below zero */ + BLI_assert(rng_skip_tot > 0); /* should never be below zero */ + if (rng_skip_tot > 0) { BLI_rng_skip(thread->rng, rng_skip_tot); + } } static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p) { ParticleThreadContext *ctx= thread->ctx; - DerivedMesh *dm= ctx->dm; + Mesh *mesh = ctx->mesh; float randu, randv; int distr= ctx->distr; int i; @@ -503,7 +504,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i MFace *mface; pa->num = i = ctx->index[p]; - mface = dm->getTessFaceData(dm,i,CD_MFACE); + mface = &mesh->mface[i]; switch (distr) { case PART_DISTR_JIT: @@ -530,13 +531,15 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i } pa->foffset= 0.0f; - if (rng_skip_tot > 0) /* should never be below zero */ + BLI_assert(rng_skip_tot > 0); /* should never be below zero */ + if (rng_skip_tot > 0) { BLI_rng_skip(thread->rng, rng_skip_tot); + } } static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) { ParticleThreadContext *ctx= thread->ctx; - DerivedMesh *dm= ctx->dm; + Mesh *mesh = ctx->mesh; float *v1, *v2, *v3, *v4, nor[3], co[3]; float cur_d, min_d, randu, randv; int distr= ctx->distr; @@ -544,10 +547,10 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */ MFace *mface; - MVert *mvert=dm->getVertDataArray(dm,CD_MVERT); + MVert *mvert = mesh->mvert; pa->num = i = ctx->index[p]; - mface = dm->getTessFaceData(dm,i,CD_MFACE); + mface = &mesh->mface[i]; switch (distr) { case PART_DISTR_JIT: @@ -575,9 +578,9 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, pa->foffset= 0.0f; /* experimental */ - tot=dm->getNumTessFaces(dm); + tot = mesh->totface; - psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0); + psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0); normalize_v3(nor); negate_v3(nor); @@ -585,7 +588,7 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, min_d=FLT_MAX; intersect=0; - for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) { + for (i=0, mface=mesh->mface; i<tot; i++,mface++) { if (i==pa->num) continue; v1=mvert[mface->v1].co; @@ -619,19 +622,22 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)]; break; case PART_DISTR_RAND: - pa->foffset *= BLI_frand(); + pa->foffset *= BLI_rng_get_float(thread->rng); + rng_skip_tot--; break; } } - if (rng_skip_tot > 0) /* should never be below zero */ + BLI_assert(rng_skip_tot > 0); /* should never be below zero */ + if (rng_skip_tot > 0) { BLI_rng_skip(thread->rng, rng_skip_tot); + } } static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) { ParticleThreadContext *ctx= thread->ctx; Object *ob= ctx->sim.ob; - DerivedMesh *dm= ctx->dm; + Mesh *mesh = ctx->mesh; float orco1[3], co1[3], nor1[3]; float randu, randv; int cfrom= ctx->cfrom; @@ -647,7 +653,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i return; } - mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE); + mf = &mesh->mface[ctx->index[p]]; randu= BLI_rng_get_float(thread->rng); randv= BLI_rng_get_float(thread->rng); @@ -664,8 +670,8 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i int parent[10]; float pweight[10]; - psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1); + psys_particle_on_dm(mesh,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1); + BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1); maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3); maxd=ptn[maxw-1].dist; @@ -743,16 +749,10 @@ static void exec_distribute_child(TaskPool * __restrict UNUSED(pool), void *task /* RNG skipping at the beginning */ cpa = psys->child; for (p = 0; p < task->begin; ++p, ++cpa) { - if (task->ctx->skip) /* simplification skip */ - BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]); - BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP); } for (; p < task->end; ++p, ++cpa) { - if (task->ctx->skip) /* simplification skip */ - BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]); - distribute_children_exec(task, cpa, p); } } @@ -779,11 +779,15 @@ static int distribute_compare_orig_index(const void *p1, const void *p2, void *u return 1; } -static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from) +static void distribute_invalid(ParticleSimulationData *sim, int from) { + Scene *scene = sim->scene; + ParticleSystem *psys = sim->psys; + const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER); + if (from == PART_FROM_CHILD) { ChildParticle *cpa; - int p, totchild = psys_get_tot_child(scene, psys); + int p, totchild = psys_get_tot_child(scene, psys, use_render_params); if (psys->child && totchild) { for (p=0,cpa=psys->child; p<totchild; p++,cpa++) { @@ -805,19 +809,18 @@ static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from) } } -/* Creates a distribution of coordinates on a DerivedMesh */ -/* This is to denote functionality that does not yet work with mesh - only derived mesh */ +/* Creates a distribution of coordinates on a Mesh */ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from) { Scene *scene = sim->scene; - DerivedMesh *finaldm = sim->psmd->dm_final; + Mesh *final_mesh = sim->psmd->mesh_final; Object *ob = sim->ob; ParticleSystem *psys= sim->psys; ParticleData *pa=0, *tpars= 0; ParticleSettings *part; ParticleSeam *seams= 0; KDTree *tree=0; - DerivedMesh *dm= NULL; + Mesh *mesh = NULL; float *jit= NULL; int i, p=0; int cfrom=0; @@ -825,6 +828,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti int jitlevel= 1, distr; float *element_weight=NULL,*jitter_offset=NULL, *vweight=NULL; float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3]; + RNG *rng = NULL; if (ELEM(NULL, ob, psys, psys->part)) return 0; @@ -834,7 +838,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti if (totpart==0) return 0; - if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) { + if (!final_mesh->runtime.deformed_only && !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) { printf("Can't create particles with the current modifier stack, disable destructive modifiers\n"); // XXX error("Can't paint with the current modifier stack, disable destructive modifiers"); return 0; @@ -847,32 +851,37 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti psys_thread_context_init(ctx, sim); + const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER); + /* First handle special cases */ if (from == PART_FROM_CHILD) { /* Simple children */ if (part->childtype != PART_CHILD_FACES) { - BLI_srandom(31415926 + psys->seed + psys->child_seed); - distribute_simple_children(scene, ob, finaldm, sim->psmd->dm_deformed, psys); + distribute_simple_children(scene, ob, final_mesh, sim->psmd->mesh_original, psys, use_render_params); return 0; } } else { /* Grid distribution */ if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) { - BLI_srandom(31415926 + psys->seed); - if (psys->part->use_modifier_stack) { - dm = finaldm; + mesh = final_mesh; } else { - dm = CDDM_from_mesh((Mesh*)ob->data); + BKE_id_copy_ex( + NULL, ob->data, (ID **)&mesh, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); } - DM_ensure_tessface(dm); + BKE_mesh_tessface_ensure(mesh); - distribute_grid(dm,psys); + distribute_grid(mesh,psys); - if (dm != finaldm) { - dm->release(dm); + if (mesh != final_mesh) { + BKE_id_free(NULL, mesh); } return 0; @@ -881,54 +890,61 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti /* Create trees and original coordinates if needed */ if (from == PART_FROM_CHILD) { - distr=PART_DISTR_RAND; - BLI_srandom(31415926 + psys->seed + psys->child_seed); - dm= finaldm; + distr = PART_DISTR_RAND; + rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed); + mesh= final_mesh; /* BMESH ONLY */ - DM_ensure_tessface(dm); + BKE_mesh_tessface_ensure(mesh); children=1; tree=BLI_kdtree_new(totpart); for (p=0,pa=psys->particles; p<totpart; p++,pa++) { - psys_particle_on_dm(dm,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,NULL); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco, 1, 1); + psys_particle_on_dm(mesh,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco); + BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1); BLI_kdtree_insert(tree, p, orco); } BLI_kdtree_balance(tree); - totpart = psys_get_tot_child(scene, psys); + totpart = psys_get_tot_child(scene, psys, use_render_params); cfrom = from = PART_FROM_FACE; } else { distr = part->distr; - BLI_srandom(31415926 + psys->seed); + + rng = BLI_rng_new_srandom(31415926 + psys->seed); if (psys->part->use_modifier_stack) - dm = finaldm; + mesh = final_mesh; else - dm= CDDM_from_mesh((Mesh*)ob->data); + BKE_id_copy_ex( + NULL, ob->data, (ID **)&mesh, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); - DM_ensure_tessface(dm); + BKE_mesh_tessface_ensure(mesh); /* we need orco for consistent distributions */ - if (!CustomData_has_layer(&dm->vertData, CD_ORCO)) - DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob)); + if (!CustomData_has_layer(&mesh->vdata, CD_ORCO)) + CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert); if (from == PART_FROM_VERT) { - MVert *mv= dm->getVertDataArray(dm, CD_MVERT); - float (*orcodata)[3] = dm->getVertDataArray(dm, CD_ORCO); - int totvert = dm->getNumVerts(dm); + MVert *mv = mesh->mvert; + float (*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO); + int totvert = mesh->totvert; tree=BLI_kdtree_new(totvert); for (p=0; p<totvert; p++) { if (orcodata) { copy_v3_v3(co,orcodata[p]); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co, 1, 1); + BKE_mesh_orco_verts_transform(ob->data, &co, 1, 1); } else copy_v3_v3(co,mv[p].co); @@ -940,17 +956,18 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti } /* Get total number of emission elements and allocate needed arrays */ - totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm); + totelem = (from == PART_FROM_VERT) ? mesh->totvert : mesh->totface; if (totelem == 0) { - distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0); + distribute_invalid(sim, children ? PART_FROM_CHILD : 0); if (G.debug & G_DEBUG) fprintf(stderr,"Particle distribution error: Nothing to emit from!\n"); - if (dm != finaldm) dm->release(dm); + if (mesh != final_mesh) BKE_id_free(NULL, mesh); BLI_kdtree_free(tree); + BLI_rng_free(rng); return 0; } @@ -960,37 +977,37 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti jitter_offset = MEM_callocN(sizeof(float) * totelem, "particle_distribution_jitoff"); /* Calculate weights from face areas */ - if ((part->flag&PART_EDISTR || children) && from != PART_FROM_VERT) { + if ((part->flag & PART_EDISTR || children) && from != PART_FROM_VERT) { MVert *v1, *v2, *v3, *v4; float totarea=0.f, co1[3], co2[3], co3[3], co4[3]; float (*orcodata)[3]; - orcodata= dm->getVertDataArray(dm, CD_ORCO); + orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO); for (i=0; i<totelem; i++) { - MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE); + MFace *mf = &mesh->mface[i]; if (orcodata) { copy_v3_v3(co1, orcodata[mf->v1]); copy_v3_v3(co2, orcodata[mf->v2]); copy_v3_v3(co3, orcodata[mf->v3]); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co1, 1, 1); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co2, 1, 1); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co3, 1, 1); + BKE_mesh_orco_verts_transform(ob->data, &co1, 1, 1); + BKE_mesh_orco_verts_transform(ob->data, &co2, 1, 1); + BKE_mesh_orco_verts_transform(ob->data, &co3, 1, 1); if (mf->v4) { copy_v3_v3(co4, orcodata[mf->v4]); - BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co4, 1, 1); + BKE_mesh_orco_verts_transform(ob->data, &co4, 1, 1); } } else { - v1= (MVert*)dm->getVertData(dm,mf->v1,CD_MVERT); - v2= (MVert*)dm->getVertData(dm,mf->v2,CD_MVERT); - v3= (MVert*)dm->getVertData(dm,mf->v3,CD_MVERT); + v1 = &mesh->mvert[mf->v1]; + v2 = &mesh->mvert[mf->v2]; + v3 = &mesh->mvert[mf->v3]; copy_v3_v3(co1, v1->co); copy_v3_v3(co2, v2->co); copy_v3_v3(co3, v3->co); if (mf->v4) { - v4= (MVert*)dm->getVertData(dm,mf->v4,CD_MVERT); + v4 = &mesh->mvert[mf->v4]; copy_v3_v3(co4, v4->co); } } @@ -1017,7 +1034,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti } /* Calculate weights from vgroup */ - vweight = psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY); + vweight = psys_cache_vgroup(mesh,psys,PSYS_VG_DENSITY); if (vweight) { if (from==PART_FROM_VERT) { @@ -1026,7 +1043,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti } else { /* PART_FROM_FACE / PART_FROM_VOLUME */ for (i=0;i<totelem; i++) { - MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE); + MFace *mf = &mesh->mface[i]; tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3]; if (mf->v4) { @@ -1087,11 +1104,11 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti totmapped = i_mapped; /* Finally assign elements to particles */ - if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) { + if (part->flag & PART_TRAND) { for (p = 0; p < totpart; p++) { /* In theory element_sum[totmapped - 1] should be 1.0, * but due to float errors this is not necessarily always true, so scale pos accordingly. */ - const float pos = BLI_frand() * element_sum[totmapped - 1]; + const float pos = BLI_rng_get_float(rng) * element_sum[totmapped - 1]; const int eidx = distribute_binary_search(element_sum, totmapped, pos); particle_element[p] = element_map[eidx]; BLI_assert(pos <= element_sum[eidx]); @@ -1129,12 +1146,12 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti int *orig_index = NULL; if (from == PART_FROM_VERT) { - if (dm->numVertData) - orig_index = dm->getVertDataArray(dm, CD_ORIGINDEX); + if (mesh->totvert) + orig_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); } else { - if (dm->numTessFaceData) - orig_index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + if (mesh->totface) + orig_index = CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX); } if (orig_index) { @@ -1177,14 +1194,15 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti ctx->maxweight= maxweight; ctx->cfrom= cfrom; ctx->distr= distr; - ctx->dm= dm; + ctx->mesh= mesh; ctx->tpars= tpars; if (children) { - totpart= psys_render_simplify_distribution(ctx, totpart); alloc_child_particles(psys, totpart); } + BLI_rng_free(rng); + return 1; } @@ -1202,7 +1220,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) TaskPool *task_pool; ParticleThreadContext ctx; ParticleTask *tasks; - DerivedMesh *finaldm = sim->psmd->dm_final; + Mesh *final_mesh = sim->psmd->mesh_final; int i, totpart, numtasks; /* create a task pool for distribution tasks */ @@ -1227,10 +1245,10 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) BLI_task_pool_free(task_pool); - psys_calc_dmcache(sim->ob, finaldm, sim->psmd->dm_deformed, sim->psys); + psys_calc_dmcache(sim->ob, final_mesh, sim->psmd->mesh_original, sim->psys); - if (ctx.dm != finaldm) - ctx.dm->release(ctx.dm); + if (ctx.mesh != final_mesh) + BKE_id_free(NULL, ctx.mesh); psys_tasks_free(tasks, numtasks); @@ -1240,7 +1258,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from) /* ready for future use, to emit particles without geometry */ static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from)) { - distribute_invalid(sim->scene, sim->psys, 0); + distribute_invalid(sim, 0); fprintf(stderr,"Shape emission not yet possible!\n"); } @@ -1251,7 +1269,7 @@ void distribute_particles(ParticleSimulationData *sim, int from) int distr_error=0; if (psmd) { - if (psmd->dm_final) + if (psmd->mesh_final) distribute_particles_on_dm(sim, from); else distr_error=1; @@ -1260,250 +1278,8 @@ void distribute_particles(ParticleSimulationData *sim, int from) distribute_particles_on_shape(sim, from); if (distr_error) { - distribute_invalid(sim->scene, sim->psys, from); + distribute_invalid(sim, from); fprintf(stderr,"Particle distribution error!\n"); } } - -/* ======== Simplify ======== */ - -static float psys_render_viewport_falloff(double rate, float dist, float width) -{ - return pow(rate, dist / width); -} - -static float psys_render_projected_area(ParticleSystem *psys, const float center[3], float area, double vprate, float *viewport) -{ - ParticleRenderData *data = psys->renderdata; - float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius; - - /* transform to view space */ - copy_v3_v3(co, center); - co[3] = 1.0f; - mul_m4_v4(data->viewmat, co); - - /* compute two vectors orthogonal to view vector */ - normalize_v3_v3(view, co); - ortho_basis_v3v3_v3(ortho1, ortho2, view); - - /* compute on screen minification */ - w = co[2] * data->winmat[2][3] + data->winmat[3][3]; - dx = data->winx * ortho2[0] * data->winmat[0][0]; - dy = data->winy * ortho2[1] * data->winmat[1][1]; - w = sqrtf(dx * dx + dy * dy) / w; - - /* w squared because we are working with area */ - area = area * w * w; - - /* viewport of the screen test */ - - /* project point on screen */ - mul_m4_v4(data->winmat, co); - if (co[3] != 0.0f) { - co[0] = 0.5f * data->winx * (1.0f + co[0] / co[3]); - co[1] = 0.5f * data->winy * (1.0f + co[1] / co[3]); - } - - /* screen space radius */ - radius = sqrtf(area / (float)M_PI); - - /* make smaller using fallof once over screen edge */ - *viewport = 1.0f; - - if (co[0] + radius < 0.0f) - *viewport *= psys_render_viewport_falloff(vprate, -(co[0] + radius), data->winx); - else if (co[0] - radius > data->winx) - *viewport *= psys_render_viewport_falloff(vprate, (co[0] - radius) - data->winx, data->winx); - - if (co[1] + radius < 0.0f) - *viewport *= psys_render_viewport_falloff(vprate, -(co[1] + radius), data->winy); - else if (co[1] - radius > data->winy) - *viewport *= psys_render_viewport_falloff(vprate, (co[1] - radius) - data->winy, data->winy); - - return area; -} - -/* BMESH_TODO, for orig face data, we need to use MPoly */ -static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) -{ - DerivedMesh *dm = ctx->dm; - Mesh *me = (Mesh *)(ctx->sim.ob->data); - MFace *mf, *mface; - MVert *mvert; - ParticleRenderData *data; - ParticleRenderElem *elems, *elem; - ParticleSettings *part = ctx->sim.psys->part; - float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp; - float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport; - double vprate; - int *facetotvert; - int a, b, totorigface, totface, newtot, skipped; - - /* double lookup */ - const int *index_mf_to_mpoly; - const int *index_mp_to_orig; - - if (part->ren_as != PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) - return tot; - if (!ctx->sim.psys->renderdata) - return tot; - - data = ctx->sim.psys->renderdata; - if (data->timeoffset) - return 0; - if (!(part->simplify_flag & PART_SIMPLIFY_ENABLE)) - return tot; - - mvert = dm->getVertArray(dm); - mface = dm->getTessFaceArray(dm); - totface = dm->getNumTessFaces(dm); - totorigface = me->totpoly; - - if (totface == 0 || totorigface == 0) - return tot; - - index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); - index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); - if (index_mf_to_mpoly == NULL) { - index_mp_to_orig = NULL; - } - - facearea = MEM_callocN(sizeof(float) * totorigface, "SimplifyFaceArea"); - facecenter = MEM_callocN(sizeof(float[3]) * totorigface, "SimplifyFaceCenter"); - facetotvert = MEM_callocN(sizeof(int) * totorigface, "SimplifyFaceArea"); - elems = MEM_callocN(sizeof(ParticleRenderElem) * totorigface, "SimplifyFaceElem"); - - if (data->elems) - MEM_freeN(data->elems); - - data->do_simplify = true; - data->elems = elems; - data->index_mf_to_mpoly = index_mf_to_mpoly; - data->index_mp_to_orig = index_mp_to_orig; - - /* compute number of children per original face */ - for (a = 0; a < tot; a++) { - b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a]; - if (b != ORIGINDEX_NONE) { - elems[b].totchild++; - } - } - - /* compute areas and centers of original faces */ - for (mf = mface, a = 0; a < totface; a++, mf++) { - b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; - - if (b != ORIGINDEX_NONE) { - copy_v3_v3(co1, mvert[mf->v1].co); - copy_v3_v3(co2, mvert[mf->v2].co); - copy_v3_v3(co3, mvert[mf->v3].co); - - add_v3_v3(facecenter[b], co1); - add_v3_v3(facecenter[b], co2); - add_v3_v3(facecenter[b], co3); - - if (mf->v4) { - copy_v3_v3(co4, mvert[mf->v4].co); - add_v3_v3(facecenter[b], co4); - facearea[b] += area_quad_v3(co1, co2, co3, co4); - facetotvert[b] += 4; - } - else { - facearea[b] += area_tri_v3(co1, co2, co3); - facetotvert[b] += 3; - } - } - } - - for (a = 0; a < totorigface; a++) - if (facetotvert[a] > 0) - mul_v3_fl(facecenter[a], 1.0f / facetotvert[a]); - - /* for conversion from BU area / pixel area to reference screen size */ - BKE_mesh_texspace_get(me, 0, 0, size); - fac = ((size[0] + size[1] + size[2]) / 3.0f) / part->simplify_refsize; - fac = fac * fac; - - powrate = log(0.5f) / log(part->simplify_rate * 0.5f); - if (part->simplify_flag & PART_SIMPLIFY_VIEWPORT) - vprate = pow(1.0f - part->simplify_viewport, 5.0); - else - vprate = 1.0; - - /* set simplification parameters per original face */ - for (a = 0, elem = elems; a < totorigface; a++, elem++) { - area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport); - arearatio = fac * area / facearea[a]; - - if ((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) { - /* lambda is percentage of elements to keep */ - lambda = (arearatio < 1.0f) ? powf(arearatio, powrate) : 1.0f; - lambda *= viewport; - - lambda = MAX2(lambda, 1.0f / elem->totchild); - - /* compute transition region */ - t = part->simplify_transition; - elem->t = (lambda - t < 0.0f) ? lambda : (lambda + t > 1.0f) ? 1.0f - lambda : t; - elem->reduce = 1; - - /* scale at end and beginning of the transition region */ - elem->scalemax = (lambda + t < 1.0f) ? 1.0f / lambda : 1.0f / (1.0f - elem->t * elem->t / t); - elem->scalemin = (lambda + t < 1.0f) ? 0.0f : elem->scalemax * (1.0f - elem->t / t); - - elem->scalemin = sqrtf(elem->scalemin); - elem->scalemax = sqrtf(elem->scalemax); - - /* clamp scaling */ - scaleclamp = (float)min_ii(elem->totchild, 10); - elem->scalemin = MIN2(scaleclamp, elem->scalemin); - elem->scalemax = MIN2(scaleclamp, elem->scalemax); - - /* extend lambda to include transition */ - lambda = lambda + elem->t; - if (lambda > 1.0f) - lambda = 1.0f; - } - else { - lambda = arearatio; - - elem->scalemax = 1.0f; //sqrt(lambda); - elem->scalemin = 1.0f; //sqrt(lambda); - elem->reduce = 0; - } - - elem->lambda = lambda; - elem->scalemin = sqrtf(elem->scalemin); - elem->scalemax = sqrtf(elem->scalemax); - elem->curchild = 0; - } - - MEM_freeN(facearea); - MEM_freeN(facecenter); - MEM_freeN(facetotvert); - - /* move indices and set random number skipping */ - ctx->skip = MEM_callocN(sizeof(int) * tot, "SimplificationSkip"); - - skipped = 0; - for (a = 0, newtot = 0; a < tot; a++) { - b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a]; - - if (b != ORIGINDEX_NONE) { - if (elems[b].curchild++ < ceil(elems[b].lambda * elems[b].totchild)) { - ctx->index[newtot] = ctx->index[a]; - ctx->skip[newtot] = skipped; - skipped = 0; - newtot++; - } - else skipped++; - } - else skipped++; - } - - for (a = 0, elem = elems; a < totorigface; a++, elem++) - elem->curchild = 0; - - return newtot; -} diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index cc6e28b2a82..bcaebc9bf15 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -70,15 +70,16 @@ #include "BKE_animsys.h" #include "BKE_boids.h" -#include "BKE_cdderivedmesh.h" #include "BKE_collision.h" #include "BKE_colortools.h" #include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_main.h" #include "BKE_particle.h" -#include "BKE_DerivedMesh.h" +#include "BKE_collection.h" #include "BKE_object.h" #include "BKE_material.h" #include "BKE_cloth.h" @@ -88,12 +89,14 @@ #include "BKE_modifier.h" #include "BKE_scene.h" #include "BKE_bvhutils.h" -#include "BKE_depsgraph.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_physics.h" +#include "DEG_depsgraph_query.h" #include "PIL_time.h" #include "RE_shader_ext.h" -#include "DEG_depsgraph.h" /* fluid sim particle import */ #ifdef WITH_MOD_FLUID @@ -121,11 +124,11 @@ static int particles_are_dynamic(ParticleSystem *psys) return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID); } -float psys_get_current_display_percentage(ParticleSystem *psys) +float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params) { ParticleSettings *part=psys->part; - if ((psys->renderdata && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */ + if ((use_render_params && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */ (part->child_nbr && part->childtype) || /* display percentage applies to children */ (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */ { @@ -287,31 +290,31 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart) } } -int psys_get_child_number(Scene *scene, ParticleSystem *psys) +int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params) { int nbr; if (!psys->part->childtype) return 0; - if (psys->renderdata) + if (use_render_params) nbr= psys->part->ren_child_nbr; else nbr= psys->part->child_nbr; - return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL); + return get_render_child_particle_number(&scene->r, nbr, use_render_params); } -int psys_get_tot_child(Scene *scene, ParticleSystem *psys) +int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params) { - return psys->totpart*psys_get_child_number(scene, psys); + return psys->totpart*psys_get_child_number(scene, psys, use_render_params); } /************************************************/ /* Distribution */ /************************************************/ -void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deformed, ParticleSystem *psys) +void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, ParticleSystem *psys) { /* use for building derived mesh mapping info: * @@ -324,13 +327,13 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform PARTICLE_P; /* CACHE LOCATIONS */ - if (!dm_final->deformedOnly) { - /* Will use later to speed up subsurf/derivedmesh */ + if (!mesh_final->runtime.deformed_only) { + /* Will use later to speed up subsurf/evaluated mesh. */ LinkNode *node, *nodedmelem, **nodearray; int totdmelem, totelem, i, *origindex, *origindex_poly = NULL; if (psys->part->from == PART_FROM_VERT) { - totdmelem= dm_final->getNumVerts(dm_final); + totdmelem = mesh_final->totvert; if (use_modifier_stack) { totelem= totdmelem; @@ -338,11 +341,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform } else { totelem= me->totvert; - origindex= dm_final->getVertDataArray(dm_final, CD_ORIGINDEX); + origindex = CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX); } } else { /* FROM_FACE/FROM_VOLUME */ - totdmelem= dm_final->getNumTessFaces(dm_final); + totdmelem= mesh_final->totface; if (use_modifier_stack) { totelem= totdmelem; @@ -350,11 +353,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform origindex_poly= NULL; } else { - totelem = dm_deformed->getNumTessFaces(dm_deformed); - origindex = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX); + totelem = mesh_original->totface; + origindex = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX); /* for face lookups we need the poly origindex too */ - origindex_poly= dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX); + origindex_poly = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX); if (origindex_poly == NULL) { origindex= NULL; } @@ -414,7 +417,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform pa->num_dmcache = DMCACHE_NOTFOUND; } else { /* FROM_FACE/FROM_VOLUME */ - pa->num_dmcache = psys_particle_dm_face_lookup(dm_final, dm_deformed, pa->num, pa->fuv, nodearray); + pa->num_dmcache = psys_particle_dm_face_lookup(mesh_final, mesh_original, pa->num, pa->fuv, nodearray); } } } @@ -438,7 +441,7 @@ void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData { memset(ctx, 0, sizeof(ParticleThreadContext)); ctx->sim = *sim; - ctx->dm = ctx->sim.psmd->dm_final; + ctx->mesh = ctx->sim.psmd->mesh_final; ctx->ma = give_current_material(sim->ob, sim->psys->part->omat); } @@ -513,7 +516,6 @@ void psys_thread_context_free(ParticleThreadContext *ctx) if (ctx->jitoff) MEM_freeN(ctx->jitoff); if (ctx->weight) MEM_freeN(ctx->weight); if (ctx->index) MEM_freeN(ctx->index); - if (ctx->skip) MEM_freeN(ctx->skip); if (ctx->seams) MEM_freeN(ctx->seams); //if (ctx->vertpart) MEM_freeN(ctx->vertpart); BLI_kdtree_free(ctx->tree); @@ -704,9 +706,9 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic /* get birth location from object */ if (use_tangents) - psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0); + psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0); else - psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0); + psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0); /* get possible textural influence */ psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra); @@ -990,14 +992,14 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic } /* recursively evaluate emitter parent anim at cfra */ -static void evaluate_emitter_anim(Scene *scene, Object *ob, float cfra) +static void evaluate_emitter_anim(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra) { if (ob->parent) - evaluate_emitter_anim(scene, ob->parent, cfra); + evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra); /* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */ - BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM); - BKE_object_where_is_calc_time(scene, ob, cfra); + BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM); + BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra); } /* sets particle to the emitter surface with initial velocity & rotation */ @@ -1011,7 +1013,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime, /* get precise emitter matrix if particle is born */ if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) { - evaluate_emitter_anim(sim->scene, sim->ob, pa->time); + evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time); psys->flag |= PSYS_OB_ANIM_RESTORE; } @@ -1145,7 +1147,8 @@ static void set_keyed_keys(ParticleSimulationData *sim) int totpart = psys->totpart, k, totkeys = psys->totkeyed; int keyed_flag = 0; - ksim.scene= sim->scene; + ksim.depsgraph = sim->depsgraph; + ksim.scene = sim->scene; /* no proper targets so let's clear and bail out */ if (psys->totkeyed==0) { @@ -1305,9 +1308,10 @@ void psys_update_particle_tree(ParticleSystem *psys, float cfra) static void psys_update_effectors(ParticleSimulationData *sim) { - pdEndEffectors(&sim->psys->effectors); - sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys, - sim->psys->part->effector_weights, true); + BKE_effectors_free(sim->psys->effectors); + sim->psys->effectors = BKE_effectors_create(sim->depsgraph, + sim->ob, sim->psys, + sim->psys->part->effector_weights); precalc_guides(sim, sim->psys->effectors); } @@ -2059,11 +2063,12 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo ParticleSettings *part = sim->psys->part; ParticleData *pa = efdata->pa; EffectedPoint epoint; + RNG *rng = sim->rng; /* add effectors */ pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint); if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR) - pdDoEffectors(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse); + BKE_effectors_apply(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse); mul_v3_fl(force, efdata->ptex.field); mul_v3_fl(impulse, efdata->ptex.field); @@ -2074,9 +2079,9 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo /* brownian force */ if (part->brownfac != 0.0f) { - force[0] += (BLI_frand()-0.5f) * part->brownfac; - force[1] += (BLI_frand()-0.5f) * part->brownfac; - force[2] += (BLI_frand()-0.5f) * part->brownfac; + force[0] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac; + force[1] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac; + force[2] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac; } if (part->flag & PART_ROT_DYN && epoint.ave) @@ -2127,7 +2132,7 @@ static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, floa tkey.time=pa->state.time; if (part->type != PART_HAIR) { - if (do_guides(sim->psys->part, sim->psys->effectors, &tkey, p, time)) { + if (do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, &tkey, p, time)) { copy_v3_v3(pa->state.co,tkey.co); /* guides don't produce valid velocity */ sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co); @@ -2647,16 +2652,17 @@ static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRay return hit->index >= 0; } -static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation) +static int collision_response(ParticleSimulationData *sim, ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation) { ParticleCollisionElement *pce = &col->pce; PartDeflect *pd = col->hit->pd; + RNG *rng = sim->rng; float co[3]; /* point of collision */ float x = hit->dist/col->original_ray_length; /* location factor of collision between this iteration */ float f = col->f + x * (1.0f - col->f); /* time factor of collision between timestep */ float dt1 = (f - col->f) * col->total_time; /* time since previous collision (in seconds) */ float dt2 = (1.0f - f) * col->total_time; /* time left after collision (in seconds) */ - int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */ + int through = (BLI_rng_get_float(rng) < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */ /* calculate exact collision location */ interp_v3_v3v3(co, col->co1, col->co2, x); @@ -2681,8 +2687,8 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR float v0_tan[3];/* tangential component of v0 */ float vc_tan[3];/* tangential component of collision surface velocity */ float v0_dot, vc_dot; - float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_frand() - 0.5f); - float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_frand() - 0.5f); + float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_rng_get_float(rng) - 0.5f); + float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_rng_get_float(rng) - 0.5f); float distance, nor[3], dot; CLAMP(damp,0.0f, 1.0f); @@ -2892,7 +2898,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS) collision_fail(pa, &col); - else if (collision_response(pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0) + else if (collision_response(sim, pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0) return; } else @@ -2908,10 +2914,9 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; ParticleEditSettings *pset = &sim->scene->toolsettings->particle; - Base *base; int distr=0, alloc=0, skip=0; - if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) + if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) || psys->recalc&PSYS_RECALC_RESET) alloc=1; if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT))) @@ -2921,7 +2926,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons if (alloc) realloc_particles(sim, sim->psys->totpart); - if (psys_get_tot_child(sim->scene, psys)) { + if (psys_get_tot_child(sim->scene, psys, use_render_params)) { /* don't generate children while computing the hair keys */ if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { distribute_particles(sim, PART_FROM_CHILD); @@ -2938,12 +2943,13 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons skip = 1; /* only hair, keyed and baked stuff can have paths */ else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR))) skip = 1; /* particle visualization must be set as path */ - else if (!psys->renderdata) { + else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) { if (part->draw_as != PART_DRAW_REND) skip = 1; /* draw visualization */ else if (psys->pointcache->flag & PTCACHE_BAKING) skip = 1; /* no need to cache paths while baking dynamics */ - else if (psys_in_edit_mode(sim->scene, psys)) { + + else if (psys_in_edit_mode(sim->depsgraph, psys)) { if ((pset->flag & PE_DRAW_PART)==0) skip = 1; else if (part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0) @@ -2953,15 +2959,19 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons /* particle instance modifier with "path" option need cached paths even if particle system doesn't */ - for (base = sim->scene->base.first; base; base= base->next) { - ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance); - if (md) { - ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; - if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) { - skip = 0; - break; + if (skip) { + FOREACH_SCENE_OBJECT_BEGIN(sim->scene, ob) + { + ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance); + if (md) { + ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md; + if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) { + skip = 0; + break; + } } } + FOREACH_SCENE_OBJECT_END; } if (!skip) { @@ -3021,11 +3031,11 @@ static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight) return dvert; } -static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int totedge, DerivedMesh **r_dm, ClothHairData **r_hairdata) +static void hair_create_input_mesh(ParticleSimulationData *sim, int totpoint, int totedge, Mesh **r_mesh, ClothHairData **r_hairdata) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; - DerivedMesh *dm; + Mesh *mesh; ClothHairData *hairdata; MVert *mvert; MEdge *medge; @@ -3037,14 +3047,15 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int float max_length; float hair_radius; - dm = *r_dm; - if (!dm) { - *r_dm = dm = CDDM_new(totpoint, totedge, 0, 0, 0); - DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL); + mesh = *r_mesh; + if (!mesh) { + *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0); + CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert); + BKE_mesh_update_customdata_pointers(mesh, false); } - mvert = CDDM_get_verts(dm); - medge = CDDM_get_edges(dm); - dvert = DM_get_vert_data_layer(dm, CD_MDEFORMVERT); + mvert = mesh->mvert; + medge = mesh->medge; + dvert = mesh->dvert; hairdata = *r_hairdata; if (!hairdata) { @@ -3079,7 +3090,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int pa->hair_index = hair_index; use_hair = psys_hair_use_simulation(pa, max_length); - psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat); + psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat); mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat); normalize_m4(root_mat); @@ -3159,8 +3170,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim) if (!psys->clmd) { psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth); psys->clmd->sim_parms->goalspring = 0.0f; - psys->clmd->sim_parms->vel_damping = 1.0f; - psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL|CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS; + psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS; psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF; } @@ -3176,26 +3186,26 @@ static void do_hair_dynamics(ParticleSimulationData *sim) } realloc_roots = false; /* whether hair root info array has to be reallocated */ - if (psys->hair_in_dm) { - DerivedMesh *dm = psys->hair_in_dm; - if (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm)) { - dm->release(dm); - psys->hair_in_dm = NULL; + if (psys->hair_in_mesh) { + Mesh *mesh = psys->hair_in_mesh; + if (totpoint != mesh->totvert || totedge != mesh->totedge) { + BKE_id_free(NULL, mesh); + psys->hair_in_mesh = NULL; realloc_roots = true; } } - if (!psys->hair_in_dm || !psys->clmd->hairdata || realloc_roots) { + if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) { if (psys->clmd->hairdata) { MEM_freeN(psys->clmd->hairdata); psys->clmd->hairdata = NULL; } } - hair_create_input_dm(sim, totpoint, totedge, &psys->hair_in_dm, &psys->clmd->hairdata); + hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata); - if (psys->hair_out_dm) - psys->hair_out_dm->release(psys->hair_out_dm); + if (psys->hair_out_mesh) + BKE_id_free(NULL, psys->hair_out_mesh); psys->clmd->point_cache = psys->pointcache; /* for hair sim we replace the internal cloth effector weights temporarily @@ -3204,13 +3214,16 @@ static void do_hair_dynamics(ParticleSimulationData *sim) clmd_effweights = psys->clmd->sim_parms->effector_weights; psys->clmd->sim_parms->effector_weights = psys->part->effector_weights; - deformedVerts = MEM_mallocN(sizeof(*deformedVerts) * psys->hair_in_dm->getNumVerts(psys->hair_in_dm), "do_hair_dynamics vertexCos"); - psys->hair_out_dm = CDDM_copy(psys->hair_in_dm); - psys->hair_out_dm->getVertCos(psys->hair_out_dm, deformedVerts); - - clothModifier_do(psys->clmd, sim->scene, sim->ob, psys->hair_in_dm, deformedVerts); - - CDDM_apply_vert_coords(psys->hair_out_dm, deformedVerts); + BKE_id_copy_ex( + NULL, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh, + LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_DEG_TAG | + LIB_ID_COPY_NO_PREVIEW, + false); + deformedVerts = BKE_mesh_vertexCos_get(psys->hair_out_mesh, NULL); + clothModifier_do(psys->clmd, sim->depsgraph, sim->scene, sim->ob, psys->hair_in_mesh, deformedVerts); + BKE_mesh_apply_vert_coords(psys->hair_out_mesh, deformedVerts); MEM_freeN(deformedVerts); @@ -3222,7 +3235,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; PARTICLE_P; - float disp = psys_get_current_display_percentage(psys); + float disp = psys_get_current_display_percentage(psys, use_render_params); LOOP_PARTICLES { pa->size = part->size; @@ -3237,7 +3250,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re if (psys->recalc & PSYS_RECALC_RESET) { /* need this for changing subsurf levels */ - psys_calc_dmcache(sim->ob, sim->psmd->dm_final, sim->psmd->dm_deformed, psys); + psys_calc_dmcache(sim->ob, sim->psmd->mesh_final, sim->psmd->mesh_original, psys); if (psys->clmd) cloth_free_modifier(psys->clmd); @@ -3284,7 +3297,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) if (pa->totkey) { sub_v3_v3(key->co, root->co); - psys_vec_rot_to_face(sim->psmd->dm_final, pa, key->co); + psys_vec_rot_to_face(sim->psmd->mesh_final, pa, key->co); } key->time = pa->state.time; @@ -3494,7 +3507,6 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) { ParticleSystem *psys = sim->psys; ParticleSettings *part=psys->part; - RNG *rng; BoidBrainData bbd; ParticleTexture ptex; PARTICLE_P; @@ -3521,14 +3533,13 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) return; } - BLI_srandom(31415926 + (int)cfra + psys->seed); /* for now do both, boids us 'rng' */ - rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed); + sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed); psys_update_effectors(sim); if (part->type != PART_HAIR) - sim->colliders = get_collider_cache(sim->scene, sim->ob, part->collision_group); + sim->colliders = BKE_collider_cache_create(sim->depsgraph, sim->ob, part->collision_group); /* initialize physics type specific stuff */ switch (part->phystype) { @@ -3540,7 +3551,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) bbd.cfra = cfra; bbd.dfra = dfra; bbd.timestep = timestep; - bbd.rng = rng; + bbd.rng = sim->rng; psys_update_particle_tree(psys, cfra); @@ -3735,16 +3746,18 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) pa->state.time=cfra; } - free_collider_cache(&sim->colliders); - BLI_rng_free(rng); + BKE_collider_cache_free(&sim->colliders); + BLI_rng_free(sim->rng); + sim->rng = NULL; } -static void update_children(ParticleSimulationData *sim) + +static void update_children(ParticleSimulationData *sim, const bool use_render_params) { if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0) /* don't generate children while growing hair - waste of time */ psys_free_children(sim->psys); else if (sim->psys->part->childtype) { - if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys)) + if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params)) distribute_particles(sim, PART_FROM_CHILD); else { /* Children are up to date, nothing to do. */ @@ -3754,7 +3767,7 @@ static void update_children(ParticleSimulationData *sim) psys_free_children(sim->psys); } /* updates cached particles' alive & other flags etc..*/ -static void cached_step(ParticleSimulationData *sim, float cfra) +static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -3764,7 +3777,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra) psys_update_effectors(sim); - disp= psys_get_current_display_percentage(psys); + disp= psys_get_current_display_percentage(psys, use_render_params); LOOP_PARTICLES { psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra); @@ -3800,7 +3813,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra) } static void particles_fluid_step( - Main *bmain, ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params) + ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params) { ParticleSystem *psys = sim->psys; if (psys->particles) { @@ -3831,7 +3844,7 @@ static void particles_fluid_step( // ok, start loading BLI_join_dirfile(filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME); - BLI_path_abs(filename, modifier_path_relbase(bmain, sim->ob)); + BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob)); BLI_path_frame(filename, curFrame, 0); // fixed #frame-no @@ -3905,7 +3918,7 @@ static void particles_fluid_step( } // fluid sim particles done } #else - UNUSED_VARS(bmain, use_render_params); + UNUSED_VARS(use_render_params); #endif // WITH_MOD_FLUID } @@ -3987,8 +4000,8 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ int cache_result = BKE_ptcache_read(pid, cache_cfra, true); if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) { - cached_step(sim, cfra); - update_children(sim); + cached_step(sim, cfra, use_render_params); + update_children(sim, use_render_params); psys_update_path_cache(sim, cfra, use_render_params); BKE_ptcache_validate(cache, (int)cache_cfra); @@ -4005,7 +4018,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ } else if (cache_result == PTCACHE_READ_OLD) { psys->cfra = (float)cache->simframe; - cached_step(sim, psys->cfra); + cached_step(sim, psys->cfra, use_render_params); } /* if on second frame, write cache for first frame */ @@ -4017,7 +4030,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ /* 3. do dynamics */ /* set particles to be not calculated TODO: can't work with pointcache */ - disp= psys_get_current_display_percentage(psys); + disp= psys_get_current_display_percentage(psys, use_render_params); LOOP_PARTICLES { if (psys_frand(psys, p) > disp) @@ -4055,9 +4068,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ sim->courant_num = 0.0f; dynamics_step(sim, cfra+dframe+t_frac - 1.f); psys->cfra = cfra+dframe+t_frac - 1.f; -#if 0 - printf("%f,%f,%f,%f\n", cfra+dframe+t_frac - 1.f, t_frac, dt_frac, sim->courant_num); -#endif + if (part->time_flag & PART_TIME_AUTOSF) update_timestep(psys, sim); /* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */ @@ -4073,7 +4084,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ BKE_ptcache_write(pid, (int)cache_cfra); } - update_children(sim); + update_children(sim, use_render_params); /* cleanup */ if (psys->lattice_deform_data) { @@ -4199,11 +4210,13 @@ static int hair_needs_recalc(ParticleSystem *psys) /* main particle update call, checks that things are ok on the large scale and * then advances in to actual particle calculations depending on particle type */ -void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params) +void particle_system_update(struct Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params) { ParticleSimulationData sim= {0}; ParticleSettings *part = psys->part; + ParticleSystem *psys_orig = psys_orig_get(psys); float cfra; + ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); /* drawdata is outdated after ANY change */ if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; @@ -4211,12 +4224,13 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste if (!psys_check_enabled(ob, psys, use_render_params)) return; - cfra= BKE_scene_frame_get(scene); + cfra = DEG_get_ctime(depsgraph); - sim.scene= scene; - sim.ob= ob; - sim.psys= psys; - sim.psmd= psys_get_modifier(ob, psys); + sim.depsgraph = depsgraph; + sim.scene = scene; + sim.ob = ob; + sim.psys = psys; + sim.psmd = psmd; /* system was already updated from modifier stack */ if (sim.psmd->flag & eParticleSystemFlag_psys_updated) { @@ -4226,22 +4240,19 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste return; } - if (!sim.psmd->dm_final) + if (!sim.psmd->mesh_final) return; if (part->from != PART_FROM_VERT) { - DM_ensure_tessface(sim.psmd->dm_final); + BKE_mesh_tessface_ensure(sim.psmd->mesh_final); } /* execute drivers only, as animation has already been done */ - BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS); /* to verify if we need to restore object afterwards */ psys->flag &= ~PSYS_OB_ANIM_RESTORE; - if (psys->recalc & PSYS_RECALC_TYPE) - psys_changed_type(sim.ob, sim.psys); - if (psys->recalc & PSYS_RECALC_RESET) psys->totunexist = 0; @@ -4264,10 +4275,10 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste free_hair(ob, psys, 0); - if (psys->edit && psys->free_edit) { - psys->free_edit(psys->edit); - psys->edit = NULL; - psys->free_edit = NULL; + if (psys_orig->edit && psys_orig->free_edit) { + psys_orig->free_edit(psys_orig->edit); + psys_orig->edit = NULL; + psys_orig->free_edit = NULL; } /* first step is negative so particles get killed and reset */ @@ -4276,7 +4287,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste for (i=0; i<=part->hair_step; i++) { hcfra=100.0f*(float)i/(float)psys->part->hair_step; if ((part->flag & PART_HAIR_REGROW)==0) - BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM); system_step(&sim, hcfra, use_render_params); psys->cfra = hcfra; psys->recalc = 0; @@ -4295,7 +4306,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste } case PART_FLUID: { - particles_fluid_step(bmain, &sim, (int)cfra, use_render_params); + particles_fluid_step(&sim, (int)cfra, use_render_params); break; } default: @@ -4305,7 +4316,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste case PART_PHYS_KEYED: { PARTICLE_P; - float disp = psys_get_current_display_percentage(psys); + float disp = psys_get_current_display_percentage(psys, use_render_params); bool free_unexisting = false; /* Particles without dynamics haven't been reset yet because they don't use pointcache */ @@ -4359,16 +4370,33 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste /* make sure emitter is left at correct time (particle emission can change this) */ if (psys->flag & PSYS_OB_ANIM_RESTORE) { - evaluate_emitter_anim(scene, ob, cfra); + evaluate_emitter_anim(depsgraph, scene, ob, cfra); psys->flag &= ~PSYS_OB_ANIM_RESTORE; } + if (psys_orig->edit) { + psys_orig->edit->flags |= PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL; + } + + if (DEG_is_active(depsgraph)) { + if (psys_orig != psys) { + if (psys_orig->edit != NULL && + psys_orig->edit->psys == psys_orig) + { + psys_orig->edit->psys_eval = psys; + psys_orig->edit->psmd_eval = psmd; + } + psys_orig->flag = (psys->flag & ~PSYS_SHARED_CACHES); + } + } + psys->cfra = cfra; psys->recalc = 0; /* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */ - if (psys->renderdata==0) - invert_m4_m4(psys->imat, ob->obmat); + invert_m4_m4(psys->imat, ob->obmat); + + BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); } /* ID looper */ @@ -4399,10 +4427,16 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, /* **** Depsgraph evaluation **** */ -void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx), +void BKE_particle_system_eval_init(struct Depsgraph *depsgraph, Scene *scene, Object *ob) { - DEG_debug_print_eval(__func__, ob->id.name, ob); + DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); + for (ParticleSystem *psys = ob->particlesystem.first; + psys != NULL; + psys = psys->next) + { + psys->recalc |= (psys->part->id.recalc & DEG_TAG_PSYS_ALL); + } BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH); } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 746e8b63a18..413f0407c86 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -41,6 +41,7 @@ #include "BKE_paint.h" #include "GPU_buffers.h" +#include "GPU_immediate.h" #include "bmesh.h" @@ -636,7 +637,6 @@ void BKE_pbvh_free(PBVH *bvh) BLI_gset_free(node->bm_other_verts, NULL); } } - GPU_pbvh_multires_buffers_free(&bvh->grid_common_gpu_buffer); if (bvh->deformed) { if (bvh->verts) { @@ -1101,7 +1101,6 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) static int pbvh_get_buffers_update_flags(PBVH *bvh) { int update_flags = 0; - update_flags |= bvh->show_diffuse_color ? GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR : 0; update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0; return update_flags; } @@ -1117,19 +1116,21 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) switch (bvh->type) { case PBVH_GRIDS: node->draw_buffers = - GPU_pbvh_grid_buffers_build(node->prim_indices, - node->totprim, - bvh->grid_hidden, - bvh->gridkey.grid_size, - &bvh->gridkey, &bvh->grid_common_gpu_buffer); + GPU_pbvh_grid_buffers_build( + node->prim_indices, + node->totprim, + bvh->grid_hidden, + bvh->gridkey.grid_size, + &bvh->gridkey); break; case PBVH_FACES: node->draw_buffers = - GPU_pbvh_mesh_buffers_build(node->face_vert_indices, - bvh->mpoly, bvh->mloop, bvh->looptri, - bvh->verts, - node->prim_indices, - node->totprim); + GPU_pbvh_mesh_buffers_build( + node->face_vert_indices, + bvh->mpoly, bvh->mloop, bvh->looptri, + bvh->verts, + node->prim_indices, + node->totprim); break; case PBVH_BMESH: node->draw_buffers = @@ -1180,19 +1181,6 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) } } -void BKE_pbvh_draw_BB(PBVH *bvh) -{ - GPU_pbvh_BB_draw_init(); - - for (int a = 0; a < bvh->totnode; a++) { - PBVHNode *node = &bvh->nodes[a]; - - GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0)); - } - - GPU_pbvh_BB_draw_end(); -} - static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) { int update = 0; @@ -1353,6 +1341,12 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) *key = bvh->gridkey; } +struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids) +{ + BLI_assert(bvh->type == PBVH_GRIDS); + *num_grids = bvh->totgrid; + return bvh->grids; +} BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) { @@ -1996,42 +1990,6 @@ bool BKE_pbvh_node_find_nearest_to_ray( return hit; } -typedef struct { - DMSetMaterial setMaterial; - bool wireframe; - bool fast; -} PBVHNodeDrawData; - -void BKE_pbvh_node_draw(PBVHNode *node, void *data_v) -{ - PBVHNodeDrawData *data = data_v; - -#if 0 - /* XXX: Just some quick code to show leaf nodes in different colors */ - float col[3]; - float spec[3] = {0.0f, 0.0f, 0.0f}; - - if (0) { //is_partial) { - col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6; - } - else { - srand((long long)node); - for (int i = 0; i < 3; ++i) - col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7; - } - - GPU_basic_shader_colors(col, spec, 0, 1.0f); - glColor3f(1, 0, 0); -#endif - - if (!(node->flag & PBVH_FullyHidden)) { - GPU_pbvh_buffers_draw(node->draw_buffers, - data->setMaterial, - data->wireframe, - data->fast); - } -} - typedef enum { ISECT_INSIDE, ISECT_OUTSIDE, @@ -2091,37 +2049,44 @@ bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } -static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node) -{ - if (!node->draw_buffers) - return; - - if (GPU_pbvh_buffers_diffuse_changed(node->draw_buffers, node->bm_faces, bvh->show_diffuse_color)) - node->flag |= PBVH_UpdateDrawBuffers; -} +struct PBVHNodeDrawCallbackData { + void (*draw_fn)(void *user_data, GPUBatch *batch); + void *user_data; + bool fast; + bool only_mask; /* Only draw nodes that have mask data. */ +}; -static void pbvh_node_check_mask_changed(PBVH *bvh, PBVHNode *node) +static void pbvh_node_draw_cb(PBVHNode *node, void *data_v) { - if (!node->draw_buffers) { - return; - } - if (GPU_pbvh_buffers_mask_changed(node->draw_buffers, bvh->show_mask)) { - node->flag |= PBVH_UpdateDrawBuffers; + struct PBVHNodeDrawCallbackData *data = data_v; + + if (!(node->flag & PBVH_FullyHidden)) { + GPUBatch *triangles = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast); + bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers); + if (!data->only_mask || show_mask) { + if (triangles != NULL) { + data->draw_fn(data->user_data, triangles); + } + } } } -void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], - DMSetMaterial setMaterial, bool wireframe, bool fast) -{ - PBVHNodeDrawData draw_data = {setMaterial, wireframe, fast}; +/** + * Version of #BKE_pbvh_draw that runs a callback. + */ +void BKE_pbvh_draw_cb( + PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, bool only_mask, + void (*draw_fn)(void *user_data, GPUBatch *batch), void *user_data) +{ + struct PBVHNodeDrawCallbackData draw_data = { + .only_mask = only_mask, + .fast = fast, + .draw_fn = draw_fn, + .user_data = user_data, + }; PBVHNode **nodes; int totnode; - for (int a = 0; a < bvh->totnode; a++) { - pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); - pbvh_node_check_mask_changed(bvh, &bvh->nodes[a]); - } - BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), &nodes, &totnode); @@ -2131,15 +2096,19 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], if (nodes) MEM_freeN(nodes); if (planes) { - BKE_pbvh_search_callback(bvh, BKE_pbvh_node_planes_contain_AABB, - planes, BKE_pbvh_node_draw, &draw_data); + BKE_pbvh_search_callback( + bvh, BKE_pbvh_node_planes_contain_AABB, + planes, pbvh_node_draw_cb, &draw_data); } else { - BKE_pbvh_search_callback(bvh, NULL, NULL, BKE_pbvh_node_draw, &draw_data); + BKE_pbvh_search_callback( + bvh, NULL, + NULL, pbvh_node_draw_cb, &draw_data); } - +#if 0 if (G.debug_value == 14) - BKE_pbvh_draw_BB(bvh); + pbvh_draw_BB(bvh); +#endif } void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, @@ -2195,8 +2164,13 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3] return vertCos; } -void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) +void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3], const int totvert) { + if (totvert != pbvh->totvert) { + BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!"); + return; + } + if (!pbvh->deformed) { if (pbvh->verts) { /* if pbvh is not already deformed, verts/faces points to the */ @@ -2351,24 +2325,24 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK); } -void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color) +bool pbvh_has_mask(PBVH *bvh) { - bool has_mask = false; - switch (bvh->type) { case PBVH_GRIDS: - has_mask = (bvh->gridkey.has_mask != 0); - break; + return (bvh->gridkey.has_mask != 0); case PBVH_FACES: - has_mask = (bvh->vdata && CustomData_get_layer(bvh->vdata, - CD_PAINT_MASK)); - break; + return (bvh->vdata && CustomData_get_layer(bvh->vdata, + CD_PAINT_MASK)); case PBVH_BMESH: - has_mask = (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1)); - break; + return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1)); } - bvh->show_diffuse_color = !has_mask || show_diffuse_color; + return false; +} + +void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color) +{ + bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color; } void pbvh_show_mask_set(PBVH *bvh, bool show_mask) diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index e32a5d0681e..3369b05ea60 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -27,7 +27,7 @@ #include "BLI_utildefines.h" #include "BLI_buffer.h" #include "BLI_ghash.h" -#include "BLI_heap.h" +#include "BLI_heap_simple.h" #include "BLI_math.h" #include "BLI_memarena.h" @@ -721,7 +721,7 @@ static void pbvh_bmesh_node_drop_orig(PBVHNode *node) struct EdgeQueue; typedef struct EdgeQueue { - Heap *heap; + HeapSimple *heap; const float *center; float center_proj[3]; /* for when we use projected coords. */ float radius_squared; @@ -840,7 +840,7 @@ static void edge_queue_insert( BMVert **pair = BLI_mempool_alloc(eq_ctx->pool); pair[0] = e->v1; pair[1] = e->v2; - BLI_heap_insert(eq_ctx->q->heap, priority, pair); + BLI_heapsimple_insert(eq_ctx->q->heap, priority, pair); #ifdef USE_EDGEQUEUE_TAG BLI_assert(EDGE_QUEUE_TEST(e) == false); EDGE_QUEUE_ENABLE(e); @@ -1008,7 +1008,7 @@ static void long_edge_queue_create( PBVH *bvh, const float center[3], const float view_normal[3], float radius, const bool use_frontface, const bool use_projected) { - eq_ctx->q->heap = BLI_heap_new(); + eq_ctx->q->heap = BLI_heapsimple_new(); eq_ctx->q->center = center; eq_ctx->q->radius_squared = radius * radius; eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len; @@ -1070,7 +1070,7 @@ static void short_edge_queue_create( PBVH *bvh, const float center[3], const float view_normal[3], float radius, const bool use_frontface, const bool use_projected) { - eq_ctx->q->heap = BLI_heap_new(); + eq_ctx->q->heap = BLI_heapsimple_new(); eq_ctx->q->center = center; eq_ctx->q->radius_squared = radius * radius; eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; @@ -1237,8 +1237,8 @@ static bool pbvh_bmesh_subdivide_long_edges( { bool any_subdivided = false; - while (!BLI_heap_is_empty(eq_ctx->q->heap)) { - BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap); + while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) { + BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap); BMVert *v1 = pair[0], *v2 = pair[1]; BMEdge *e; @@ -1454,8 +1454,8 @@ static bool pbvh_bmesh_collapse_short_edges( /* deleted verts point to vertices they were merged into, or NULL when removed. */ GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts"); - while (!BLI_heap_is_empty(eq_ctx->q->heap)) { - BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap); + while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) { + BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap); BMVert *v1 = pair[0], *v2 = pair[1]; BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; @@ -1961,7 +1961,7 @@ bool BKE_pbvh_bmesh_update_topology( short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected); modified |= pbvh_bmesh_collapse_short_edges( &eq_ctx, bvh, &deleted_faces); - BLI_heap_free(q.heap, NULL); + BLI_heapsimple_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } @@ -1976,7 +1976,7 @@ bool BKE_pbvh_bmesh_update_topology( long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected); modified |= pbvh_bmesh_subdivide_long_edges( &eq_ctx, bvh, &edge_loops); - BLI_heap_free(q.heap, NULL); + BLI_heapsimple_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 4aef97bda47..ea8bd1933cd 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -144,11 +144,6 @@ struct PBVH { const DMFlagMat *grid_flag_mats; int totgrid; BLI_bitmap **grid_hidden; - /* index_buf of GPU_PBVH_Buffers can be the same for all 'fully drawn' nodes (same size). - * Previously was stored in a static var in gpu_buffer.c, but this breaks in case we handle several different - * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer - * in an opaque pointer per pbvh. See T47637. */ - struct GridCommonGPUBuffer *grid_common_gpu_buffer; /* Only used during BVH build and update, * don't need to remain valid after */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index f611e7a94cd..99451a7b6c1 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -37,6 +37,7 @@ #include "MEM_guardedalloc.h" #include "DNA_ID.h" +#include "DNA_collection_types.h" #include "DNA_dynamicpaint_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -59,8 +60,10 @@ #include "BKE_appdir.h" #include "BKE_anim.h" #include "BKE_cloth.h" +#include "BKE_collection.h" #include "BKE_dynamicpaint.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -72,6 +75,8 @@ #include "BIK_api.h" +#include "DEG_depsgraph.h" + #ifdef WITH_BULLET # include "RBI_api.h" #endif @@ -1291,8 +1296,8 @@ static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUS 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); + RB_body_get_position(rbo->shared->physics_object, rbo->pos); + RB_body_get_orientation(rbo->shared->physics_object, rbo->orn); #endif PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos); PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn); @@ -1385,9 +1390,9 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->ob= ob; pid->calldata= sb; pid->type= PTCACHE_TYPE_SOFTBODY; - pid->cache= sb->pointcache; - pid->cache_ptr= &sb->pointcache; - pid->ptcaches= &sb->ptcaches; + pid->cache= sb->shared->pointcache; + pid->cache_ptr= &sb->shared->pointcache; + pid->ptcaches= &sb->shared->ptcaches; pid->totpoint= pid->totwrite= ptcache_softbody_totpoint; pid->error = ptcache_softbody_error; @@ -1615,9 +1620,9 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r 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->cache= rbw->shared->pointcache; + pid->cache_ptr= &rbw->shared->pointcache; + pid->ptcaches= &rbw->shared->ptcaches; pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint; pid->error = ptcache_rigidbody_error; @@ -1648,7 +1653,26 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->file_type = PTCACHE_FILE_PTCACHE; } -void BKE_ptcache_ids_from_object(Main *bmain, ListBase *lb, Object *ob, Scene *scene, int duplis) +PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache) +{ + PTCacheID result = {0}; + + ListBase pidlist; + BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR); + + for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) { + if (pid->cache == cache) { + result = *pid; + break; + } + } + + BLI_freelistN(&pidlist); + + return result; +} + +void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis) { PTCacheID *pid; ParticleSystem *psys; @@ -1716,23 +1740,19 @@ void BKE_ptcache_ids_from_object(Main *bmain, ListBase *lb, Object *ob, Scene *s BLI_addtail(lb, pid); } - if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) { - ListBase *lb_dupli_ob; - /* don't update the dupli groups, we only want their pid's */ - if ((lb_dupli_ob = object_duplilist_ex(bmain, bmain->eval_ctx, scene, ob, false))) { - DupliObject *dob; - for (dob= lb_dupli_ob->first; dob; dob= dob->next) { - if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */ - ListBase lb_dupli_pid; - BKE_ptcache_ids_from_object(bmain, &lb_dupli_pid, dob->ob, scene, duplis); - BLI_movelisttolist(lb, &lb_dupli_pid); - if (lb_dupli_pid.first) - printf("Adding Dupli\n"); - } + /* Consider all object in dupli groups to be part of the same object, + * for baking with linking dupligroups. Once we have better overrides + * this can be revisited so users select the local objects directly. */ + if (scene && (duplis-- > 0) && (ob->dup_group)) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->dup_group, object) + { + if (object != ob) { + ListBase lb_dupli_pid; + BKE_ptcache_ids_from_object(&lb_dupli_pid, object, scene, duplis); + BLI_movelisttolist(lb, &lb_dupli_pid); } - - free_object_duplilist(lb_dupli_ob); /* does restore */ } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } @@ -3151,19 +3171,6 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra if (startframe && endframe) { *startframe= cache->startframe; *endframe= cache->endframe; - - /* TODO: time handling with object offsets and simulated vs. cached - * particles isn't particularly easy, so for now what you see is what - * you get. In the future point cache could handle the whole particle - * system timing. */ -#if 0 - if ((ob->partype & PARSLOW)==0) { - offset= ob->sf; - - *startframe += (int)(offset+0.5f); - *endframe += (int)(offset+0.5f); - } -#endif } /* verify cached_frames array is up to date */ @@ -3269,12 +3276,6 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode) sbFreeSimulation(pid->calldata); else if (pid->type == PTCACHE_TYPE_PARTICLES) psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH); -#if 0 - else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN) - smokeModifier_reset(pid->calldata); - else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES) - smokeModifier_reset_turbulence(pid->calldata); -#endif else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT) dynamicPaint_clearSurface(scene, (DynamicPaintSurface*)pid->calldata); } @@ -3356,6 +3357,7 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) if (ob->type == OB_ARMATURE) BIK_clear_cache(ob->pose); + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); return reset; } @@ -3510,13 +3512,14 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcach * every user action changing stuff, and then it runs a complete bake??? (ton) */ /* Baking */ -void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene) +void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer) { PTCacheBaker baker; memset(&baker, 0, sizeof(baker)); baker.bmain = bmain; baker.scene = scene; + baker.view_layer = view_layer; baker.bake = 0; baker.render = 0; baker.anim_init = 0; @@ -3542,6 +3545,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker) { Main *bmain = baker->bmain; Scene *scene = baker->scene; + ViewLayer *view_layer = baker->view_layer; + struct Depsgraph *depsgraph = baker->depsgraph; Scene *sce_iter; /* SETLOOPER macro only */ Base *base; ListBase pidlist; @@ -3571,7 +3576,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) /* get all pids from the object and search for smoke low res */ ListBase pidlist2; PTCacheID *pid2; - BKE_ptcache_ids_from_object(bmain, &pidlist2, pid->ob, scene, MAX_DUPLI_RECUR); + BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR); for (pid2=pidlist2.first; pid2; pid2=pid2->next) { if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) { if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) { @@ -3604,9 +3609,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker) } } else { - for (SETLOOPER(scene, sce_iter, base)) { + for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) { /* cache/bake everything in the scene */ - BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR); + BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR); for (pid=pidlist.first; pid; pid=pid->next) { cache = pid->cache; @@ -3660,7 +3665,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) stime = ptime = PIL_check_seconds_timer(); for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) { - BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); if (baker->update_progress) { float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe)); @@ -3715,8 +3720,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker) } } else { - for (SETLOOPER(scene, sce_iter, base)) { - BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR); + for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) { + BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR); for (pid=pidlist.first; pid; pid=pid->next) { /* skip hair particles */ @@ -3746,7 +3751,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) CFRA = cfrao; if (bake) { /* already on cfra unless baking */ - BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); } /* TODO: call redraw all windows somehow */ diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c deleted file mode 100644 index cb297744ab8..00000000000 --- a/source/blender/blenkernel/intern/property.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): ton roosendaal - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/property.c - * \ingroup bke - * - * This module deals with bProperty only, - * they are used on blender objects in the game engine - * (where they get converted into C++ classes - CValue and subclasses) - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <ctype.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_property_types.h" -#include "DNA_object_types.h" - -#include "BLI_blenlib.h" - -#include "BKE_property.h" - -void BKE_bproperty_free(bProperty *prop) -{ - - if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin); - MEM_freeN(prop); - -} - -void BKE_bproperty_free_list(ListBase *lb) -{ - bProperty *prop; - - while ((prop = BLI_pophead(lb))) { - BKE_bproperty_free(prop); - } -} - -bProperty *BKE_bproperty_copy(const bProperty *prop) -{ - bProperty *propn; - - propn = MEM_dupallocN(prop); - if (prop->poin && prop->poin != &prop->data) { - propn->poin = MEM_dupallocN(prop->poin); - } - else { - propn->poin = &propn->data; - } - - return propn; -} - -void BKE_bproperty_copy_list(ListBase *lbn, const ListBase *lbo) -{ - bProperty *prop, *propn; - BKE_bproperty_free_list(lbn); /* in case we are copying to an object with props */ - prop = lbo->first; - while (prop) { - propn = BKE_bproperty_copy(prop); - BLI_addtail(lbn, propn); - prop = prop->next; - } - - -} - -void BKE_bproperty_init(bProperty *prop) -{ - /* also use when property changes type */ - - if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin); - prop->poin = NULL; - - prop->data = 0; - - switch (prop->type) { - case GPROP_BOOL: - case GPROP_INT: - case GPROP_FLOAT: - case GPROP_TIME: - prop->poin = &prop->data; - break; - case GPROP_STRING: - prop->poin = MEM_callocN(MAX_PROPSTRING, "property string"); - break; - } -} - - -bProperty *BKE_bproperty_new(int type) -{ - bProperty *prop; - - prop = MEM_callocN(sizeof(bProperty), "property"); - prop->type = type; - - BKE_bproperty_init(prop); - - strcpy(prop->name, "prop"); - - return prop; -} - - -bProperty *BKE_bproperty_object_get(Object *ob, const char *name) -{ - return BLI_findstring(&ob->prop, name, offsetof(bProperty, name)); -} - -void BKE_bproperty_object_set(Object *ob, bProperty *propc) -{ - bProperty *prop; - prop = BKE_bproperty_object_get(ob, propc->name); - if (prop) { - BLI_remlink(&ob->prop, prop); - BKE_bproperty_free(prop); - } - BLI_addtail(&ob->prop, BKE_bproperty_copy(propc)); -} - -/* negative: prop is smaller - * positive: prop is larger - */ -#if 0 /* UNUSED */ -int BKE_bproperty_cmp(bProperty *prop, const char *str) -{ -// extern int Gdfra; /* sector.c */ - float fvalue, ftest; - - switch (prop->type) { - case GPROP_BOOL: - if (BLI_strcasecmp(str, "true") == 0) { - if (prop->data == 1) return 0; - else return 1; - } - else if (BLI_strcasecmp(str, "false") == 0) { - if (prop->data == 0) return 0; - else return 1; - } - /* no break, do GPROP_int too! */ - - case GPROP_INT: - return prop->data - atoi(str); - - case GPROP_FLOAT: - case GPROP_TIME: - /* WARNING: untested for GPROP_TIME - * function isn't used currently */ - fvalue = *((float *)&prop->data); - ftest = (float)atof(str); - if (fvalue > ftest) return 1; - else if (fvalue < ftest) return -1; - return 0; - - case GPROP_STRING: - return strcmp(prop->poin, str); - } - - return 0; -} -#endif - -void BKE_bproperty_set(bProperty *prop, const char *str) -{ -// extern int Gdfra; /* sector.c */ - - switch (prop->type) { - case GPROP_BOOL: - if (BLI_strcasecmp(str, "true") == 0) prop->data = 1; - else if (BLI_strcasecmp(str, "false") == 0) prop->data = 0; - else prop->data = (atoi(str) != 0); - break; - case GPROP_INT: - prop->data = atoi(str); - break; - case GPROP_FLOAT: - case GPROP_TIME: - *((float *)&prop->data) = (float)atof(str); - break; - case GPROP_STRING: - strcpy(prop->poin, str); /* TODO - check size? */ - break; - } - -} - -void BKE_bproperty_add(bProperty *prop, const char *str) -{ -// extern int Gdfra; /* sector.c */ - - switch (prop->type) { - case GPROP_BOOL: - case GPROP_INT: - prop->data += atoi(str); - break; - case GPROP_FLOAT: - case GPROP_TIME: - *((float *)&prop->data) += (float)atof(str); - break; - case GPROP_STRING: - /* strcpy(prop->poin, str); */ - break; - } -} - -/* reads value of property, sets it in chars in str */ -void BKE_bproperty_set_valstr(bProperty *prop, char str[MAX_PROPSTRING]) -{ -// extern int Gdfra; /* sector.c */ - - if (str == NULL) return; - - switch (prop->type) { - case GPROP_BOOL: - case GPROP_INT: - sprintf(str, "%d", prop->data); - break; - case GPROP_FLOAT: - case GPROP_TIME: - sprintf(str, "%f", *((float *)&prop->data)); - break; - case GPROP_STRING: - BLI_strncpy(str, prop->poin, MAX_PROPSTRING); - break; - } -} - -#if 0 /* UNUSED */ -void cp_property(bProperty *prop1, bProperty *prop2) -{ - char str[128]; - - BKE_bproperty_set_valstr(prop2, str); - - BKE_bproperty_set(prop1, str); -} -#endif diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 7fb313c838f..9ba3593f6b8 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -47,34 +47,39 @@ #endif #include "DNA_ID.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_object_force_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -#include "BKE_cdderivedmesh.h" -#include "BKE_depsgraph.h" +#include "BKE_collection.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_query.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_pointcache.h" #include "BKE_rigidbody.h" #include "BKE_scene.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" /* ************************************** */ /* Memory Management */ /* Freeing Methods --------------------- */ -#ifndef WITH_BULLET +#ifdef WITH_BULLET +static void rigidbody_update_ob_array(RigidBodyWorld *rbw); +#else static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {} static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {} static void RB_dworld_delete(void *UNUSED(world)) {} @@ -85,44 +90,51 @@ static void RB_constraint_delete(void *UNUSED(con)) {} #endif /* Free rigidbody world */ -void BKE_rigidbody_free_world(RigidBodyWorld *rbw) +void BKE_rigidbody_free_world(Scene *scene) { + bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0; + RigidBodyWorld *rbw = scene->rigidbody_world; + scene->rigidbody_world = NULL; + /* sanity check */ if (!rbw) return; - if (rbw->physics_world) { + if (is_orig && rbw->shared->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); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) + { + if (object->rigidbody_constraint) { + RigidBodyCon *rbc = object->rigidbody_constraint; + if (rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + } } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } - 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); - } + if (rbw->group) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) + { + BKE_rigidbody_free_object(object, rbw); } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } /* free dynamics world */ - RB_dworld_delete(rbw->physics_world); + RB_dworld_delete(rbw->shared->physics_world); } if (rbw->objects) free(rbw->objects); - /* free cache */ - BKE_ptcache_free_list(&(rbw->ptcaches)); - rbw->pointcache = NULL; + if (is_orig) { + /* free cache */ + BKE_ptcache_free_list(&(rbw->shared->ptcaches)); + rbw->shared->pointcache = NULL; + + MEM_freeN(rbw->shared); + } /* free effector weights */ if (rbw->effector_weights) @@ -133,8 +145,9 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) } /* Free RigidBody settings and sim instances */ -void BKE_rigidbody_free_object(Object *ob) +void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw) { + bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0; RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL; /* sanity check */ @@ -142,14 +155,26 @@ void BKE_rigidbody_free_object(Object *ob) return; /* free physics references */ - if (rbo->physics_object) { - RB_body_delete(rbo->physics_object); - rbo->physics_object = NULL; - } + if (is_orig) { + if (rbo->shared->physics_object) { + BLI_assert(rbw); + if (rbw) { + /* We can only remove the body from the world if the world is known. + * The world is generally only unknown if it's an evaluated copy of + * an object that's being freed, in which case this code isn't run anyway. */ + RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); + } - if (rbo->physics_shape) { - RB_shape_delete(rbo->physics_shape); - rbo->physics_shape = NULL; + RB_body_delete(rbo->shared->physics_object); + rbo->shared->physics_object = NULL; + } + + if (rbo->shared->physics_shape) { + RB_shape_delete(rbo->shared->physics_shape); + rbo->shared->physics_shape = NULL; + } + + MEM_freeN(rbo->shared); } /* free data itself */ @@ -186,7 +211,7 @@ void BKE_rigidbody_free_constraint(Object *ob) * be added to relevant groups later... */ -RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag)) +RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) { RigidBodyOb *rboN = NULL; @@ -194,12 +219,13 @@ RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag)) /* just duplicate the whole struct first (to catch all the settings) */ rboN = MEM_dupallocN(ob->rigidbody_object); + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + /* This is a regular copy, and not a CoW copy for depsgraph evaluation */ + rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared"); + } + /* 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 */ @@ -228,32 +254,39 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(f /* ************************************** */ /* Setup Utilities - Validate Sim Instances */ -/* get the appropriate DerivedMesh based on rigid body mesh source */ -static DerivedMesh *rigidbody_get_mesh(Object *ob) +/* get the appropriate evaluated mesh based on rigid body mesh source */ +static Mesh *rigidbody_get_mesh(Object *ob) { - if (ob->rigidbody_object->mesh_source == RBO_MESH_DEFORM) { - return ob->derivedDeform; - } - else if (ob->rigidbody_object->mesh_source == RBO_MESH_FINAL) { - return ob->derivedFinal; - } - else { - return CDDM_from_mesh(ob->data); - } + switch (ob->rigidbody_object->mesh_source) { + case RBO_MESH_DEFORM: + return ob->runtime.mesh_deform_eval; + case RBO_MESH_FINAL: + return ob->runtime.mesh_eval; + case RBO_MESH_BASE: + /* This mesh may be used for computing looptris, which should be done + * on the original; otherwise every time the CoW is recreated it will + * have to be recomputed. */ + BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE); + return ob->runtime.mesh_orig; + } + + /* Just return something sensible so that at least Blender won't crash. */ + BLI_assert(!"Unknown mesh source"); + return ob->runtime.mesh_eval; } /* 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; - DerivedMesh *dm = NULL; + Mesh *mesh = NULL; MVert *mvert = NULL; int totvert = 0; if (ob->type == OB_MESH && ob->data) { - dm = rigidbody_get_mesh(ob); - mvert = (dm) ? dm->getVertArray(dm) : NULL; - totvert = (dm) ? dm->getNumVerts(dm) : 0; + mesh = rigidbody_get_mesh(ob); + mvert = (mesh) ? mesh->mvert : NULL; + totvert = (mesh) ? mesh->totvert : 0; } else { printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n"); @@ -266,9 +299,6 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, fl printf("ERROR: no vertices to define Convex Hull collision shape with\n"); } - if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE) - dm->release(dm); - return shape; } @@ -280,24 +310,24 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) rbCollisionShape *shape = NULL; if (ob->type == OB_MESH) { - DerivedMesh *dm = NULL; + Mesh *mesh = NULL; MVert *mvert; const MLoopTri *looptri; int totvert; int tottri; const MLoop *mloop; - dm = rigidbody_get_mesh(ob); + mesh = rigidbody_get_mesh(ob); /* ensure mesh validity, then grab data */ - if (dm == NULL) + if (mesh == NULL) return NULL; - mvert = dm->getVertArray(dm); - totvert = dm->getNumVerts(dm); - looptri = dm->getLoopTriArray(dm); - tottri = dm->getNumLoopTri(dm); - mloop = dm->getLoopArray(dm); + mvert = mesh->mvert; + totvert = mesh->totvert; + looptri = BKE_mesh_runtime_looptri_ensure(mesh); + tottri = mesh->runtime.looptris.len; + mloop = mesh->mloop; /* sanity checking - potential case when no data will be present */ if ((totvert == 0) || (tottri == 0)) { @@ -347,11 +377,6 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) shape = RB_shape_new_gimpact_mesh(mdata); } } - - /* cleanup temp data */ - if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) { - dm->release(dm); - } } else { printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n"); @@ -381,7 +406,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) return; /* don't create a new shape if we already have one and don't want to rebuild it */ - if (rbo->physics_shape && !rebuild) + if (rbo->shared->physics_shape && !rebuild) return; /* if automatically determining dimensions, use the Object's boundbox @@ -445,15 +470,16 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) break; } /* use box shape if we can't fall back to old shape */ - if (new_shape == NULL && rbo->physics_shape == NULL) { + if (new_shape == NULL && rbo->shared->physics_shape == NULL) { new_shape = RB_shape_new_box(size[0], size[1], size[2]); } /* 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)); + if (rbo->shared->physics_shape) { + RB_shape_delete(rbo->shared->physics_shape); + } + rbo->shared->physics_shape = new_shape; + RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo)); } } @@ -514,30 +540,25 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) case RB_SHAPE_TRIMESH: { if (ob->type == OB_MESH) { - DerivedMesh *dm = rigidbody_get_mesh(ob); + Mesh *mesh = rigidbody_get_mesh(ob); MVert *mvert; const MLoopTri *lt = NULL; int totvert, tottri = 0; const MLoop *mloop = NULL; /* ensure mesh validity, then grab data */ - if (dm == NULL) + if (mesh == NULL) return; - mvert = dm->getVertArray(dm); - totvert = dm->getNumVerts(dm); - lt = dm->getLoopTriArray(dm); - tottri = dm->getNumLoopTri(dm); - mloop = dm->getLoopArray(dm); + mvert = mesh->mvert; + totvert = mesh->totvert; + lt = BKE_mesh_runtime_looptri_ensure(mesh); + tottri = mesh->runtime.looptris.len; + mloop = mesh->mloop; if (totvert > 0 && tottri > 0) { BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL); } - - /* cleanup temp data */ - if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) { - dm->release(dm); - } } else { /* rough estimate from boundbox as fallback */ @@ -546,12 +567,6 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) } break; } - -#if 0 // XXX: not defined yet - case RB_SHAPE_COMPOUND: - volume = 0.0f; - break; -#endif } /* return the volume calculated */ @@ -597,39 +612,28 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) case RB_SHAPE_TRIMESH: { if (ob->type == OB_MESH) { - DerivedMesh *dm = rigidbody_get_mesh(ob); + Mesh *mesh = rigidbody_get_mesh(ob); MVert *mvert; const MLoopTri *looptri; int totvert, tottri; const MLoop *mloop; /* ensure mesh validity, then grab data */ - if (dm == NULL) + if (mesh == NULL) return; - mvert = dm->getVertArray(dm); - totvert = dm->getNumVerts(dm); - looptri = dm->getLoopTriArray(dm); - tottri = dm->getNumLoopTri(dm); - mloop = dm->getLoopArray(dm); + mvert = mesh->mvert; + totvert = mesh->totvert; + looptri = BKE_mesh_runtime_looptri_ensure(mesh); + tottri = mesh->runtime.looptris.len; + mloop = mesh->mloop; if (totvert > 0 && tottri > 0) { BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center); } - - /* cleanup temp data */ - if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) { - dm->release(dm); - } } break; } - -#if 0 // XXX: not defined yet - case RB_SHAPE_COMPOUND: - volume = 0.0f; - break; -#endif } } @@ -654,48 +658,48 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool /* 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) + if (rbo->shared->physics_shape == NULL || rebuild) rigidbody_validate_sim_shape(ob, true); - if (rbo->physics_object && rebuild == false) { - RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); + if (rbo->shared->physics_object) { + RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); } - if (!rbo->physics_object || rebuild) { + if (!rbo->shared->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); + if (rbo->shared->physics_object) { + RB_body_delete(rbo->shared->physics_object); } mat4_to_loc_quat(loc, rot, ob->obmat); - rbo->physics_object = RB_body_new(rbo->physics_shape, loc, rot); + rbo->shared->physics_object = RB_body_new(rbo->shared->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_friction(rbo->shared->physics_object, rbo->friction); + RB_body_set_restitution(rbo->shared->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); + RB_body_set_damping(rbo->shared->physics_object, rbo->lin_damping, rbo->ang_damping); + RB_body_set_sleep_thresh(rbo->shared->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh); + RB_body_set_activation_state(rbo->shared->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_deactivate(rbo->shared->physics_object); - RB_body_set_linear_factor(rbo->physics_object, + RB_body_set_linear_factor(rbo->shared->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, + RB_body_set_angular_factor(rbo->shared->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); + RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo)); + RB_body_set_kinematic_state(rbo->shared->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); + if (rbw && rbw->shared->physics_world) + RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups); } /* --------------------- */ @@ -729,7 +733,8 @@ static void rigidbody_constraint_init_spring( set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); } -static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float)) +static void rigidbody_constraint_set_limits( + RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float)) { if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); @@ -787,7 +792,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b if (ELEM(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_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); RB_constraint_delete(rbc->physics_constraint); rbc->physics_constraint = NULL; } @@ -795,11 +800,11 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b } if (rbc->physics_constraint && rebuild == false) { - RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); + RB_dworld_remove_constraint(rbw->shared->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; + rbRigidBody *rb1 = rbc->ob1->rigidbody_object->shared->physics_object; + rbRigidBody *rb2 = rbc->ob2->rigidbody_object->shared->physics_object; /* remove constraint if it already exists before creating a new one */ if (rbc->physics_constraint) { @@ -903,8 +908,8 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b 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); + if (rbw && rbw->shared->physics_world && rbc->physics_constraint) { + RB_dworld_add_constraint(rbw->shared->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS); } } @@ -919,14 +924,14 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re 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); + if (rebuild || rbw->shared->physics_world == NULL) { + if (rbw->shared->physics_world) + RB_dworld_delete(rbw->shared->physics_world); + rbw->shared->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); + RB_dworld_set_solver_iterations(rbw->shared->physics_world, rbw->num_solver_iterations); + RB_dworld_set_split_impulse(rbw->shared->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE); } /* ************************************** */ @@ -947,6 +952,7 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) /* create a new sim world */ rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld"); + rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared"); /* set default settings */ rbw->effector_weights = BKE_add_effector_weights(NULL); @@ -958,8 +964,8 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) 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; + rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches)); + rbw->shared->pointcache->step = 1; /* return this sim world */ return rbw; @@ -977,12 +983,16 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) id_us_plus((ID *)rbw_copy->constraints); } - /* XXX Never copy caches here? */ - rbw_copy->pointcache = BKE_ptcache_copy_list(&rbw_copy->ptcaches, &rbw->ptcaches, flag & ~LIB_ID_COPY_CACHES); + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + /* This is a regular copy, and not a CoW copy for depsgraph evaluation */ + rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared"); + BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES); + rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first; + } rbw_copy->objects = NULL; - rbw_copy->physics_world = NULL; rbw_copy->numbodies = 0; + rigidbody_update_ob_array(rbw_copy); return rbw_copy; } @@ -1024,6 +1034,7 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) /* create new settings data, and link it up */ rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb"); + rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyOb_Shared"); /* set default settings */ rbo->type = type; @@ -1038,8 +1049,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) 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->lin_damping = 0.04f; + rbo->ang_damping = 0.1f; rbo->col_groups = 1; @@ -1148,18 +1159,13 @@ RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) return scene->rigidbody_world; } -void BKE_rigidbody_remove_object(Scene *scene, Object *ob) +void BKE_rigidbody_remove_object(struct Main *bmain, 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) { @@ -1173,8 +1179,8 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) /* remove object from rigid body constraints */ if (rbw->constraints) { - for (go = rbw->constraints->gobject.first; go; go = go->next) { - Object *obt = go->ob; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, obt) + { if (obt && obt->rigidbody_constraint) { rbc = obt->rigidbody_constraint; if (ELEM(ob, rbc->ob1, rbc->ob2)) { @@ -1182,11 +1188,13 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob) } } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } + BKE_collection_object_remove(bmain, rbw->group, ob, false); } /* remove object's settings */ - BKE_rigidbody_free_object(ob); + BKE_rigidbody_free_object(ob, rbw); /* flag cache as outdated */ BKE_rigidbody_cache_reset(rbw); @@ -1198,8 +1206,8 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) RigidBodyCon *rbc = ob->rigidbody_constraint; /* 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); + if (rbw && rbw->shared->physics_world && rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); } /* remove object's settings */ BKE_rigidbody_free_constraint(ob); @@ -1215,20 +1223,32 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) /* 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; + if (rbw->group == NULL) { + rbw->numbodies = 0; + rbw->objects = realloc(rbw->objects, 0); + return; + } - n = BLI_listbase_count(&rbw->group->gobject); + int n = 0; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) + { + (void)object; + n++; + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; 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; + int i = 0; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) + { + rbw->objects[i] = object; + i++; } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) @@ -1245,51 +1265,51 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) } /* update gravity, since this RNA setting is not part of RigidBody settings */ - RB_dworld_set_gravity(rbw->physics_world, adj_gravity); + RB_dworld_set_gravity(rbw->shared->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) +static void rigidbody_update_sim_ob(Depsgraph *depsgraph, 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) + if (rbo->shared->physics_object == NULL) return; if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) { - DerivedMesh *dm = ob->derivedDeform; - if (dm) { - MVert *mvert = dm->getVertArray(dm); - int totvert = dm->getNumVerts(dm); + Mesh *mesh = ob->runtime.mesh_deform_eval; + if (mesh) { + MVert *mvert = mesh->mvert; + int totvert = mesh->totvert; BoundBox *bb = BKE_object_boundbox_get(ob); - RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]); + RB_shape_trimesh_update(rbo->shared->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]); } } mat4_decompose(loc, rot, scale, ob->obmat); /* update scale for all objects */ - RB_body_set_scale(rbo->physics_object, scale); + RB_body_set_scale(rbo->shared->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])); + RB_shape_set_margin(rbo->shared->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) { - RB_body_set_kinematic_state(rbo->physics_object, true); - RB_body_set_mass(rbo->physics_object, 0.0f); + RB_body_set_kinematic_state(rbo->shared->physics_object, true); + RB_body_set_mass(rbo->shared->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); + RB_body_activate(rbo->shared->physics_object); + RB_body_set_loc_rot(rbo->shared->physics_object, loc, rot); } /* update influence of effectors - but don't do it on an effector */ /* only dynamic bodies need effector update */ @@ -1299,34 +1319,34 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o ListBase *effectors; /* get effectors present in the group specified by effector_weights */ - effectors = pdInitEffectors(scene, ob, NULL, effector_weights, true); + effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights); if (effectors) { float eff_force[3] = {0.0f, 0.0f, 0.0f}; float eff_loc[3], eff_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, eff_loc); - RB_body_get_linear_velocity(rbo->physics_object, eff_vel); + RB_body_get_position(rbo->shared->physics_object, eff_loc); + RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel); pd_point_from_loc(scene, eff_loc, eff_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, eff_force, NULL); + BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL); if (G.f & G_DEBUG) printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2); /* activate object in case it is deactivated */ if (!is_zero_v3(eff_force)) - RB_body_activate(rbo->physics_object); - RB_body_apply_central_force(rbo->physics_object, eff_force); + RB_body_activate(rbo->shared->physics_object); + RB_body_apply_central_force(rbo->shared->physics_object, eff_force); } else if (G.f & G_DEBUG) printf("\tno forces to apply to '%s'\n", ob->id.name + 2); /* cleanup */ - pdEndEffectors(&effectors); + BKE_effectors_free(effectors); } /* NOTE: passive objects don't need to be updated since they don't move */ @@ -1340,10 +1360,8 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o * * \param rebuild Rebuild entire simulation */ -static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool rebuild) +static void rigidbody_update_simulation(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, bool rebuild) { - GroupObject *go; - /* update world */ if (rebuild) BKE_rigidbody_validate_sim_world(scene, rbw, true); @@ -1356,28 +1374,26 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool * Memory management needs redesign here, this is just a dirty workaround. */ if (rebuild && rbw->constraints) { - for (go = rbw->constraints->gobject.first; go; go = go->next) { - Object *ob = go->ob; - if (ob) { - RigidBodyCon *rbc = ob->rigidbody_constraint; - if (rbc && rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); - RB_constraint_delete(rbc->physics_constraint); - rbc->physics_constraint = NULL; - } + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob) + { + RigidBodyCon *rbc = ob->rigidbody_constraint; + if (rbc && rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } /* update objects */ - for (go = rbw->group->gobject.first; go; go = go->next) { - Object *ob = go->ob; - - if (ob && ob->type == OB_MESH) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob) + { + if (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); + BKE_object_where_is_calc(depsgraph, scene, ob); if (rbo == NULL) { /* Since this object is included in the sim group but doesn't have @@ -1394,6 +1410,9 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool /* refresh object... */ if (rebuild) { /* World has been rebuilt so rebuild object */ + /* TODO(Sybren): rigidbody_validate_sim_object() can call rigidbody_validate_sim_shape(), + * but neither resets the RBO_FLAG_NEEDS_RESHAPE flag nor calls RB_body_set_collision_shape(). + * This results in the collision shape being created twice, which is unnecessary. */ rigidbody_validate_sim_object(rbw, ob, true); } else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) { @@ -1405,76 +1424,75 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool 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); + RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape); } rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); } /* update simulation object... */ - rigidbody_update_sim_ob(scene, rbw, ob, rbo); + rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo); } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; /* 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); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, 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(depsgraph, 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); - rigidbody_validate_sim_constraint(rbw, ob, true); + 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); + rigidbody_validate_sim_constraint(rbw, ob, true); - rbc = ob->rigidbody_constraint; + rbc = ob->rigidbody_constraint; + } + else { + /* perform simulation data updates as tagged */ + if (rebuild) { + /* World has been rebuilt so rebuild constraint */ + rigidbody_validate_sim_constraint(rbw, ob, true); } - else { - /* perform simulation data updates as tagged */ - if (rebuild) { - /* World has been rebuilt so rebuild constraint */ - rigidbody_validate_sim_constraint(rbw, ob, true); - } - else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { - rigidbody_validate_sim_constraint(rbw, ob, false); - } - rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; + else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { + rigidbody_validate_sim_constraint(rbw, ob, false); } + rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } -static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) +static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, 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 (rbo && (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)); - /* deactivate passive objects so they don't interfere with deactivation of active objects */ - if (rbo->type == RBO_TYPE_PASSIVE) - RB_body_deactivate(rbo->physics_object); - } + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob) + { + Base *base = BKE_view_layer_base_find(view_layer, ob); + RigidBodyOb *rbo = ob->rigidbody_object; + /* Reset kinematic state for transformed objects. */ + if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) { + RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); + RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo)); + /* Deactivate passive objects so they don't interfere with deactivation of active objects. */ + if (rbo->type == RBO_TYPE_PASSIVE) + RB_body_deactivate(rbo->shared->physics_object); } } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { - return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->pointcache->startframe); + return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe); } /* Sync rigid body and object transformations */ @@ -1564,11 +1582,11 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo copy_qt_qt(ob->quat, quat); } - if (rbo->physics_object) { + if (rbo->shared->physics_object) { /* allow passive objects to return to original transform */ if (rbo->type == RBO_TYPE_PASSIVE) - RB_body_set_kinematic_state(rbo->physics_object, true); - RB_body_set_loc_rot(rbo->physics_object, rbo->pos, rbo->orn); + RB_body_set_kinematic_state(rbo->shared->physics_object, true); + RB_body_set_loc_rot(rbo->shared->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) } @@ -1576,7 +1594,7 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) { if (rbw) { - rbw->pointcache->flag |= PTCACHE_OUTDATED; + rbw->shared->pointcache->flag |= PTCACHE_OUTDATED; } } @@ -1584,7 +1602,7 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) /* Rebuild rigid body world */ /* NOTE: this needs to be called before frame update to work correctly */ -void BKE_rigidbody_rebuild_world(Scene *scene, float ctime) +void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) { RigidBodyWorld *rbw = scene->rigidbody_world; PointCache *cache; @@ -1593,17 +1611,25 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime) BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw); BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); - cache = rbw->pointcache; + cache = rbw->shared->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_listbase_count(&rbw->group->gobject)) { + int n = 0; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) + { + (void)object; + n++; + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + if (rbw->shared->physics_world == NULL || rbw->numbodies != n) { cache->flag |= PTCACHE_OUTDATED; } if (ctime == startframe + 1 && rbw->ltime == startframe) { if (cache->flag & PTCACHE_OUTDATED) { BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); - rigidbody_update_simulation(scene, rbw, true); + rigidbody_update_simulation(depsgraph, scene, rbw, true); BKE_ptcache_validate(cache, (int)ctime); cache->last_exact = 0; cache->flag &= ~PTCACHE_REDO_NEEDED; @@ -1612,7 +1638,7 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime) } /* Run RigidBody simulation for the specified physics world */ -void BKE_rigidbody_do_simulation(Scene *scene, float ctime) +void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) { float timestep; RigidBodyWorld *rbw = scene->rigidbody_world; @@ -1622,7 +1648,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw); BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); - cache = rbw->pointcache; + cache = rbw->shared->pointcache; if (ctime <= startframe) { rbw->ltime = startframe; @@ -1634,7 +1660,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) } /* 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)) + if (rbw->shared->physics_world == NULL && !(cache->flag & PTCACHE_BAKED)) return; else if (rbw->objects == NULL) rigidbody_update_ob_array(rbw); @@ -1649,22 +1675,28 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) return; } + if (!DEG_is_active(depsgraph)) { + /* When the depsgraph is inactive we should neither write to the cache + * nor run the simulation. */ + return; + } + /* advance simulation, we can only step one frame forward */ - if (can_simulate) { + if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) { /* 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); + rigidbody_update_simulation(depsgraph, 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)); + RB_dworld_step_simulation(rbw->shared->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); + rigidbody_update_simulation_post_step(depsgraph, rbw); /* write cache for current frame */ BKE_ptcache_validate(cache, (int)ctime); @@ -1695,14 +1727,14 @@ void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFun 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_object(struct Main *bmain, Scene *scene, Object *ob) {} void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) {} void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, 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) {} bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { return false; } void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) {} -void BKE_rigidbody_rebuild_world(Scene *scene, float ctime) {} -void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {} +void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) {} +void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) {} #if defined(__GNUC__) || defined(__clang__) # pragma GCC diagnostic pop @@ -1710,38 +1742,42 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {} #endif /* WITH_BULLET */ + + /* -------------------- */ /* Depsgraph evaluation */ -void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx), +void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph, Scene *scene) { - float ctime = BKE_scene_frame_get(scene); - DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime); + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime); /* rebuild sim data (i.e. after resetting to start of timeline) */ if (BKE_scene_check_rigidbody_active(scene)) { - BKE_rigidbody_rebuild_world(scene, ctime); + BKE_rigidbody_rebuild_world(depsgraph, scene, ctime); } } -void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx), +void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph, Scene *scene) { - float ctime = BKE_scene_frame_get(scene); - DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime); + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime); + /* evaluate rigidbody sim */ - if (BKE_scene_check_rigidbody_active(scene)) { - BKE_rigidbody_do_simulation(scene, ctime); + if (!BKE_scene_check_rigidbody_active(scene)) { + return; } + BKE_rigidbody_do_simulation(depsgraph, scene, ctime); } -void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx), +void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph, Scene *scene, Object *ob) { RigidBodyWorld *rbw = scene->rigidbody_world; - float ctime = BKE_scene_frame_get(scene); - DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime); + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime); /* read values pushed into RBO from sim/cache... */ BKE_rigidbody_sync_transforms(rbw, ob, ctime); } diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c deleted file mode 100644 index 56e64387096..00000000000 --- a/source/blender/blenkernel/intern/sca.c +++ /dev/null @@ -1,1178 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * these all are linked to objects (listbase) - * all data is 'direct data', not Blender lib data. - */ - -/** \file blender/blenkernel/intern/sca.c - * \ingroup bke - */ - - -#include <stdio.h> -#include <string.h> -#include <float.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_controller_types.h" -#include "DNA_sensor_types.h" -#include "DNA_actuator_types.h" -#include "DNA_object_types.h" - -#include "BLI_blenlib.h" -#include "BLI_ghash.h" -#include "BLI_math.h" - -#include "BKE_global.h" -#include "BKE_main.h" -#include "BKE_library.h" -#include "BKE_library_query.h" -#include "BKE_sca.h" - -/* ******************* SENSORS ************************ */ - -void free_sensor(bSensor *sens) -{ - if (sens->links) MEM_freeN(sens->links); - if (sens->data) MEM_freeN(sens->data); - MEM_freeN(sens); - -} - -void free_sensors(ListBase *lb) -{ - bSensor *sens; - - while ((sens = BLI_pophead(lb))) { - free_sensor(sens); - } -} - -bSensor *copy_sensor(bSensor *sens, const int UNUSED(flag)) -{ - bSensor *sensn; - - sensn= MEM_dupallocN(sens); - sensn->flag |= SENS_NEW; - if (sens->data) { - sensn->data= MEM_dupallocN(sens->data); - } - - if (sens->links) sensn->links= MEM_dupallocN(sens->links); - - return sensn; -} - -void copy_sensors(ListBase *lbn, const ListBase *lbo, const int flag) -{ - bSensor *sens, *sensn; - - lbn->first= lbn->last= NULL; - sens= lbo->first; - while (sens) { - sensn= copy_sensor(sens, flag); - BLI_addtail(lbn, sensn); - sens= sens->next; - } -} - -void init_sensor(bSensor *sens) -{ - /* also use when sensor changes type */ - bNearSensor *ns; - bMouseSensor *ms; - bJoystickSensor *js; - bRaySensor *rs; - - if (sens->data) MEM_freeN(sens->data); - sens->data= NULL; - sens->pulse = 0; - - switch (sens->type) { - case SENS_ALWAYS: - sens->pulse = 0; - break; - case SENS_NEAR: - ns=sens->data= MEM_callocN(sizeof(bNearSensor), "nearsens"); - ns->dist= 1.0; - ns->resetdist= 2.0; - break; - case SENS_KEYBOARD: - sens->data= MEM_callocN(sizeof(bKeyboardSensor), "keysens"); - break; - case SENS_PROPERTY: - sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens"); - break; - case SENS_ARMATURE: - sens->data= MEM_callocN(sizeof(bArmatureSensor), "armsens"); - break; - case SENS_ACTUATOR: - sens->data= MEM_callocN(sizeof(bActuatorSensor), "actsens"); - break; - case SENS_DELAY: - sens->data= MEM_callocN(sizeof(bDelaySensor), "delaysens"); - break; - case SENS_MOUSE: - ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens"); - ms->type= 1; // LEFTMOUSE workaround because Mouse Sensor types enum starts in 1 - break; - case SENS_COLLISION: - sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens"); - break; - case SENS_RADAR: - sens->data= MEM_callocN(sizeof(bRadarSensor), "radarsens"); - break; - case SENS_RANDOM: - sens->data= MEM_callocN(sizeof(bRandomSensor), "randomsens"); - break; - case SENS_RAY: - sens->data= MEM_callocN(sizeof(bRaySensor), "raysens"); - rs = sens->data; - rs->range = 0.01f; - break; - case SENS_MESSAGE: - sens->data= MEM_callocN(sizeof(bMessageSensor), "messagesens"); - break; - case SENS_JOYSTICK: - sens->data= MEM_callocN(sizeof(bJoystickSensor), "joysticksens"); - js= sens->data; - js->hatf = SENS_JOY_HAT_UP; - js->axis = 1; - js->hat = 1; - break; - default: - ; /* this is very severe... I cannot make any memory for this */ - /* logic brick... */ - } -} - -bSensor *new_sensor(int type) -{ - bSensor *sens; - - sens= MEM_callocN(sizeof(bSensor), "Sensor"); - sens->type= type; - sens->flag= SENS_SHOW; - - init_sensor(sens); - - strcpy(sens->name, "sensor"); -// XXX make_unique_prop_names(sens->name); - - return sens; -} - -/* ******************* CONTROLLERS ************************ */ - -void unlink_controller(bController *cont) -{ - bSensor *sens; - Object *ob; - - /* check for controller pointers in sensors */ - ob= G.main->object.first; - while (ob) { - sens= ob->sensors.first; - while (sens) { - unlink_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks); - sens= sens->next; - } - ob= ob->id.next; - } -} - -void unlink_controllers(ListBase *lb) -{ - bController *cont; - - for (cont= lb->first; cont; cont= cont->next) - unlink_controller(cont); -} - -void free_controller(bController *cont) -{ - if (cont->links) MEM_freeN(cont->links); - - /* the controller itself */ - if (cont->data) MEM_freeN(cont->data); - MEM_freeN(cont); - -} - -void free_controllers(ListBase *lb) -{ - bController *cont; - - while ((cont = BLI_pophead(lb))) { - if (cont->slinks) - MEM_freeN(cont->slinks); - free_controller(cont); - } -} - -bController *copy_controller(bController *cont, const int UNUSED(flag)) -{ - bController *contn; - - cont->mynew=contn= MEM_dupallocN(cont); - contn->flag |= CONT_NEW; - if (cont->data) { - contn->data= MEM_dupallocN(cont->data); - } - - if (cont->links) contn->links= MEM_dupallocN(cont->links); - contn->slinks= NULL; - contn->totslinks= 0; - - return contn; -} - -void copy_controllers(ListBase *lbn, const ListBase *lbo, const int flag) -{ - bController *cont, *contn; - - lbn->first= lbn->last= NULL; - cont= lbo->first; - while (cont) { - contn= copy_controller(cont, flag); - BLI_addtail(lbn, contn); - cont= cont->next; - } -} - -void init_controller(bController *cont) -{ - /* also use when controller changes type, leave actuators... */ - - if (cont->data) MEM_freeN(cont->data); - cont->data= NULL; - - switch (cont->type) { - case CONT_EXPRESSION: - cont->data= MEM_callocN(sizeof(bExpressionCont), "expcont"); - break; - case CONT_PYTHON: - cont->data= MEM_callocN(sizeof(bPythonCont), "pycont"); - break; - } -} - -bController *new_controller(int type) -{ - bController *cont; - - cont= MEM_callocN(sizeof(bController), "Controller"); - cont->type= type; - cont->flag= CONT_SHOW; - - init_controller(cont); - - strcpy(cont->name, "cont"); -// XXX make_unique_prop_names(cont->name); - - return cont; -} - -/* ******************* ACTUATORS ************************ */ - -void unlink_actuator(bActuator *act) -{ - bController *cont; - Object *ob; - - /* check for actuator pointers in controllers */ - ob= G.main->object.first; - while (ob) { - cont= ob->controllers.first; - while (cont) { - unlink_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks); - cont= cont->next; - } - ob= ob->id.next; - } -} - -void unlink_actuators(ListBase *lb) -{ - bActuator *act; - - for (act= lb->first; act; act= act->next) - unlink_actuator(act); -} - -void free_actuator(bActuator *act) -{ - if (act->data) { - switch (act->type) { - case ACT_ACTION: - case ACT_SHAPEACTION: - { - bActionActuator *aa = (bActionActuator *)act->data; - if (aa->act) - id_us_min((ID *)aa->act); - break; - } - case ACT_SOUND: - { - bSoundActuator *sa = (bSoundActuator *) act->data; - if (sa->sound) - id_us_min((ID *)sa->sound); - break; - } - } - - MEM_freeN(act->data); - } - MEM_freeN(act); -} - -void free_actuators(ListBase *lb) -{ - bActuator *act; - - while ((act = BLI_pophead(lb))) { - free_actuator(act); - } -} - -bActuator *copy_actuator(bActuator *act, const int flag) -{ - bActuator *actn; - - act->mynew=actn= MEM_dupallocN(act); - actn->flag |= ACT_NEW; - if (act->data) { - actn->data= MEM_dupallocN(act->data); - } - - switch (act->type) { - case ACT_ACTION: - case ACT_SHAPEACTION: - { - bActionActuator *aa = (bActionActuator *)act->data; - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - id_us_plus((ID *)aa->act); - } - break; - } - case ACT_SOUND: - { - bSoundActuator *sa = (bSoundActuator *)act->data; - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - id_us_plus((ID *)sa->sound); - } - break; - } - } - return actn; -} - -void copy_actuators(ListBase *lbn, const ListBase *lbo, const int flag) -{ - bActuator *act, *actn; - - lbn->first= lbn->last= NULL; - act= lbo->first; - while (act) { - actn= copy_actuator(act, flag); - BLI_addtail(lbn, actn); - act= act->next; - } -} - -void init_actuator(bActuator *act) -{ - /* also use when actuator changes type */ - bCameraActuator *ca; - bObjectActuator *oa; - bRandomActuator *ra; - bSoundActuator *sa; - bSteeringActuator *sta; - bArmatureActuator *arma; - bMouseActuator *ma; - bEditObjectActuator *eoa; - - if (act->data) MEM_freeN(act->data); - act->data= NULL; - - switch (act->type) { - case ACT_ACTION: - case ACT_SHAPEACTION: - act->data= MEM_callocN(sizeof(bActionActuator), "actionact"); - break; - case ACT_SOUND: - sa = act->data= MEM_callocN(sizeof(bSoundActuator), "soundact"); - sa->volume = 1.0f; - sa->sound3D.rolloff_factor = 1.0f; - sa->sound3D.reference_distance = 1.0f; - sa->sound3D.max_gain = 1.0f; - sa->sound3D.cone_inner_angle = DEG2RADF(360.0f); - sa->sound3D.cone_outer_angle = DEG2RADF(360.0f); - sa->sound3D.max_distance = FLT_MAX; - break; - case ACT_OBJECT: - act->data= MEM_callocN(sizeof(bObjectActuator), "objectact"); - oa= act->data; - oa->flag= 15; - break; - case ACT_PROPERTY: - act->data= MEM_callocN(sizeof(bPropertyActuator), "propact"); - break; - case ACT_CAMERA: - act->data= MEM_callocN(sizeof(bCameraActuator), "camact"); - ca = act->data; - ca->axis = OB_POSX; - ca->damping = 1.0/32.0; - break; - case ACT_EDIT_OBJECT: - act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact"); - eoa = act->data; - eoa->upflag= ACT_TRACK_UP_Z; - eoa->trackflag= ACT_TRACK_TRAXIS_Y; - break; - case ACT_CONSTRAINT: - act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act"); - break; - case ACT_SCENE: - act->data= MEM_callocN(sizeof(bSceneActuator), "scene act"); - break; - case ACT_GROUP: - act->data= MEM_callocN(sizeof(bGroupActuator), "group act"); - break; - case ACT_RANDOM: - act->data= MEM_callocN(sizeof(bRandomActuator), "random act"); - ra=act->data; - ra->float_arg_1 = 0.1f; - break; - case ACT_MESSAGE: - act->data= MEM_callocN(sizeof(bMessageActuator), "message act"); - break; - case ACT_GAME: - act->data= MEM_callocN(sizeof(bGameActuator), "game act"); - break; - case ACT_VISIBILITY: - act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act"); - break; - case ACT_2DFILTER: - act->data = MEM_callocN(sizeof( bTwoDFilterActuator ), "2d filter act"); - break; - case ACT_PARENT: - act->data = MEM_callocN(sizeof( bParentActuator ), "parent act"); - break; - case ACT_STATE: - act->data = MEM_callocN(sizeof( bStateActuator ), "state act"); - break; - case ACT_ARMATURE: - act->data = MEM_callocN(sizeof( bArmatureActuator ), "armature act"); - arma = act->data; - arma->influence = 1.f; - break; - case ACT_STEERING: - act->data = MEM_callocN(sizeof( bSteeringActuator), "steering act"); - sta = act->data; - sta->acceleration = 3.f; - sta->turnspeed = 120.f; - sta->dist = 1.f; - sta->velocity= 3.f; - sta->flag = ACT_STEERING_AUTOMATICFACING | ACT_STEERING_LOCKZVEL; - sta->facingaxis = 1; - break; - case ACT_MOUSE: - ma = act->data = MEM_callocN(sizeof( bMouseActuator ), "mouse act"); - ma->flag = ACT_MOUSE_VISIBLE|ACT_MOUSE_USE_AXIS_X|ACT_MOUSE_USE_AXIS_Y|ACT_MOUSE_RESET_X|ACT_MOUSE_RESET_Y|ACT_MOUSE_LOCAL_Y; - ma->sensitivity[0] = ma->sensitivity[1] = 2.f; - ma->object_axis[0] = ACT_MOUSE_OBJECT_AXIS_Z; - ma->object_axis[1] = ACT_MOUSE_OBJECT_AXIS_X; - ma->limit_y[0] = DEG2RADF(-90.0f); - ma->limit_y[1] = DEG2RADF(90.0f); - break; - default: - ; /* this is very severe... I cannot make any memory for this */ - /* logic brick... */ - } -} - -bActuator *new_actuator(int type) -{ - bActuator *act; - - act= MEM_callocN(sizeof(bActuator), "Actuator"); - act->type= type; - act->flag= ACT_SHOW; - - init_actuator(act); - - strcpy(act->name, "act"); -// XXX make_unique_prop_names(act->name); - - return act; -} - -/* ******************** GENERAL ******************* */ -void clear_sca_new_poins_ob(Object *ob) -{ - bSensor *sens; - bController *cont; - bActuator *act; - - sens= ob->sensors.first; - while (sens) { - sens->flag &= ~SENS_NEW; - sens= sens->next; - } - cont= ob->controllers.first; - while (cont) { - cont->mynew= NULL; - cont->flag &= ~CONT_NEW; - cont= cont->next; - } - act= ob->actuators.first; - while (act) { - act->mynew= NULL; - act->flag &= ~ACT_NEW; - act= act->next; - } -} - -void clear_sca_new_poins(void) -{ - Object *ob; - - ob= G.main->object.first; - while (ob) { - clear_sca_new_poins_ob(ob); - ob= ob->id.next; - } -} - -void set_sca_new_poins_ob(Object *ob) -{ - bSensor *sens; - bController *cont; - bActuator *act; - int a; - - sens= ob->sensors.first; - while (sens) { - if (sens->flag & SENS_NEW) { - for (a=0; a<sens->totlinks; a++) { - if (sens->links[a] && sens->links[a]->mynew) - sens->links[a] = sens->links[a]->mynew; - } - } - sens= sens->next; - } - - cont= ob->controllers.first; - while (cont) { - if (cont->flag & CONT_NEW) { - for (a=0; a<cont->totlinks; a++) { - if ( cont->links[a] && cont->links[a]->mynew) - cont->links[a] = cont->links[a]->mynew; - } - } - cont= cont->next; - } - - - act= ob->actuators.first; - while (act) { - if (act->flag & ACT_NEW) { - if (act->type==ACT_EDIT_OBJECT) { - bEditObjectActuator *eoa= act->data; - ID_NEW_REMAP(eoa->ob); - } - else if (act->type==ACT_SCENE) { - bSceneActuator *sca= act->data; - ID_NEW_REMAP(sca->camera); - } - else if (act->type==ACT_CAMERA) { - bCameraActuator *ca= act->data; - ID_NEW_REMAP(ca->ob); - } - else if (act->type==ACT_OBJECT) { - bObjectActuator *oa= act->data; - ID_NEW_REMAP(oa->reference); - } - else if (act->type==ACT_MESSAGE) { - bMessageActuator *ma= act->data; - ID_NEW_REMAP(ma->toObject); - } - else if (act->type==ACT_PARENT) { - bParentActuator *para = act->data; - ID_NEW_REMAP(para->ob); - } - else if (act->type==ACT_ARMATURE) { - bArmatureActuator *aa = act->data; - ID_NEW_REMAP(aa->target); - ID_NEW_REMAP(aa->subtarget); - } - else if (act->type==ACT_PROPERTY) { - bPropertyActuator *pa= act->data; - ID_NEW_REMAP(pa->ob); - } - else if (act->type==ACT_STEERING) { - bSteeringActuator *sta = act->data; - ID_NEW_REMAP(sta->navmesh); - ID_NEW_REMAP(sta->target); - } - } - act= act->next; - } -} - - -void set_sca_new_poins(void) -{ - Object *ob; - - ob= G.main->object.first; - while (ob) { - set_sca_new_poins_ob(ob); - ob= ob->id.next; - } -} - -/** - * Try to remap logic links to new object... Very, *very* weak. - */ -/* XXX Logick bricks... I don't have words to say what I think about this behavior. - * They have silent hidden ugly inter-objects dependencies (a sensor can link into any other - * object's controllers, and same between controllers and actuators, without *any* explicit reference - * to data-block involved). - * This is bad, bad, bad!!! - * ...and forces us to add yet another very ugly hack to get remapping with logic bricks working. */ -void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new) -{ - if (ob_new == NULL || (ob_old->controllers.first == NULL && ob_old->actuators.first == NULL)) { - /* Nothing to do here... */ - return; - } - - GHash *controllers_map = ob_old->controllers.first ? - BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->controllers)) : NULL; - GHash *actuators_map = ob_old->actuators.first ? - BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->actuators)) : NULL; - - /* We try to remap old controllers/actuators to new ones - in a very basic way. */ - for (bController *cont_old = ob_old->controllers.first, *cont_new = ob_new->controllers.first; - cont_old; - cont_old = cont_old->next) - { - bController *cont_new2 = cont_new; - - if (cont_old->mynew != NULL) { - cont_new2 = cont_old->mynew; - if (!(cont_new2 == cont_new || BLI_findindex(&ob_new->controllers, cont_new2) >= 0)) { - cont_new2 = NULL; - } - } - else if (cont_new && cont_old->type != cont_new->type) { - cont_new2 = NULL; - } - - BLI_ghash_insert(controllers_map, cont_old, cont_new2); - - if (cont_new) { - cont_new = cont_new->next; - } - } - - for (bActuator *act_old = ob_old->actuators.first, *act_new = ob_new->actuators.first; - act_old; - act_old = act_old->next) - { - bActuator *act_new2 = act_new; - - if (act_old->mynew != NULL) { - act_new2 = act_old->mynew; - if (!(act_new2 == act_new || BLI_findindex(&ob_new->actuators, act_new2) >= 0)) { - act_new2 = NULL; - } - } - else if (act_new && act_old->type != act_new->type) { - act_new2 = NULL; - } - - BLI_ghash_insert(actuators_map, act_old, act_new2); - - if (act_new) { - act_new = act_new->next; - } - } - - for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { - if (controllers_map != NULL) { - for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) { - for (int a = 0; a < sens->totlinks; a++) { - if (sens->links[a]) { - bController *old_link = sens->links[a]; - bController **new_link_p = (bController **)BLI_ghash_lookup_p(controllers_map, old_link); - - if (new_link_p == NULL) { - /* old_link is *not* in map's keys (i.e. not to any ob_old->controllers), - * which means we ignore it totally here. */ - } - else if (*new_link_p == NULL) { - unlink_logicbricks((void **)&old_link, (void ***)&(sens->links), &sens->totlinks); - a--; - } - else { - sens->links[a] = *new_link_p; - } - } - } - } - } - - if (actuators_map != NULL) { - for (bController *cont = ob->controllers.first; cont; cont = cont->next) { - for (int a = 0; a < cont->totlinks; a++) { - if (cont->links[a]) { - bActuator *old_link = cont->links[a]; - bActuator **new_link_p = (bActuator **)BLI_ghash_lookup_p(actuators_map, old_link); - - if (new_link_p == NULL) { - /* old_link is *not* in map's keys (i.e. not to any ob_old->actuators), - * which means we ignore it totally here. */ - } - else if (*new_link_p == NULL) { - unlink_logicbricks((void **)&old_link, (void ***)&(cont->links), &cont->totlinks); - a--; - } - else { - cont->links[a] = *new_link_p; - } - } - } - } - } - } - - if (controllers_map) { - BLI_ghash_free(controllers_map, NULL, NULL); - } - if (actuators_map) { - BLI_ghash_free(actuators_map, NULL, NULL); - } -} - -/** - * Handle the copying of logic data into a new object, including internal logic links update. - * External links (links between logic bricks of different objects) must be handled separately. - */ -void BKE_sca_logic_copy(Object *ob_new, const Object *ob, const int flag) -{ - copy_sensors(&ob_new->sensors, &ob->sensors, flag); - copy_controllers(&ob_new->controllers, &ob->controllers, flag); - copy_actuators(&ob_new->actuators, &ob->actuators, flag); - - for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) { - if (sens->flag & SENS_NEW) { - for (int a = 0; a < sens->totlinks; a++) { - if (sens->links[a] && sens->links[a]->mynew) { - sens->links[a] = sens->links[a]->mynew; - } - } - } - } - - for (bController *cont = ob_new->controllers.first; cont; cont = cont->next) { - if (cont->flag & CONT_NEW) { - for (int a = 0; a < cont->totlinks; a++) { - if (cont->links[a] && cont->links[a]->mynew) { - cont->links[a] = cont->links[a]->mynew; - } - } - } - } -} - -/* ******************** INTERFACE ******************* */ -void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up) -{ - bSensor *sens, *tmp; - - int val; - val = move_up ? 1 : 2; - - /* make sure this sensor belongs to this object */ - sens= ob->sensors.first; - while (sens) { - if (sens == sens_to_move) break; - sens= sens->next; - } - if (!sens) return; - - /* move up */ - if (val == 1 && sens->prev) { - for (tmp=sens->prev; tmp; tmp=tmp->prev) { - if (tmp->flag & SENS_VISIBLE) - break; - } - if (tmp) { - BLI_remlink(&ob->sensors, sens); - BLI_insertlinkbefore(&ob->sensors, tmp, sens); - } - } - /* move down */ - else if (val == 2 && sens->next) { - for (tmp=sens->next; tmp; tmp=tmp->next) { - if (tmp->flag & SENS_VISIBLE) - break; - } - if (tmp) { - BLI_remlink(&ob->sensors, sens); - BLI_insertlinkafter(&ob->sensors, tmp, sens); - } - } -} - -void sca_move_controller(bController *cont_to_move, Object *ob, int move_up) -{ - bController *cont, *tmp; - - int val; - val = move_up ? 1 : 2; - - /* make sure this controller belongs to this object */ - cont= ob->controllers.first; - while (cont) { - if (cont == cont_to_move) break; - cont= cont->next; - } - if (!cont) return; - - /* move up */ - if (val == 1 && cont->prev) { - /* locate the controller that has the same state mask but is earlier in the list */ - tmp = cont->prev; - while (tmp) { - if (tmp->state_mask & cont->state_mask) - break; - tmp = tmp->prev; - } - if (tmp) { - BLI_remlink(&ob->controllers, cont); - BLI_insertlinkbefore(&ob->controllers, tmp, cont); - } - } - - /* move down */ - else if (val == 2 && cont->next) { - tmp = cont->next; - while (tmp) { - if (tmp->state_mask & cont->state_mask) - break; - tmp = tmp->next; - } - BLI_remlink(&ob->controllers, cont); - BLI_insertlinkafter(&ob->controllers, tmp, cont); - } -} - -void sca_move_actuator(bActuator *act_to_move, Object *ob, int move_up) -{ - bActuator *act, *tmp; - int val; - - val = move_up ? 1 : 2; - - /* make sure this actuator belongs to this object */ - act= ob->actuators.first; - while (act) { - if (act == act_to_move) break; - act= act->next; - } - if (!act) return; - - /* move up */ - if (val == 1 && act->prev) { - /* locate the first visible actuators before this one */ - for (tmp = act->prev; tmp; tmp=tmp->prev) { - if (tmp->flag & ACT_VISIBLE) - break; - } - if (tmp) { - BLI_remlink(&ob->actuators, act); - BLI_insertlinkbefore(&ob->actuators, tmp, act); - } - } - /* move down */ - else if (val == 2 && act->next) { - /* locate the first visible actuators after this one */ - for (tmp=act->next; tmp; tmp=tmp->next) { - if (tmp->flag & ACT_VISIBLE) - break; - } - if (tmp) { - BLI_remlink(&ob->actuators, act); - BLI_insertlinkafter(&ob->actuators, tmp, act); - } - } -} - -void link_logicbricks(void **poin, void ***ppoin, short *tot, short size) -{ - void **old_links= NULL; - - int ibrick; - - /* check if the bricks are already linked */ - for (ibrick=0; ibrick < *tot; ibrick++) { - if ((*ppoin)[ibrick] == *poin) - return; - } - - if (*ppoin) { - old_links= *ppoin; - - (*tot) ++; - *ppoin = MEM_callocN((*tot)*size, "new link"); - - for (ibrick=0; ibrick < *(tot) - 1; ibrick++) { - (*ppoin)[ibrick] = old_links[ibrick]; - } - (*ppoin)[ibrick] = *poin; - - if (old_links) MEM_freeN(old_links); - } - else { - (*tot) = 1; - *ppoin = MEM_callocN((*tot)*size, "new link"); - (*ppoin)[0] = *poin; - } -} - -void unlink_logicbricks(void **poin, void ***ppoin, short *tot) -{ - int ibrick, removed; - - removed= 0; - for (ibrick=0; ibrick < *tot; ibrick++) { - if (removed) (*ppoin)[ibrick - removed] = (*ppoin)[ibrick]; - else if ((*ppoin)[ibrick] == *poin) removed = 1; - } - - if (removed) { - (*tot) --; - - if (*tot == 0) { - MEM_freeN(*ppoin); - (*ppoin)= NULL; - } - return; - } -} - -void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *userdata) -{ - bSensor *sensor; - - for (sensor = senslist->first; sensor; sensor = sensor->next) { - func(sensor, (ID **)&sensor->ob, userdata, IDWALK_CB_NOP); - - switch (sensor->type) { - case SENS_TOUCH: /* DEPRECATED */ - { - bTouchSensor *ts = sensor->data; - func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP); - break; - } - case SENS_MESSAGE: - { - bMessageSensor *ms = sensor->data; - func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP); - break; - } - case SENS_ALWAYS: - case SENS_NEAR: - case SENS_KEYBOARD: - case SENS_PROPERTY: - case SENS_MOUSE: - case SENS_COLLISION: - case SENS_RADAR: - case SENS_RANDOM: - case SENS_RAY: - case SENS_JOYSTICK: - case SENS_ACTUATOR: - case SENS_DELAY: - case SENS_ARMATURE: - default: - break; - } - } -} - -void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, void *userdata) -{ - bController *controller; - - for (controller = contlist->first; controller; controller = controller->next) { - switch (controller->type) { - case CONT_PYTHON: - { - bPythonCont *pc = controller->data; - func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP); - break; - } - case CONT_LOGIC_AND: - case CONT_LOGIC_OR: - case CONT_EXPRESSION: - case CONT_LOGIC_NAND: - case CONT_LOGIC_NOR: - case CONT_LOGIC_XOR: - case CONT_LOGIC_XNOR: - default: - break; - } - } -} - -void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *userdata) -{ - bActuator *actuator; - - for (actuator = actlist->first; actuator; actuator = actuator->next) { - func(actuator, (ID **)&actuator->ob, userdata, IDWALK_CB_NOP); - - switch (actuator->type) { - case ACT_ADD_OBJECT: /* DEPRECATED */ - { - bAddObjectActuator *aoa = actuator->data; - func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP); - break; - } - case ACT_ACTION: - { - bActionActuator *aa = actuator->data; - func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP); - break; - } - case ACT_SOUND: - { - bSoundActuator *sa = actuator->data; - func(actuator, (ID **)&sa->sound, userdata, IDWALK_CB_NOP); - break; - } - case ACT_EDIT_OBJECT: - { - bEditObjectActuator *eoa = actuator->data; - func(actuator, (ID **)&eoa->ob, userdata, IDWALK_CB_NOP); - func(actuator, (ID **)&eoa->me, userdata, IDWALK_CB_NOP); - break; - } - case ACT_SCENE: - { - bSceneActuator *sa = actuator->data; - func(actuator, (ID **)&sa->scene, userdata, IDWALK_CB_NOP); - func(actuator, (ID **)&sa->camera, userdata, IDWALK_CB_NOP); - break; - } - case ACT_PROPERTY: - { - bPropertyActuator *pa = actuator->data; - func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP); - break; - } - case ACT_OBJECT: - { - bObjectActuator *oa = actuator->data; - func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP); - break; - } - case ACT_CAMERA: - { - bCameraActuator *ca = actuator->data; - func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP); - break; - } - case ACT_MESSAGE: - { - bMessageActuator *ma = actuator->data; - func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP); - break; - } - case ACT_2DFILTER: - { - bTwoDFilterActuator *tdfa = actuator->data; - func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP); - break; - } - case ACT_PARENT: - { - bParentActuator *pa = actuator->data; - func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP); - break; - } - case ACT_ARMATURE: - { - bArmatureActuator *aa = actuator->data; - func(actuator, (ID **)&aa->target, userdata, IDWALK_CB_NOP); - func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_CB_NOP); - break; - } - case ACT_STEERING: - { - bSteeringActuator *sa = actuator->data; - func(actuator, (ID **)&sa->target, userdata, IDWALK_CB_NOP); - func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_CB_NOP); - break; - } - /* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */ - case ACT_LAMP: - case ACT_MATERIAL: - case ACT_END_OBJECT: /* DEPRECATED */ - case ACT_CONSTRAINT: - case ACT_GROUP: - case ACT_RANDOM: - case ACT_GAME: - case ACT_VISIBILITY: - case ACT_SHAPEACTION: - case ACT_STATE: - case ACT_MOUSE: - default: - break; - } - } -} - -const char *sca_state_name_get(Object *ob, short bit) -{ - bController *cont; - unsigned int mask; - - mask = (1<<bit); - cont = ob->controllers.first; - while (cont) { - if (cont->state_mask & mask) { - return cont->name; - } - cont = cont->next; - } - return NULL; -} diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 9689ab173a8..af27103b07e 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -37,7 +37,7 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" -#include "DNA_group_types.h" +#include "DNA_collection_types.h" #include "DNA_linestyle_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" @@ -49,6 +49,7 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" #include "DNA_gpencil_types.h" #include "BLI_math.h" @@ -67,17 +68,17 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_colortools.h" -#include "BKE_depsgraph.h" #include "BKE_editmesh.h" #include "BKE_fcurve.h" #include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_group.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -92,12 +93,18 @@ #include "BKE_sequencer.h" #include "BKE_sound.h" #include "BKE_unit.h" +#include "BKE_workspace.h" #include "BKE_world.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_debug.h" +#include "DEG_depsgraph_query.h" #include "RE_engine.h" +#include "engines/eevee/eevee_lightcache.h" + #include "PIL_time.h" #include "IMB_colormanagement.h" @@ -105,8 +112,8 @@ #include "bmesh.h" -const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER"; -const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME"; +const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE"; +const char *RE_engine_id_BLENDER_OPENGL = "BLENDER_OPENGL"; const char *RE_engine_id_CYCLES = "CYCLES"; void free_avicodecdata(AviCodecData *acd) @@ -166,6 +173,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag); } + if (ts->gp_paint) { + ts->gp_paint = MEM_dupallocN(ts->gp_paint); + BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag); + } BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag); ts->imapaint.paintcursor = NULL; @@ -173,15 +184,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) ts->particle.scene = NULL; ts->particle.object = NULL; - /* duplicate Grease Pencil Drawing Brushes */ - BLI_listbase_clear(&ts->gp_brushes); - for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) { - bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); - BLI_addtail(&ts->gp_brushes, newbrush); - } - /* duplicate Grease Pencil interpolation curve */ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); + /* duplicate Grease Pencil multiframe fallof */ + ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff); return ts; } @@ -206,16 +212,20 @@ void BKE_toolsettings_free(ToolSettings *toolsettings) BKE_paint_free(&toolsettings->uvsculpt->paint); MEM_freeN(toolsettings->uvsculpt); } + if (toolsettings->gp_paint) { + BKE_paint_free(&toolsettings->gp_paint->paint); + MEM_freeN(toolsettings->gp_paint); + } BKE_paint_free(&toolsettings->imapaint.paint); - /* free Grease Pencil Drawing Brushes */ - BKE_gpencil_free_brushes(&toolsettings->gp_brushes); - BLI_freelistN(&toolsettings->gp_brushes); - /* free Grease Pencil interpolation curve */ if (toolsettings->gp_interpolate.custom_ipo) { curvemapping_free(toolsettings->gp_interpolate.custom_ipo); } + /* free Grease Pencil multiframe falloff curve */ + if (toolsettings->gp_sculpt.cur_falloff) { + curvemapping_free(toolsettings->gp_sculpt.cur_falloff); + } MEM_freeN(toolsettings); } @@ -234,25 +244,25 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; sce_dst->ed = NULL; - sce_dst->theDag = NULL; - sce_dst->depsgraph = NULL; - sce_dst->obedit = NULL; - sce_dst->stats = NULL; + sce_dst->depsgraph_hash = NULL; sce_dst->fps_info = NULL; - BLI_duplicatelist(&(sce_dst->base), &(sce_src->base)); - for (Base *base_dst = sce_dst->base.first, *base_src = sce_src->base.first; - base_dst; - base_dst = base_dst->next, base_src = base_src->next) + /* Master Collection */ + if (sce_src->master_collection) { + sce_dst->master_collection = BKE_collection_copy_master(bmain, sce_src->master_collection, flag); + } + + /* View Layers */ + BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers); + for (ViewLayer *view_layer_src = sce_src->view_layers.first, *view_layer_dst = sce_dst->view_layers.first; + view_layer_src; + view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next) { - if (base_src == sce_src->basact) { - sce_dst->basact = base_dst; - } + BKE_view_layer_copy_data(sce_dst, sce_src, view_layer_dst, view_layer_src, flag_subdata); } BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers)); BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces)); - BLI_duplicatelist(&(sce_dst->r.layers), &(sce_src->r.layers)); BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views)); BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets)); @@ -267,17 +277,6 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata); } - /* copy Freestyle settings */ - for (SceneRenderLayer *srl_dst = sce_dst->r.layers.first, *srl_src = sce_src->r.layers.first; - srl_src; - srl_dst = srl_dst->next, srl_src = srl_src->next) - { - if (srl_dst->prop != NULL) { - srl_dst->prop = IDP_CopyProperty_ex(srl_dst->prop, flag_subdata); - } - BKE_freestyle_config_copy(&srl_dst->freestyleConfig, &srl_src->freestyleConfig, flag_subdata); - } - /* copy color management settings */ BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings); BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings); @@ -322,6 +321,9 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons else { sce_dst->preview = NULL; } + + sce_dst->eevee.light_cache = NULL; + /* TODO Copy the cache. */ } Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) @@ -331,20 +333,16 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) /* TODO this should/could most likely be replaced by call to more generic code at some point... * But for now, let's keep it well isolated here. */ if (type == SCE_COPY_EMPTY) { - ListBase rl, rv; + ListBase rv; sce_copy = BKE_scene_add(bmain, sce->id.name + 2); - rl = sce_copy->r.layers; rv = sce_copy->r.views; curvemapping_free_data(&sce_copy->r.mblur_shutter_curve); sce_copy->r = sce->r; - sce_copy->r.layers = rl; - sce_copy->r.actlay = 0; sce_copy->r.views = rv; sce_copy->unit = sce->unit; sce_copy->physics_settings = sce->physics_settings; - sce_copy->gm = sce->gm; sce_copy->audio = sce->audio; if (sce->id.properties) @@ -366,6 +364,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve); + /* viewport display settings */ + sce_copy->display = sce->display; + /* tool settings */ sce_copy->toolsettings = BKE_toolsettings_copy(sce->toolsettings, 0); @@ -399,8 +400,8 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) if (type == SCE_COPY_FULL) { /* Copy Freestyle LineStyle datablocks. */ - for (SceneRenderLayer *srl_dst = sce_copy->r.layers.first; srl_dst; srl_dst = srl_dst->next) { - for (FreestyleLineSet *lineset = srl_dst->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst; view_layer_dst = view_layer_dst->next) { + for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset; lineset = lineset->next) { if (lineset->linestyle) { id_us_min(&lineset->linestyle->id); /* XXX Not copying anim/actions here? */ @@ -415,6 +416,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false); } + /* Collections */ + BKE_collection_copy_full(bmain, sce_copy->master_collection); + /* Full copy of GreasePencil. */ /* XXX Not copying anim/actions here? */ if (sce_copy->gpd) { @@ -430,7 +434,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) } /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations - * are done outside of blenkernel with ED_objects_single_users! */ + * are done outside of blenkernel with ED_object_single_users! */ /* camera */ /* XXX This is most certainly useless? Object have not yet been duplicated... */ @@ -456,15 +460,11 @@ void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local) } /** Free (or release) any data used by this scene (does not free the scene itself). */ -void BKE_scene_free(Scene *sce) +void BKE_scene_free_ex(Scene *sce, const bool do_id_user) { - SceneRenderLayer *srl; - BKE_animdata_free((ID *)sce, false); - sce->basact = NULL; - BLI_freelistN(&sce->base); - BKE_sequencer_editing_free(sce, false); + BKE_sequencer_editing_free(sce, do_id_user); BKE_keyingsets_free(&sce->keyingsets); @@ -476,8 +476,7 @@ void BKE_scene_free(Scene *sce) } if (sce->rigidbody_world) { - BKE_rigidbody_free_world(sce->rigidbody_world); - sce->rigidbody_world = NULL; + BKE_rigidbody_free_world(sce); } if (sce->r.avicodecdata) { @@ -491,27 +490,15 @@ void BKE_scene_free(Scene *sce) sce->r.ffcodecdata.properties = NULL; } - for (srl = sce->r.layers.first; srl; srl = srl->next) { - if (srl->prop != NULL) { - IDP_FreeProperty(srl->prop); - MEM_freeN(srl->prop); - } - BKE_freestyle_config_free(&srl->freestyleConfig); - } - BLI_freelistN(&sce->markers); BLI_freelistN(&sce->transform_spaces); - BLI_freelistN(&sce->r.layers); BLI_freelistN(&sce->r.views); BKE_toolsettings_free(sce->toolsettings); sce->toolsettings = NULL; - DAG_scene_free(sce); - if (sce->depsgraph) - DEG_graph_free(sce->depsgraph); + BKE_scene_free_depsgraph_hash(sce); - MEM_SAFE_FREE(sce->stats); MEM_SAFE_FREE(sce->fps_info); BKE_sound_destroy_scene(sce); @@ -520,6 +507,37 @@ void BKE_scene_free(Scene *sce) BKE_previewimg_free(&sce->preview); curvemapping_free_data(&sce->r.mblur_shutter_curve); + + for (ViewLayer *view_layer = sce->view_layers.first, *view_layer_next; view_layer; view_layer = view_layer_next) { + view_layer_next = view_layer->next; + + BLI_remlink(&sce->view_layers, view_layer); + BKE_view_layer_free_ex(view_layer, do_id_user); + } + + /* Master Collection */ + // TODO: what to do with do_id_user? it's also true when just + // closing the file which seems wrong? should decrement users + // for objects directly in the master collection? then other + // collections in the scene need to do it too? + if (sce->master_collection) { + BKE_collection_free(sce->master_collection); + MEM_freeN(sce->master_collection); + sce->master_collection = NULL; + } + + if (sce->eevee.light_cache) { + EEVEE_lightcache_free(sce->eevee.light_cache); + sce->eevee.light_cache = NULL; + } + + /* These are freed on doversion. */ + BLI_assert(sce->layer_properties == NULL); +} + +void BKE_scene_free(Scene *sce) +{ + BKE_scene_free_ex(sce, true); } void BKE_scene_init(Scene *sce) @@ -532,9 +550,7 @@ void BKE_scene_init(Scene *sce) BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id)); - sce->lay = sce->layact = 1; - - sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE; + sce->r.mode = R_OSA; sce->r.cfra = 1; sce->r.sfra = 1; sce->r.efra = 250; @@ -545,9 +561,7 @@ void BKE_scene_init(Scene *sce) sce->r.yasp = 1; sce->r.tilex = 256; sce->r.tiley = 256; - sce->r.mblur_samples = 1; - sce->r.filtertype = R_FILTER_MITCH; - sce->r.size = 50; + sce->r.size = 100; sce->r.im_format.planes = R_IMF_PLANES_RGBA; sce->r.im_format.imtype = R_IMF_IMTYPE_PNG; @@ -555,15 +569,13 @@ void BKE_scene_init(Scene *sce) sce->r.im_format.quality = 90; sce->r.im_format.compress = 15; - sce->r.displaymode = R_OUTPUT_AREA; + sce->r.displaymode = R_OUTPUT_WINDOW; sce->r.framapto = 100; sce->r.images = 100; sce->r.framelen = 1.0; sce->r.blurfac = 0.5; sce->r.frs_sec = 24; sce->r.frs_sec_base = 1; - sce->r.edgeint = 10; - sce->r.ocres = 128; /* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used, * images would look in the same way as in current blender @@ -572,18 +584,11 @@ void BKE_scene_init(Scene *sce) */ sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT; - sce->r.gauss = 1.0; - - /* deprecated but keep for upwards compat */ - sce->r.postgamma = 1.0; - sce->r.posthue = 0.0; - sce->r.postsat = 1.0; + sce->r.dither_intensity = 1.0f; - sce->r.bake_mode = 1; /* prevent to include render stuff here */ + sce->r.bake_mode = 0; sce->r.bake_filter = 16; - sce->r.bake_osa = 5; sce->r.bake_flag = R_BAKE_CLEAR; - sce->r.bake_normal_space = R_BAKE_SPACE_TANGENT; sce->r.bake_samples = 256; sce->r.bake_biasdist = 0.001; @@ -611,7 +616,6 @@ void BKE_scene_init(Scene *sce) sce->r.fg_stamp[3] = 1.0f; sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f; sce->r.bg_stamp[3] = 0.25f; - sce->r.raytrace_options = R_RAYTRACE_USE_INSTANCES; sce->r.seq_prev_type = OB_SOLID; sce->r.seq_rend_type = OB_SOLID; @@ -621,8 +625,6 @@ void BKE_scene_init(Scene *sce) sce->r.simplify_subsurf = 6; sce->r.simplify_particles = 1.0f; - sce->r.simplify_shadowsamples = 16; - sce->r.simplify_aosss = 1.0f; sce->r.border.xmin = 0.0f; sce->r.border.ymin = 0.0f; @@ -643,33 +645,25 @@ void BKE_scene_init(Scene *sce) CURVEMAP_SLOPE_POS_NEG); sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct"); + + sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK; sce->toolsettings->doublimit = 0.001; sce->toolsettings->vgroup_weight = 1.0f; sce->toolsettings->uvcalc_margin = 0.001f; + sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT; sce->toolsettings->unwrapper = 1; sce->toolsettings->select_thresh = 0.01f; + sce->toolsettings->gizmo_flag = SCE_GIZMO_SHOW_TRANSLATE | SCE_GIZMO_SHOW_ROTATE | SCE_GIZMO_SHOW_SCALE; sce->toolsettings->selectmode = SCE_SELECT_VERTEX; sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX; - sce->toolsettings->normalsize = 0.1; sce->toolsettings->autokey_mode = U.autokey_mode; - sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; - sce->toolsettings->skgen_resolution = 100; - sce->toolsettings->skgen_threshold_internal = 0.01f; - sce->toolsettings->skgen_threshold_external = 0.01f; - sce->toolsettings->skgen_angle_limit = 45.0f; - sce->toolsettings->skgen_length_ratio = 1.3f; - sce->toolsettings->skgen_length_limit = 1.5f; - sce->toolsettings->skgen_correlation_limit = 0.98f; - sce->toolsettings->skgen_symmetry_limit = 0.1f; - sce->toolsettings->skgen_postpro = SKGEN_SMOOTH; - sce->toolsettings->skgen_postpro_passes = 1; - sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL | SKGEN_FILTER_EXTERNAL | SKGEN_FILTER_SMART | SKGEN_HARMONIC | SKGEN_SUB_CORRELATION | SKGEN_STICK_TO_EMBEDDING; - sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION; - sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH; - sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE; + sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN; + sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; + sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; + sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT; sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER; sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT; @@ -694,12 +688,25 @@ void BKE_scene_init(Scene *sce) sce->toolsettings->imapaint.normal_angle = 80; sce->toolsettings->imapaint.seam_bleed = 2; + /* grease pencil multiframe falloff curve */ + sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff; + curvemapping_initialize(gp_falloff_curve); + curvemap_reset(gp_falloff_curve->cm, + &gp_falloff_curve->clipr, + CURVE_PRESET_GAUSS, + CURVEMAP_SLOPE_POSITIVE); + sce->physics_settings.gravity[0] = 0.0f; sce->physics_settings.gravity[1] = 0.0f; sce->physics_settings.gravity[2] = -9.81f; sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY; + sce->unit.system = USER_UNIT_METRIC; sce->unit.scale_length = 1.0f; + sce->unit.length_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH); + sce->unit.mass_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS); + sce->unit.time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME); pset = &sce->toolsettings->particle; pset->flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY; @@ -724,12 +731,13 @@ void BKE_scene_init(Scene *sce) sce->r.ffcodecdata.audio_bitrate = 192; sce->r.ffcodecdata.audio_channels = 2; - BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine)); + BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine)); sce->audio.distance_model = 2.0f; sce->audio.doppler_factor = 1.0f; sce->audio.speed_of_sound = 343.3f; sce->audio.volume = 1.0f; + sce->audio.flag = AUDIO_SYNC; BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic)); @@ -737,7 +745,6 @@ void BKE_scene_init(Scene *sce) sce->r.osa = 8; /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */ - BKE_scene_add_render_layer(sce, NULL); /* multiview - stereo */ BKE_scene_add_render_view(sce, STEREO_LEFT_NAME); @@ -748,59 +755,6 @@ void BKE_scene_init(Scene *sce) srv = sce->r.views.last; BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix)); - /* game data */ - sce->gm.stereoflag = STEREO_NOSTEREO; - sce->gm.stereomode = STEREO_ANAGLYPH; - sce->gm.eyeseparation = 0.10; - - sce->gm.dome.angle = 180; - sce->gm.dome.mode = DOME_FISHEYE; - sce->gm.dome.res = 4; - sce->gm.dome.resbuf = 1.0f; - sce->gm.dome.tilt = 0; - - sce->gm.xplay = 640; - sce->gm.yplay = 480; - sce->gm.freqplay = 60; - sce->gm.depth = 32; - - sce->gm.gravity = 9.8f; - sce->gm.physicsEngine = WOPHY_BULLET; - sce->gm.mode = 32; //XXX ugly harcoding, still not sure we should drop mode. 32 == 1 << 5 == use_occlusion_culling - sce->gm.occlusionRes = 128; - sce->gm.ticrate = 60; - sce->gm.maxlogicstep = 5; - sce->gm.physubstep = 1; - sce->gm.maxphystep = 5; - sce->gm.lineardeactthreshold = 0.8f; - sce->gm.angulardeactthreshold = 1.0f; - sce->gm.deactivationtime = 0.0f; - - sce->gm.flag = GAME_DISPLAY_LISTS; - sce->gm.matmode = GAME_MAT_MULTITEX; - - sce->gm.obstacleSimulation = OBSTSIMULATION_NONE; - sce->gm.levelHeight = 2.f; - - sce->gm.recastData.cellsize = 0.3f; - sce->gm.recastData.cellheight = 0.2f; - sce->gm.recastData.agentmaxslope = M_PI_4; - sce->gm.recastData.agentmaxclimb = 0.9f; - sce->gm.recastData.agentheight = 2.0f; - sce->gm.recastData.agentradius = 0.6f; - sce->gm.recastData.edgemaxlen = 12.0f; - sce->gm.recastData.edgemaxerror = 1.3f; - sce->gm.recastData.regionminsize = 8.f; - sce->gm.recastData.regionmergesize = 20.f; - sce->gm.recastData.vertsperpoly = 6; - sce->gm.recastData.detailsampledist = 6.0f; - sce->gm.recastData.detailsamplemaxerror = 1.0f; - - sce->gm.lodflag = SCE_LOD_USE_HYST; - sce->gm.scehysteresis = 10; - - sce->gm.exitkey = 218; // Blender key code for ESC - BKE_sound_create_scene(sce); /* color management */ @@ -823,46 +777,65 @@ void BKE_scene_init(Scene *sce) { GP_BrushEdit_Settings *gset = &sce->toolsettings->gp_sculpt; GP_EditBrush_Data *gp_brush; + float curcolor_add[3], curcolor_sub[3]; + ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f); + ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH]; gp_brush->size = 25; gp_brush->strength = 0.3f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS]; gp_brush->size = 25; gp_brush->strength = 0.5f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH]; gp_brush->size = 25; gp_brush->strength = 0.5f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB]; gp_brush->size = 50; gp_brush->strength = 0.3f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH]; gp_brush->size = 25; gp_brush->strength = 0.3f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST]; gp_brush->size = 50; gp_brush->strength = 0.3f; // XXX? - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH]; gp_brush->size = 50; gp_brush->strength = 0.5f; // XXX? - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE]; gp_brush->size = 25; gp_brush->strength = 0.5f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); } /* GP Stroke Placement */ @@ -870,6 +843,87 @@ void BKE_scene_init(Scene *sce) sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE; + + /* Annotations */ + sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR; + sce->toolsettings->annotate_thickness = 3; + + sce->orientation_index_custom = -1; + + /* Master Collection */ + sce->master_collection = BKE_collection_master_add(); + + BKE_view_layer_add(sce, "View Layer"); + + /* SceneDisplay */ + copy_v3_v3(sce->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3}); + sce->display.shadow_shift = 0.1; + + sce->display.matcap_ssao_distance = 0.2f; + sce->display.matcap_ssao_attenuation = 1.0f; + sce->display.matcap_ssao_samples = 16; + + /* OpenGL Render. */ + BKE_screen_view3d_shading_init(&sce->display.shading); + + /* SceneEEVEE */ + sce->eevee.gi_diffuse_bounces = 3; + sce->eevee.gi_cubemap_resolution = 512; + sce->eevee.gi_visibility_resolution = 32; + sce->eevee.gi_cubemap_draw_size = 0.3f; + sce->eevee.gi_irradiance_draw_size = 0.1f; + + sce->eevee.taa_samples = 16; + sce->eevee.taa_render_samples = 64; + + sce->eevee.sss_samples = 7; + sce->eevee.sss_jitter_threshold = 0.3f; + + sce->eevee.ssr_quality = 0.25f; + sce->eevee.ssr_max_roughness = 0.5f; + sce->eevee.ssr_thickness = 0.2f; + sce->eevee.ssr_border_fade = 0.075f; + sce->eevee.ssr_firefly_fac = 10.0f; + + sce->eevee.volumetric_start = 0.1f; + sce->eevee.volumetric_end = 100.0f; + sce->eevee.volumetric_tile_size = 8; + sce->eevee.volumetric_samples = 64; + sce->eevee.volumetric_sample_distribution = 0.8f; + sce->eevee.volumetric_light_clamp = 0.0f; + sce->eevee.volumetric_shadow_samples = 16; + + sce->eevee.gtao_distance = 0.2f; + sce->eevee.gtao_factor = 1.0f; + sce->eevee.gtao_quality = 0.25f; + + sce->eevee.bokeh_max_size = 100.0f; + sce->eevee.bokeh_threshold = 1.0f; + + copy_v3_fl(sce->eevee.bloom_color, 1.0f); + sce->eevee.bloom_threshold = 0.8f; + sce->eevee.bloom_knee = 0.5f; + sce->eevee.bloom_intensity = 0.8f; + sce->eevee.bloom_radius = 6.5f; + sce->eevee.bloom_clamp = 1.0f; + + sce->eevee.motion_blur_samples = 8; + sce->eevee.motion_blur_shutter = 1.0f; + + sce->eevee.shadow_method = SHADOW_ESM; + sce->eevee.shadow_cube_size = 512; + sce->eevee.shadow_cascade_size = 1024; + + sce->eevee.light_cache = NULL; + + sce->eevee.overscan = 3.0f; + + sce->eevee.flag = + SCE_EEVEE_VOLUMETRIC_LIGHTS | + SCE_EEVEE_GTAO_BENT_NORMALS | + SCE_EEVEE_GTAO_BOUNCE | + SCE_EEVEE_TAA_REPROJECTION | + SCE_EEVEE_SSR_HALF_RESOLUTION; } Scene *BKE_scene_add(Main *bmain, const char *name) @@ -885,75 +939,54 @@ Scene *BKE_scene_add(Main *bmain, const char *name) return sce; } -Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) +/** + * Check if there is any instance of the object in the scene + */ +bool BKE_scene_object_find(Scene *scene, Object *ob) { - Base *base; - - for (base = scene->base.first; base; base = base->next) { - if (STREQ(base->object->id.name + 2, name)) { - break; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) { + return true; } } - - return base; + return false; } -Base *BKE_scene_base_find(Scene *scene, Object *ob) +Object *BKE_scene_object_find_by_name(Scene *scene, const char *name) { - return BLI_findptr(&scene->base, ob, offsetof(Base, object)); + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (STREQ(base->object->id.name + 2, name)) { + return base->object; + } + } + } + return NULL; } /** * Sets the active scene, mainly used when running in background mode (``--scene`` command line argument). * This is also called to set the scene directly, bypassing windowing code. - * Otherwise #ED_screen_set_scene is used when changing scenes by the user. + * Otherwise #WM_window_set_active_scene is used when changing scenes by the user. */ void BKE_scene_set_background(Main *bmain, Scene *scene) { - Scene *sce; - Base *base; Object *ob; - Group *group; - GroupObject *go; - int flag; /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); - /* can happen when switching modes in other scenes */ - if (scene->obedit && !(scene->obedit->mode & OB_MODE_EDIT)) - scene->obedit = NULL; - /* deselect objects (for dataselect) */ for (ob = bmain->object.first; ob; ob = ob->id.next) - ob->flag &= ~(SELECT | OB_FROMGROUP); - - /* group flags again */ - for (group = bmain->group.first; group; group = group->id.next) { - for (go = group->gobject.first; go; go = go->next) { - if (go->ob) { - go->ob->flag |= OB_FROMGROUP; - } - } - } - - /* sort baselist for scene and sets */ - for (sce = scene; sce; sce = sce->set) - DAG_scene_relations_rebuild(bmain, sce); + ob->flag &= ~SELECT; /* copy layers and flags from bases to objects */ - for (base = scene->base.first; base; base = base->next) { - ob = base->object; - ob->lay = base->lay; - - /* group patch... */ - base->flag &= ~(OB_FROMGROUP); - flag = ob->flag & (OB_FROMGROUP); - base->flag |= flag; - - /* not too nice... for recovering objects with lost data */ - //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE; - ob->flag = base->flag; + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + ob = base->object; + /* collection patch... */ + BKE_scene_object_base_flag_sync_from_base(base); + } } /* no full animation update, this to enable render code to work (render code calls own animation updates) */ } @@ -973,8 +1006,8 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) } /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ -int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBaseIter *iter, - Scene **scene, int val, Base **base, Object **ob) +int BKE_scene_base_iter_next(Depsgraph *depsgraph, SceneBaseIter *iter, + Scene **scene, int val, Base **base, Object **ob) { bool run_again = true; @@ -992,17 +1025,21 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase /* the first base */ if (iter->phase == F_START) { - *base = (*scene)->base.first; + ViewLayer *view_layer = (depsgraph) ? + DEG_get_evaluated_view_layer(depsgraph) : + BKE_view_layer_context_active_PLACEHOLDER(*scene); + *base = view_layer->object_bases.first; if (*base) { *ob = (*base)->object; iter->phase = F_SCENE; } else { - /* exception: empty scene */ + /* exception: empty scene layer */ while ((*scene)->set) { (*scene) = (*scene)->set; - if ((*scene)->base.first) { - *base = (*scene)->base.first; + ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene)); + if (view_layer_set->object_bases.first) { + *base = view_layer_set->object_bases.first; *ob = (*base)->object; iter->phase = F_SCENE; break; @@ -1021,8 +1058,9 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase /* (*scene) is finished, now do the set */ while ((*scene)->set) { (*scene) = (*scene)->set; - if ((*scene)->base.first) { - *base = (*scene)->base.first; + ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene)); + if (view_layer_set->object_bases.first) { + *base = view_layer_set->object_bases.first; *ob = (*base)->object; break; } @@ -1037,12 +1075,12 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase } else { if (iter->phase != F_DUPLI) { - if ( (*base)->object->transflag & OB_DUPLI) { - /* groups cannot be duplicated for mballs yet, + if (depsgraph && (*base)->object->transflag & OB_DUPLI) { + /* collections cannot be duplicated for mballs yet, * this enters eternal loop because of - * makeDispListMBall getting called inside of group_duplilist */ + * makeDispListMBall getting called inside of collection_duplilist */ if ((*base)->object->dup_group == NULL) { - iter->duplilist = object_duplilist_ex(bmain, eval_ctx, (*scene), (*base)->object, false); + iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object); iter->dupob = iter->duplilist->first; @@ -1056,7 +1094,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase } /* handle dupli's */ if (iter->dupob) { - (*base)->flag |= OB_FROMDUPLI; + (*base)->flag_legacy |= OB_FROMDUPLI; *ob = iter->dupob->ob; iter->phase = F_DUPLI; @@ -1075,7 +1113,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase } else if (iter->phase == F_DUPLI) { iter->phase = F_SCENE; - (*base)->flag &= ~OB_FROMDUPLI; + (*base)->flag_legacy &= ~OB_FROMDUPLI; if (iter->dupli_refob) { /* Restore last object's real matrix. */ @@ -1091,22 +1129,18 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase } } -#if 0 - if (ob && *ob) { - printf("Scene: '%s', '%s'\n", (*scene)->id.name + 2, (*ob)->id.name + 2); - } -#endif - return iter->phase; } -Object *BKE_scene_camera_find(Scene *sc) +Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection) { - Base *base; - - for (base = sc->base.first; base; base = base->next) - if (base->object->type == OB_CAMERA) - return base->object; + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) { + if (BKE_view_layer_has_collection(layer, collection)) { + return scene; + } + } + } return NULL; } @@ -1160,6 +1194,7 @@ int BKE_scene_camera_switch_update(Scene *scene) Object *camera = BKE_scene_camera_switch_find(scene); if (camera) { scene->camera = camera; + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE); return 1; } #else @@ -1218,49 +1253,14 @@ int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, in return (delta_prev < delta_next) ? second_prev : second_next; } - -Base *BKE_scene_base_add(Scene *sce, Object *ob) -{ - Base *b = MEM_callocN(sizeof(*b), __func__); - BLI_addhead(&sce->base, b); - - b->object = ob; - b->flag = ob->flag; - b->lay = ob->lay; - - return b; -} - -void BKE_scene_base_unlink(Scene *sce, Base *base) +void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob) { /* remove rigid body constraint from world before removing object */ - if (base->object->rigidbody_constraint) - BKE_rigidbody_remove_constraint(sce, base->object); + if (ob->rigidbody_constraint) + BKE_rigidbody_remove_constraint(scene, ob); /* 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); - if (sce->basact == base) - sce->basact = NULL; -} - -void BKE_scene_base_deselect_all(Scene *sce) -{ - Base *b; - - for (b = sce->base.first; b; b = b->next) { - b->flag &= ~SELECT; - b->object->flag = b->flag; - } -} - -void BKE_scene_base_select(Scene *sce, Base *selbase) -{ - selbase->flag |= SELECT; - selbase->object->flag = selbase->flag; - - sce->basact = selbase; + if (ob->rigidbody_object) + BKE_rigidbody_remove_object(bmain, scene, ob); } /* checks for cycle, returns 1 if it's all OK */ @@ -1312,109 +1312,6 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra) scene->r.cfra = (int)intpart; } -#ifdef WITH_LEGACY_DEPSGRAPH -/* drivers support/hacks - * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render - * - these are always run since the depsgraph can't handle non-object data - * - these happen after objects are all done so that we can read in their final transform values, - * though this means that objects can't refer to scene info for guidance... - */ -static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) -{ - SceneRenderLayer *srl; - float ctime = BKE_scene_frame_get(scene); - - /* scene itself */ - if (scene->adt && scene->adt->drivers.first) { - BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* world */ - /* TODO: what about world textures? but then those have nodes too... */ - if (scene->world) { - ID *wid = (ID *)scene->world; - AnimData *adt = BKE_animdata_from_id(wid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* nodes */ - if (scene->nodetree) { - ID *nid = (ID *)scene->nodetree; - AnimData *adt = BKE_animdata_from_id(nid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* world nodes */ - if (scene->world && scene->world->nodetree) { - ID *nid = (ID *)scene->world->nodetree; - AnimData *adt = BKE_animdata_from_id(nid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); - } - - /* freestyle */ - for (srl = scene->r.layers.first; srl; srl = srl->next) { - FreestyleConfig *config = &srl->freestyleConfig; - FreestyleLineSet *lineset; - - for (lineset = config->linesets.first; lineset; lineset = lineset->next) { - if (lineset->linestyle) { - ID *lid = &lineset->linestyle->id; - AnimData *adt = BKE_animdata_from_id(lid); - - if (adt && adt->drivers.first) - BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS); - } - } - } -} - -/* deps hack - do extra recalcs at end */ -static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) -{ - Base *base; - - scene->customdata_mask = scene_parent->customdata_mask; - - /* sets first, we allow per definition current scene to have - * dependencies on sets, but not the other way around. */ - if (scene->set) - scene_depsgraph_hack(bmain, eval_ctx, scene->set, scene_parent); - - for (base = scene->base.first; base; base = base->next) { - Object *ob = base->object; - - if (ob->depsflag) { - int recalc = 0; - // printf("depshack %s\n", ob->id.name + 2); - - if (ob->depsflag & OB_DEPS_EXTRA_OB_RECALC) - recalc |= OB_RECALC_OB; - if (ob->depsflag & OB_DEPS_EXTRA_DATA_RECALC) - recalc |= OB_RECALC_DATA; - - ob->recalc |= recalc; - BKE_object_handle_update(bmain, eval_ctx, scene_parent, ob); - - if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) { - GroupObject *go; - - for (go = ob->dup_group->gobject.first; go; go = go->next) { - if (go->ob) - go->ob->recalc |= recalc; - } - BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, ob, ob->dup_group); - } - } - } -} -#endif /* WITH_LEGACY_DEPSGRAPH */ - /* That's like really a bummer, because currently animation data for armatures * might want to use pose, and pose might be missing on the object. * This happens when changing visible layers, which leads to situations when @@ -1427,392 +1324,41 @@ static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene #define POSE_ANIMATION_WORKAROUND #ifdef POSE_ANIMATION_WORKAROUND -static void scene_armature_depsgraph_workaround(Main *bmain) +static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph) { Object *ob; - if (BLI_listbase_is_empty(&bmain->armature) || !DAG_id_type_tagged(bmain, ID_OB)) { + if (BLI_listbase_is_empty(&bmain->armature) || !DEG_id_type_updated(depsgraph, ID_OB)) { return; } for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->type == OB_ARMATURE && ob->adt && ob->adt->recalc & ADT_RECALC_ANIM) { if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(ob, ob->data); - } - } - } -} -#endif - -#ifdef WITH_LEGACY_DEPSGRAPH -static void scene_rebuild_rbw_recursive(Scene *scene, float ctime) -{ - if (scene->set) - scene_rebuild_rbw_recursive(scene->set, ctime); - - if (BKE_scene_check_rigidbody_active(scene)) - BKE_rigidbody_rebuild_world(scene, ctime); -} - -static void scene_do_rb_simulation_recursive(Scene *scene, float ctime) -{ - if (scene->set) - scene_do_rb_simulation_recursive(scene->set, ctime); - - if (BKE_scene_check_rigidbody_active(scene)) - BKE_rigidbody_do_simulation(scene, ctime); -} -#endif - -/* Used to visualize CPU threads activity during threaded object update, - * would pollute STDERR with whole bunch of timing information which then - * could be parsed and nicely visualized. - */ -#ifdef WITH_LEGACY_DEPSGRAPH -# undef DETAILED_ANALYSIS_OUTPUT -#else -/* ALWAYS KEEY DISABLED! */ -# undef DETAILED_ANALYSIS_OUTPUT -#endif - -/* Mballs evaluation uses BKE_scene_base_iter_next which calls - * duplilist for all objects in the scene. This leads to conflict - * accessing and writing same data from multiple threads. - * - * Ideally Mballs shouldn't do such an iteration and use DAG - * queries instead. For the time being we've got new DAG - * let's keep it simple and update mballs in a single thread. - */ -#define MBALL_SINGLETHREAD_HACK - -#ifdef WITH_LEGACY_DEPSGRAPH -typedef struct StatisicsEntry { - struct StatisicsEntry *next, *prev; - Object *object; - double start_time; - double duration; -} StatisicsEntry; - -typedef struct ThreadedObjectUpdateState { - /* TODO(sergey): We might want this to be per-thread object. */ - EvaluationContext *eval_ctx; - Main *bmain; - Scene *scene; - Scene *scene_parent; - double base_time; - -#ifdef MBALL_SINGLETHREAD_HACK - bool has_mballs; -#endif - - int num_threads; - - /* Execution statistics */ - bool has_updated_objects; - ListBase *statistics; -} ThreadedObjectUpdateState; - -static void scene_update_object_add_task(void *node, void *user_data); - -static void scene_update_all_bases(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent) -{ - Base *base; - - for (base = scene->base.first; base; base = base->next) { - Object *object = base->object; - - BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, true); - - if (object->dup_group && (object->transflag & OB_DUPLIGROUP)) - BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, object, object->dup_group); - - /* always update layer, so that animating layers works (joshua july 2010) */ - /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes - * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */ - // base->lay = ob->lay; - } -} - -static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid) -{ -/* Disable print for now in favor of summary statistics at the end of update. */ -#define PRINT if (false) printf - - ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool); - void *node = taskdata; - Object *object = DAG_get_node_object(node); - EvaluationContext *eval_ctx = state->eval_ctx; - Main *bmain = state->bmain; - Scene *scene = state->scene; - Scene *scene_parent = state->scene_parent; - -#ifdef MBALL_SINGLETHREAD_HACK - if (object && object->type == OB_MBALL) { - state->has_mballs = true; - } - else -#endif - if (object) { - double start_time = 0.0; - bool add_to_stats = false; - - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - if (object->recalc & OB_RECALC_ALL) { - printf("Thread %d: update object %s\n", threadid, object->id.name); - } - - start_time = PIL_check_seconds_timer(); - - if (object->recalc & OB_RECALC_ALL) { - state->has_updated_objects = true; - add_to_stats = true; + BKE_pose_rebuild(bmain, ob, ob->data, true); } } - - /* We only update object itself here, dupli-group will be updated - * separately from main thread because of we've got no idea about - * dependencies inside the group. - */ - BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, false); - - /* Calculate statistics. */ - if (add_to_stats) { - StatisicsEntry *entry; - - entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics"); - entry->object = object; - entry->start_time = start_time; - entry->duration = PIL_check_seconds_timer() - start_time; - - BLI_addtail(&state->statistics[threadid], entry); - } } - else { - PRINT("Threda %d: update node %s\n", threadid, - DAG_get_node_name(scene, node)); - } - - /* Update will decrease child's valency and schedule child with zero valency. */ - DAG_threaded_update_handle_node_updated(node, scene_update_object_add_task, pool); - -#undef PRINT -} - -static void scene_update_object_add_task(void *node, void *user_data) -{ - TaskPool *task_pool = user_data; - - BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW); } - -static void print_threads_statistics(ThreadedObjectUpdateState *state) -{ - double finish_time; - - if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { - return; - } - -#ifdef DETAILED_ANALYSIS_OUTPUT - if (state->has_updated_objects) { - tot_thread = BLI_system_thread_count(); - - fprintf(stderr, "objects update base time %f\n", state->base_time); - - for (i = 0; i < tot_thread; i++) { - StatisicsEntry *entry; - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - fprintf(stderr, "thread %d object %s start_time %f duration %f\n", - i, entry->object->id.name + 2, - entry->start_time, entry->duration); - } - BLI_freelistN(&state->statistics[i]); - } - } -#else - finish_time = PIL_check_seconds_timer(); - int total_objects = 0; - - for (int i = 0; i < state->num_threads; i++) { - int thread_total_objects = 0; - double thread_total_time = 0.0; - StatisicsEntry *entry; - - if (state->has_updated_objects) { - /* Don't pollute output if no objects were updated. */ - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - thread_total_objects++; - thread_total_time += entry->duration; - } - - printf("Thread %d: total %d objects in %f sec.\n", - i, - thread_total_objects, - thread_total_time); - - for (entry = state->statistics[i].first; - entry; - entry = entry->next) - { - printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration); - } - - total_objects += thread_total_objects; - } - - BLI_freelistN(&state->statistics[i]); - } - if (state->has_updated_objects) { - printf("Scene updated %d objects in %f sec\n", - total_objects, - finish_time - state->base_time); - } #endif -} - -static bool scene_need_update_objects(Main *bmain) -{ - return - /* Object datablocks themselves (for OB_RECALC_OB) */ - DAG_id_type_tagged(bmain, ID_OB) || - - /* Objects data datablocks (for OB_RECALC_DATA) */ - DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */ - DAG_id_type_tagged(bmain, ID_CU) || /* Curve */ - DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */ - DAG_id_type_tagged(bmain, ID_LA) || /* Lamp */ - DAG_id_type_tagged(bmain, ID_LT) || /* Lattice */ - DAG_id_type_tagged(bmain, ID_CA) || /* Camera */ - DAG_id_type_tagged(bmain, ID_KE) || /* KE */ - DAG_id_type_tagged(bmain, ID_SPK) || /* Speaker */ - DAG_id_type_tagged(bmain, ID_AR); /* Armature */ -} - -static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent) -{ - TaskScheduler *task_scheduler; - TaskPool *task_pool; - ThreadedObjectUpdateState state; - bool need_singlethread_pass; - bool need_free_scheduler; - - /* Early check for whether we need to invoke all the task-based - * things (spawn new ppol, traverse dependency graph and so on). - * - * Basically if there's no ID datablocks tagged for update which - * corresponds to object->recalc flags (which are checked in - * BKE_object_handle_update() then we do nothing here. - */ - if (!scene_need_update_objects(bmain)) { - return; - } - - state.eval_ctx = eval_ctx; - state.bmain = bmain; - state.scene = scene; - state.scene_parent = scene_parent; - - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { - task_scheduler = BLI_task_scheduler_create(1); - need_free_scheduler = true; - } - else { - task_scheduler = BLI_task_scheduler_get(); - need_free_scheduler = false; - } - - /* Those are only needed when blender is run with --debug argument. */ - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler); - state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics), - "scene update objects stats"); - state.has_updated_objects = false; - state.base_time = PIL_check_seconds_timer(); - state.num_threads = tot_thread; - } - -#ifdef MBALL_SINGLETHREAD_HACK - state.has_mballs = false; -#endif - - task_pool = BLI_task_pool_create(task_scheduler, &state); - - DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - print_threads_statistics(&state); - MEM_freeN(state.statistics); - } - - /* We do single thread pass to update all the objects which are in cyclic dependency. - * Such objects can not be handled by a generic DAG traverse and it's really tricky - * to detect whether cycle could be solved or not. - * - * In this situation we simply update all remaining objects in a single thread and - * it'll happen in the same exact order as it was in single-threaded DAG. - * - * We couldn't use threaded update for objects which are in cycle because they might - * access data of each other which is being re-evaluated. - * - * Also, as was explained above, for now we also update all the mballs in single thread. - * - * - sergey - - */ - need_singlethread_pass = DAG_is_acyclic(scene) == false; -#ifdef MBALL_SINGLETHREAD_HACK - need_singlethread_pass |= state.has_mballs; -#endif - - if (need_singlethread_pass) { - scene_update_all_bases(bmain, eval_ctx, scene, scene_parent); - } - - if (need_free_scheduler) { - BLI_task_scheduler_free(task_scheduler); - } -} - -static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent) -{ - scene->customdata_mask = scene_parent->customdata_mask; - - /* sets first, we allow per definition current scene to have - * dependencies on sets, but not the other way around. */ - if (scene->set) - scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent); - - /* scene objects */ - scene_update_objects(eval_ctx, bmain, scene, scene_parent); - - /* scene drivers... */ - scene_update_drivers(bmain, scene); - - /* update masking curves */ - BKE_mask_update_scene(bmain, scene); - -} -#endif /* WITH_LEGACY_DEPSGRAPH */ static bool check_rendered_viewport_visible(Main *bmain) { wmWindowManager *wm = bmain->wm.first; wmWindow *window; for (window = wm->windows.first; window != NULL; window = window->next) { - bScreen *screen = window->screen; - ScrArea *area; - for (area = screen->areabase.first; area != NULL; area = area->next) { + const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + Scene *scene = window->scene; + RenderEngineType *type = RE_engines_find(scene->r.engine); + + if (type->draw_engine || !type->render) { + continue; + } + + for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) { View3D *v3d = area->spacedata.first; if (area->spacetype != SPACE_VIEW3D) { continue; } - if (v3d->drawtype == OB_RENDER) { + if (v3d->shading.type == OB_RENDER) { return true; } } @@ -1820,7 +1366,10 @@ static bool check_rendered_viewport_visible(Main *bmain) return false; } -static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) +/* TODO(campbell): shouldn't we be able to use 'DEG_get_view_layer' here? + * Currently this is NULL on load, so don't. */ +static void prepare_mesh_for_viewport_render( + Main *bmain, const ViewLayer *view_layer) { /* This is needed to prepare mesh to be used by the render * engine from the viewport rendering. We do loading here @@ -1831,7 +1380,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) * call loading of the edit data for the mesh objects. */ - Object *obedit = scene->obedit; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); if (obedit) { Mesh *mesh = obedit->data; if ((obedit->type == OB_MESH) && @@ -1845,318 +1394,96 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) (&(struct BMeshToMeshParams){ .calc_object_remap = true, })); - DAG_id_tag_update(&mesh->id, 0); + DEG_id_tag_update(&mesh->id, 0); } } } } -void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) +/* TODO(sergey): This actually should become view_layer_graph or so. + * Same applies to update_for_newframe. + */ +void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, + Main *bmain) { - Scene *sce_iter; -#ifdef WITH_LEGACY_DEPSGRAPH - bool use_new_eval = !DEG_depsgraph_use_legacy(); -#endif - - /* keep this first */ - BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE); + Scene *scene = DEG_get_input_scene(depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); - /* (re-)build dependency graph if needed */ - for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) { - DAG_scene_relations_update(bmain, sce_iter); - /* Uncomment this to check if dependency graph was properly tagged for update. */ -#if 0 -#ifdef WITH_LEGACY_DEPSGRAPH - if (use_new_eval) -#endif - { - DAG_scene_relations_validate(bmain, sce_iter); - } -#endif - } - - /* flush editing data if needed */ - prepare_mesh_for_viewport_render(bmain, scene); - - /* flush recalc flags to dependencies */ - DAG_ids_flush_tagged(bmain); - - /* removed calls to quick_cache, see pointcache.c */ - - /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later - * when trying to find materials with drivers that need evaluating [#32017] + /* TODO(sergey): Some functions here are changing global state, + * for example, clearing update tags from bmain. */ - BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false); - - /* update all objects: drivers, matrices, displists, etc. flags set - * by depgraph or manual, no layer check here, gets correct flushed - * - * in the future this should handle updates for all datablocks, not - * only objects and scenes. - brecht */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_update_tagged_recursive(eval_ctx, bmain, scene, scene); - } - else -#endif - { - DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene); - } - - /* update sound system animation (TODO, move to depsgraph) */ - BKE_sound_update_scene(bmain, scene); - - /* extra call here to recalc scene animation (for sequencer) */ - { - AnimData *adt = BKE_animdata_from_id(&scene->id); - float ctime = BKE_scene_frame_get(scene); - - if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0); - } - - /* Extra call here to recalc material animation. - * - * Need to do this so changing material settings from the graph/dopesheet - * will update stuff in the viewport. + /* (Re-)build dependency graph if needed. */ + DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); + /* Uncomment this to check if graph was properly tagged for update. */ + // DEG_debug_graph_relations_validate(depsgraph, bmain, scene); + /* Flush editing data if needed. */ + prepare_mesh_for_viewport_render(bmain, view_layer); + /* Flush recalc flags to dependencies. */ + DEG_graph_flush_update(bmain, depsgraph); + /* Update all objects: drivers, matrices, displists, etc. flags set + * by depgraph or manual, no layer check here, gets correct flushed. */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) { - Material *material; - float ctime = BKE_scene_frame_get(scene); - - for (material = bmain->mat.first; - material; - material = material->id.next) - { - AnimData *adt = BKE_animdata_from_id(&material->id); - if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0); - } - } - - /* Also do the same for node trees. */ - if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) { - float ctime = BKE_scene_frame_get(scene); - - FOREACH_NODETREE(bmain, ntree, id) - { - AnimData *adt = BKE_animdata_from_id(&ntree->id); - if (adt && (adt->recalc & ADT_RECALC_ANIM)) - BKE_animsys_evaluate_animdata(scene, &ntree->id, adt, ctime, 0); - } - FOREACH_NODETREE_END - } -#endif - - /* notify editors and python about recalc */ - BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST); - + DEG_evaluate_on_refresh(depsgraph); + /* Update sound system animation (TODO, move to depsgraph). */ + BKE_sound_update_scene(bmain, scene); /* Inform editors about possible changes. */ - DAG_ids_check_recalc(bmain, scene, false); - - /* clear recalc flags */ - DAG_ids_clear_recalc(bmain); + DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false); + /* Clear recalc flags. */ + DEG_ids_clear_recalc(bmain, depsgraph); } /* applies changes right away, does all sets too */ -void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay) -{ - BKE_scene_update_for_newframe_ex(eval_ctx, bmain, sce, lay, false); -} - -void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool do_invisible_flush) +void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, + Main *bmain) { - float ctime = BKE_scene_frame_get(sce); - Scene *sce_iter; -#ifdef DETAILED_ANALYSIS_OUTPUT - double start_time = PIL_check_seconds_timer(); -#endif -#ifdef WITH_LEGACY_DEPSGRAPH - bool use_new_eval = !DEG_depsgraph_use_legacy(); -#else - /* TODO(sergey): Pass to evaluation routines instead of storing layer in the dependency graph? */ - (void) do_invisible_flush; -#endif - - DAG_editors_update_pre(bmain, sce, true); - - /* keep this first */ - BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE); - BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_PRE); - - /* update animated image textures for particles, modifiers, gpu, etc, - * call this at the start so modifiers with textures don't lag 1 frame */ - BKE_image_update_frame(bmain, sce->r.cfra); + Scene *scene = DEG_get_input_scene(depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); -#ifdef WITH_LEGACY_DEPSGRAPH - /* rebuild rigid body worlds before doing the actual frame update - * this needs to be done on start frame but animation playback usually starts one frame later - * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive + /* TODO(sergey): Some functions here are changing global state, + * for example, clearing update tags from bmain. */ - if (!use_new_eval) { - scene_rebuild_rbw_recursive(sce, ctime); - } -#endif - - BKE_sound_set_cfra(sce->r.cfra); - - /* clear animation overrides */ - /* XXX TODO... */ - - for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set) - DAG_scene_relations_update(bmain, sce_iter); - -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - /* flush recalc flags to dependencies, if we were only changing a frame - * this would not be necessary, but if a user or a script has modified - * some datablock before BKE_scene_update_tagged was called, we need the flush */ - DAG_ids_flush_tagged(bmain); - - /* Following 2 functions are recursive - * so don't call within 'scene_update_tagged_recursive' */ - DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still - BKE_mask_evaluate_all_masks(bmain, ctime, true); - } -#endif - - /* Update animated cache files for modifiers. */ - BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base)); - -#ifdef POSE_ANIMATION_WORKAROUND - scene_armature_depsgraph_workaround(bmain); -#endif - - /* All 'standard' (i.e. without any dependencies) animation is handled here, - * with an 'local' to 'macro' order of evaluation. This should ensure that - * settings stored nestled within a hierarchy (i.e. settings in a Texture block - * can be overridden by settings from Scene, which owns the Texture through a hierarchy - * such as Scene->World->MTex/Texture) can still get correctly overridden. + const float ctime = BKE_scene_frame_get(scene); + /* Keep this first. */ + BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE); + /* Update animated image textures for particles, modifiers, gpu, etc, + * call this at the start so modifiers with textures don't lag 1 frame. */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - BKE_animsys_evaluate_all_animation(bmain, sce, ctime); - /*...done with recursive funcs */ - } -#endif - - /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later - * when trying to find materials with drivers that need evaluating [#32017] + BKE_image_update_frame(bmain, scene->r.cfra); + BKE_sound_set_cfra(scene->r.cfra); + DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); + /* Update animated cache files for modifiers. + * + * TODO(sergey): Make this a depsgraph node? */ - BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false); - BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false); - - /* run rigidbody sim */ - /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_do_rb_simulation_recursive(sce, ctime); - } -#endif - - /* BKE_object_handle_update() on all objects, groups and sets */ -#ifdef WITH_LEGACY_DEPSGRAPH - if (use_new_eval) { - DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); - } - else { - scene_update_tagged_recursive(eval_ctx, bmain, sce, sce); - } -#else - DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay); -#endif - - /* update sound system animation (TODO, move to depsgraph) */ - BKE_sound_update_scene(bmain, sce); - -#ifdef WITH_LEGACY_DEPSGRAPH - if (!use_new_eval) { - scene_depsgraph_hack(bmain, eval_ctx, sce, sce); - } + BKE_cachefile_update_frame(bmain, depsgraph, scene, ctime, + (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base)); +#ifdef POSE_ANIMATION_WORKAROUND + scene_armature_depsgraph_workaround(bmain, depsgraph); #endif - - /* notify editors and python about recalc */ - BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST); - BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST); - + /* Update all objects: drivers, matrices, displists, etc. flags set + * by depgraph or manual, no layer check here, gets correct flushed. + */ + DEG_evaluate_on_framechange(bmain, depsgraph, ctime); + /* Update sound system animation (TODO, move to depsgraph). */ + BKE_sound_update_scene(bmain, scene); + /* Notify editors and python about recalc. */ + BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST); /* Inform editors about possible changes. */ - DAG_ids_check_recalc(bmain, sce, true); - + DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true); /* clear recalc flags */ - DAG_ids_clear_recalc(bmain); - -#ifdef DETAILED_ANALYSIS_OUTPUT - fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time); -#endif + DEG_ids_clear_recalc(bmain, depsgraph); } -/* return default layer, also used to patch old files */ -SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name) +/** Ensures given scene/view_layer pair has a valid, up-to-date depsgraph. + * + * \warning Sets matching depsgraph as active, so should only be called from the active editing context + * (usually, from operators). + */ +void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer) { - SceneRenderLayer *srl; - - if (!name) - name = DATA_("RenderLayer"); - - srl = MEM_callocN(sizeof(SceneRenderLayer), "new render layer"); - BLI_strncpy(srl->name, name, sizeof(srl->name)); - BLI_uniquename(&sce->r.layers, srl, DATA_("RenderLayer"), '.', offsetof(SceneRenderLayer, name), sizeof(srl->name)); - BLI_addtail(&sce->r.layers, srl); - - /* note, this is also in render, pipeline.c, to make layer when scenedata doesnt have it */ - srl->lay = (1 << 20) - 1; - srl->layflag = 0x7FFF; /* solid ztra halo edge strand */ - srl->passflag = SCE_PASS_COMBINED | SCE_PASS_Z; - srl->pass_alpha_threshold = 0.5f; - BKE_freestyle_config_init(&srl->freestyleConfig); - - return srl; -} - -bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *srl) -{ - const int act = BLI_findindex(&scene->r.layers, srl); - Scene *sce; - - if (act == -1) { - return false; - } - else if ( (scene->r.layers.first == scene->r.layers.last) && - (scene->r.layers.first == srl)) - { - /* ensure 1 layer is kept */ - return false; - } - - BKE_freestyle_config_free(&srl->freestyleConfig); - - if (srl->prop) { - IDP_FreeProperty(srl->prop); - MEM_freeN(srl->prop); - } - - BLI_remlink(&scene->r.layers, srl); - MEM_freeN(srl); - - scene->r.actlay = 0; - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->nodetree) { - bNode *node; - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { - if (node->custom1 == act) - node->custom1 = 0; - else if (node->custom1 > act) - node->custom1--; - } - } - } - } - - return true; + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + DEG_make_active(depsgraph); + BKE_scene_graph_update_tagged(depsgraph, bmain); } /* return default view */ @@ -2223,37 +1550,34 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend } } -int get_render_shadow_samples(const RenderData *r, int samples) -{ - if ((r->mode & R_SIMPLIFY) && samples > 0) - return min_ii(r->simplify_shadowsamples, samples); - else - return samples; -} - -float get_render_aosss_error(const RenderData *r, float error) -{ - if (r->mode & R_SIMPLIFY) - return ((1.0f - r->simplify_aosss) * 10.0f + 1.0f) * error; - else - return error; -} - -/* helper function for the SETLOOPER macro */ -Base *_setlooper_base_step(Scene **sce_iter, Base *base) +/** + * Helper function for the SETLOOPER and SETLOOPER_VIEW_LAYER macros + * + * It iterates over the bases of the active layer and then the bases + * of the active layer of the background (set) scenes recursively. + */ +Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base) { if (base && base->next) { - /* common case, step to the next */ + /* Common case, step to the next. */ return base->next; } - else if (base == NULL && (*sce_iter)->base.first) { - /* first time looping, return the scenes first base */ - return (Base *)(*sce_iter)->base.first; + else if ((base == NULL) && (view_layer != NULL)) { + /* First time looping, return the scenes first base. */ + /* For the first loop we should get the layer from workspace when available. */ + if (view_layer->object_bases.first) { + return (Base *)view_layer->object_bases.first; + } + /* No base on this scene layer. */ + goto next_set; } else { - /* reached the end, get the next base in the set */ +next_set: + /* Reached the end, get the next base in the set. */ while ((*sce_iter = (*sce_iter)->set)) { - base = (Base *)(*sce_iter)->base.first; + ViewLayer *view_layer_set = BKE_view_layer_default_render((*sce_iter)); + base = (Base *)view_layer_set->object_bases.first; + if (base) { return base; } @@ -2263,58 +1587,68 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base) return NULL; } -bool BKE_scene_use_new_shading_nodes(const Scene *scene) -{ - const RenderEngineType *type = RE_engines_find(scene->r.engine); - return (type && type->flag & RE_USE_SHADING_NODES); -} - bool BKE_scene_use_shading_nodes_custom(Scene *scene) { RenderEngineType *type = RE_engines_find(scene->r.engine); return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM); } -bool BKE_scene_use_world_space_shading(Scene *scene) -{ - const RenderEngineType *type = RE_engines_find(scene->r.engine); - return ((scene->r.mode & R_USE_WS_SHADING) || - (type && (type->flag & RE_USE_SHADING_NODES))); -} - bool BKE_scene_use_spherical_stereo(Scene *scene) { RenderEngineType *type = RE_engines_find(scene->r.engine); return (type && type->flag & RE_USE_SPHERICAL_STEREO); } -bool BKE_scene_uses_blender_internal(const Scene *scene) +bool BKE_scene_uses_blender_eevee(const Scene *scene) +{ + return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE); +} + +bool BKE_scene_uses_blender_opengl(const Scene *scene) { - return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER); + return STREQ(scene->r.engine, RE_engine_id_BLENDER_OPENGL); } -bool BKE_scene_uses_blender_game(const Scene *scene) +bool BKE_scene_uses_cycles(const Scene *scene) { - return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME); + return STREQ(scene->r.engine, RE_engine_id_CYCLES); } -void BKE_scene_base_flag_to_objects(struct Scene *scene) +void BKE_scene_base_flag_to_objects(ViewLayer *view_layer) { - Base *base = scene->base.first; + Base *base = view_layer->object_bases.first; while (base) { - base->object->flag = base->flag; + BKE_scene_object_base_flag_sync_from_base(base); base = base->next; } } -void BKE_scene_base_flag_from_objects(struct Scene *scene) +void BKE_scene_object_base_flag_sync_from_base(Base *base) { - Base *base = scene->base.first; + Object *ob = base->object; - while (base) { - base->flag = base->object->flag; - base = base->next; + ob->flag = base->flag; + + if ((base->flag & BASE_SELECTED) != 0) { + ob->flag |= SELECT; + } + else { + ob->flag &= ~SELECT; + } +} + +void BKE_scene_object_base_flag_sync_from_object(Base *base) +{ + Object *ob = base->object; + base->flag = ob->flag; + + if ((ob->flag & SELECT) != 0) { + base->flag |= BASE_SELECTED; + BLI_assert((base->flag & BASE_SELECTABLE) != 0); + } + else { + base->flag &= ~BASE_SELECTED; } } @@ -2683,3 +2017,146 @@ int BKE_scene_multiview_num_videos_get(const RenderData *rd) return BKE_scene_multiview_num_views_get(rd); } } + +/* Manipulation of depsgraph storage. */ + +/* This is a key which identifies depsgraph. */ +typedef struct DepsgraphKey { + ViewLayer *view_layer; + /* TODO(sergey): Need to include window somehow (same layer might be in a + * different states in different windows). + */ +} DepsgraphKey; + +static unsigned int depsgraph_key_hash(const void *key_v) +{ + const DepsgraphKey *key = key_v; + unsigned int hash = BLI_ghashutil_ptrhash(key->view_layer); + /* TODO(sergey): Include hash from other fields in the key. */ + return hash; +} + +static bool depsgraph_key_compare(const void *key_a_v, const void *key_b_v) +{ + const DepsgraphKey *key_a = key_a_v; + const DepsgraphKey *key_b = key_b_v; + /* TODO(sergey): Compare rest of */ + return !(key_a->view_layer == key_b->view_layer); +} + +static void depsgraph_key_free(void *key_v) +{ + DepsgraphKey *key = key_v; + MEM_freeN(key); +} + +static void depsgraph_key_value_free(void *value) +{ + Depsgraph *depsgraph = value; + DEG_graph_free(depsgraph); +} + +void BKE_scene_allocate_depsgraph_hash(Scene *scene) +{ + scene->depsgraph_hash = BLI_ghash_new(depsgraph_key_hash, + depsgraph_key_compare, + "Scene Depsgraph Hash"); +} + +void BKE_scene_ensure_depsgraph_hash(Scene *scene) +{ + if (scene->depsgraph_hash == NULL) { + BKE_scene_allocate_depsgraph_hash(scene); + } +} + +void BKE_scene_free_depsgraph_hash(Scene *scene) +{ + if (scene->depsgraph_hash == NULL) { + return; + } + BLI_ghash_free(scene->depsgraph_hash, + depsgraph_key_free, + depsgraph_key_value_free); +} + +/* Query depsgraph for a specific contexts. */ + +Depsgraph *BKE_scene_get_depsgraph(Scene *scene, + ViewLayer *view_layer, + bool allocate) +{ + BLI_assert(scene != NULL); + BLI_assert(view_layer != NULL); + /* Make sure hash itself exists. */ + if (allocate) { + BKE_scene_ensure_depsgraph_hash(scene); + } + if (scene->depsgraph_hash == NULL) { + return NULL; + } + /* Either ensure item is in the hash or simply return NULL if it's not, + * depending on whether caller wants us to create depsgraph or not. + */ + DepsgraphKey key; + key.view_layer = view_layer; + Depsgraph *depsgraph; + if (allocate) { + DepsgraphKey **key_ptr; + Depsgraph **depsgraph_ptr; + if (!BLI_ghash_ensure_p_ex(scene->depsgraph_hash, + &key, + (void ***)&key_ptr, + (void ***)&depsgraph_ptr)) + { + *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__); + **key_ptr = key; + *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT); + /* TODO(sergey): Would be cool to avoid string format print, + * but is a bit tricky because we can't know in advance whether + * we will ever enable debug messages for this depsgraph. + */ + char name[1024]; + BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name); + DEG_debug_name_set(*depsgraph_ptr, name); + } + depsgraph = *depsgraph_ptr; + } + else { + depsgraph = BLI_ghash_lookup(scene->depsgraph_hash, &key); + } + return depsgraph; +} + +/* -------------------------------------------------------------------- */ +/** \name Scene Orientation + * \{ */ + +void BKE_scene_transform_orientation_remove( + Scene *scene, TransformOrientation *orientation) +{ + const int orientation_index = BKE_scene_transform_orientation_get_index(scene, orientation); + if (scene->orientation_index_custom == orientation_index) { + /* could also use orientation_index-- */ + scene->orientation_type = V3D_MANIP_GLOBAL; + scene->orientation_index_custom = -1; + } + BLI_freelinkN(&scene->transform_spaces, orientation); +} + +TransformOrientation *BKE_scene_transform_orientation_find( + const Scene *scene, const int index) +{ + return BLI_findlink(&scene->transform_spaces, index); +} + +/** + * \return the index that \a orientation has within \a scene's transform-orientation list or -1 if not found. + */ +int BKE_scene_transform_orientation_get_index( + const Scene *scene, const TransformOrientation *orientation) +{ + return BLI_findindex(&scene->transform_spaces, orientation); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 3c615221564..84962e9b03f 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -39,19 +39,21 @@ #include "MEM_guardedalloc.h" -#include "GPU_compositing.h" - #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" +#include "DNA_workspace_types.h" +#include "BLI_math_vector.h" #include "BLI_listbase.h" -#include "BLI_utildefines.h" #include "BLI_rect.h" +#include "BLI_utildefines.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_screen.h" +#include "BKE_workspace.h" /* ************ Spacetype/regiontype handling ************** */ @@ -72,6 +74,8 @@ static void spacetype_free(SpaceType *st) if (pt->ext.free) { pt->ext.free(pt->ext.data); } + + BLI_freelistN(&pt->children); } for (ht = art->headertypes.first; ht; ht = ht->next) { @@ -85,8 +89,6 @@ static void spacetype_free(SpaceType *st) } BLI_freelistN(&st->regiontypes); - BLI_freelistN(&st->toolshelf); - } void BKE_spacetypes_free(void) @@ -184,10 +186,35 @@ void BKE_spacedata_freelist(ListBase *lb) BLI_freelistN(lb); } +static void panel_list_copy(ListBase *newlb, const ListBase *lb) +{ + BLI_listbase_clear(newlb); + BLI_duplicatelist(newlb, lb); + + /* copy panel pointers */ + Panel *newpa = newlb->first; + Panel *pa = lb->first; + for (; newpa; newpa = newpa->next, pa = pa->next) { + newpa->activedata = NULL; + + Panel *newpatab = newlb->first; + Panel *patab = lb->first; + while (newpatab) { + if (newpa->paneltab == patab) { + newpa->paneltab = newpatab; + break; + } + newpatab = newpatab->next; + patab = patab->next; + } + + panel_list_copy(&newpa->children, &pa->children); + } +} + ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) { ARegion *newar = MEM_dupallocN(ar); - Panel *pa, *newpa, *patab; newar->prev = newar->next = NULL; BLI_listbase_clear(&newar->handlers); @@ -195,9 +222,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) BLI_listbase_clear(&newar->panels_category); BLI_listbase_clear(&newar->panels_category_active); BLI_listbase_clear(&newar->ui_lists); - newar->swinid = 0; + newar->visible = 0; + newar->gizmo_map = NULL; newar->regiontimer = NULL; newar->headerstr = NULL; + newar->draw_buffer = NULL; /* use optional regiondata callback */ if (ar->regiondata) { @@ -217,26 +246,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) if (ar->v2d.tab_offset) newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset); - BLI_listbase_clear(&newar->panels); - BLI_duplicatelist(&newar->panels, &ar->panels); + panel_list_copy(&newar->panels, &ar->panels); BLI_listbase_clear(&newar->ui_previews); BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews); - /* copy panel pointers */ - for (newpa = newar->panels.first; newpa; newpa = newpa->next) { - patab = newar->panels.first; - pa = ar->panels.first; - while (patab) { - if (newpa->paneltab == pa) { - newpa->paneltab = patab; - break; - } - patab = patab->next; - pa = pa->next; - } - } - return newar; } @@ -310,6 +324,57 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID } } +/** + * Avoid bad-level calls to #WM_gizmomap_tag_refresh. + */ +static void (*region_refresh_tag_gizmomap_callback)(struct wmGizmoMap *) = NULL; + +void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *)) +{ + region_refresh_tag_gizmomap_callback = callback; +} + +void BKE_screen_gizmo_tag_refresh(struct bScreen *sc) +{ + if (region_refresh_tag_gizmomap_callback == NULL) { + return; + } + + ScrArea *sa; + ARegion *ar; + for (sa = sc->areabase.first; sa; sa = sa->next) { + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->gizmo_map != NULL) { + region_refresh_tag_gizmomap_callback(ar->gizmo_map); + } + } + } +} + +/** + * Avoid bad-level calls to #WM_gizmomap_delete. + */ +static void (*region_free_gizmomap_callback)(struct wmGizmoMap *) = NULL; + +void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *)) +{ + region_free_gizmomap_callback = callback; +} + +void BKE_area_region_panels_free(ListBase *lb) +{ + Panel *pa, *pa_next; + for (pa = lb->first; pa; pa = pa_next) { + pa_next = pa->next; + if (pa->activedata) { + MEM_freeN(pa->activedata); + } + BKE_area_region_panels_free(&pa->children); + } + + BLI_freelistN(lb); +} + /* not region itself */ void BKE_area_region_free(SpaceType *st, ARegion *ar) { @@ -332,16 +397,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) ar->v2d.tab_offset = NULL; } - if (!BLI_listbase_is_empty(&ar->panels)) { - Panel *pa, *pa_next; - for (pa = ar->panels.first; pa; pa = pa_next) { - pa_next = pa->next; - if (pa->activedata) { - MEM_freeN(pa->activedata); - } - MEM_freeN(pa); - } - } + BKE_area_region_panels_free(&ar->panels); for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) { if (uilst->dyn_data) { @@ -359,6 +415,11 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) MEM_freeN(uilst->properties); } } + + if (ar->gizmo_map != NULL) { + region_free_gizmomap_callback(ar->gizmo_map); + } + BLI_freelistN(&ar->ui_lists); BLI_freelistN(&ar->ui_previews); BLI_freelistN(&ar->panels_category); @@ -374,6 +435,7 @@ void BKE_screen_area_free(ScrArea *sa) for (ar = sa->regionbase.first; ar; ar = ar->next) BKE_area_region_free(st, ar); + MEM_SAFE_FREE(sa->global); BLI_freelistN(&sa->regionbase); BKE_spacedata_freelist(&sa->spacedata); @@ -381,10 +443,21 @@ void BKE_screen_area_free(ScrArea *sa) BLI_freelistN(&sa->actionzones); } +void BKE_screen_area_map_free(ScrAreaMap *area_map) +{ + for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) { + area_next = area->next; + BKE_screen_area_free(area); + } + + BLI_freelistN(&area_map->vertbase); + BLI_freelistN(&area_map->edgebase); + BLI_freelistN(&area_map->areabase); +} + /** Free (or release) any data used by this screen (does not free the screen itself). */ void BKE_screen_free(bScreen *sc) { - ScrArea *sa, *san; ARegion *ar; /* No animdata here. */ @@ -394,36 +467,179 @@ void BKE_screen_free(bScreen *sc) BLI_freelistN(&sc->regionbase); - for (sa = sc->areabase.first; sa; sa = san) { - san = sa->next; - BKE_screen_area_free(sa); - } + BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc)); - BLI_freelistN(&sc->vertbase); - BLI_freelistN(&sc->edgebase); - BLI_freelistN(&sc->areabase); + BKE_previewimg_free(&sc->preview); /* Region and timer are freed by the window manager. */ MEM_SAFE_FREE(sc->tool_tip); } -/* for depsgraph */ -unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene) +/* ***************** Screen edges & verts ***************** */ + +ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2) +{ + ScrEdge *se; + + BKE_screen_sort_scrvert(&v1, &v2); + for (se = sc->edgebase.first; se; se = se->next) { + if (se->v1 == v1 && se->v2 == v2) { + return se; + } + } + + return NULL; +} + +void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2) +{ + ScrVert *tmp; + + if (*v1 > *v2) { + tmp = *v1; + *v1 = *v2; + *v2 = tmp; + } +} + +void BKE_screen_remove_double_scrverts(bScreen *sc) { + ScrVert *v1, *verg; + ScrEdge *se; ScrArea *sa; - unsigned int layer = 0; - if (screen) { - /* get all used view3d layers */ - for (sa = screen->areabase.first; sa; sa = sa->next) - if (sa->spacetype == SPACE_VIEW3D) - layer |= ((View3D *)sa->spacedata.first)->lay; + verg = sc->vertbase.first; + while (verg) { + if (verg->newv == NULL) { /* !!! */ + v1 = verg->next; + while (v1) { + if (v1->newv == NULL) { /* !?! */ + if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) { + /* printf("doublevert\n"); */ + v1->newv = verg; + } + } + v1 = v1->next; + } + } + verg = verg->next; + } + + /* replace pointers in edges and faces */ + se = sc->edgebase.first; + while (se) { + if (se->v1->newv) se->v1 = se->v1->newv; + if (se->v2->newv) se->v2 = se->v2->newv; + /* edges changed: so.... */ + BKE_screen_sort_scrvert(&(se->v1), &(se->v2)); + se = se->next; + } + sa = sc->areabase.first; + while (sa) { + if (sa->v1->newv) sa->v1 = sa->v1->newv; + if (sa->v2->newv) sa->v2 = sa->v2->newv; + if (sa->v3->newv) sa->v3 = sa->v3->newv; + if (sa->v4->newv) sa->v4 = sa->v4->newv; + sa = sa->next; + } + + /* remove */ + verg = sc->vertbase.first; + while (verg) { + v1 = verg->next; + if (verg->newv) { + BLI_remlink(&sc->vertbase, verg); + MEM_freeN(verg); + } + verg = v1; + } + +} + +void BKE_screen_remove_double_scredges(bScreen *sc) +{ + ScrEdge *verg, *se, *sn; + + /* compare */ + verg = sc->edgebase.first; + while (verg) { + se = verg->next; + while (se) { + sn = se->next; + if (verg->v1 == se->v1 && verg->v2 == se->v2) { + BLI_remlink(&sc->edgebase, se); + MEM_freeN(se); + } + se = sn; + } + verg = verg->next; } +} + +void BKE_screen_remove_unused_scredges(bScreen *sc) +{ + ScrEdge *se, *sen; + ScrArea *sa; + int a = 0; + + /* sets flags when edge is used in area */ + sa = sc->areabase.first; + while (sa) { + se = BKE_screen_find_edge(sc, sa->v1, sa->v2); + if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a); + else se->flag = 1; + se = BKE_screen_find_edge(sc, sa->v2, sa->v3); + if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a); + else se->flag = 1; + se = BKE_screen_find_edge(sc, sa->v3, sa->v4); + if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a); + else se->flag = 1; + se = BKE_screen_find_edge(sc, sa->v4, sa->v1); + if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a); + else se->flag = 1; + sa = sa->next; + a++; + } + se = sc->edgebase.first; + while (se) { + sen = se->next; + if (se->flag == 0) { + BLI_remlink(&sc->edgebase, se); + MEM_freeN(se); + } + else { + se->flag = 0; + } + se = sen; + } +} + +void BKE_screen_remove_unused_scrverts(bScreen *sc) +{ + ScrVert *sv, *svn; + ScrEdge *se; - if (!layer) - return scene->lay; + /* we assume edges are ok */ - return layer; + se = sc->edgebase.first; + while (se) { + se->v1->flag = 1; + se->v2->flag = 1; + se = se->next; + } + + sv = sc->vertbase.first; + while (sv) { + svn = sv->next; + if (sv->flag == 0) { + BLI_remlink(&sc->vertbase, sv); + MEM_freeN(sv); + } + else { + sv->flag = 0; + } + sv = svn; + } } /* ***************** Utilities ********************** */ @@ -514,71 +730,26 @@ ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short return big; } -ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y) +ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap, const int spacetype, int x, int y) { - ScrArea *sa, *sa_found = NULL; - - for (sa = sc->areabase.first; sa; sa = sa->next) { + for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) { if (BLI_rcti_isect_pt(&sa->totrct, x, y)) { if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) { - sa_found = sa; + return sa; } break; } } - return sa_found; -} - - -/** - * Utility function to get the active layer to use when adding new objects. - */ -unsigned int BKE_screen_view3d_layer_active_ex(const View3D *v3d, const Scene *scene, bool use_localvd) -{ - unsigned int lay; - if ((v3d == NULL) || (v3d->scenelock && !v3d->localvd)) { - lay = scene->layact; - } - else { - lay = v3d->layact; - } - - if (use_localvd) { - if (v3d && v3d->localvd) { - lay |= v3d->lay; - } - } - - return lay; -} -unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const struct Scene *scene) -{ - return BKE_screen_view3d_layer_active_ex(v3d, scene, true); + return NULL; } - -/** - * Accumulate all visible layers on this screen. - */ -unsigned int BKE_screen_view3d_layer_all(const bScreen *sc) +ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y) { - const ScrArea *sa; - unsigned int lay = 0; - for (sa = sc->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_VIEW3D) { - View3D *v3d = sa->spacedata.first; - lay |= v3d->lay; - } - } - - return lay; + return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y); } void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) { - int bit; - if (v3d->scenelock && v3d->localvd == NULL) { - v3d->lay = scene->lay; v3d->camera = scene->camera; if (v3d->camera == NULL) { @@ -592,19 +763,10 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) } } } - - if ((v3d->lay & v3d->layact) == 0) { - for (bit = 0; bit < 32; bit++) { - if (v3d->lay & (1u << bit)) { - v3d->layact = (1u << bit); - break; - } - } - } } } -void BKE_screen_view3d_scene_sync(bScreen *sc) +void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene) { /* are there cameras in the views that are not in the scene? */ ScrArea *sa; @@ -613,59 +775,27 @@ void BKE_screen_view3d_scene_sync(bScreen *sc) for (sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *) sl; - BKE_screen_view3d_sync(v3d, sc->scene); + BKE_screen_view3d_sync(v3d, scene); } } } } -void BKE_screen_view3d_main_sync(ListBase *screen_lb, Scene *scene) +void BKE_screen_view3d_shading_init(View3DShading *shading) { - bScreen *sc; - ScrArea *sa; - SpaceLink *sl; + memset(shading, 0, sizeof(*shading)); - /* from scene copy to the other views */ - for (sc = screen_lb->first; sc; sc = sc->id.next) { - if (sc->scene != scene) - continue; - - for (sa = sc->areabase.first; sa; sa = sa->next) - for (sl = sa->spacedata.first; sl; sl = sl->next) - if (sl->spacetype == SPACE_VIEW3D) - BKE_screen_view3d_sync((View3D *)sl, scene); - } -} - -void BKE_screen_view3d_twmode_remove(View3D *v3d, const int i) -{ - const int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM); - if (selected_index == i) { - v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */ - } - else if (selected_index > i) { - v3d->twmode--; - } -} - -void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, Scene *scene, const int i) -{ - bScreen *sc; - - for (sc = screen_lb->first; sc; sc = sc->id.next) { - if (sc->scene == scene) { - ScrArea *sa; - for (sa = sc->areabase.first; sa; sa = sa->next) { - SpaceLink *sl; - for (sl = sa->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *)sl; - BKE_screen_view3d_twmode_remove(v3d, i); - } - } - } - } - } + shading->type = OB_SOLID; + shading->prev_type = OB_SOLID; + shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_WIREFRAME; + shading->light = V3D_LIGHTING_STUDIO; + shading->shadow_intensity = 0.5f; + shading->xray_alpha = 0.5f; + shading->xray_alpha_wire = 0.5f; + shading->cavity_valley_factor = 1.0f; + shading->cavity_ridge_factor = 1.0f; + copy_v3_fl(shading->single_color, 0.8f); + copy_v3_fl(shading->background_color, 0.05f); } /* magic zoom calculation, no idea what @@ -686,25 +816,12 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac) return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f); } -void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings) +bool BKE_screen_is_fullscreen_area(const bScreen *screen) { - /* currently we use DOF from the camera _only_, - * so we never allocate this, only copy from the Camera */ -#if 0 - if ((fx_settings->dof == NULL) && - (fx_settings->fx_flag & GPU_FX_FLAG_DOF)) - { - GPUDOFSettings *fx_dof; - fx_dof = fx_settings->dof = MEM_callocN(sizeof(GPUDOFSettings), __func__); - } -#endif - - if ((fx_settings->ssao == NULL) && - (fx_settings->fx_flag & GPU_FX_FLAG_SSAO)) - { - GPUSSAOSettings *fx_ssao; - fx_ssao = fx_settings->ssao = MEM_callocN(sizeof(GPUSSAOSettings), __func__); + return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL); +} - GPU_fx_compositor_init_ssao_settings(fx_ssao); - } +bool BKE_screen_is_used(const bScreen *screen) +{ + return (screen->winid != 0); } diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index c69f8ff074f..d5e32ac7e39 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -1767,76 +1767,6 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f if (output != output) output = 1; if (wipe->forward) output = 1 - output; break; - /* BOX WIPE IS NOT WORKING YET */ - /* case DO_CROSS_WIPE: */ - /* BOX WIPE IS NOT WORKING YET */ -#if 0 - case DO_BOX_WIPE: - if (!wipe->forward) { - facf0 = 1.0f - facf0; /* Go the other direction */ - } - - width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0)); - hwidth = (float)width / 2.0; - if (angle == 0) angle = 0.000001; - b1 = posy / 2 - (-angle) * posx / 2; - b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2); - b2 = y - (-angle) * x; - - hyp = abs(angle * x + y + (-posy / 2 - angle * posx / 2)) * wipezone->pythangle; - hyp2 = abs(angle * x + y + (-(yo - posy / 2) - angle * (xo - posx / 2))) * wipezone->pythangle; - - temp1 = xo * (1 - facf0 / 2) - xo * facf0 / 2; - temp2 = yo * (1 - facf0 / 2) - yo * facf0 / 2; - pointdist = hypot(temp1, temp2); - - if (b2 < b1 && b2 < b3) { - if (hwidth < pointdist) - output = in_band(hwidth, hyp, 0, 1); - } - else if (b2 > b1 && b2 > b3) { - if (hwidth < pointdist) - output = in_band(hwidth, hyp2, 0, 1); - } - else { - if (hyp < hwidth && hyp2 > hwidth) - output = in_band(hwidth, hyp, 1, 1); - else if (hyp > hwidth && hyp2 < hwidth) - output = in_band(hwidth, hyp2, 1, 1); - else - output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1); - } - - if (!wipe->forward) { - facf0 = 1.0f - facf0; /* Go the other direction */ - } - angle = -1 / angle; - b1 = posy / 2 - (-angle) * posx / 2; - b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2); - b2 = y - (-angle) * x; - - hyp = abs(angle * x + y + (-posy / 2 - angle * posx / 2)) * wipezone->pythangle; - hyp2 = abs(angle * x + y + (-(yo - posy / 2) - angle * (xo - posx / 2))) * wipezone->pythangle; - - if (b2 < b1 && b2 < b3) { - if (hwidth < pointdist) - output *= in_band(hwidth, hyp, 0, 1); - } - else if (b2 > b1 && b2 > b3) { - if (hwidth < pointdist) - output *= in_band(hwidth, hyp2, 0, 1); - } - else { - if (hyp < hwidth && hyp2 > hwidth) - output *= in_band(hwidth, hyp, 1, 1); - else if (hyp > hwidth && hyp2 < hwidth) - output *= in_band(hwidth, hyp2, 1, 1); - else - output *= in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1); - } - - break; -#endif case DO_IRIS_WIPE: if (xo > yo) yo = xo; else xo = yo; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index c2a96d4f1ff..0d506effae6 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -63,9 +63,9 @@ #include "BLT_translation.h" #include "BKE_animsys.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_sequencer.h" #include "BKE_movieclip.h" @@ -75,6 +75,9 @@ #include "BKE_library.h" #include "BKE_idprop.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "RNA_access.h" #include "RE_pipeline.h" @@ -89,8 +92,10 @@ #include "BKE_context.h" #include "BKE_sound.h" +#include "RE_engine.h" + #ifdef WITH_AUDASPACE -# include AUD_SPECIAL_H +# include <AUD_Special.h> #endif /* mutable state for sequencer */ @@ -588,17 +593,17 @@ void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixe /*********************** sequencer pipeline functions *************************/ void BKE_sequencer_new_render_data( - EvaluationContext *eval_ctx, - Main *bmain, Scene *scene, int rectx, int recty, - int preview_render_size, + Main *bmain, struct Depsgraph *depsgraph, Scene *scene, int rectx, int recty, + int preview_render_size, int for_render, SeqRenderData *r_context) { - r_context->eval_ctx = eval_ctx; r_context->bmain = bmain; + r_context->depsgraph = depsgraph; r_context->scene = scene; r_context->rectx = rectx; r_context->recty = recty; r_context->preview_render_size = preview_render_size; + r_context->for_render = for_render; r_context->motion_blur_samples = 0; r_context->motion_blur_shutter = 0; r_context->skip_cache = false; @@ -1458,6 +1463,7 @@ typedef struct SeqIndexBuildContext { int view_id; Main *bmain; + Depsgraph *depsgraph; Scene *scene; Sequence *seq, *orig_seq; } SeqIndexBuildContext; @@ -1590,12 +1596,8 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) } if (sanim->anim) { -#if 0 - seq_anim_add_suffix(scene, sanim->anim, i); -#else /* we already have the suffix */ IMB_suffix_anim(sanim->anim, suffix); -#endif } else { if (openfile) { @@ -1946,7 +1948,9 @@ static int seq_proxy_context_count(Sequence *seq, Scene *scene) return num_views; } -void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue) +void BKE_sequencer_proxy_rebuild_context( + Main *bmain, Depsgraph *depsgraph, Scene *scene, + Sequence *seq, struct GSet *file_list, ListBase *queue) { SeqIndexBuildContext *context; Sequence *nseq; @@ -1978,6 +1982,7 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *se context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0; context->bmain = bmain; + context->depsgraph = depsgraph; context->scene = scene; context->orig_seq = seq; context->seq = nseq; @@ -2031,9 +2036,10 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho /* fail safe code */ BKE_sequencer_new_render_data( - bmain->eval_ctx, bmain, context->scene, + bmain, context->depsgraph, context->scene, (scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f, (scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100, + false, &render_context); render_context.skip_cache = true; @@ -2753,17 +2759,12 @@ static ImBuf *seq_render_effect_strip_impl( if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) { sh.get_default_fac(seq, cfra, &fac, &facf); - - if ((scene->r.mode & R_FIELDS) == 0) - facf = fac; + facf = fac; } else { fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL); if (fcu) { fac = facf = evaluate_fcurve(fcu, cfra); - if (scene->r.mode & R_FIELDS) { - facf = evaluate_fcurve(fcu, cfra + 0.5f); - } } else { fac = facf = seq->effect_fader; @@ -3131,7 +3132,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr /* anim-data */ adt = BKE_animdata_from_id(&mask->id); - BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM); + BKE_animsys_evaluate_animdata(context->depsgraph, context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM); maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__); @@ -3268,6 +3269,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq // have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */ have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree; + /* Get view layer for the strip. */ + ViewLayer *view_layer = BKE_view_layer_default_render(scene); + /* Depsgraph will be NULL when doing rendering. */ + Depsgraph *depsgraph = NULL; + orig_data.scemode = scene->r.scemode; orig_data.cfra = scene->r.cfra; orig_data.subframe = scene->r.subframe; @@ -3323,12 +3329,16 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq context->scene->r.seq_prev_type = 3 /* == OB_SOLID */; /* opengl offscreen render */ - BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); + depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + BKE_scene_graph_update_for_newframe(depsgraph, context->bmain); ibuf = sequencer_view3d_cb( /* set for OpenGL render (NULL when scrubbing) */ - context->bmain, scene, camera, width, height, IB_rect, draw_flags, context->scene->r.seq_prev_type, + depsgraph, scene, + context->scene->r.seq_prev_type, + camera, width, height, IB_rect, + draw_flags, scene->r.alphamode, context->gpu_samples, viewname, - context->gpu_fx, context->gpu_offscreen, err_out); + context->gpu_offscreen, err_out); if (ibuf == NULL) { fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out); } @@ -3349,12 +3359,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq * When rendering from command line renderer is called from main thread, in this * case it's always safe to render scene here */ - if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) { + if (!is_thread_main || is_rendering == false || is_background || context->for_render) { if (re == NULL) re = RE_NewSceneRender(scene); - BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); - RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false); + RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, frame, false); /* restore previous state after it was toggled on & off by RE_BlenderFrame */ G.is_rendering = is_rendering; @@ -3412,8 +3421,8 @@ finally: scene->r.cfra = orig_data.cfra; scene->r.subframe = orig_data.subframe; - if (is_frame_update) { - BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); + if (is_frame_update && (depsgraph != NULL)) { + BKE_scene_graph_update_for_newframe(depsgraph, context->bmain); } #ifdef DURIAN_CAMERA_SWITCH @@ -3503,7 +3512,7 @@ static ImBuf *do_render_strip_uncached( ibuf = seq_render_scene_strip(context, seq, nr, cfra); /* Scene strips update all animation, so we need to restore original state.*/ - BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra); + BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, context->scene, cfra); copy_to_ibuf_still(context, seq, nr, ibuf); } @@ -5240,11 +5249,6 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad if (sound->playback_handle == NULL) { BKE_libblock_free(bmain, sound); -#if 0 - if (op) - BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); -#endif - return NULL; } @@ -5252,10 +5256,6 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad if (info.specs.channels == AUD_CHANNELS_INVALID) { BKE_libblock_free(bmain, sound); -#if 0 - if (op) - BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); -#endif return NULL; } diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c new file mode 100644 index 00000000000..f19b450dece --- /dev/null +++ b/source/blender/blenkernel/intern/shader_fx.c @@ -0,0 +1,245 @@ +/* + * ***** 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) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/shader_fx.c + * \ingroup bke + */ + + +#include <stdio.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_string_utils.h" + +#include "BLT_translation.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_shader_fx_types.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_gpencil.h" +#include "BKE_shader_fx.h" +#include "BKE_object.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "FX_shader_types.h" + +static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL }; + +/* *************************************************** */ +/* Methods - Evaluation Loops, etc. */ + +/* check if exist grease pencil effects */ +bool BKE_shaderfx_has_gpencil(Object *ob) +{ + ShaderFxData *fx; + for (fx = ob->shader_fx.first; fx; fx = fx->next) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + if (fxi->type == eShaderFxType_GpencilType) { + return true; + } + } + return false; +} + +void BKE_shaderfx_init(void) +{ + /* Initialize shaders */ + shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */ +} + +ShaderFxData *BKE_shaderfx_new(int type) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type); + ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name); + + /* note, this name must be made unique later */ + BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name)); + + fx->type = type; + fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded; + fx->flag = eShaderFxFlag_StaticOverride_Local; + + if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode) + fx->mode |= eShaderFxMode_Editmode; + + if (fxi->initData) fxi->initData(fx); + + return fx; +} + +static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_min(id); + } +} + +void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (fxi->foreachIDLink) { + fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL); + } + else if (fxi->foreachObjectLink) { + fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL); + } + } + + if (fxi->freeData) fxi->freeData(fx); + if (fx->error) MEM_freeN(fx->error); + + MEM_freeN(fx); +} + +void BKE_shaderfx_free(ShaderFxData *fx) +{ + BKE_shaderfx_free_ex(fx, 0); +} + +/* check unique name */ +bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx) +{ + if (shaders && fx) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + return BLI_uniquename(shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name)); + } + return false; +} + +bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + return fxi->dependsOnTime && fxi->dependsOnTime(fx); +} + +const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type) +{ + /* type unsigned, no need to check < 0 */ + if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') { + return shader_fx_types[type]; + } + else { + return NULL; + } +} + +void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type); + + /* fx_dst may have already be fully initialized with some extra allocated data, + * we need to free it now to avoid memleak. */ + if (fxi->freeData) { + fxi->freeData(fx_dst); + } + + const size_t data_size = sizeof(ShaderFxData); + const char *fx_src_data = ((const char *)fx_src) + data_size; + char *fx_dst_data = ((char *)fx_dst) + data_size; + BLI_assert(data_size <= (size_t)fxi->struct_size); + memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size); +} + +static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(id); + } +} + +void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + target->mode = fx->mode; + target->flag = fx->flag; + + if (fxi->copyData) { + fxi->copyData(fx, target); + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (fxi->foreachIDLink) { + fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL); + } + else if (fxi->foreachObjectLink) { + fxi->foreachObjectLink(target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL); + } + } +} + +void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target) +{ + BKE_shaderfx_copyData_ex(fx, target, 0); +} + +ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type) +{ + ShaderFxData *fx = ob->shader_fx.first; + + for (; fx; fx = fx->next) + if (fx->type == type) + break; + + return fx; +} + +void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData) +{ + ShaderFxData *fx = ob->shader_fx.first; + + for (; fx; fx = fx->next) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + if (fxi->foreachIDLink) fxi->foreachIDLink(fx, ob, walk, userData); + else if (fxi->foreachObjectLink) { + /* each Object can masquerade as an ID, so this should be OK */ + ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk; + fxi->foreachObjectLink(fx, ob, fp, userData); + } + } +} + +ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name) +{ + return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name)); +} diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 65d42467f67..0da60b92f4b 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -45,15 +45,22 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_task.h" +#include "BLI_math_solvers.h" #include "BKE_shrinkwrap.h" +#include "BKE_cdderivedmesh.h" #include "BKE_DerivedMesh.h" #include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_modifier.h" #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" /* for OMP limits. */ #include "BKE_subsurf.h" +#include "BKE_mesh_runtime.h" + +#include "MEM_guardedalloc.h" #include "BLI_strict_flags.h" @@ -67,20 +74,262 @@ /* Util macros */ #define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) +typedef struct ShrinkwrapCalcData { + ShrinkwrapModifierData *smd; //shrinkwrap modifier data + + struct Object *ob; //object we are applying shrinkwrap to + + struct MVert *vert; //Array of verts being projected (to fetch normals or other data) + float(*vertexCos)[3]; //vertexs being shrinkwraped + int numVerts; + + struct MDeformVert *dvert; //Pointer to mdeform array + int vgroup; //Vertex group num + bool invert_vgroup; /* invert vertex group influence */ + + struct Mesh *target; //mesh we are shrinking to + struct SpaceTransform local2target; //transform to move between local and target space + struct ShrinkwrapTreeData *tree; // mesh BVH tree data + + float keepDist; //Distance to keep above target surface (units are in local space) + +} ShrinkwrapCalcData; + typedef struct ShrinkwrapCalcCBData { ShrinkwrapCalcData *calc; - void *treeData; - void *auxData; - BVHTree *targ_tree; - BVHTree *aux_tree; - void *targ_callback; - void *aux_callback; + ShrinkwrapTreeData *tree; + ShrinkwrapTreeData *aux_tree; float *proj_axis; SpaceTransform *local2aux; } ShrinkwrapCalcCBData; + +/* Checks if the modifier needs target normals with these settings. */ +bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode) +{ + return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) || + (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE); +} + +/* Initializes the mesh data structure from the given mesh and settings. */ +bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals) +{ + memset(data, 0, sizeof(*data)); + + if (!mesh || mesh->totvert <= 0) { + return false; + } + + data->mesh = mesh; + + if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) { + data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2); + + return data->bvh != NULL; + } + else { + if (mesh->totpoly <= 0) { + return false; + } + + data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRI, 4); + + if (data->bvh == NULL) { + return false; + } + + if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) { + if ((mesh->flag & ME_AUTOSMOOTH) != 0) { + data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + } + } + + if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + data->boundary = mesh->runtime.shrinkwrap_data; + } + + return true; + } +} + +/* Frees the tree data if necessary. */ +void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data) +{ + free_bvhtree_from_mesh(&data->treeData); +} + +/* Free boundary data for target project */ +void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh) +{ + struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data; + + if (data != NULL) { + MEM_freeN((void *)data->edge_is_boundary); + MEM_freeN((void *)data->looptri_has_boundary); + MEM_freeN((void *)data->vert_boundary_id); + MEM_freeN((void *)data->boundary_verts); + + MEM_freeN(data); + } + + mesh->runtime.shrinkwrap_data = NULL; +} + +/* Accumulate edge for average boundary edge direction. */ +static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata, signed char *status, int index, const float edge_dir[3], signed char side) +{ + BLI_assert(index >= 0); + float *direction = vdata[index].direction; + + /* Invert the direction vector if either: + * - This is the second edge and both edges have the vertex as start or end. + * - For third and above, if it points in the wrong direction. + */ + if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) { + sub_v3_v3(direction, edge_dir); + } + else { + add_v3_v3(direction, edge_dir); + } + + status[index] = (status[index] == 0) ? side : -1; +} + +static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh) +{ + const MLoop *mloop = mesh->mloop; + const MEdge *medge = mesh->medge; + const MVert *mvert = mesh->mvert; + + /* Count faces per edge (up to 2). */ + char *edge_mode = MEM_calloc_arrayN((size_t)mesh->totedge, sizeof(char), __func__); + + for (int i = 0; i < mesh->totloop; i++) { + unsigned int eidx = mloop[i].e; + + if (edge_mode[eidx] < 2) { + edge_mode[eidx]++; + } + } + + /* Build the boundary edge bitmask. */ + BLI_bitmap *edge_is_boundary = BLI_BITMAP_NEW(mesh->totedge, "ShrinkwrapBoundaryData::edge_is_boundary"); + unsigned int num_boundary_edges = 0; + + for (int i = 0; i < mesh->totedge; i++) { + edge_mode[i] = (edge_mode[i] == 1); + + if (edge_mode[i]) { + BLI_BITMAP_ENABLE(edge_is_boundary, i); + num_boundary_edges++; + } + } + + /* If no boundary, return NULL. */ + if (num_boundary_edges == 0) { + MEM_freeN(edge_is_boundary); + MEM_freeN(edge_mode); + return NULL; + } + + /* Allocate the data object. */ + ShrinkwrapBoundaryData *data = MEM_callocN(sizeof(ShrinkwrapBoundaryData), "ShrinkwrapBoundaryData"); + + data->edge_is_boundary = edge_is_boundary; + + /* Build the boundary looptri bitmask. */ + const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh); + int totlooptri = BKE_mesh_runtime_looptri_len(mesh); + + BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri, "ShrinkwrapBoundaryData::looptri_is_boundary"); + + for (int i = 0; i < totlooptri; i++) { + int edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges); + + for (int j = 0; j < 3; j++) { + if (edges[j] >= 0 && edge_mode[edges[j]]) { + BLI_BITMAP_ENABLE(looptri_has_boundary, i); + break; + } + } + } + + data->looptri_has_boundary = looptri_has_boundary; + + /* Find boundary vertices and build a mapping table for compact storage of data. */ + int *vert_boundary_id = MEM_calloc_arrayN((size_t)mesh->totvert, sizeof(int), "ShrinkwrapBoundaryData::vert_boundary_id"); + + for (int i = 0; i < mesh->totedge; i++) { + if (edge_mode[i]) { + const MEdge *edge = &medge[i]; + + vert_boundary_id[edge->v1] = 1; + vert_boundary_id[edge->v2] = 1; + } + } + + unsigned int num_boundary_verts = 0; + + for (int i = 0; i < mesh->totvert; i++) { + vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? (int)num_boundary_verts++ : -1; + } + + data->vert_boundary_id = vert_boundary_id; + data->num_boundary_verts = num_boundary_verts; + + /* Compute average directions. */ + ShrinkwrapBoundaryVertData *boundary_verts = MEM_calloc_arrayN(num_boundary_verts, sizeof(*boundary_verts), "ShrinkwrapBoundaryData::boundary_verts"); + + signed char *vert_status = MEM_calloc_arrayN(num_boundary_verts, sizeof(char), __func__); + + for (int i = 0; i < mesh->totedge; i++) { + if (edge_mode[i]) { + const MEdge *edge = &medge[i]; + + float dir[3]; + sub_v3_v3v3(dir, mvert[edge->v2].co, mvert[edge->v1].co); + normalize_v3(dir); + + merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v1], dir, 1); + merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v2], dir, 2); + } + } + + MEM_freeN(vert_status); + + /* Finalize average direction and compute normal. */ + for (int i = 0; i < mesh->totvert; i++) { + int bidx = vert_boundary_id[i]; + + if (bidx >= 0) { + ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx]; + float no[3], tmp[3]; + + normalize_v3(vdata->direction); + + normal_short_to_float_v3(no, mesh->mvert[i].no); + cross_v3_v3v3(tmp, no, vdata->direction); + cross_v3_v3v3(vdata->normal_plane, tmp, no); + normalize_v3(vdata->normal_plane); + } + } + + data->boundary_verts = boundary_verts; + + MEM_freeN(edge_mode); + return data; +} + +void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh) +{ + BKE_shrinkwrap_discard_boundary_data(mesh); + + mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh); +} + /* * Shrinkwrap to the nearest vertex * @@ -95,7 +344,7 @@ static void shrinkwrap_calc_nearest_vertex_cb_ex( ShrinkwrapCalcCBData *data = userdata; ShrinkwrapCalcData *calc = data->calc; - BVHTreeFromMesh *treeData = data->treeData; + BVHTreeFromMesh *treeData = &data->tree->treeData; BVHTreeNearest *nearest = tls->userdata_chunk; float *co = calc->vertexCos[i]; @@ -151,24 +400,13 @@ static void shrinkwrap_calc_nearest_vertex_cb_ex( static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) { - BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; BVHTreeNearest nearest = NULL_BVHTreeNearest; - if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) { - return; - } - - TIMEIT_BENCH(bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_VERTS, 2), bvhtree_verts); - if (treeData.tree == NULL) { - OUT_OF_MEMORY(); - return; - } - /* Setup nearest */ nearest.index = -1; nearest.dist_sq = FLT_MAX; - ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData}; + ShrinkwrapCalcCBData data = {.calc = calc, .tree = calc->tree}; ParallelRangeSettings settings; BLI_parallel_range_settings_defaults(&settings); settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); @@ -177,8 +415,6 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) BLI_task_parallel_range(0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings); - - free_bvhtree_from_mesh(&treeData); } @@ -193,8 +429,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) bool BKE_shrinkwrap_project_normal( char options, const float vert[3], const float dir[3], const float ray_radius, const SpaceTransform *transf, - BVHTree *tree, BVHTreeRayHit *hit, - BVHTree_RayCastCallback callback, void *userdata) + ShrinkwrapTreeData *tree, BVHTreeRayHit *hit) { /* don't use this because this dist value could be incompatible * this value used by the callback for comparing prev/new dist values. @@ -229,7 +464,7 @@ bool BKE_shrinkwrap_project_normal( hit_tmp.index = -1; - BLI_bvhtree_ray_cast(tree, co, no, ray_radius, &hit_tmp, callback, userdata); + BLI_bvhtree_ray_cast(tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData); if (hit_tmp.index != -1) { /* invert the normal first so face culling works on rotated objects */ @@ -237,7 +472,7 @@ bool BKE_shrinkwrap_project_normal( BLI_space_transform_invert_normal(transf, hit_tmp.no); } - if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) { + if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) { /* apply backface */ const float dot = dot_v3v3(dir, hit_tmp.no); if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) || @@ -271,12 +506,8 @@ static void shrinkwrap_calc_normal_projection_cb_ex( ShrinkwrapCalcCBData *data = userdata; ShrinkwrapCalcData *calc = data->calc; - void *treeData = data->treeData; - void *auxData = data->auxData; - BVHTree *targ_tree = data->targ_tree; - BVHTree *aux_tree = data->aux_tree; - void *targ_callback = data->targ_callback; - void *aux_callback = data->aux_callback; + ShrinkwrapTreeData *tree = data->tree; + ShrinkwrapTreeData *aux_tree = data->aux_tree; float *proj_axis = data->proj_axis; SpaceTransform *local2aux = data->local2aux; @@ -297,7 +528,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex( } if (calc->vert) { - /* calc->vert contains verts from derivedMesh */ + /* calc->vert contains verts from evaluated mesh. */ /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */ /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { @@ -318,19 +549,25 @@ static void shrinkwrap_calc_normal_projection_cb_ex( hit->index = -1; hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */ + bool is_aux = false; + /* Project over positive direction of axis */ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { if (aux_tree) { - BKE_shrinkwrap_project_normal( - 0, tmp_co, tmp_no, 0.0, - local2aux, aux_tree, hit, - aux_callback, auxData); + if (BKE_shrinkwrap_project_normal( + 0, tmp_co, tmp_no, 0.0, + local2aux, aux_tree, hit)) + { + is_aux = true; + } } - BKE_shrinkwrap_project_normal( - calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0, - &calc->local2target, targ_tree, hit, - targ_callback, treeData); + if (BKE_shrinkwrap_project_normal( + calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0, + &calc->local2target, tree, hit)) + { + is_aux = false; + } } /* Project over negative direction of axis */ @@ -338,34 +575,54 @@ static void shrinkwrap_calc_normal_projection_cb_ex( float inv_no[3]; negate_v3_v3(inv_no, tmp_no); + char options = calc->smd->shrinkOpts; + + if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) && (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) { + options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK; + } + if (aux_tree) { - BKE_shrinkwrap_project_normal( - 0, tmp_co, inv_no, 0.0, - local2aux, aux_tree, hit, - aux_callback, auxData); + if (BKE_shrinkwrap_project_normal( + 0, tmp_co, inv_no, 0.0, + local2aux, aux_tree, hit)) + { + is_aux = true; + } } - BKE_shrinkwrap_project_normal( - calc->smd->shrinkOpts, tmp_co, inv_no, 0.0, - &calc->local2target, targ_tree, hit, - targ_callback, treeData); + if (BKE_shrinkwrap_project_normal( + options, tmp_co, inv_no, 0.0, + &calc->local2target, tree, hit)) + { + is_aux = false; + } } /* don't set the initial dist (which is more efficient), * because its calculated in the targets space, we want the dist in our own space */ if (proj_limit_squared != 0.0f) { - if (len_squared_v3v3(hit->co, co) > proj_limit_squared) { + if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) { hit->index = -1; } } if (hit->index != -1) { - madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist); + if (is_aux) { + BKE_shrinkwrap_snap_point_to_surface( + aux_tree, local2aux, calc->smd->shrinkMode, + hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co); + } + else { + BKE_shrinkwrap_snap_point_to_surface( + tree, &calc->local2target, calc->smd->shrinkMode, + hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co); + } + interp_v3_v3v3(co, co, hit->co, weight); } } -static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render) +static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) { /* Options about projection direction */ float proj_axis[3] = {0.0f, 0.0f, 0.0f}; @@ -376,11 +633,12 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for * for finding the best hit, to get the real dist, * measure the len_v3v3() from the input coord to hit.co */ BVHTreeRayHit hit; - void *treeData = NULL; /* auxiliary target */ - DerivedMesh *auxMesh = NULL; - void *auxData = NULL; + Mesh *auxMesh = NULL; + bool auxMesh_free; + ShrinkwrapTreeData *aux_tree = NULL; + ShrinkwrapTreeData aux_tree_stack; SpaceTransform local2aux; /* If the user doesn't allows to project in any direction of projection axis @@ -388,10 +646,6 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0) return; - if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) { - return; - } - /* Prepare data to retrieve the direction in which we should project each vertex */ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) { if (calc->vert == NULL) return; @@ -412,97 +666,382 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for } if (calc->smd->auxTarget) { - auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render); + auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->smd->auxTarget, &auxMesh_free); if (!auxMesh) return; BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); } - /* use editmesh to avoid array allocation */ - BMEditMesh *emtarget = NULL, *emaux = NULL; - union { - BVHTreeFromEditMesh emtreedata; - BVHTreeFromMesh dmtreedata; - } treedata_stack, auxdata_stack; + if (BKE_shrinkwrap_init_tree(&aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false)) { + aux_tree = &aux_tree_stack; + } - BVHTree *targ_tree; - void *targ_callback; - if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) { - emtarget = BKE_editmesh_from_object(calc->smd->target); - if ((targ_tree = bvhtree_from_editmesh_looptri( - &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache))) - { - targ_callback = treedata_stack.emtreedata.raycast_callback; - treeData = &treedata_stack.emtreedata; - } + /* After successfully build the trees, start projection vertices. */ + ShrinkwrapCalcCBData data = { + .calc = calc, .tree = calc->tree, .aux_tree = aux_tree, + .proj_axis = proj_axis, .local2aux = &local2aux + }; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.userdata_chunk = &hit; + settings.userdata_chunk_size = sizeof(hit); + BLI_task_parallel_range(0, calc->numVerts, + &data, + shrinkwrap_calc_normal_projection_cb_ex, + &settings); + + /* free data structures */ + if (aux_tree) { + BKE_shrinkwrap_free_tree(aux_tree); } - else { - if ((targ_tree = bvhtree_from_mesh_get( - &treedata_stack.dmtreedata, calc->target, BVHTREE_FROM_LOOPTRI, 4))) - { - targ_callback = treedata_stack.dmtreedata.raycast_callback; - treeData = &treedata_stack.dmtreedata; - } - } - if (targ_tree) { - BVHTree *aux_tree = NULL; - void *aux_callback = NULL; - if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) { - /* use editmesh to avoid array allocation */ - if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { - emaux = BKE_editmesh_from_object(calc->smd->auxTarget); - if ((aux_tree = bvhtree_from_editmesh_looptri( - &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache))) - { - aux_callback = auxdata_stack.emtreedata.raycast_callback; - auxData = &auxdata_stack.emtreedata; + if (auxMesh != NULL && auxMesh_free) { + BKE_id_free(NULL, auxMesh); + } +} + +/* + * Shrinkwrap Target Surface Project mode + * + * It uses Newton's method to find a surface location with its + * smooth normal pointing at the original point. + * + * The equation system on barycentric weights and normal multiplier: + * + * (w0*V0 + w1*V1 + w2*V2) + l * (w0*N0 + w1*N1 + w2*N2) - CO = 0 + * w0 + w1 + w2 = 1 + * + * The actual solution vector is [ w0, w1, l ], with w2 eliminated. + */ + +//#define TRACE_TARGET_PROJECT + +typedef struct TargetProjectTriData { + const float **vtri_co; + const float (*vtri_no)[3]; + const float *point_co; + + float n0_minus_n2[3], n1_minus_n2[3]; + float c0_minus_c2[3], c1_minus_c2[3]; + + /* Current interpolated position and normal. */ + float co_interp[3], no_interp[3]; +} TargetProjectTriData; + +/* Computes the deviation of the equation system from goal. */ +static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3]) +{ + TargetProjectTriData *data = userdata; + + float w[3] = { x[0], x[1], 1.0f - x[0] - x[1] }; + interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w); + interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w); + + madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]); + sub_v3_v3(r_delta, data->point_co); +} + +/* Computes the Jacobian matrix of the equation system. */ +static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3]) +{ + TargetProjectTriData *data = userdata; + + madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]); + madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]); + + copy_v3_v3(r_jacobian[2], data->vtri_no[2]); + madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]); + madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]); +} + +/* Clamp barycentric weights to the triangle. */ +static void target_project_tri_clamp(float x[3]) +{ + if (x[0] < 0.0f) { + x[0] = 0.0f; + } + if (x[1] < 0.0f) { + x[1] = 0.0f; + } + if (x[0] + x[1] > 1.0f) { + x[0] = x[0] / (x[0] + x[1]); + x[1] = 1.0f - x[0]; + } +} + +/* Correct the Newton's method step to keep the coordinates within the triangle. */ +static bool target_project_tri_correct(void *UNUSED(userdata), const float x[3], float step[3], float x_next[3]) +{ + /* Insignificant correction threshold */ + const float epsilon = 1e-6f; + const float dir_epsilon = 0.05f; + bool fixed = false, locked = false; + + /* Weight 0 and 1 boundary check. */ + for (int i = 0; i < 2; i++) { + if (step[i] > x[i]) { + if (step[i] > dir_epsilon * fabsf(step[1 - i])) { + /* Abort if the solution is clearly outside the domain. */ + if (x[i] < epsilon) { + return false; } + + /* Scale a significant step down to arrive at the boundary. */ + mul_v3_fl(step, x[i] / step[i]); + fixed = true; } else { - if ((aux_tree = bvhtree_from_mesh_get( - &auxdata_stack.dmtreedata, auxMesh, BVHTREE_FROM_LOOPTRI, 4)) != NULL) - { - aux_callback = auxdata_stack.dmtreedata.raycast_callback; - auxData = &auxdata_stack.dmtreedata; - } + /* Reset precision errors to stay at the boundary. */ + step[i] = x[i]; + fixed = locked = true; } } - /* After sucessufuly build the trees, start projection vertexs */ - ShrinkwrapCalcCBData data = { - .calc = calc, - .treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback, - .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback, - .proj_axis = proj_axis, .local2aux = &local2aux, - }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); - settings.userdata_chunk = &hit; - settings.userdata_chunk_size = sizeof(hit); - BLI_task_parallel_range(0, calc->numVerts, - &data, - shrinkwrap_calc_normal_projection_cb_ex, - &settings); } - /* free data structures */ - if (treeData) { - if (emtarget) { - free_bvhtree_from_editmesh(treeData); + /* Weight 2 boundary check. */ + float sum = x[0] + x[1]; + float sstep = step[0] + step[1]; + + if (sum - sstep > 1.0f) { + if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) { + /* Abort if the solution is clearly outside the domain. */ + if (sum > 1.0f - epsilon) { + return false; + } + + /* Scale a significant step down to arrive at the boundary. */ + mul_v3_fl(step, (1.0f - sum) / -sstep); + fixed = true; } else { - free_bvhtree_from_mesh(treeData); + /* Reset precision errors to stay at the boundary. */ + if (locked) { + step[0] = step[1] = 0.0f; + } + else { + step[0] -= 0.5f * sstep; + step[1] = -step[0]; + fixed = true; + } } } - if (auxData) { - if (emaux) { - free_bvhtree_from_editmesh(auxData); + /* Recompute and clamp the new coordinates after step correction. */ + if (fixed) { + sub_v3_v3v3(x_next, x, step); + target_project_tri_clamp(x_next); + } + + return true; +} + +static bool target_project_solve_point_tri( + const float *vtri_co[3], const float vtri_no[3][3], const float point_co[3], + const float hit_co[3], float hit_dist_sq, + float r_hit_co[3], float r_hit_no[3]) +{ + float x[3], tmp[3]; + float dist = sqrtf(hit_dist_sq); + float epsilon = dist * 1.0e-5f; + + CLAMP_MIN(epsilon, 1.0e-5f); + + /* Initial solution vector: barycentric weights plus distance along normal. */ + interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co); + + interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x); + sub_v3_v3v3(tmp, point_co, hit_co); + + x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist; + + /* Solve the equations iteratively. */ + TargetProjectTriData tri_data = { .vtri_co = vtri_co, .vtri_no = vtri_no, .point_co = point_co }; + + sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]); + sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]); + sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]); + sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]); + + target_project_tri_clamp(x); + +#ifdef TRACE_TARGET_PROJECT + const bool trace = true; +#else + const bool trace = false; +#endif + + bool ok = BLI_newton3d_solve(target_project_tri_deviation, target_project_tri_jacobian, target_project_tri_correct, &tri_data, epsilon, 20, trace, x, x); + + if (ok) { + copy_v3_v3(r_hit_co, tri_data.co_interp); + copy_v3_v3(r_hit_no, tri_data.no_interp); + + return true; + } + + return false; +} + +static bool update_hit(BVHTreeNearest *nearest, int index, const float co[3], const float hit_co[3], const float hit_no[3]) +{ + float dist_sq = len_squared_v3v3(hit_co, co); + + if (dist_sq < nearest->dist_sq) { +#ifdef TRACE_TARGET_PROJECT + printf("===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq); +#endif + nearest->index = index; + nearest->dist_sq = dist_sq; + copy_v3_v3(nearest->co, hit_co); + normalize_v3_v3(nearest->no, hit_no); + return true; + } + + return false; +} + +/* Target projection on a non-manifold boundary edge - treats it like an infinitely thin cylinder. */ +static void target_project_edge(const ShrinkwrapTreeData *tree, int index, const float co[3], BVHTreeNearest *nearest, int eidx) +{ + const BVHTreeFromMesh *data = &tree->treeData; + const MEdge *edge = &tree->mesh->medge[eidx]; + const float *vedge_co[2] = { data->vert[edge->v1].co, data->vert[edge->v2].co }; + +#ifdef TRACE_TARGET_PROJECT + printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n", eidx, UNPACK3(vedge_co[0]), UNPACK3(vedge_co[1])); +#endif + + /* Retrieve boundary vertex IDs */ + const int *vert_boundary_id = tree->boundary->vert_boundary_id; + int bid1 = vert_boundary_id[edge->v1], bid2 = vert_boundary_id[edge->v2]; + + if (bid1 < 0 || bid2 < 0) { + return; + } + + /* Retrieve boundary vertex normals and align them to direction. */ + const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts; + float vedge_dir[2][3], dir[3]; + + copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane); + copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane); + + sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]); + + if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) { + negate_v3(vedge_dir[0]); + } + if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) { + negate_v3(vedge_dir[1]); + } + + /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */ + float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]); + float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]); + float d0co = dot_v3v3(vedge_dir[0], co); + + float a = d0v1 - d0v0 + d1v0 - d1v1; + float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co); + float c = d0co - d0v0; + float det = b * b - 4 * a * c; + + if (det >= 0) { + const float epsilon = 1e-6f; + float sdet = sqrtf(det); + float hit_co[3], hit_no[3]; + + for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) { + float x = (- b + ((float)i - 1) * sdet) / (2 * a); + + if (x >= -epsilon && x <= 1.0f + epsilon) { + CLAMP(x, 0, 1); + + float vedge_no[2][3]; + normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no); + normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no); + + interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x); + interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x); + + update_hit(nearest, index, co, hit_co, hit_no); + } } - else { - free_bvhtree_from_mesh(auxData); + } +} + +/* Target normal projection BVH callback - based on mesh_looptri_nearest_point. */ +static void mesh_looptri_target_project(void *userdata, int index, const float co[3], BVHTreeNearest *nearest) +{ + const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata; + const BVHTreeFromMesh *data = &tree->treeData; + const MLoopTri *lt = &data->looptri[index]; + const MLoop *loop[3] = { &data->loop[lt->tri[0]], &data->loop[lt->tri[1]], &data->loop[lt->tri[2]] }; + const MVert *vtri[3] = { &data->vert[loop[0]->v], &data->vert[loop[1]->v], &data->vert[loop[2]->v] }; + const float *vtri_co[3] = { vtri[0]->co, vtri[1]->co, vtri[2]->co }; + float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3]; + + /* First find the closest point and bail out if it's worse than the current solution. */ + closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co)); + dist_sq = len_squared_v3v3(co, raw_hit_co); + +#ifdef TRACE_TARGET_PROJECT + printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n", + index, UNPACK3(vtri_co[0]), UNPACK3(vtri_co[1]), UNPACK3(vtri_co[2]), dist_sq, nearest->dist_sq); +#endif + + if (dist_sq >= nearest->dist_sq) + return; + + /* Decode normals */ + normal_short_to_float_v3(vtri_no[0], vtri[0]->no); + normal_short_to_float_v3(vtri_no[1], vtri[1]->no); + normal_short_to_float_v3(vtri_no[2], vtri[2]->no); + + /* Solve the equations for the triangle */ + if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) { + update_hit(nearest, index, co, hit_co, hit_no); + } + /* Boundary edges */ + else if (tree->boundary && BLI_BITMAP_TEST(tree->boundary->looptri_has_boundary, index)) { + const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary; + int edges[3]; + + BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges); + + for (int i = 0; i < 3; i++) { + if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) { + target_project_edge(tree, index, co, nearest, edges[i]); + } + } + } +} + +/* + * Maps the point to the nearest surface, either by simple nearest, or by target normal projection. + */ +void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, BVHTreeNearest *nearest, float co[3], int type) +{ + BVHTreeFromMesh *treeData = &tree->treeData; + + if (type == MOD_SHRINKWRAP_TARGET_PROJECT) { +#ifdef TRACE_TARGET_PROJECT + printf("====== TARGET PROJECT START ======\n"); +#endif + + BLI_bvhtree_find_nearest_ex(tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER); + +#ifdef TRACE_TARGET_PROJECT + printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq); +#endif + + if (nearest->index < 0) { + /* fallback to simple nearest */ + BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData); } } + else { + BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData); + } } /* @@ -519,7 +1058,6 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex( ShrinkwrapCalcCBData *data = userdata; ShrinkwrapCalcData *calc = data->calc; - BVHTreeFromMesh *treeData = data->treeData; BVHTreeNearest *nearest = tls->userdata_chunk; float *co = calc->vertexCos[i]; @@ -548,31 +1086,26 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex( * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex * so we can initiate the "nearest.dist" with the expected value to that last hit. * This will lead in pruning of the search tree. */ - if (nearest->index != -1) - nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co); + if (nearest->index != -1) { + if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + /* Heuristic doesn't work because of additional restrictions. */ + nearest->index = -1; + nearest->dist_sq = FLT_MAX; + } + else { + nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co); + } + } else nearest->dist_sq = FLT_MAX; - BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData); + BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType); /* Found the nearest vertex */ if (nearest->index != -1) { - if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) { - /* Make the vertex stay on the front side of the face */ - madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist); - } - else { - /* Adjusting the vertex weight, - * so that after interpolating it keeps a certain distance from the nearest position */ - const float dist = sasqrt(nearest->dist_sq); - if (dist > FLT_EPSILON) { - /* linear interpolation */ - interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist); - } - else { - copy_v3_v3(tmp_co, nearest->co); - } - } + BKE_shrinkwrap_snap_point_to_surface( + data->tree, NULL, calc->smd->shrinkMode, + nearest->index, nearest->co, nearest->no, calc->keepDist, tmp_co, tmp_co); /* Convert the coordinates back to mesh coordinates */ BLI_space_transform_invert(&calc->local2target, tmp_co); @@ -580,28 +1113,161 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex( } } -static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) +/** + * Compute a smooth normal of the target (if applicable) at the hit location. + * + * \param tree: information about the mesh + * \param transform: transform from the hit coordinate space to the object space; may be null + * \param r_no: output in hit coordinate space; may be shared with inputs + */ +void BKE_shrinkwrap_compute_smooth_normal( + const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform, + int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3]) { - BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh; - BVHTreeNearest nearest = NULL_BVHTreeNearest; + const BVHTreeFromMesh *treeData = &tree->treeData; + const MLoopTri *tri = &treeData->looptri[looptri_idx]; + + /* Interpolate smooth normals if enabled. */ + if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) { + const MVert *verts[] = { + &treeData->vert[treeData->loop[tri->tri[0]].v], + &treeData->vert[treeData->loop[tri->tri[1]].v], + &treeData->vert[treeData->loop[tri->tri[2]].v], + }; + float w[3], no[3][3], tmp_co[3]; - if (calc->target->getNumPolys(calc->target) == 0) { - return; + /* Custom and auto smooth split normals. */ + if (tree->clnors) { + copy_v3_v3(no[0], tree->clnors[tri->tri[0]]); + copy_v3_v3(no[1], tree->clnors[tri->tri[1]]); + copy_v3_v3(no[2], tree->clnors[tri->tri[2]]); + } + /* Ordinary vertex normals. */ + else { + normal_short_to_float_v3(no[0], verts[0]->no); + normal_short_to_float_v3(no[1], verts[1]->no); + normal_short_to_float_v3(no[2], verts[2]->no); + } + + /* Barycentric weights from hit point. */ + copy_v3_v3(tmp_co, hit_co); + + if (transform) { + BLI_space_transform_apply(transform, tmp_co); + } + + interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co); + + /* Interpolate using weights. */ + interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w); + + if (transform) { + BLI_space_transform_invert_normal(transform, r_no); + } + else { + normalize_v3(r_no); + } } + /* Use the looptri normal if flat. */ + else { + copy_v3_v3(r_no, hit_no); + } +} - /* Create a bvh-tree of the given target */ - bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_LOOPTRI, 2); - if (treeData.tree == NULL) { - OUT_OF_MEMORY(); - return; +/* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */ +static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[3], const float hit_co[3], const float hit_no[3], float goal_dist, float forcesign, bool forcesnap) +{ + float dist = len_v3v3(point_co, hit_co); + + /* If exactly on the surface, push out along normal */ + if (dist < FLT_EPSILON) { + madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign); } + /* Move to the correct side if needed */ + else { + float delta[3]; + sub_v3_v3v3(delta, point_co, hit_co); + float dsign = signf(dot_v3v3(delta, hit_no)); + + /* If on the wrong side or too close, move to correct */ + if (forcesnap || dsign * forcesign < 0 || dist < goal_dist) { + interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign * forcesign) / dist); + } + else { + copy_v3_v3(r_point_co, point_co); + } + } +} + +/** + * Apply the shrink to surface modes to the given original coordinates and nearest point. + * + * \param tree: mesh data for smooth normals + * \param transform: transform from the hit coordinate space to the object space; may be null + * \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no. + */ +void BKE_shrinkwrap_snap_point_to_surface( + const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform, + int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist, + const float point_co[3], float r_point_co[3]) +{ + float dist, tmp[3]; + + switch (mode) { + /* Offsets along the line between point_co and hit_co. */ + case MOD_SHRINKWRAP_ON_SURFACE: + if (goal_dist > 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) { + interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + break; + + case MOD_SHRINKWRAP_INSIDE: + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false); + break; + + case MOD_SHRINKWRAP_OUTSIDE: + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false); + break; + + case MOD_SHRINKWRAP_OUTSIDE_SURFACE: + if (goal_dist > 0) { + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + break; + + /* Offsets along the normal */ + case MOD_SHRINKWRAP_ABOVE_SURFACE: + if (goal_dist > 0) { + BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp); + madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + break; + + default: + printf("Unknown Shrinkwrap surface snap mode: %d\n", mode); + copy_v3_v3(r_point_co, hit_co); + } +} + +static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) +{ + BVHTreeNearest nearest = NULL_BVHTreeNearest; /* Setup nearest */ nearest.index = -1; nearest.dist_sq = FLT_MAX; /* Find the nearest vertex */ - ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData}; + ShrinkwrapCalcCBData data = {.calc = calc, .tree = calc->tree}; ParallelRangeSettings settings; BLI_parallel_range_settings_defaults(&settings); settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); @@ -611,17 +1277,16 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings); - - free_bvhtree_from_mesh(&treeData); } /* Main shrinkwrap function */ -void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts, bool for_render) +void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, struct Scene *scene, Object *ob, Mesh *mesh, + float (*vertexCos)[3], int numVerts) { DerivedMesh *ss_mesh = NULL; ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; + bool target_free = false; /* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */ if (smd->target == ob) smd->target = NULL; @@ -637,8 +1302,8 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM /* DeformVertex */ calc.vgroup = defgroup_name_index(calc.ob, calc.smd->vgroup_name); - if (dm) { - calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + if (mesh) { + calc.dvert = mesh->dvert; } else if (calc.ob->type == OB_LATTICE) { calc.dvert = BKE_lattice_deform_verts_get(calc.ob); @@ -646,7 +1311,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM if (smd->target) { - calc.target = object_get_derived_final(smd->target, for_render); + calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(smd->target, &target_free); /* TODO there might be several "bugs" on non-uniform scales matrixs * because it will no longer be nearest surface, not sphere projection @@ -661,10 +1326,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM calc.vgroup = defgroup_name_index(calc.ob, smd->vgroup_name); - if (dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) { + if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) { /* Setup arrays to get vertexs positions, normals and deform weights */ - calc.vert = dm->getVertDataArray(dm, CD_MVERT); - calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + calc.vert = mesh->mvert; + calc.dvert = mesh->dvert; /* Using vertexs positions/normals as if a subsurface was applied */ if (smd->subsurfLevels) { @@ -672,7 +1337,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */ ssmd.levels = smd->subsurfLevels; /* levels */ - ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0); + /* TODO to be moved to Mesh once we are done with changes in subsurf code. */ + DerivedMesh *dm = CDDM_from_mesh(mesh); + + ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0); if (ss_mesh) { calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); @@ -684,29 +1352,42 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM } /* Just to make sure we are not leaving any memory behind */ - assert(ssmd.emCache == NULL); - assert(ssmd.mCache == NULL); + BLI_assert(ssmd.emCache == NULL); + BLI_assert(ssmd.mCache == NULL); + + dm->release(dm); } } /* Projecting target defined - lets work! */ - if (calc.target) { + ShrinkwrapTreeData tree; + + if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) { + calc.tree = &tree; + switch (smd->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: + case MOD_SHRINKWRAP_TARGET_PROJECT: TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface); break; case MOD_SHRINKWRAP_PROJECT: - TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc, for_render), deform_project); + TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project); break; case MOD_SHRINKWRAP_NEAREST_VERTEX: TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex); break; } + + BKE_shrinkwrap_free_tree(&tree); } /* free memory */ if (ss_mesh) ss_mesh->release(ss_mesh); + + if (target_free && calc.target) { + BKE_id_free(NULL, calc.target); + } } diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c deleted file mode 100644 index 0bf7a9f278e..00000000000 --- a/source/blender/blenkernel/intern/sketch.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * ***** 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. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/sketch.c - * \ingroup bke - */ - - -#include <string.h> -#include <math.h> -#include <float.h> - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "BKE_sketch.h" - - -#include "DNA_userdef_types.h" - -void freeSketch(SK_Sketch *sketch) -{ - SK_Stroke *stk, *next; - - for (stk = sketch->strokes.first; stk; stk = next) { - next = stk->next; - - sk_freeStroke(stk); - } - - MEM_freeN(sketch); -} - -SK_Sketch *createSketch(void) -{ - SK_Sketch *sketch; - - sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch"); - - sketch->active_stroke = NULL; - sketch->gesture = NULL; - - BLI_listbase_clear(&sketch->strokes); - - return sketch; -} - -void sk_initPoint(SK_Point *pt, SK_DrawData *dd, const float no[3]) -{ - if (no) { - normalize_v3_v3(pt->no, no); - } - else { - pt->no[0] = 0.0f; - pt->no[1] = 0.0f; - pt->no[2] = 1.0f; - } - pt->p2d[0] = dd->mval[0]; - pt->p2d[1] = dd->mval[1]; - - pt->size = 0.0f; - pt->type = PT_CONTINUOUS; - pt->mode = PT_SNAP; - /* more init code here */ -} - -void sk_copyPoint(SK_Point *dst, SK_Point *src) -{ - memcpy(dst, src, sizeof(SK_Point)); -} - -void sk_allocStrokeBuffer(SK_Stroke *stk) -{ - stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer"); -} - -void sk_freeStroke(SK_Stroke *stk) -{ - MEM_freeN(stk->points); - MEM_freeN(stk); -} - -SK_Stroke *sk_createStroke(void) -{ - SK_Stroke *stk; - - stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke"); - - stk->selected = 0; - stk->nb_points = 0; - stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE; - - sk_allocStrokeBuffer(stk); - - return stk; -} - -void sk_shrinkStrokeBuffer(SK_Stroke *stk) -{ - if (stk->nb_points < stk->buf_size) { - SK_Point *old_points = stk->points; - - stk->buf_size = stk->nb_points; - - sk_allocStrokeBuffer(stk); - - memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); - - MEM_freeN(old_points); - } -} - -void sk_growStrokeBuffer(SK_Stroke *stk) -{ - if (stk->nb_points == stk->buf_size) { - SK_Point *old_points = stk->points; - - stk->buf_size *= 2; - - sk_allocStrokeBuffer(stk); - - memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); - - MEM_freeN(old_points); - } -} - -void sk_growStrokeBufferN(SK_Stroke *stk, int n) -{ - if (stk->nb_points + n > stk->buf_size) { - SK_Point *old_points = stk->points; - - while (stk->nb_points + n > stk->buf_size) { - stk->buf_size *= 2; - } - - sk_allocStrokeBuffer(stk); - - memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); - - MEM_freeN(old_points); - } -} - - -void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n) -{ - memcpy(stk->points + n, pt, sizeof(SK_Point)); -} - -void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n) -{ - int size = stk->nb_points - n; - - sk_growStrokeBuffer(stk); - - memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point)); - - memcpy(stk->points + n, pt, sizeof(SK_Point)); - - stk->nb_points++; -} - -void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt) -{ - sk_growStrokeBuffer(stk); - - memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point)); - - stk->nb_points++; -} - -void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end) -{ - int size = end - start; - - sk_growStrokeBufferN(stk, len - size); - - if (len != size) { - int tail_size = stk->nb_points - end; - - memmove(stk->points + start + len, stk->points + end, tail_size * sizeof(SK_Point)); - } - - memcpy(stk->points + start, pts, len * sizeof(SK_Point)); - - stk->nb_points += len - size; -} - -void sk_trimStroke(SK_Stroke *stk, int start, int end) -{ - int size = end - start + 1; - - if (start > 0) { - memmove(stk->points, stk->points + start, size * sizeof(SK_Point)); - } - - stk->nb_points = size; -} - -void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]) -{ - SK_Point pt1, pt2; - SK_Point *prev, *next; - float delta_p[3]; - int i, total; - - total = end - start; - - sub_v3_v3v3(delta_p, p_end, p_start); - - prev = stk->points + start; - next = stk->points + end; - - copy_v3_v3(pt1.p, p_start); - copy_v3_v3(pt1.no, prev->no); - pt1.mode = prev->mode; - pt1.type = prev->type; - - copy_v3_v3(pt2.p, p_end); - copy_v3_v3(pt2.no, next->no); - pt2.mode = next->mode; - pt2.type = next->type; - - sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */ - sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */ - - for (i = 1; i < total; i++) { - float delta = (float)i / (float)total; - float *p = stk->points[start + 1 + i].p; - - mul_v3_v3fl(p, delta_p, delta); - add_v3_v3(p, p_start); - } -} - -void sk_polygonizeStroke(SK_Stroke *stk, int start, int end) -{ - int offset; - int i; - - /* find first exact points outside of range */ - for (; start > 0; start--) { - if (stk->points[start].type == PT_EXACT) { - break; - } - } - - for (; end < stk->nb_points - 1; end++) { - if (stk->points[end].type == PT_EXACT) { - break; - } - } - - offset = start + 1; - - for (i = start + 1; i < end; i++) { - if (stk->points[i].type == PT_EXACT) { - if (offset != i) { - memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point)); - } - - offset++; - } - } - - /* some points were removes, move end of array */ - if (offset < end) { - int size = stk->nb_points - end; - memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point)); - stk->nb_points = offset + size; - } -} - -void sk_flattenStroke(SK_Stroke *stk, int start, int end) -{ - float normal[3], distance[3]; - float limit; - int i, total; - - total = end - start + 1; - - copy_v3_v3(normal, stk->points[start].no); - - sub_v3_v3v3(distance, stk->points[end].p, stk->points[start].p); - project_v3_v3v3(normal, distance, normal); - limit = normalize_v3(normal); - - for (i = 1; i < total - 1; i++) { - float d = limit * i / total; - float offset[3]; - float *p = stk->points[start + i].p; - - sub_v3_v3v3(distance, p, stk->points[start].p); - project_v3_v3v3(distance, distance, normal); - - copy_v3_v3(offset, normal); - mul_v3_fl(offset, d); - - sub_v3_v3(p, distance); - add_v3_v3(p, offset); - } -} - -void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk) -{ - if (sketch->active_stroke == stk) { - sketch->active_stroke = NULL; - } - - BLI_remlink(&sketch->strokes, stk); - sk_freeStroke(stk); -} - -void sk_reverseStroke(SK_Stroke *stk) -{ - SK_Point *old_points = stk->points; - int i = 0; - - sk_allocStrokeBuffer(stk); - - for (i = 0; i < stk->nb_points; i++) { - sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i); - } - - MEM_freeN(old_points); -} - - -/* Ramer-Douglas-Peucker algorithm for line simplification */ -void sk_filterStroke(SK_Stroke *stk, int start, int end) -{ - SK_Point *old_points = stk->points; - int nb_points = stk->nb_points; - char *marked = NULL; - char work; - int i; - - if (start == -1) { - start = 0; - end = stk->nb_points - 1; - } - - sk_allocStrokeBuffer(stk); - stk->nb_points = 0; - - /* adding points before range */ - for (i = 0; i < start; i++) { - sk_appendStrokePoint(stk, old_points + i); - } - - marked = MEM_callocN(nb_points, "marked array"); - marked[start] = 1; - marked[end] = 1; - - work = 1; - - /* while still reducing */ - while (work) { - int ls, le; - work = 0; - - ls = start; - le = start + 1; - - /* while not over interval */ - while (ls < end) { - int max_i = 0; - short v1[2]; - float max_dist = 16; /* more than 4 pixels */ - - /* find the next marked point */ - while (marked[le] == 0) { - le++; - } - - /* perpendicular vector to ls-le */ - v1[1] = old_points[le].p2d[0] - old_points[ls].p2d[0]; - v1[0] = old_points[ls].p2d[1] - old_points[le].p2d[1]; - - - for (i = ls + 1; i < le; i++) { - float mul; - float dist; - short v2[2]; - - v2[0] = old_points[i].p2d[0] - old_points[ls].p2d[0]; - v2[1] = old_points[i].p2d[1] - old_points[ls].p2d[1]; - - if (v2[0] == 0 && v2[1] == 0) { - continue; - } - - mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]); - - dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]); - - if (dist > max_dist) { - max_dist = dist; - max_i = i; - } - } - - if (max_i != 0) { - work = 1; - marked[max_i] = 1; - } - - ls = le; - le = ls + 1; - } - } - - - /* adding points after range */ - for (i = start; i <= end; i++) { - if (marked[i]) { - sk_appendStrokePoint(stk, old_points + i); - } - } - - MEM_freeN(marked); - - /* adding points after range */ - for (i = end + 1; i < nb_points; i++) { - sk_appendStrokePoint(stk, old_points + i); - } - - MEM_freeN(old_points); - - sk_shrinkStrokeBuffer(stk); -} - - -void sk_filterLastContinuousStroke(SK_Stroke *stk) -{ - int start, end; - - end = stk->nb_points - 1; - - for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--) { - /* nothing to do here*/ - } - - if (end - start > 1) { - sk_filterStroke(stk, start, end); - } -} - -SK_Point *sk_lastStrokePoint(SK_Stroke *stk) -{ - SK_Point *pt = NULL; - - if (stk->nb_points > 0) { - pt = stk->points + (stk->nb_points - 1); - } - - return pt; -} - -void sk_endContinuousStroke(SK_Stroke *stk) -{ - stk->points[stk->nb_points - 1].type = PT_EXACT; -} - -void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk) -{ - if (stk) { - memcpy(&(sketch->next_point), &(stk->points[stk->nb_points - 1]), sizeof(SK_Point)); - } -} - -int sk_stroke_filtermval(SK_DrawData *dd) -{ - int retval = 0; - if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist) { - retval = 1; - } - - return retval; -} - -void sk_initDrawData(SK_DrawData *dd, const int mval[2]) -{ - dd->mval[0] = mval[0]; - dd->mval[1] = mval[1]; - dd->previous_mval[0] = -1; - dd->previous_mval[1] = -1; - dd->type = PT_EXACT; -} - - -void sk_deleteSelectedStrokes(SK_Sketch *sketch) -{ - SK_Stroke *stk, *next; - - for (stk = sketch->strokes.first; stk; stk = next) { - next = stk->next; - - if (stk->selected == 1) { - sk_removeStroke(sketch, stk); - } - } -} - -void sk_selectAllSketch(SK_Sketch *sketch, int mode) -{ - SK_Stroke *stk = NULL; - - if (mode == -1) { - for (stk = sketch->strokes.first; stk; stk = stk->next) { - stk->selected = 0; - } - } - else if (mode == 0) { - for (stk = sketch->strokes.first; stk; stk = stk->next) { - stk->selected = 1; - } - } - else if (mode == 1) { - int selected = 1; - - for (stk = sketch->strokes.first; stk; stk = stk->next) { - selected &= stk->selected; - } - - selected ^= 1; - - for (stk = sketch->strokes.first; stk; stk = stk->next) { - stk->selected = selected; - } - } -} diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index ccc991ed24a..26d9f59853c 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -54,6 +54,7 @@ #include "DNA_constraint_types.h" #include "DNA_customdata_types.h" #include "DNA_lamp_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -65,17 +66,17 @@ #include "BKE_animsys.h" #include "BKE_armature.h" #include "BKE_bvhutils.h" -#include "BKE_cdderivedmesh.h" #include "BKE_collision.h" #include "BKE_colortools.h" #include "BKE_constraint.h" #include "BKE_customdata.h" #include "BKE_deform.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -84,6 +85,9 @@ #include "BKE_smoke.h" #include "BKE_texture.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "RE_shader_ext.h" #include "GPU_glew.h" @@ -103,9 +107,9 @@ static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER; +struct Mesh; struct Object; struct Scene; -struct DerivedMesh; struct SmokeModifierData; // timestep default value for nice appearance 0.1f @@ -127,7 +131,7 @@ void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(s void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity), int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color), float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {} -struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; } +struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *UNUSED(me)) { return NULL; } float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; } #endif /* WITH_SMOKE */ @@ -192,20 +196,20 @@ static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3]) pos[2] *= 1.0f / sds->cell_size[2]; } -/* set domain transformations and base resolution from object derivedmesh */ -static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *ob, DerivedMesh *dm, bool init_resolution) +/* set domain transformations and base resolution from object mesh */ +static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, Object *ob, Mesh *me, bool init_resolution) { size_t i; float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; float size[3]; - MVert *verts = dm->getVertArray(dm); + MVert *verts = me->mvert; float scale = 0.0; int res; res = sds->maxres; // get BB of domain - for (i = 0; i < dm->getNumVerts(dm); i++) + for (i = 0; i < me->totvert; i++) { // min BB min[0] = MIN2(min[0], verts[i].co[0]); @@ -271,14 +275,14 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object * sds->cell_size[2] /= (float)sds->base_res[2]; } -static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm) +static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me) { if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) { SmokeDomainSettings *sds = smd->domain; int res[3]; - /* set domain dimensions from derivedmesh */ - smoke_set_domain_from_derivedmesh(sds, ob, dm, true); + /* set domain dimensions from mesh */ + smoke_set_domain_from_mesh(sds, ob, me, true); /* reset domain values */ zero_v3_int(sds->shift); zero_v3(sds->shift_f); @@ -302,7 +306,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, /* allocate fluid */ smoke_reallocate_fluid(sds, sds->dx, sds->res, 0); - smd->time = scene->r.cfra; + smd->time = scene_framenr; /* allocate highres fluid */ if (sds->flags & MOD_SMOKE_HIGHRES) { @@ -316,7 +320,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, } else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { - smd->time = scene->r.cfra; + smd->time = scene_framenr; return 1; } @@ -327,7 +331,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, smokeModifier_createType(smd); } - smd->time = scene->r.cfra; + smd->time = scene_framenr; return 1; } @@ -358,8 +362,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd) MEM_freeN(smd->domain->effector_weights); smd->domain->effector_weights = NULL; - BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); - smd->domain->point_cache[0] = NULL; + if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) { + BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); + smd->domain->point_cache[0] = NULL; + } if (smd->domain->coba) { MEM_freeN(smd->domain->coba); @@ -374,7 +380,7 @@ static void smokeModifier_freeFlow(SmokeModifierData *smd) { if (smd->flow) { - if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm); + if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh); if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old); MEM_freeN(smd->flow); smd->flow = NULL; @@ -396,9 +402,9 @@ static void smokeModifier_freeCollision(SmokeModifierData *smd) } } - if (smd->coll->dm) - smd->coll->dm->release(smd->coll->dm); - smd->coll->dm = NULL; + if (smd->coll->mesh) + BKE_id_free(NULL, smd->coll->mesh); + smd->coll->mesh = NULL; MEM_freeN(smd->coll); smd->coll = NULL; @@ -581,7 +587,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->flow->color[1] = 0.7f; smd->flow->color[2] = 0.7f; - smd->flow->dm = NULL; + smd->flow->mesh = NULL; smd->flow->psys = NULL; } @@ -596,16 +602,12 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->coll->verts_old = NULL; smd->coll->numverts = 0; smd->coll->type = 0; // static obstacle - smd->coll->dm = NULL; - -#ifdef USE_SMOKE_COLLISION_DM - smd->coll->dm = NULL; -#endif + smd->coll->mesh = NULL; } } } -void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd) +void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag) { tsmd->type = smd->type; tsmd->time = smd->time; @@ -613,80 +615,102 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie smokeModifier_createType(tsmd); if (tsmd->domain) { - tsmd->domain->fluid_group = smd->domain->fluid_group; - tsmd->domain->coll_group = smd->domain->coll_group; - - tsmd->domain->adapt_margin = smd->domain->adapt_margin; - tsmd->domain->adapt_res = smd->domain->adapt_res; - tsmd->domain->adapt_threshold = smd->domain->adapt_threshold; - - tsmd->domain->alpha = smd->domain->alpha; - tsmd->domain->beta = smd->domain->beta; - tsmd->domain->amplify = smd->domain->amplify; - tsmd->domain->maxres = smd->domain->maxres; - tsmd->domain->flags = smd->domain->flags; - tsmd->domain->highres_sampling = smd->domain->highres_sampling; - tsmd->domain->viewsettings = smd->domain->viewsettings; - tsmd->domain->noise = smd->domain->noise; - tsmd->domain->diss_speed = smd->domain->diss_speed; - tsmd->domain->strength = smd->domain->strength; - - tsmd->domain->border_collisions = smd->domain->border_collisions; - tsmd->domain->vorticity = smd->domain->vorticity; - tsmd->domain->time_scale = smd->domain->time_scale; - - tsmd->domain->burning_rate = smd->domain->burning_rate; - tsmd->domain->flame_smoke = smd->domain->flame_smoke; - tsmd->domain->flame_vorticity = smd->domain->flame_vorticity; - tsmd->domain->flame_ignition = smd->domain->flame_ignition; - tsmd->domain->flame_max_temp = smd->domain->flame_max_temp; - copy_v3_v3(tsmd->domain->flame_smoke_color, smd->domain->flame_smoke_color); - - MEM_freeN(tsmd->domain->effector_weights); - tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights); - tsmd->domain->openvdb_comp = smd->domain->openvdb_comp; - tsmd->domain->data_depth = smd->domain->data_depth; - tsmd->domain->cache_file_format = smd->domain->cache_file_format; - - tsmd->domain->slice_method = smd->domain->slice_method; - tsmd->domain->axis_slice_method = smd->domain->axis_slice_method; - tsmd->domain->slice_per_voxel = smd->domain->slice_per_voxel; - tsmd->domain->slice_depth = smd->domain->slice_depth; - tsmd->domain->slice_axis = smd->domain->slice_axis; - tsmd->domain->draw_velocity = smd->domain->draw_velocity; - tsmd->domain->vector_draw_type = smd->domain->vector_draw_type; - tsmd->domain->vector_scale = smd->domain->vector_scale; + SmokeDomainSettings *tsds = tsmd->domain; + SmokeDomainSettings *sds = smd->domain; - if (smd->domain->coba) { - tsmd->domain->coba = MEM_dupallocN(smd->domain->coba); + BKE_ptcache_free_list(&(tsds->ptcaches[0])); + + if (flag & LIB_ID_CREATE_NO_MAIN) { + /* Share the cache with the original object's modifier. */ + tsmd->modifier.flag |= eModifierFlag_SharedCaches; + tsds->point_cache[0] = sds->point_cache[0]; + tsds->ptcaches[0] = sds->ptcaches[0]; + } + else { + tsds->point_cache[0] = BKE_ptcache_copy_list(&(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag); + } + + tsds->fluid_group = sds->fluid_group; + tsds->coll_group = sds->coll_group; + + tsds->adapt_margin = sds->adapt_margin; + tsds->adapt_res = sds->adapt_res; + tsds->adapt_threshold = sds->adapt_threshold; + + tsds->alpha = sds->alpha; + tsds->beta = sds->beta; + tsds->amplify = sds->amplify; + tsds->maxres = sds->maxres; + tsds->flags = sds->flags; + tsds->highres_sampling = sds->highres_sampling; + tsds->viewsettings = sds->viewsettings; + tsds->noise = sds->noise; + tsds->diss_speed = sds->diss_speed; + tsds->strength = sds->strength; + + tsds->border_collisions = sds->border_collisions; + tsds->vorticity = sds->vorticity; + tsds->time_scale = sds->time_scale; + + tsds->burning_rate = sds->burning_rate; + tsds->flame_smoke = sds->flame_smoke; + tsds->flame_vorticity = sds->flame_vorticity; + tsds->flame_ignition = sds->flame_ignition; + tsds->flame_max_temp = sds->flame_max_temp; + copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color); + + MEM_freeN(tsds->effector_weights); + tsds->effector_weights = MEM_dupallocN(sds->effector_weights); + tsds->openvdb_comp = sds->openvdb_comp; + tsds->data_depth = sds->data_depth; + tsds->cache_file_format = sds->cache_file_format; + + tsds->display_thickness = sds->display_thickness; + tsds->slice_method = sds->slice_method; + tsds->axis_slice_method = sds->axis_slice_method; + tsds->slice_per_voxel = sds->slice_per_voxel; + tsds->slice_depth = sds->slice_depth; + tsds->slice_axis = sds->slice_axis; + tsds->interp_method = sds->interp_method; + tsds->draw_velocity = sds->draw_velocity; + tsds->vector_draw_type = sds->vector_draw_type; + tsds->vector_scale = sds->vector_scale; + + tsds->use_coba = sds->use_coba; + tsds->coba_field = sds->coba_field; + if (sds->coba) { + tsds->coba = MEM_dupallocN(sds->coba); } } else if (tsmd->flow) { - tsmd->flow->psys = smd->flow->psys; - tsmd->flow->noise_texture = smd->flow->noise_texture; - - tsmd->flow->vel_multi = smd->flow->vel_multi; - tsmd->flow->vel_normal = smd->flow->vel_normal; - tsmd->flow->vel_random = smd->flow->vel_random; - - tsmd->flow->density = smd->flow->density; - copy_v3_v3(tsmd->flow->color, smd->flow->color); - tsmd->flow->fuel_amount = smd->flow->fuel_amount; - tsmd->flow->temp = smd->flow->temp; - tsmd->flow->volume_density = smd->flow->volume_density; - tsmd->flow->surface_distance = smd->flow->surface_distance; - tsmd->flow->particle_size = smd->flow->particle_size; - tsmd->flow->subframes = smd->flow->subframes; - - tsmd->flow->texture_size = smd->flow->texture_size; - tsmd->flow->texture_offset = smd->flow->texture_offset; - BLI_strncpy(tsmd->flow->uvlayer_name, smd->flow->uvlayer_name, sizeof(tsmd->flow->uvlayer_name)); - tsmd->flow->vgroup_density = smd->flow->vgroup_density; - - tsmd->flow->type = smd->flow->type; - tsmd->flow->source = smd->flow->source; - tsmd->flow->texture_type = smd->flow->texture_type; - tsmd->flow->flags = smd->flow->flags; + SmokeFlowSettings *tsfs = tsmd->flow; + SmokeFlowSettings *sfs = smd->flow; + + tsfs->psys = sfs->psys; + tsfs->noise_texture = sfs->noise_texture; + + tsfs->vel_multi = sfs->vel_multi; + tsfs->vel_normal = sfs->vel_normal; + tsfs->vel_random = sfs->vel_random; + + tsfs->density = sfs->density; + copy_v3_v3(tsfs->color, sfs->color); + tsfs->fuel_amount = sfs->fuel_amount; + tsfs->temp = sfs->temp; + tsfs->volume_density = sfs->volume_density; + tsfs->surface_distance = sfs->surface_distance; + tsfs->particle_size = sfs->particle_size; + tsfs->subframes = sfs->subframes; + + tsfs->texture_size = sfs->texture_size; + tsfs->texture_offset = sfs->texture_offset; + BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name)); + tsfs->vgroup_density = sfs->vgroup_density; + + tsfs->type = sfs->type; + tsfs->source = sfs->source; + tsfs->texture_type = sfs->texture_type; + tsfs->flags = sfs->flags; } else if (tsmd->coll) { /* leave it as initialized, collision settings is mostly caches */ @@ -695,17 +719,17 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie #ifdef WITH_SMOKE -// forward decleration -static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene); +// forward declaration +static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer); static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct); -static int get_lamp(Scene *scene, float *light) +static int get_lamp(ViewLayer *view_layer, float *light) { Base *base_tmp = NULL; int found_lamp = 0; // try to find a lamp, preferably local - for (base_tmp = scene->base.first; base_tmp; base_tmp = base_tmp->next) { + for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) { if (base_tmp->object->type == OB_LAMP) { Lamp *la = base_tmp->object->data; @@ -741,7 +765,7 @@ typedef struct ObstaclesFromDMData { int *num_obstacles; } ObstaclesFromDMData; -static void obstacles_from_derivedmesh_task_cb( +static void obstacles_from_mesh_task_cb( void *__restrict userdata, const int z, const ParallelRangeTLS *__restrict UNUSED(tls)) @@ -798,13 +822,13 @@ static void obstacles_from_derivedmesh_task_cb( } } -static void obstacles_from_derivedmesh( +static void obstacles_from_mesh( Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs, unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt) { - if (!scs->dm) return; + if (!scs->mesh) return; { - DerivedMesh *dm = NULL; + Mesh *me = NULL; MVert *mvert = NULL; const MLoopTri *looptri; const MLoop *mloop; @@ -814,12 +838,12 @@ static void obstacles_from_derivedmesh( float *vert_vel = NULL; bool has_velocity = false; - dm = CDDM_copy(scs->dm); - CDDM_calc_normals(dm); - mvert = dm->getVertArray(dm); - mloop = dm->getLoopArray(dm); - looptri = dm->getLoopTriArray(dm); - numverts = dm->getNumVerts(dm); + me = BKE_mesh_copy_for_eval(scs->mesh, true); + BKE_mesh_ensure_normals(me); + mvert = me->mvert; + mloop = me->mloop; + looptri = BKE_mesh_runtime_looptri_ensure(me); + numverts = me->totvert; // DG TODO // if (scs->type > SM_COLL_STATIC) @@ -866,7 +890,7 @@ static void obstacles_from_derivedmesh( copy_v3_v3(&scs->verts_old[i * 3], co); } - if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) { + if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { ObstaclesFromDMData data = { .sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri, .tree = &treeData, .obstacle_map = obstacle_map, @@ -879,19 +903,19 @@ static void obstacles_from_derivedmesh( settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(sds->res_min[2], sds->res_max[2], &data, - obstacles_from_derivedmesh_task_cb, + obstacles_from_mesh_task_cb, &settings); } /* free bvh tree */ free_bvhtree_from_mesh(&treeData); - dm->release(dm); + BKE_id_free(NULL, me); if (vert_vel) MEM_freeN(vert_vel); } } /* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */ -static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt, +static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettings *sds, float dt, int UNUSED(substep), int UNUSED(totalsteps)) { Object **collobjs = NULL; @@ -931,7 +955,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, } - collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj, eModifierType_Smoke); + collobjs = BKE_collision_objects_create(depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke); // update obstacle tags in cells for (collIndex = 0; collIndex < numcollobj; collIndex++) @@ -944,12 +968,11 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) { SmokeCollSettings *scs = smd2->coll; - obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt); + obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt); } } - if (collobjs) - MEM_freeN(collobjs); + BKE_collision_objects_free(collobjs); /* obstacle cells should not contain any velocity from the smoke simulation */ for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) @@ -1264,7 +1287,7 @@ static void emit_from_particles_task_cb( } static void emit_from_particles( - Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Scene *scene, float dt) + Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Depsgraph *depsgraph, Scene *scene, float dt) { if (sfs && sfs->psys && sfs->psys->part && ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected { @@ -1283,6 +1306,7 @@ static void emit_from_particles( int hires_multiplier = 1; KDTree *tree = NULL; + sim.depsgraph = depsgraph; sim.scene = scene; sim.ob = flow_ob; sim.psys = psys; @@ -1335,7 +1359,7 @@ static void emit_from_particles( continue; } - state.time = BKE_scene_frame_get(scene); /* use scene time */ + state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */ if (psys_get_particle_state(&sim, p, &state, 0) == 0) continue; @@ -1436,7 +1460,7 @@ static void emit_from_particles( } } -static void sample_derivedmesh( +static void sample_mesh( SmokeFlowSettings *sfs, const MVert *mvert, const MLoop *mloop, const MLoopTri *mlooptri, const MLoopUV *mloopuv, float *influence_map, float *velocity_map, int index, const int base_res[3], float flow_center[3], @@ -1593,7 +1617,7 @@ typedef struct EmitFromDMData { int *min, *max, *res; } EmitFromDMData; -static void emit_from_derivedmesh_task_cb( +static void emit_from_mesh_task_cb( void *__restrict userdata, const int z, const ParallelRangeTLS *__restrict UNUSED(tls)) @@ -1615,7 +1639,7 @@ static void emit_from_derivedmesh_task_cb( lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; - sample_derivedmesh( + sample_mesh( data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv, em->influence, em->velocity, index, data->sds->base_res, data->flow_center, data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert, @@ -1633,7 +1657,7 @@ static void emit_from_derivedmesh_task_cb( x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; - sample_derivedmesh( + sample_mesh( data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv, em->influence_high, NULL, index, data->sds->base_res, data->flow_center, data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert, @@ -1644,14 +1668,13 @@ static void emit_from_derivedmesh_task_cb( } } -static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt) +static void emit_from_mesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt) { - if (sfs->dm) { - DerivedMesh *dm; + if (sfs->mesh) { + Mesh *me; int defgrp_index = sfs->vgroup_density - 1; MDeformVert *dvert = NULL; MVert *mvert = NULL; - MVert *mvert_orig = NULL; const MLoopTri *mlooptri = NULL; const MLoopUV *mloopuv = NULL; const MLoop *mloop = NULL; @@ -1664,19 +1687,24 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo int min[3], max[3], res[3]; int hires_multiplier = 1; - /* copy derivedmesh for thread safety because we modify it, + /* copy mesh for thread safety because we modify it, * main issue is its VertArray being modified, then replaced and freed */ - dm = CDDM_copy(sfs->dm); + me = BKE_mesh_copy_for_eval(sfs->mesh, true); + + /* Duplicate vertices to modify. */ + if (me->mvert) { + me->mvert = MEM_dupallocN(me->mvert); + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + } - CDDM_calc_normals(dm); - mvert = dm->getVertArray(dm); - mvert_orig = dm->dupVertArray(dm); /* copy original mvert and restore when done */ - numOfVerts = dm->getNumVerts(dm); - dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); - mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, sfs->uvlayer_name); - mloop = dm->getLoopArray(dm); - mlooptri = dm->getLoopTriArray(dm); + BKE_mesh_ensure_normals(me); + mvert = me->mvert; + numOfVerts = me->totvert; + dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); + mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name); + mloop = me->mloop; + mlooptri = BKE_mesh_runtime_looptri_ensure(me); if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity"); @@ -1691,8 +1719,8 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo } } - /* Transform dm vertices to - * domain grid space for fast lookups */ + /* Transform mesh vertices to + * domain grid space for fast lookups */ for (i = 0; i < numOfVerts; i++) { float n[3]; /* vert pos */ @@ -1737,7 +1765,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo res[i] = em->res[i] * hires_multiplier; } - if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) { + if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { const float hr = 1.0f / ((float)hires_multiplier); EmitFromDMData data = { @@ -1754,23 +1782,20 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(min[2], max[2], &data, - emit_from_derivedmesh_task_cb, + emit_from_mesh_task_cb, &settings); } /* free bvh tree */ free_bvhtree_from_mesh(&treeData); - /* restore original mverts */ - CustomData_set_layer(&dm->vertData, CD_MVERT, mvert_orig); - if (mvert) { - MEM_freeN(mvert); - } if (vert_vel) { MEM_freeN(vert_vel); } - dm->needsFree = 1; - dm->release(dm); + if (me->mvert) { + MEM_freeN(me->mvert); + } + BKE_id_free(NULL, me); } } @@ -2107,7 +2132,7 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value } static void update_flowsfluids( - Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt) + Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt) { Object **flowobjs = NULL; EmissionMap *emaps = NULL; @@ -2149,7 +2174,7 @@ static void update_flowsfluids( sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2]; } - flowobjs = get_collisionobjects(scene, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke); + flowobjs = BKE_collision_objects_create(depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke); /* init emission maps for each flow */ emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps"); @@ -2171,21 +2196,25 @@ static void update_flowsfluids( /* just sample flow directly to emission map if no subframes */ if (!subframes) { if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { - emit_from_particles(collob, sds, sfs, em, scene, dt); + emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt); } else { - emit_from_derivedmesh(collob, sds, sfs, em, dt); + emit_from_mesh(collob, sds, sfs, em, dt); } } /* sample subframes */ else { - int scene_frame = scene->r.cfra; +#if 0 + int scene_frame = (int)DEG_get_ctime(depsgraph); +#endif // float scene_subframe = scene->r.subframe; // UNUSED int subframe; for (subframe = 0; subframe <= subframes; subframe++) { EmissionMap em_temp = {NULL}; float sample_size = 1.0f / (float)(subframes+1); +#if 0 float prev_frame_pos = sample_size * (float)(subframe+1); +#endif float sdt = dt * sample_size; int hires_multiplier = 1; @@ -2193,6 +2222,8 @@ static void update_flowsfluids( hires_multiplier = sds->amplify + 1; } + /* TODO: setting the scene frame no longer works with the new depsgraph. */ +#if 0 /* set scene frame to match previous frame + subframe * or use current frame for last sample */ if (subframe < subframes) { @@ -2203,10 +2234,11 @@ static void update_flowsfluids( scene->r.cfra = scene_frame; scene->r.subframe = 0.0f; } +#endif if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { /* emit_from_particles() updates timestep internally */ - emit_from_particles(collob, sds, sfs, &em_temp, scene, sdt); + emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt); if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { hires_multiplier = 1; } @@ -2214,13 +2246,11 @@ static void update_flowsfluids( else { /* MOD_SMOKE_FLOW_SOURCE_MESH */ /* update flow object frame */ BLI_mutex_lock(&object_update_lock); - BKE_object_modifier_update_subframe( - bmain, eval_ctx, scene, collob, - true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke); + BKE_object_modifier_update_subframe(depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke); BLI_mutex_unlock(&object_update_lock); /* apply flow */ - emit_from_derivedmesh(collob, sds, sfs, &em_temp, sdt); + emit_from_mesh(collob, sds, sfs, &em_temp, sdt); } /* combine emission maps */ @@ -2452,8 +2482,7 @@ static void update_flowsfluids( } } - if (flowobjs) - MEM_freeN(flowobjs); + BKE_collision_objects_free(flowobjs); if (emaps) MEM_freeN(emaps); } @@ -2512,7 +2541,7 @@ static void update_effectors_task_cb( mul_m4_v3(sds->obmat, voxelCenter); pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint); - pdDoEffectors(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); + BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); /* convert retvel to local space */ mag = len_v3(retvel); @@ -2528,12 +2557,12 @@ static void update_effectors_task_cb( } } -static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt)) +static void update_effectors(Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt)) { ListBase *effectors; /* make sure smoke flow influence is 0.0f */ sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; - effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true); + effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights); if (effectors) { // precalculate wind forces @@ -2560,12 +2589,12 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, &settings); } - pdEndEffectors(&effectors); + BKE_effectors_free(effectors); } static void step( - Main *bmain, EvaluationContext *eval_ctx, - Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps) + Depsgraph *depsgraph, + Scene *scene, Object *ob, SmokeModifierData *smd, Mesh *domain_me, float fps) { SmokeDomainSettings *sds = smd->domain; /* stability values copied from wturbulence.cpp */ @@ -2581,19 +2610,10 @@ static void step( float gravity[3] = {0.0f, 0.0f, -1.0f}; float gravity_mag; -#if 0 /* UNUSED */ - /* get max velocity and lower the dt value if it is too high */ - size_t size = sds->res[0] * sds->res[1] * sds->res[2]; - float *velX = smoke_get_velocity_x(sds->fluid); - float *velY = smoke_get_velocity_y(sds->fluid); - float *velZ = smoke_get_velocity_z(sds->fluid); - size_t i; -#endif - /* update object state */ invert_m4_m4(sds->imat, ob->obmat); copy_m4_m4(sds->obmat, ob->obmat); - smoke_set_domain_from_derivedmesh(sds, ob, domain_dm, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0); + smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0); /* use global gravity if enabled */ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { @@ -2612,14 +2632,6 @@ static void step( // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel maxVel = (sds->dx * 5.0f); -#if 0 - for (i = 0; i < size; i++) { - float vtemp = (velX[i] * velX[i] + velY[i] * velY[i] + velZ[i] * velZ[i]); - if (vtemp > maxVelMag) - maxVelMag = vtemp; - } -#endif - maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale; totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */ totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; @@ -2635,19 +2647,19 @@ static void step( for (substep = 0; substep < totalSubsteps; substep++) { // calc animated obstacle velocities - update_flowsfluids(bmain, eval_ctx, scene, ob, sds, dtSubdiv); - update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps); + update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv); + update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps); if (sds->total_cells > 1) { - update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt + update_effectors(depsgraph, scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt smoke_step(sds->fluid, gravity, dtSubdiv); } } } -static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) +static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) { - DerivedMesh *result; + Mesh *result; MVert *mverts; MPoly *mpolys; MLoop *mloops; @@ -2669,11 +2681,10 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) num_faces = 0; } - result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces); - mverts = CDDM_get_verts(result); - mpolys = CDDM_get_polys(result); - mloops = CDDM_get_loops(result); - + result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces); + mverts = result->mvert; + mpolys = result->mpoly; + mloops = result->mloop; if (num_verts) { /* volume bounds */ @@ -2726,48 +2737,49 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) } } - - CDDM_calc_edges(result); - result->dirty |= DM_DIRTY_NORMALS; + BKE_mesh_calc_edges(result, false, false); + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; return result; } static void smokeModifier_process( - Main *bmain, EvaluationContext *eval_ctx, SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) + SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) { + const int scene_framenr = (int)DEG_get_ctime(depsgraph); + if ((smd->type & MOD_SMOKE_TYPE_FLOW)) { - if (scene->r.cfra >= smd->time) - smokeModifier_init(smd, ob, scene, dm); + if (scene_framenr >= smd->time) + smokeModifier_init(smd, ob, scene_framenr, me); - if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm); - smd->flow->dm = CDDM_copy(dm); + if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh); + smd->flow->mesh = BKE_mesh_copy_for_eval(me, false); - if (scene->r.cfra > smd->time) + if (scene_framenr > smd->time) { - smd->time = scene->r.cfra; + smd->time = scene_framenr; } - else if (scene->r.cfra < smd->time) + else if (scene_framenr < smd->time) { - smd->time = scene->r.cfra; + smd->time = scene_framenr; smokeModifier_reset_ex(smd, false); } } else if (smd->type & MOD_SMOKE_TYPE_COLL) { - if (scene->r.cfra >= smd->time) - smokeModifier_init(smd, ob, scene, dm); + if (scene_framenr >= smd->time) + smokeModifier_init(smd, ob, scene_framenr, me); if (smd->coll) { - if (smd->coll->dm) - smd->coll->dm->release(smd->coll->dm); + if (smd->coll->mesh) + BKE_id_free(NULL, smd->coll->mesh); - smd->coll->dm = CDDM_copy(dm); + smd->coll->mesh = BKE_mesh_copy_for_eval(me, false); } - smd->time = scene->r.cfra; - if (scene->r.cfra < smd->time) + smd->time = scene_framenr; + if (scene_framenr < smd->time) { smokeModifier_reset_ex(smd, false); } @@ -2780,9 +2792,7 @@ static void smokeModifier_process( int startframe, endframe, framenr; float timescale; - framenr = scene->r.cfra; - - //printf("time: %d\n", scene->r.cfra); + framenr = scene_framenr; cache = sds->point_cache[0]; BKE_ptcache_id_from_smoke(&pid, ob, smd); @@ -2803,10 +2813,10 @@ static void smokeModifier_process( CLAMP(framenr, startframe, endframe); /* If already viewing a pre/after frame, no need to reload */ - if ((smd->time == framenr) && (framenr != scene->r.cfra)) + if ((smd->time == framenr) && (framenr != scene_framenr)) return; - if (smokeModifier_init(smd, ob, scene, dm) == 0) + if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) { printf("bad smokeModifier_init\n"); return; @@ -2814,7 +2824,7 @@ static void smokeModifier_process( /* only calculate something when we advanced a single frame */ /* don't simulate if viewing start frame, but scene frame is not real start frame */ - bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene->r.cfra); + bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr); /* try to read from cache */ if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) { @@ -2836,7 +2846,7 @@ static void smokeModifier_process( } // set new time - smd->time = scene->r.cfra; + smd->time = scene_framenr; /* do simulation */ @@ -2854,11 +2864,11 @@ static void smokeModifier_process( } - step(bmain, eval_ctx, scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base); + step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base); } // create shadows before writing cache so they get stored - smoke_calc_transparency(sds, scene); + smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph)); if (sds->wt && sds->total_cells > 1) { smoke_turbulence_step(sds->wt, sds->fluid); @@ -2875,14 +2885,14 @@ static void smokeModifier_process( } } -struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm) +struct Mesh *smokeModifier_do( + SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) { /* lock so preview render does not read smoke data while it gets modified */ if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); - /* Ugly G.main, hopefully won't be needed anymore in 2.8 */ - smokeModifier_process(G.main, G.main->eval_ctx , smd, scene, ob, dm); + smokeModifier_process(smd, depsgraph, scene, ob, me); if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) BLI_rw_mutex_unlock(smd->domain->fluid_mutex); @@ -2895,7 +2905,7 @@ struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Objec return createDomainGeometry(smd->domain, ob); } else { - return CDDM_copy(dm); + return BKE_mesh_copy_for_eval(me, false); } } @@ -2997,7 +3007,7 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f cb(result, input, res, pixel, tRay, correct); } -static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene) +static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer) { float bv[6] = {0}; float light[3]; @@ -3005,7 +3015,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene) float *density = smoke_get_density(sds->fluid); float correct = -7.0f * sds->dx; - if (!get_lamp(scene, light)) return; + if (!get_lamp(view_layer, light)) return; /* convert light pos to sim cell space */ mul_m4_v3(sds->imat, light); diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 940f7f72d62..4c1555e9451 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -55,13 +55,13 @@ #include "MEM_guardedalloc.h" /* types */ -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_lattice_types.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_mesh_types.h" +#include "DNA_lattice_types.h" #include "DNA_meshdata_types.h" -#include "DNA_group_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -69,9 +69,12 @@ #include "BLI_ghash.h" #include "BLI_threads.h" +#include "BKE_collection.h" +#include "BKE_collision.h" #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_modifier.h" #include "BKE_softbody.h" #include "BKE_pointcache.h" @@ -79,6 +82,9 @@ #include "BKE_mesh.h" #include "BKE_scene.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "PIL_time.h" /* callbacks for errors and interrupts and some goo */ @@ -132,7 +138,7 @@ typedef struct SB_thread_context { float timenow; int ifirst; int ilast; - ListBase *do_effector; + ListBase *effectors; int do_deflector; float fieldfactor; float windfactor; @@ -508,39 +514,24 @@ static void ccd_build_deflector_hash_single(GHash *hash, Object *ob) } /** - * \note group overrides scene when not NULL. + * \note collection overrides scene when not NULL. */ -static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash) +static void ccd_build_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash) { - Object *ob; - if (!hash) return; - if (group) { - /* Explicit collision group */ - for (GroupObject *go = group->gobject.first; go; go = go->next) { - ob = go->ob; + unsigned int numobjects; + Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision); - if (ob == vertexowner || ob->type != OB_MESH) - continue; + for (int i = 0; i < numobjects; i++) { + Object *ob = objects[i]; + if (ob->type == OB_MESH) { ccd_build_deflector_hash_single(hash, ob); } } - else { - for (Base *base = scene->base.first; base; base = base->next) { - /*Only proceed for mesh object in same layer */ - if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { - ob= base->object; - if ((vertexowner) && (ob == vertexowner)) { - /* if vertexowner is given we don't want to check collision with owner object */ - continue; - } - ccd_build_deflector_hash_single(hash, ob); - } - } - } + BKE_collision_objects_free(objects); } static void ccd_update_deflector_hash_single(GHash *hash, Object *ob) @@ -554,42 +545,26 @@ static void ccd_update_deflector_hash_single(GHash *hash, Object *ob) } /** - * \note group overrides scene when not NULL. + * \note collection overrides scene when not NULL. */ -static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash) +static void ccd_update_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash) { - Object *ob; - if ((!hash) || (!vertexowner)) return; - if (group) { - /* Explicit collision group */ - for (GroupObject *go = group->gobject.first; go; go = go->next) { - ob = go->ob; + unsigned int numobjects; + Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision); - if (ob == vertexowner || ob->type != OB_MESH) - continue; + for (int i = 0; i < numobjects; i++) { + Object *ob = objects[i]; + if (ob->type == OB_MESH) { ccd_update_deflector_hash_single(hash, ob); } } - else { - for (Base *base = scene->base.first; base; base = base->next) { - /*Only proceed for mesh object in same layer */ - if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { - ob= base->object; - if (ob == vertexowner) { - /* if vertexowner is given we don't want to check collision with owner object */ - continue; - } - ccd_update_deflector_hash_single(hash, ob); - } - } - } + BKE_collision_objects_free(objects); } - /*--- collider caching and dicing ---*/ @@ -975,37 +950,21 @@ static void free_softbody_intern(SoftBody *sb) /* +++ dependency information functions*/ /** - * \note group overrides scene when not NULL. + * \note collection overrides scene when not NULL. */ -static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer) +static int query_external_colliders(Depsgraph *depsgraph, Collection *collection) { - if (group) { - for (GroupObject *go = group->gobject.first; go; go = go->next) { - if (go->ob->pd && go->ob->pd->deflect) - return 1; - } - } - else { - for (Base *base = scene->base.first; base; base= base->next) { - if ( (base->lay & layer) && base->object->pd) { - if (base->object->pd->deflect) - return 1; - } - } - } + unsigned int numobjects; + Object **objects = BKE_collision_objects_create(depsgraph, NULL, collection, &numobjects, eModifierType_Collision); + BKE_collision_objects_free(objects); - return 0; -} - -static int query_external_colliders(Scene *scene, Group *group, Object *me) -{ - return(are_there_deflectors(scene, group, me->lay)); + return (numobjects != 0); } /* --- dependency information functions*/ /* +++ the aabb "force" section*/ -static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int UNUSED(par_layer), struct Object *vertexowner, float UNUSED(time)) +static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), struct Object *vertexowner, float UNUSED(time)) { Object *ob; SoftBody *sb=vertexowner->soft; @@ -1066,7 +1025,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U /* +++ the face external section*/ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp, - float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time) + float force[3], struct Object *vertexowner, float time) { Object *ob; GHash *hash; @@ -1167,7 +1126,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp, - float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time) + float force[3], struct Object *vertexowner, float time) { Object *ob; GHash *hash; @@ -1304,7 +1263,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow) zero_v3(feedback); if (sb_detect_face_collisionCached( sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos, - &damp, feedback, ob->lay, ob, timenow)) + &damp, feedback, ob, timenow)) { madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune); madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune); @@ -1322,7 +1281,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow) zero_v3(feedback); if (sb_detect_face_pointCached( sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos, - &damp, feedback, ob->lay, ob, timenow)) + &damp, feedback, ob, timenow)) { madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune); madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune); @@ -1351,7 +1310,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow) /* +++ the spring external section*/ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], float *damp, - float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time) + float force[3], struct Object *vertexowner, float time) { Object *ob; GHash *hash; @@ -1470,7 +1429,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl return deflected; } -static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *do_effector) +static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *effectors) { SoftBody *sb = ob->soft; int a; @@ -1488,7 +1447,7 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, /* +++ springs colliding */ if (ob->softflag & OB_SB_EDGECOLL) { if ( sb_detect_edge_collisionCached (sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos, - &damp, feedback, ob->lay, ob, timenow)) { + &damp, feedback, ob, timenow)) { add_v3_v3(bs->ext_force, feedback); bs->flag |= BSF_INTERSECT; //bs->cf=damp; @@ -1504,14 +1463,14 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, float vel[3], sp[3], pr[3], force[3]; float f, windfactor = 0.25f; /*see if we have wind*/ - if (do_effector) { + if (effectors) { EffectedPoint epoint; float speed[3] = {0.0f, 0.0f, 0.0f}; float pos[3]; mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos); mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec); pd_point_from_soft(scene, pos, vel, -1, &epoint); - pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed); + BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed); mul_v3_fl(speed, windfactor); add_v3_v3(vel, speed); @@ -1544,32 +1503,30 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, } -static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow) +static void scan_for_ext_spring_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float timenow) { SoftBody *sb = ob->soft; - ListBase *do_effector = NULL; - do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights, true); - _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector); - pdEndEffectors(&do_effector); + ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights); + _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, effectors); + BKE_effectors_free(effectors); } static void *exec_scan_for_ext_spring_forces(void *data) { SB_thread_context *pctx = (SB_thread_context*)data; - _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->do_effector); + _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->effectors); return NULL; } -static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void))) +static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void))) { - ListBase *do_effector = NULL; ListBase threads; SB_thread_context *sb_threads; int i, totthread, left, dec; int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ - do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true); + ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights); /* figure the number of threads while preventing pretty pointless threading overhead */ totthread= BKE_scene_num_threads(scene); @@ -1594,7 +1551,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow, } else sb_threads[i].ifirst = 0; - sb_threads[i].do_effector = do_effector; + sb_threads[i].effectors = effectors; sb_threads[i].do_deflector = false;// not used here sb_threads[i].fieldfactor = 0.0f;// not used here sb_threads[i].windfactor = 0.0f;// not used here @@ -1614,7 +1571,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow, /* clean up */ MEM_freeN(sb_threads); - pdEndEffectors(&do_effector); + BKE_effectors_free(effectors); } @@ -1649,7 +1606,7 @@ static int choose_winner(float*w, float* pos, float*a, float*b, float*c, float*c static int sb_detect_vertex_collisionCached( float opco[3], float facenormal[3], float *damp, - float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, + float force[3], struct Object *vertexowner, float time, float vel[3], float *intrusion) { Object *ob= NULL; @@ -1845,8 +1802,8 @@ static int sb_deflect_face(Object *ob, float *actpos, float *facenormal, float * float s_actpos[3]; int deflected; copy_v3_v3(s_actpos, actpos); - deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force, ob->lay, ob, time, vel, intrusion); - //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob->lay, ob, time, vel, intrusion); + deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force, ob, time, vel, intrusion); + //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob, time, vel, intrusion); return(deflected); } @@ -1969,7 +1926,7 @@ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, floa /* since this is definitely the most CPU consuming task here .. try to spread it */ /* core function _softbody_calc_forces_slice_in_a_thread */ /* result is int to be able to flag user break */ -static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor) +static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *effectors, int do_deflector, float fieldfactor, float windfactor) { float iks; int bb, do_selfcollision, do_springcollision, do_aero; @@ -2088,14 +2045,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo } /* particle field & vortex */ - if (do_effector) { + if (effectors) { EffectedPoint epoint; float kd; float force[3] = {0.0f, 0.0f, 0.0f}; float speed[3] = {0.0f, 0.0f, 0.0f}; float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint); - pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed); + BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed); /* apply forcefield*/ mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale); @@ -2170,11 +2127,11 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo static void *exec_softbody_calc_forces(void *data) { SB_thread_context *pctx = (SB_thread_context*)data; - _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->do_effector, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor); + _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->effectors, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor); return NULL; } -static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor) +static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *effectors, int do_deflector, float fieldfactor, float windfactor) { ListBase threads; SB_thread_context *sb_threads; @@ -2206,7 +2163,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t } else sb_threads[i].ifirst = 0; - sb_threads[i].do_effector = do_effector; + sb_threads[i].effectors = effectors; sb_threads[i].do_deflector = do_deflector; sb_threads[i].fieldfactor = fieldfactor; sb_threads[i].windfactor = windfactor; @@ -2229,14 +2186,13 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t MEM_freeN(sb_threads); } -static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow) +static void softbody_calc_forcesEx(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow) { /* rule we never alter free variables :bp->vec bp->pos in here ! * this will ruin adaptive stepsize AKA heun! (BM) */ SoftBody *sb= ob->soft; /* is supposed to be there */ /*BodyPoint *bproot;*/ /* UNUSED */ - ListBase *do_effector = NULL; /* float gravity; */ /* UNUSED */ /* float iks; */ float fieldfactor = -1.0f, windfactor = 0.25; @@ -2245,7 +2201,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl /* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */ /* check conditions for various options */ - do_deflector= query_external_colliders(scene, sb->collision_group, ob); + do_deflector= query_external_colliders(depsgraph, sb->collision_group); /* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */ do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -2254,31 +2210,31 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl /* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */ if (do_springcollision || do_aero) - sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL); + sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL); /* after spring scan because it uses Effoctors too */ - do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true); + ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights); if (do_deflector) { float defforce[3]; - do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow); + do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow); } - sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, do_effector, do_deflector, fieldfactor, windfactor); + sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, effectors, do_deflector, fieldfactor, windfactor); /* finally add forces caused by face collision */ if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow); /* finish matrix and solve */ - pdEndEffectors(&do_effector); + BKE_effectors_free(effectors); } -static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow) +static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow) { /* redirection to the new threaded Version */ if (!(G.debug_value & 0x10)) { // 16 - softbody_calc_forcesEx(scene, ob, forcetime, timenow); + softbody_calc_forcesEx(depsgraph, scene, ob, forcetime, timenow); return; } else { @@ -2297,7 +2253,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa BodyPoint *bp; /* BodyPoint *bproot; */ /* UNUSED */ BodySpring *bs; - ListBase *do_effector = NULL; float iks, ks, kd, gravity[3] = {0.0f, 0.0f, 0.0f}; float fieldfactor = -1.0f, windfactor = 0.25f; float tune = sb->ballstiff; @@ -2309,7 +2264,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa } /* check conditions for various options */ - do_deflector= query_external_colliders(scene, sb->collision_group, ob); + do_deflector= query_external_colliders(depsgraph, sb->collision_group); do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -2317,13 +2272,13 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ /* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */ - if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow); + if (do_springcollision || do_aero) scan_for_ext_spring_forces(depsgraph, scene, ob, timenow); /* after spring scan because it uses Effoctors too */ - do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true); + ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights); if (do_deflector) { float defforce[3]; - do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow); + do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow); } bp = sb->bpoint; @@ -2422,13 +2377,13 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa /* particle field & vortex */ - if (do_effector) { + if (effectors) { EffectedPoint epoint; float force[3] = {0.0f, 0.0f, 0.0f}; float speed[3] = {0.0f, 0.0f, 0.0f}; float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint); - pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed); + BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed); /* apply forcefield*/ mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale); @@ -2520,7 +2475,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa /* finally add forces caused by face collision */ if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow); - pdEndEffectors(&do_effector); + BKE_effectors_free(effectors); } } @@ -3321,7 +3276,8 @@ SoftBody *sbNew(Scene *scene) sb->shearstiff = 1.0f; sb->solverflags |= SBSO_OLDERR; - sb->pointcache = BKE_ptcache_add(&sb->ptcaches); + sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared"); + sb->shared->pointcache = BKE_ptcache_add(&sb->shared->ptcaches); if (!sb->effector_weights) sb->effector_weights = BKE_add_effector_weights(NULL); @@ -3332,14 +3288,26 @@ SoftBody *sbNew(Scene *scene) } /* frees all */ -void sbFree(SoftBody *sb) +void sbFree(Object *ob) { + SoftBody *sb = ob->soft; + if (sb == NULL) { + return; + } + free_softbody_intern(sb); - BKE_ptcache_free_list(&sb->ptcaches); - sb->pointcache = NULL; + + if ((ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) { + /* Only free shared data on non-CoW copies */ + BKE_ptcache_free_list(&sb->shared->ptcaches); + sb->shared->pointcache = NULL; + MEM_freeN(sb->shared); + } if (sb->effector_weights) MEM_freeN(sb->effector_weights); MEM_freeN(sb); + + ob->soft = NULL; } void sbFreeSimulation(SoftBody *sb) @@ -3506,7 +3474,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int } } -static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) +static void softbody_step(struct Depsgraph *depsgraph, Scene *scene, Object *ob, SoftBody *sb, float dtime) { /* the simulator */ float forcetime; @@ -3520,12 +3488,10 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) */ if (dtime < 0 || dtime > 10.5f) return; - ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash); + ccd_update_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash); if (sb->scratch->needstobuildcollider) { - if (query_external_colliders(scene, sb->collision_group, ob)) { - ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash); - } + ccd_build_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash); sb->scratch->needstobuildcollider=0; } @@ -3554,12 +3520,12 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) sb->scratch->flag &= ~SBF_DOFUZZY; /* do predictive euler step */ - softbody_calc_forces(scene, ob, forcetime, timedone/dtime); + softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime); softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags); /* crop new slope values to do averaged slope step */ - softbody_calc_forces(scene, ob, forcetime, timedone/dtime); + softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime); softbody_apply_forces(ob, forcetime, 2, &err, mid_flags); softbody_apply_goalsnap(ob); @@ -3640,7 +3606,7 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) } /* simulates one step. framenr is in frames */ -void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts) +void sbObjectStep(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts) { SoftBody *sb= ob->soft; PointCache *cache; @@ -3648,8 +3614,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i float dtime, timescale; int framedelta, framenr, startframe, endframe; int cache_result; - - cache= sb->pointcache; + cache= sb->shared->pointcache; framenr= (int)cfra; framedelta= framenr - cache->simframe; @@ -3717,7 +3682,8 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i } /* try to read from cache */ - bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED); + bool can_write_cache = DEG_is_active(depsgraph); + bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED) && can_write_cache; cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate); @@ -3728,7 +3694,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i BKE_ptcache_validate(cache, framenr); - if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) + if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED && can_write_cache) BKE_ptcache_write(&pid, framenr); sb->last_frame = framenr; @@ -3740,7 +3706,9 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i } else if (/*ob->id.lib || */(cache->flag & PTCACHE_BAKED)) { /* "library linking & pointcaches" has to be solved properly at some point */ /* if baked and nothing in cache, do nothing */ - BKE_ptcache_invalidate(cache); + if (can_write_cache) { + BKE_ptcache_invalidate(cache); + } return; } @@ -3757,7 +3725,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i dtime = framedelta*timescale; /* do simulation */ - softbody_step(scene, ob, sb, dtime); + softbody_step(depsgraph, scene, ob, sb, dtime); softbody_to_object(ob, vertexCos, numVerts, 0); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index d21055ada6a..5135362bd69 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -48,13 +48,11 @@ #include "DNA_speaker_types.h" #ifdef WITH_AUDASPACE -# include AUD_SOUND_H -# include AUD_SEQUENCE_H -# include AUD_HANDLE_H -# include AUD_SPECIAL_H -# ifdef WITH_SYSTEM_AUDASPACE -# include "../../../intern/audaspace/intern/AUD_Set.h" -# endif +# include <AUD_Sound.h> +# include <AUD_Sequence.h> +# include <AUD_Handle.h> +# include <AUD_Special.h> +# include "../../../intern/audaspace/intern/AUD_Set.h" #endif #include "BKE_global.h" @@ -228,7 +226,7 @@ void BKE_sound_init_once(void) atexit(BKE_sound_exit_once); } -static AUD_Device *sound_device; +static AUD_Device *sound_device = NULL; void *BKE_sound_get_device(void) { @@ -237,6 +235,9 @@ void *BKE_sound_get_device(void) void BKE_sound_init(struct Main *bmain) { + /* Make sure no instance of the sound system is running, otherwise we get leaks. */ + BKE_sound_exit(); + AUD_DeviceSpecs specs; int device, buffersize; const char *device_name; @@ -302,7 +303,6 @@ void BKE_sound_exit_once(void) sound_device = NULL; AUD_exitOnce(); -#ifdef WITH_SYSTEM_AUDASPACE if (audio_device_names != NULL) { int i; for (i = 0; audio_device_names[i]; i++) { @@ -311,7 +311,6 @@ void BKE_sound_exit_once(void) free(audio_device_names); audio_device_names = NULL; } -#endif } /* XXX unused currently */ @@ -811,13 +810,76 @@ void BKE_sound_read_waveform(bSound *sound, short *stop) BLI_spin_unlock(sound->spinlock); } -void BKE_sound_update_scene(Main *bmain, struct Scene *scene) +static void sound_update_base(Scene *scene, Base *base, void *new_set) { - Object *ob; - Base *base; + Object *ob = base->object; NlaTrack *track; NlaStrip *strip; Speaker *speaker; + float quat[4]; + + if ((ob->id.tag & LIB_TAG_DOIT) == 0) { + return; + } + + ob->id.tag &= ~LIB_TAG_DOIT; + + if ((ob->type != OB_SPEAKER) || !ob->adt) { + return; + } + + for (track = ob->adt->nla_tracks.first; track; track = track->next) { + for (strip = track->strips.first; strip; strip = strip->next) { + if (strip->type != NLASTRIP_TYPE_SOUND) { + continue; + } + speaker = (Speaker *)ob->data; + + if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) { + if (speaker->sound) { + AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0); + } + else { + AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle); + strip->speaker_handle = NULL; + } + } + else { + if (speaker->sound) { + strip->speaker_handle = AUD_Sequence_add(scene->sound_scene, + speaker->sound->playback_handle, + (double)strip->start / FPS, FLT_MAX, 0); + AUD_SequenceEntry_setRelative(strip->speaker_handle, 0); + } + } + + if (strip->speaker_handle) { + const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED)); + AUD_addSet(new_set, strip->speaker_handle); + AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max); + AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min); + AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max); + AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference); + AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation); + AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer); + AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner); + AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer); + + mat4_to_quat(quat, ob->obmat); + AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1); + AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1); + AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1); + AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1); + AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle); + AUD_SequenceEntry_setMuted(strip->speaker_handle, mute); + } + } + } +} + +void BKE_sound_update_scene(Main *bmain, Scene *scene) +{ + Base *base; Scene *sce_it; void *new_set = AUD_createSet(); @@ -826,59 +888,18 @@ void BKE_sound_update_scene(Main *bmain, struct Scene *scene) /* cheap test to skip looping over all objects (no speakers is a common case) */ if (!BLI_listbase_is_empty(&bmain->speaker)) { - for (SETLOOPER(scene, sce_it, base)) { - ob = base->object; - if ((ob->type != OB_SPEAKER) || !ob->adt) { - continue; - } - for (track = ob->adt->nla_tracks.first; track; track = track->next) { - for (strip = track->strips.first; strip; strip = strip->next) { - if (strip->type != NLASTRIP_TYPE_SOUND) { - continue; - } - speaker = (Speaker *)ob->data; - - if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) { - if (speaker->sound) { - AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0); - } - else { - AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle); - strip->speaker_handle = NULL; - } - } - else { - if (speaker->sound) { - strip->speaker_handle = AUD_Sequence_add(scene->sound_scene, - speaker->sound->playback_handle, - (double)strip->start / FPS, FLT_MAX, 0); - AUD_SequenceEntry_setRelative(strip->speaker_handle, 0); - } - } - - if (strip->speaker_handle) { - const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED)); - AUD_addSet(new_set, strip->speaker_handle); - AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max); - AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min); - AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max); - AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference); - AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation); - AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer); - AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner); - AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer); - - mat4_to_quat(quat, ob->obmat); - AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1); - AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1); - AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1); - AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1); - AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle); - AUD_SequenceEntry_setMuted(strip->speaker_handle, mute); - } - } + BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true); + + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (base = view_layer->object_bases.first; base; base = base->next) { + sound_update_base(scene, base, new_set); } } + + for (SETLOOPER_SET_ONLY(scene, sce_it, base)) { + sound_update_base(scene, base, new_set); + } + } while ((handle = AUD_getSet(scene->speaker_handles))) { @@ -911,28 +932,12 @@ float BKE_sound_get_length(bSound *sound) char **BKE_sound_get_device_names(void) { if (audio_device_names == NULL) { -#ifdef WITH_SYSTEM_AUDASPACE audio_device_names = AUD_getDeviceNames(); -#else - static const char *names[] = { - "Null", "SDL", "OpenAL", "JACK", NULL - }; - audio_device_names = (char **)names; -#endif } return audio_device_names; } -bool BKE_sound_is_jack_supported(void) -{ -#ifdef WITH_SYSTEM_AUDASPACE - return 1; -#else - return (bool)AUD_isJackSupported(); -#endif -} - #else /* WITH_AUDASPACE */ #include "BLI_utildefines.h" @@ -979,5 +984,6 @@ void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {} void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {} float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; } -bool BKE_sound_is_jack_supported(void) { return false; } +char **BKE_sound_get_device_names(void) { static char *names[1] = {NULL}; return names; } + #endif /* WITH_AUDASPACE */ diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c new file mode 100644 index 00000000000..df5cc7551aa --- /dev/null +++ b/source/blender/blenkernel/intern/studiolight.c @@ -0,0 +1,1242 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006-2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenkernel/intern/studiolight.c + * \ingroup bke + */ + +#include "BKE_studiolight.h" + +#include "BKE_appdir.h" +#include "BKE_icons.h" + +#include "BLI_fileops.h" +#include "BLI_fileops_types.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" +#include "BLI_path_util.h" +#include "BLI_rand.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" + +#include "DNA_listBase.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "GPU_texture.h" + +#include "MEM_guardedalloc.h" + + +/* Statics */ +static ListBase studiolights; +static int last_studiolight_id = 0; +#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 128 +#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 32 +#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2) + +#define STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE 0 +#define STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS 1 +/* + * The method to calculate the irradiance buffers + * The irradiance buffer is only shown in the background when in LookDev. + * + * STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE is very slow, but very accurate + * STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS is faster but has artifacts + */ +// #define STUDIOLIGHT_IRRADIANCE_METHOD STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE +#define STUDIOLIGHT_IRRADIANCE_METHOD STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 2 +# define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING +#endif + +/* + * Disable this option so caches are not loaded from disk + * Do not checkin with this commented out + */ +#define STUDIOLIGHT_LOAD_CACHED_FILES + +static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/"; +static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/"; +static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/"; + +/* FUNCTIONS */ +#define IMB_SAFE_FREE(p) do { \ +if (p) { \ + IMB_freeImBuf(p); \ + p = NULL; \ +} \ +} while (0) + +#define GPU_TEXTURE_SAFE_FREE(p) do { \ +if (p) { \ + GPU_texture_free(p); \ + p = NULL; \ +} \ +} while (0) + +static void studiolight_free(struct StudioLight *sl) +{ +#define STUDIOLIGHT_DELETE_ICON(s) { \ + if (s != 0) { \ + BKE_icon_delete(s); \ + s = 0; \ + } \ +} + if (sl->free_function) { + sl->free_function(sl, sl->free_function_data); + } + STUDIOLIGHT_DELETE_ICON(sl->icon_id_radiance); + STUDIOLIGHT_DELETE_ICON(sl->icon_id_irradiance); + STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap); + STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap_flipped); +#undef STUDIOLIGHT_DELETE_ICON + + for (int index = 0; index < 6; index++) { + IMB_SAFE_FREE(sl->radiance_cubemap_buffers[index]); + } + GPU_TEXTURE_SAFE_FREE(sl->equirectangular_radiance_gputexture); + GPU_TEXTURE_SAFE_FREE(sl->equirectangular_irradiance_gputexture); + IMB_SAFE_FREE(sl->equirectangular_radiance_buffer); + IMB_SAFE_FREE(sl->equirectangular_irradiance_buffer); + MEM_SAFE_FREE(sl->path_irr_cache); + MEM_SAFE_FREE(sl->path_sh_cache); + MEM_SAFE_FREE(sl->gpu_matcap_3components); + MEM_SAFE_FREE(sl); +} + +static struct StudioLight *studiolight_create(int flag) +{ + struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__); + sl->path[0] = 0x00; + sl->name[0] = 0x00; + sl->path_irr_cache = NULL; + sl->path_sh_cache = NULL; + sl->free_function = NULL; + sl->flag = flag; + sl->index = ++last_studiolight_id; + if (flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) { + sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP); + sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED); + } + else { + sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE); + sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE); + } + + for (int index = 0; index < 6; index++) { + sl->radiance_cubemap_buffers[index] = NULL; + } + + return sl; +} + +static void direction_to_equirectangular(float r[2], const float dir[3]) +{ + r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2); + r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI; +} + +static void equirectangular_to_direction(float r[3], float u, float v) +{ + float phi = (-(M_PI * 2)) * u + M_PI; + float theta = -M_PI * v + M_PI; + float sin_theta = sinf(theta); + r[0] = sin_theta * cosf(phi); + r[1] = sin_theta * sinf(phi); + r[2] = cosf(theta); +} + +static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3]) +{ + float uv[2]; + direction_to_equirectangular(uv, direction); + nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y); +} + +static void studiolight_calculate_radiance_buffer( + ImBuf *ibuf, float *colbuf, + const float start_x, const float add_x, + const float start_y, const float add_y, const float z, + const int index_x, const int index_y, const int index_z) +{ + float direction[3]; + float yf = start_y; + float xf; + float *color = colbuf; + + for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++, yf += add_y) { + xf = start_x; + for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++, xf += add_x) { + direction[index_x] = xf; + direction[index_y] = yf; + direction[index_z] = z; + normalize_v3(direction); + studiolight_calculate_radiance(ibuf, color, direction); + color += 4; + } + } +} + +static void studiolight_load_equirectangular_image(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + ImBuf *ibuf = NULL; + ibuf = IMB_loadiffname(sl->path, 0, NULL); + if (ibuf == NULL) { + float *colbuf = MEM_mallocN(sizeof(float[4]), __func__); + copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f); + ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1); + } + IMB_float_from_rect(ibuf); + sl->equirectangular_radiance_buffer = ibuf; + } + sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED; +} + +static void studiolight_create_equirectangular_radiance_gputexture(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + char error[256]; + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); + ImBuf *ibuf = sl->equirectangular_radiance_buffer; + + if (sl->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) { + sl->gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__); + + float *offset4 = ibuf->rect_float; + float *offset3 = sl->gpu_matcap_3components; + for (int i = 0; i < ibuf->x * ibuf->y; i++) { + copy_v3_v3(offset3, offset4); + offset3 += 3; + offset4 += 4; + } + sl->equirectangular_radiance_gputexture = GPU_texture_create_nD( + ibuf->x, ibuf->y, 0, 2, sl->gpu_matcap_3components, GPU_R11F_G11F_B10F, GPU_DATA_FLOAT, 0, false, error); + } + else { + sl->equirectangular_radiance_gputexture = GPU_texture_create_2D( + ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error); + GPUTexture *tex = sl->equirectangular_radiance_gputexture; + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, true); + GPU_texture_wrap_mode(tex, true); + GPU_texture_unbind(tex); + } + } + sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE; +} + +static void studiolight_create_equirectangular_irradiance_gputexture(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + char error[256]; + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED); + ImBuf *ibuf = sl->equirectangular_irradiance_buffer; + sl->equirectangular_irradiance_gputexture = GPU_texture_create_2D( + ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error); + GPUTexture *tex = sl->equirectangular_irradiance_gputexture; + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, true); + GPU_texture_wrap_mode(tex, true); + GPU_texture_unbind(tex); + } + sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE; +} + +static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); + ImBuf *ibuf = sl->equirectangular_radiance_buffer; + if (ibuf) { + float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__); + const float add = 1.0f / (STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE + 1); + const float start = ((1.0f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * 0.5f) - 0.5f; + + /* front */ + studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, 0.5f, 0, 2, 1); + sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer( + NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + + /* back */ + studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, -0.5f, 0, 2, 1); + sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer( + NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + + /* left */ + studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, 0.5f, 1, 2, 0); + sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer( + NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + + /* right */ + studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 1, 2, 0); + sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer( + NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + + /* top */ + studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 0, 1, 2); + sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer( + NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + + /* bottom */ + studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, -start, -add, 0.5f, 0, 1, 2); + sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer( + NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + +#if 0 + IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat); + IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat); + IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat); + IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat); + IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat); + IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat); +#endif + MEM_freeN(colbuf); + } + } + sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED; +} + +BLI_INLINE void studiolight_evaluate_radiance_buffer( + ImBuf *radiance_buffer, const float normal[3], float color[3], int *hits, + int xoffset, int yoffset, int zoffset, float zvalue) +{ + if (radiance_buffer == NULL) { + return; + } + float angle; + float *radiance_color = radiance_buffer->rect_float; + float direction[3]; + for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) { + for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) { + // calculate light direction; + direction[zoffset] = zvalue; + direction[xoffset] = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f; + direction[yoffset] = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f; + normalize_v3(direction); + angle = fmax(0.0f, dot_v3v3(direction, normal)); + madd_v3_v3fl(color, radiance_color, angle); + (*hits)++; + radiance_color += 4; + } + } + +} + +/* + * Spherical Harmonics + */ +BLI_INLINE float studiolight_area_element(float x, float y) +{ + return atan2(x * y, sqrtf(x * x + y * y + 1)); +} + +BLI_INLINE float studiolight_texel_solid_angle(float x, float y, float halfpix) +{ + float v1x = (x - halfpix) * 2.0f - 1.0f; + float v1y = (y - halfpix) * 2.0f - 1.0f; + float v2x = (x + halfpix) * 2.0f - 1.0f; + float v2y = (y + halfpix) * 2.0f - 1.0f; + + return studiolight_area_element(v1x, v1y) - studiolight_area_element(v1x, v2y) - studiolight_area_element(v2x, v1y) + studiolight_area_element(v2x, v2y); +} + +static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y) +{ + copy_v3_fl3(normal, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f); + const float conversion_matrices[6][3][3] = { + { + {0.0f, 0.0f, 1.0f}, + {0.0f, -1.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + }, + { + {0.0f, 0.0f, -1.0f}, + {0.0f, -1.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, + }, + { + {1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, -1.0f}, + {0.0f, 1.0f, 0.0f}, + }, + { + {1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}, + {0.0f, -1.0f, 0.0f}, + }, + { + {1.0f, 0.0f, 0.0f}, + {0.0f, -1.0f, 0.0f}, + {0.0f, 0.0f, -1.0f}, + }, + { + {-1.0f, 0.0f, 0.0f}, + {0.0f, -1.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}, + } + }; + + mul_m3_v3(conversion_matrices[face], normal); + normalize_v3(normal); + const float halfpix = 1.0f / (2.0f * STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + *weight = studiolight_texel_solid_angle(x + halfpix, y + halfpix, halfpix); +} + +static void studiolight_calculate_spherical_harmonics_coefficient(StudioLight *sl, int sh_component) +{ + const float M_4PI = M_PI * 4.0f; + + float weight_accum = 0.0f; + float sh[3] = {0.0f, 0.0f, 0.0f}; + for (int face = 0; face < 6; face++) { + float *color; + color = sl->radiance_cubemap_buffers[face]->rect_float; + for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) { + float yf = y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; + for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) { + float xf = x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; + float weight, coef; + float cubevec[3]; + studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, xf, yf); + + const float nx = cubevec[0]; + const float ny = cubevec[1]; + const float nz = cubevec[2]; + const float nx2 = SQUARE(nx); + const float ny2 = SQUARE(ny); + const float nz2 = SQUARE(nz); + const float nx4 = SQUARE(nx2); + const float ny4 = SQUARE(ny2); + const float nz4 = SQUARE(nz2); + + switch (sh_component) { + /* L0 */ + case 0: + coef = 0.2822095f; + break; + /* L1 */ + case 1: + coef = -0.488603f * nz * 2.0f / 3.0f; + break; + case 2: + coef = 0.488603f * ny * 2.0f / 3.0f; + break; + case 3: + coef = -0.488603f * nx * 2.0f / 3.0f; + break; + /* L2 */ + case 4: + coef = 1.092548f * nx * nz * 1.0f / 4.0f; + break; + case 5: + coef = -1.092548f * nz * ny * 1.0f / 4.0f; + break; + case 6: + coef = 0.315392f * (3.0f * ny2 - 1.0f) * 1.0f / 4.0f; + break; + case 7: + coef = 1.092548f * nx * ny * 1.0f / 4.0f; + break; + case 8: + coef = 0.546274f * (nx2 - nz2) * 1.0f / 4.0f; + break; + /* L4 */ + case 9: + coef = (2.5033429417967046f * nx * nz * (nx2 - nz2)) / -24.0f; + break; + case 10: + coef = (-1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2)) / -24.0f; + break; + case 11: + coef = (0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2)) / -24.0f; + break; + case 12: + coef = (-0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2)) / -24.0f; + break; + case 13: + coef = ((105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f) / -24.0f; + break; + case 14: + coef = (-0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2)) / -24.0f; + break; + case 15: + coef = (0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2)) / -24.0f; + break; + case 16: + coef = (-1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2)) / -24.0f; + break; + case 17: + coef = (0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4)) / -24.0f; + break; + default: + coef = 0.0f; + } + + madd_v3_v3fl(sh, color, coef * weight); + weight_accum += weight; + color += 4; + } + } + } + + mul_v3_fl(sh, M_4PI / weight_accum); + copy_v3_v3(sl->spherical_harmonics_coefs[sh_component], sh); +} + +#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING +static void studiolight_calculate_spherical_harmonics_luminance(StudioLight *sl, float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS]) +{ + for (int index = 0; index < STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; index++) { + luminance[index] = rgb_to_grayscale(sl->spherical_harmonics_coefs[index]); + } +} + +static void studiolight_apply_spherical_harmonics_windowing(StudioLight *sl, float max_lamplacian) +{ + /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */ + float table_l[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1]; + float table_b[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1]; + + table_l[0] = 0.0f; + table_b[0] = 0.0f; + + /* convert to luminance */ + float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS]; + studiolight_calculate_spherical_harmonics_luminance(sl, luminance); + + int index = 1; + for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) { + table_l[level] = (float)(SQUARE(level) * SQUARE(level + 1)); + + float b = 0.0f; + for (int m = -1; m <= level; m++) { + b += SQUARE(luminance[index++]); + } + table_b[level] = b; + } + + float squared_lamplacian = 0.0f; + for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) { + squared_lamplacian += table_l[level] * table_b[level]; + } + + const float target_squared_laplacian = max_lamplacian * max_lamplacian; + if (squared_lamplacian <= target_squared_laplacian) { + return; + } + + float lambda = 0.0f; + + const int no_iterations = 10000000; + for (int i = 0; i < no_iterations; ++i) { + float f = 0.0f; + float fd = 0.0f; + + for (int level = 1; level <= (int)STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; ++level) { + f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]); + fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) / CUBE(1.0f + lambda * table_l[level]); + } + + f = target_squared_laplacian - f; + + float delta = -f / fd; + lambda += delta; + + if (ABS(delta) < 1e-6f) { + break; + } + } + + /* Apply windowing lambda */ + index = 0; + for (int level = 0; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) { + float s = 1.0f / (1.0f + lambda * SQUARE(level) * SQUARE(level + 1.0f)); + + for (int m = -1; m <= level; m++) { + mul_v3_fl(sl->spherical_harmonics_coefs[index++], s); + } + } +} +#endif + +BLI_INLINE void studiolight_sample_spherical_harmonics(StudioLight *sl, float color[3], float normal[3]) +{ + const float nx = normal[0]; + const float ny = normal[1]; + const float nz = normal[2]; + + copy_v3_fl(color, 0.0f); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f); + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 0 + /* Spherical Harmonics L1 */ + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * nz); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * ny); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * nx); +#endif + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 1 + /* Spherical Harmonics L2 */ + const float nx2 = SQUARE(nx); + const float ny2 = SQUARE(ny); + const float nz2 = SQUARE(nz); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * nx * nz); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * nz * ny); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * ny2 - 1.0f)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * nx * ny); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (nx2 - nz2)); +#endif + +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 3 + /* Spherical Harmonics L4 */ + const float nx4 = SQUARE(nx2); + const float ny4 = SQUARE(ny2); + const float nz4 = SQUARE(nz2); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[9], 2.5033429417967046f * nx * nz * (nx2 - nz2)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[10], -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[11], 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[12], -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[13], (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[14], -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[15], 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[16], -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2)); + madd_v3_v3fl(color, sl->spherical_harmonics_coefs[17], 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4)); +#endif + +} + +static void studiolight_calculate_diffuse_light(StudioLight *sl) +{ + /* init light to black */ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED); + + for (int comp = 0; comp < STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; comp++) { + studiolight_calculate_spherical_harmonics_coefficient(sl, comp); + } + +#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING + studiolight_apply_spherical_harmonics_windowing(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN); +#endif + + if (sl->flag & STUDIOLIGHT_USER_DEFINED) { + FILE *fp = BLI_fopen(sl->path_sh_cache, "wb"); + if (fp) { + fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp); + fclose(fp); + } + } + } + sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED; +} + +static float texel_coord_solid_angle(float a_U, float a_V, int a_Size) +{ + //scale up to [-1, 1] range (inclusive), offset by 0.5 to point to texel center. + float u = (2.0f * ((float)a_U + 0.5f) / (float)a_Size) - 1.0f; + float v = (2.0f * ((float)a_V + 0.5f) / (float)a_Size) - 1.0f; + + float resolution_inv = 1.0f / a_Size; + + // U and V are the -1..1 texture coordinate on the current face. + // Get projected area for this texel + float x0 = u - resolution_inv; + float y0 = v - resolution_inv; + float x1 = u + resolution_inv; + float y1 = v + resolution_inv; + return studiolight_area_element(x0, y0) - studiolight_area_element(x0, y1) - studiolight_area_element(x1, y0) + studiolight_area_element(x1, y1); +} + +BLI_INLINE void studiolight_evaluate_specular_radiance_buffer( + ImBuf *radiance_buffer, const float normal[3], float color[3], + int xoffset, int yoffset, int zoffset, float zvalue) +{ + if (radiance_buffer == NULL) { + return; + } + float angle; + float *radiance_color = radiance_buffer->rect_float; + float direction[3]; + for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) { + for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) { + // calculate light direction; + float u = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f; + float v = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f; + direction[zoffset] = zvalue; + direction[xoffset] = u; + direction[yoffset] = v; + normalize_v3(direction); + angle = fmax(0.0f, dot_v3v3(direction, normal)) * texel_coord_solid_angle(x, y, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE); + madd_v3_v3fl(color, radiance_color, angle); + radiance_color += 4; + } + } + +} + +#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE +static void studiolight_calculate_specular_irradiance(StudioLight *sl, float color[3], const float normal[3]) +{ + copy_v3_fl(color, 0.0f); + + /* back */ + studiolight_evaluate_specular_radiance_buffer( + sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, 0, 2, 1, 0.5); + /* front */ + studiolight_evaluate_specular_radiance_buffer( + sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, 0, 2, 1, -0.5); + + /* left */ + studiolight_evaluate_specular_radiance_buffer( + sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, 1, 2, 0, 0.5); + /* right */ + studiolight_evaluate_specular_radiance_buffer( + sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, 1, 2, 0, -0.5); + + /* top */ + studiolight_evaluate_specular_radiance_buffer( + sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, 0, 1, 2, 0.5); + /* bottom */ + studiolight_evaluate_specular_radiance_buffer( + sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, 0, 1, 2, -0.5); + + mul_v3_fl(color, 1.0 / M_PI); +} +#endif + +static bool studiolight_load_irradiance_equirectangular_image(StudioLight *sl) +{ +#ifdef STUDIOLIGHT_LOAD_CACHED_FILES + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + ImBuf *ibuf = NULL; + ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL); + if (ibuf) { + IMB_float_from_rect(ibuf); + sl->equirectangular_irradiance_buffer = ibuf; + sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED; + return true; + } + } +#endif + return false; +} + +static bool studiolight_load_spherical_harmonics_coefficients(StudioLight *sl) +{ +#ifdef STUDIOLIGHT_LOAD_CACHED_FILES + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + FILE *fp = BLI_fopen(sl->path_sh_cache, "rb"); + if (fp) { + if (fread((void *)(sl->spherical_harmonics_coefs), sizeof(sl->spherical_harmonics_coefs), 1, fp)) { + sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED; + fclose(fp); + return true; + } + fclose(fp); + } + } +#endif + return false; +} + +static void studiolight_calculate_irradiance_equirectangular_image(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { +#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED); +#endif +#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED); +#endif + + float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH * STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * sizeof(float[4]), __func__); + float *color = colbuf; + for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; y++) { + float yf = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; + + for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; x++) { + float xf = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; + float dir[3]; + equirectangular_to_direction(dir, xf, yf); + +#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE + studiolight_calculate_specular_irradiance(sl, color, dir); +#endif +#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS + studiolight_sample_spherical_harmonics(sl, color, dir); +#endif + + color[3] = 1.0f; + color += 4; + } + } + + sl->equirectangular_irradiance_buffer = IMB_allocFromBuffer( + NULL, colbuf, + STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH, + STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT); + MEM_freeN(colbuf); + +#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE + /* + * Only store cached files when using STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE + */ + if (sl->flag & STUDIOLIGHT_USER_DEFINED) { + IMB_saveiff(sl->equirectangular_irradiance_buffer, sl->path_irr_cache, IB_rectfloat); + } +#endif + } + sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED; +} + +static void studiolight_calculate_light_direction(StudioLight *sl) +{ + float best_light = 0.0; + sl->light_direction[0] = 0.0f; + sl->light_direction[1] = 0.0f; + sl->light_direction[2] = -1.0f; + + if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) && (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) { + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED); + ImBuf *ibuf = sl->equirectangular_irradiance_buffer; + if (ibuf) { + /* go over every pixel, determine light, if higher calc direction off the light */ + float new_light; + float *color = ibuf->rect_float; + for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; y++) { + for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; x++) { + new_light = color[0] + color[1] + color[2]; + if (new_light > best_light) { + float u = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; + float v = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; + equirectangular_to_direction(sl->light_direction, u, v); + SWAP(float, sl->light_direction[0], sl->light_direction[1]); + normalize_v3(sl->light_direction); + negate_v3(sl->light_direction); + best_light = new_light; + } + color += 4; + } + } + } + } + sl->flag |= STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED; +} + +static StudioLight *studiolight_add_file(const char *path, int flag) +{ + char filename[FILE_MAXFILE]; + BLI_split_file_part(path, filename, FILE_MAXFILE); + if (BLI_path_extension_check_array(filename, imb_ext_image)) { + StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag); + BLI_strncpy(sl->name, filename, FILE_MAXFILE); + BLI_strncpy(sl->path, path, FILE_MAXFILE); + sl->path_irr_cache = BLI_string_joinN(path, ".irr"); + sl->path_sh_cache = BLI_string_joinN(path, ".sh2"); + BLI_addtail(&studiolights, sl); + return sl; + } + return NULL; +} + +static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag) +{ + struct direntry *dir; + const char *folder = BKE_appdir_folder_id(folder_id, subfolder); + if (folder) { + uint totfile = BLI_filelist_dir_contents(folder, &dir); + int i; + for (i = 0; i < totfile; i++) { + if ((dir[i].type & S_IFREG)) { + studiolight_add_file(dir[i].path, flag); + } + } + BLI_filelist_free(dir, totfile); + dir = NULL; + } +} + +static int studiolight_flag_cmp_order(const StudioLight *sl) +{ + /* Internal studiolights before external studio lights */ + if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) { + return 1; + } + return 0; +} + +static int studiolight_cmp(const void *a, const void *b) +{ + const StudioLight *sl1 = a; + const StudioLight *sl2 = b; + + const int flagorder1 = studiolight_flag_cmp_order(sl1); + const int flagorder2 = studiolight_flag_cmp_order(sl2); + + if (flagorder1 < flagorder2) { + return -1; + } + else if (flagorder1 > flagorder2) { + return 1; + } + else { + return BLI_strcasecmp(sl1->name, sl2->name); + } +} + +/* icons */ + +/* Takes normalized uvs as parameter (range from 0 to 1). + * inner_edge and outer_edge are distances (from the center) + * in uv space for the alpha mask falloff. */ +static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge) +{ + /* Coords from center. */ + float co[2] = {u - 0.5f, v - 0.5f}; + float dist = len_v2(co); + float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge); + uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f)); + return mask << 24; +} + +#define STUDIOLIGHT_DIAMETER 0.95f + +static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl) +{ + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); + + float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE; + + int offset = 0; + for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) { + float dy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE; + dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) { + float dx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE; + dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + + uint pixelresult = 0x0; + uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f); + if (alphamask != 0) { + float incoming[3] = {0.0f, 0.0f, -1.0f}; + + float normal[3]; + normal[0] = dx * 2.0f - 1.0f; + normal[1] = dy * 2.0f - 1.0f; + float dist = len_v2(normal); + normal[2] = sqrtf(1.0f - SQUARE(dist)); + + float direction[3]; + reflect_v3_v3v3(direction, incoming, normal); + + /* We want to see horizon not poles. */ + SWAP(float, direction[1], direction[2]); + direction[1] = -direction[1]; + + float color[4]; + studiolight_calculate_radiance(sl->equirectangular_radiance_buffer, color, direction); + + pixelresult = rgb_to_cpack( + linearrgb_to_srgb(color[0]), + linearrgb_to_srgb(color[1]), + linearrgb_to_srgb(color[2])) | alphamask; + } + icon_buffer[offset++] = pixelresult; + } + } +} + +static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped) +{ + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED); + + float color[4]; + float fx, fy; + float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE; + int offset = 0; + ImBuf *ibuf = sl->equirectangular_radiance_buffer; + + for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) { + fy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE; + fy = fy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) { + fx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE; + fx = fx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + if (flipped) { + fx = 1.0f - fx; + } + nearest_interpolation_color(ibuf, NULL, color, fx * ibuf->x - 1.0f, fy * ibuf->y - 1.0f); + + uint alphamask = alpha_circle_mask(fx, fy, 0.5f - pixel_size, 0.5f); + + icon_buffer[offset++] = rgb_to_cpack( + linearrgb_to_srgb(color[0]), + linearrgb_to_srgb(color[1]), + linearrgb_to_srgb(color[2])) | alphamask; + } + } +} + +static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl) +{ + BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED); + + float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE; + + int offset = 0; + for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) { + float dy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE; + dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) { + float dx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE; + dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f; + + uint pixelresult = 0x0; + uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f); + if (alphamask != 0) { + /* calculate normal */ + float normal[3]; + normal[0] = dx * 2.0f - 1.0f; + normal[1] = -(dy * 2.0f - 1.0f); + float dist = len_v2(normal); + normal[2] = -sqrtf(1.0f - SQUARE(dist)); + SWAP(float, normal[1], normal[2]); + + float color[3]; + studiolight_sample_spherical_harmonics(sl, color, normal); + pixelresult = rgb_to_cpack( + linearrgb_to_srgb(color[0]), + linearrgb_to_srgb(color[1]), + linearrgb_to_srgb(color[2])) | alphamask; + } + icon_buffer[offset++] = pixelresult; + } + } +} + +/* API */ +void BKE_studiolight_init(void) +{ + StudioLight *sl; + /* go over the preset folder and add a studiolight for every image with its path */ + /* order studio lights by name */ + /* Also reserve icon space for it. */ + /* Add default studio light */ + sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA); + BLI_strncpy(sl->name, "Default", FILE_MAXFILE); + + + copy_v3_fl3(sl->spherical_harmonics_coefs[0], 1.03271556f, 1.07163882f, 1.11193657f); +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 0 + copy_v3_fl3(sl->spherical_harmonics_coefs[1], -0.00480952f, 0.05290511f, 0.16394117f); + copy_v3_fl3(sl->spherical_harmonics_coefs[2], -0.29686999f, -0.27378261f, -0.24797194f); + copy_v3_fl3(sl->spherical_harmonics_coefs[3], 0.47932500f, 0.48242140f, 0.47190312f); +#endif +#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 1 + copy_v3_fl3(sl->spherical_harmonics_coefs[4], -0.00576984f, 0.00504886f, 0.01640534f); + copy_v3_fl3(sl->spherical_harmonics_coefs[5], 0.15500379f, 0.15415503f, 0.16244425f); + copy_v3_fl3(sl->spherical_harmonics_coefs[6], -0.02483751f, -0.02245096f, -0.00536885f); + copy_v3_fl3(sl->spherical_harmonics_coefs[7], 0.11155496f, 0.11005443f, 0.10839636f); + copy_v3_fl3(sl->spherical_harmonics_coefs[8], 0.01363425f, 0.01278363f, -0.00159006f); +#endif + + BLI_addtail(&studiolights, sl); + + studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_USER_DEFINED); + studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_USER_DEFINED); + studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL); + studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_USER_DEFINED); + + /* sort studio lights on filename. */ + BLI_listbase_sort(&studiolights, studiolight_cmp); +} + +void BKE_studiolight_free(void) +{ + struct StudioLight *sl; + while ((sl = BLI_pophead(&studiolights))) { + studiolight_free(sl); + } +} + +struct StudioLight *BKE_studiolight_find_first(int flag) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if ((sl->flag & flag)) { + return sl; + } + } + return NULL; +} + +struct StudioLight *BKE_studiolight_find(const char *name, int flag) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if (STREQLEN(sl->name, name, FILE_MAXFILE)) { + if ((sl->flag & flag)) { + return sl; + } + else { + /* flags do not match, so use default */ + return BKE_studiolight_find_first(flag); + } + } + } + /* When not found, use the default studio light */ + return BKE_studiolight_find_first(flag); +} + +struct StudioLight *BKE_studiolight_findindex(int index, int flag) +{ + LISTBASE_FOREACH(StudioLight *, sl, &studiolights) { + if (sl->index == index) { + return sl; + } + } + /* When not found, use the default studio light */ + return BKE_studiolight_find_first(flag); +} + +struct ListBase *BKE_studiolight_listbase(void) +{ + return &studiolights; +} + +void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type) +{ + switch (icon_id_type) { + case STUDIOLIGHT_ICON_ID_TYPE_RADIANCE: + default: + { + studiolight_radiance_preview(icon_buffer, sl); + break; + } + case STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE: + { + studiolight_irradiance_preview(icon_buffer, sl); + break; + } + case STUDIOLIGHT_ICON_ID_TYPE_MATCAP: + { + studiolight_matcap_preview(icon_buffer, sl, false); + break; + } + case STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED: + { + studiolight_matcap_preview(icon_buffer, sl, true); + break; + } + } +} + +/* Ensure state of Studiolights */ +void BKE_studiolight_ensure_flag(StudioLight *sl, int flag) +{ + if ((sl->flag & flag) == flag) { + return; + } + + if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) { + studiolight_load_equirectangular_image(sl); + } + if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) { + studiolight_calculate_radiance_cubemap_buffers(sl); + } + if ((flag & STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED)) { + if (!studiolight_load_spherical_harmonics_coefficients(sl)) { + studiolight_calculate_diffuse_light(sl); + } + } + if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE)) { + studiolight_create_equirectangular_radiance_gputexture(sl); + } + if ((flag & STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED)) { + studiolight_calculate_light_direction(sl); + } + if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE)) { + studiolight_create_equirectangular_irradiance_gputexture(sl); + } + if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED)) { + if (!studiolight_load_irradiance_equirectangular_image(sl)) { + studiolight_calculate_irradiance_equirectangular_image(sl); + } + } +} + +/* + * Python API Functions + */ +void BKE_studiolight_remove(StudioLight *sl) +{ + if (sl->flag & STUDIOLIGHT_USER_DEFINED) { + BLI_remlink(&studiolights, sl); + studiolight_free(sl); + } +} + +StudioLight *BKE_studiolight_new(const char *path, int orientation) +{ + StudioLight *sl = studiolight_add_file(path, orientation | STUDIOLIGHT_USER_DEFINED); + return sl; +} + +void BKE_studiolight_refresh(void) +{ + BKE_studiolight_free(); + BKE_studiolight_init(); +} + +void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data) +{ + sl->free_function = free_function; + sl->free_function_data = data; +} + +void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id) +{ + BLI_assert(sl != NULL); + if (sl->icon_id_radiance == icon_id) { + sl->icon_id_radiance = 0; + } + if (sl->icon_id_irradiance == icon_id) { + sl->icon_id_irradiance = 0; + } + if (sl->icon_id_matcap == icon_id) { + sl->icon_id_matcap = 0; + } + if (sl->icon_id_matcap_flipped == icon_id) { + sl->icon_id_matcap_flipped = 0; + } +} diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c new file mode 100644 index 00000000000..b2736ed8f37 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv.c @@ -0,0 +1,149 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv.c + * \ingroup bke + */ + +#include "BKE_subdiv.h" + +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" + +#include "BLI_utildefines.h" + +#include "MEM_guardedalloc.h" + +#include "subdiv_converter.h" + +#include "opensubdiv_capi.h" +#include "opensubdiv_converter_capi.h" +#include "opensubdiv_evaluator_capi.h" +#include "opensubdiv_topology_refiner_capi.h" + +eSubdivFVarLinearInterpolation +BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth) +{ + switch (uv_smooth) { + case SUBSURF_UV_SMOOTH_NONE: + return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL; + case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS: + return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY; + case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS: + return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS; + case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE: + return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE; + case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES: + return SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES; + case SUBSURF_UV_SMOOTH_ALL: + return SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE; + } + BLI_assert(!"Unknown uv smooth flag"); + return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL; +} + +Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings, + struct OpenSubdiv_Converter *converter) +{ + SubdivStats stats; + BKE_subdiv_stats_init(&stats); + BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME); + OpenSubdiv_TopologyRefinerSettings topology_refiner_settings; + topology_refiner_settings.level = settings->level; + topology_refiner_settings.is_adaptive = settings->is_adaptive; + struct OpenSubdiv_TopologyRefiner *osd_topology_refiner = NULL; + if (converter->getNumVertices(converter) != 0) { + osd_topology_refiner = + openSubdiv_createTopologyRefinerFromConverter( + converter, &topology_refiner_settings); + + } + else { + /* TODO(sergey): Check whether original geometry had any vertices. + * The thing here is: OpenSubdiv can only deal with faces, but our + * side of subdiv also deals with loose vertices and edges. + */ + } + Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr"); + subdiv->settings = *settings; + subdiv->topology_refiner = osd_topology_refiner; + subdiv->evaluator = NULL; + subdiv->displacement_evaluator = NULL; + BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME); + subdiv->stats = stats; + return subdiv; +} + +Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings, + struct Mesh *mesh) +{ + if (mesh->totvert == 0) { + return NULL; + } + OpenSubdiv_Converter converter; + BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh); + Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter); + BKE_subdiv_converter_free(&converter); + return subdiv; +} + +void BKE_subdiv_free(Subdiv *subdiv) +{ + if (subdiv->evaluator != NULL) { + openSubdiv_deleteEvaluator(subdiv->evaluator); + } + if (subdiv->topology_refiner != NULL) { + openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner); + } + BKE_subdiv_displacement_detach(subdiv); + if (subdiv->cache_.face_ptex_offset != NULL) { + MEM_freeN(subdiv->cache_.face_ptex_offset); + } + MEM_freeN(subdiv); +} + +int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv) +{ + if (subdiv->cache_.face_ptex_offset != NULL) { + return subdiv->cache_.face_ptex_offset; + } + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + if (topology_refiner == NULL) { + return NULL; + } + const int num_coarse_faces = + topology_refiner->getNumFaces(topology_refiner); + subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN( + num_coarse_faces, sizeof(int), "subdiv face_ptex_offset"); + int ptex_offset = 0; + for (int face_index = 0; face_index < num_coarse_faces; face_index++) { + const int num_ptex_faces = + topology_refiner->getNumFacePtexFaces( + topology_refiner, face_index); + subdiv->cache_.face_ptex_offset[face_index] = ptex_offset; + ptex_offset += num_ptex_faces; + } + return subdiv->cache_.face_ptex_offset; +} diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c new file mode 100644 index 00000000000..e488b1129fc --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -0,0 +1,1188 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_ccg.c + * \ingroup bke + */ + +#include "BKE_subdiv_ccg.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math_bits.h" +#include "BLI_math_vector.h" +#include "BLI_task.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_ccg.h" +#include "BKE_mesh.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_eval.h" + +#include "opensubdiv_topology_refiner_capi.h" + +/* ============================================================================= + * Generally useful internal helpers. + */ + +/* Number of floats in per-vertex elements. */ +static int num_element_float_get(const SubdivCCG *subdiv_ccg) +{ + /* We always have 3 floats for coordinate. */ + int num_floats = 3; + if (subdiv_ccg->has_normal) { + num_floats += 3; + } + if (subdiv_ccg->has_mask) { + num_floats += 1; + } + return num_floats; +} + +/* Per-vertex element size in bytes. */ +static int element_size_bytes_get(const SubdivCCG *subdiv_ccg) +{ + return sizeof(float) * num_element_float_get(subdiv_ccg); +} + +/* ============================================================================= + * Internal helpers for CCG creation. + */ + +static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, + const SubdivToCCGSettings *settings) +{ + /* CCG always contains coordinates. Rest of layers are coming after them. */ + int layer_offset = sizeof(float) * 3; + /* Mask. */ + if (settings->need_mask) { + subdiv_ccg->has_mask = true; + subdiv_ccg->mask_offset = layer_offset; + layer_offset += sizeof(float); + } + else { + subdiv_ccg->has_mask = false; + subdiv_ccg->mask_offset = -1; + } + /* Normals. + * + * NOTE: Keep them at the end, matching old CCGDM. Doesn't really matter + * here, but some other area might in theory depend memory layout. + */ + if (settings->need_normal) { + subdiv_ccg->has_normal = true; + subdiv_ccg->normal_offset = layer_offset; + layer_offset += sizeof(float) * 3; + } + else { + subdiv_ccg->has_normal = false; + subdiv_ccg->normal_offset = -1; + } +} + +/* TODO(sergey): Make it more accessible function. */ +static int topology_refiner_count_face_corners( + OpenSubdiv_TopologyRefiner *topology_refiner) +{ + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + int num_corners = 0; + for (int face_index = 0; face_index < num_faces; face_index++) { + num_corners += topology_refiner->getNumFaceVertices( + topology_refiner, face_index); + } + return num_corners; +} + +/* NOTE: Grid size and layer flags are to be filled in before calling this + * function. + */ +static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv) +{ + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + const int element_size = element_size_bytes_get(subdiv_ccg); + /* Allocate memory for surface grids. */ + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + const int num_grids = topology_refiner_count_face_corners(topology_refiner); + const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level); + const int grid_area = grid_size * grid_size; + subdiv_ccg->num_grids = num_grids; + subdiv_ccg->grids = + MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids"); + subdiv_ccg->grids_storage = MEM_calloc_arrayN( + num_grids, ((size_t)grid_area) * element_size, + "subdiv ccg grids storage"); + const size_t grid_size_in_bytes = (size_t)grid_area * element_size; + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + const size_t grid_offset = grid_size_in_bytes * grid_index; + subdiv_ccg->grids[grid_index] = + (CCGElem *)&subdiv_ccg->grids_storage[grid_offset]; + } + /* Grid material flags. */ + subdiv_ccg->grid_flag_mats = MEM_calloc_arrayN( + num_grids, sizeof(DMFlagMat), "ccg grid material flags"); + /* Grid hidden flags. */ + subdiv_ccg->grid_hidden = MEM_calloc_arrayN( + num_grids, sizeof(BLI_bitmap *), "ccg grid material flags"); + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + subdiv_ccg->grid_hidden[grid_index] = + BLI_BITMAP_NEW(grid_area, "ccg grid hidden"); + } + /* TODO(sergey): Allocate memory for loose elements. */ + /* Allocate memory for faces. */ + subdiv_ccg->num_faces = num_faces; + if (num_faces) { + subdiv_ccg->faces = MEM_calloc_arrayN( + num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces"); + subdiv_ccg->grid_faces = MEM_calloc_arrayN( + num_grids, sizeof(SubdivCCGFace *), "Subdiv CCG grid faces"); + } +} + +/* ============================================================================= + * Grids evaluation. + */ + +typedef struct CCGEvalGridsData { + SubdivCCG *subdiv_ccg; + Subdiv *subdiv; + int *face_ptex_offset; + SubdivCCGMask *mask_evaluator; +} CCGEvalGridsData; + +static void subdiv_ccg_eval_grid_element( + CCGEvalGridsData *data, + const int ptex_face_index, + const float u, const float v, + unsigned char *element) +{ + Subdiv *subdiv = data->subdiv; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + if (subdiv->displacement_evaluator != NULL) { + BKE_subdiv_eval_final_point( + subdiv, ptex_face_index, u, v, (float *)element); + } + else if (subdiv_ccg->has_normal) { + BKE_subdiv_eval_limit_point_and_normal( + subdiv, ptex_face_index, u, v, + (float *)element, + (float *)(element + subdiv_ccg->normal_offset)); + } + else { + BKE_subdiv_eval_limit_point( + subdiv, ptex_face_index, u, v, (float *)element); + } + if (subdiv_ccg->has_mask) { + float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset); + if (data->mask_evaluator != NULL) { + *mask_value_ptr = data->mask_evaluator->eval_mask( + data->mask_evaluator, ptex_face_index, u, v); + } + else { + *mask_value_ptr = 0.0f; + } + } +} + +BLI_INLINE void rotate_corner_to_quad( + const int corner, + const float u, const float v, + float *r_u, float *r_v) +{ + if (corner == 0) { + *r_u = 0.5f - v * 0.5f; + *r_v = 0.5f - u * 0.5f; + } + else if (corner == 1) { + *r_u = 0.5f + u * 0.5f; + *r_v = 0.5f - v * 0.5f; + } + else if (corner == 2) { + *r_u = 0.5f + v * 0.5f; + *r_v = 0.5f + u * 0.5f; + } + else { + BLI_assert(corner == 3); + *r_u = 0.5f - u * 0.5f; + *r_v = 0.5f + v * 0.5f; + } +} + +static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data, + const int face_index) +{ + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + const int ptex_face_index = data->face_ptex_offset[face_index]; + const int grid_size = subdiv_ccg->grid_size; + const float grid_size_1_inv = 1.0f / (float)(grid_size - 1); + const int element_size = element_size_bytes_get(subdiv_ccg); + SubdivCCGFace *faces = subdiv_ccg->faces; + SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces; + const SubdivCCGFace *face = &faces[face_index]; + for (int corner = 0; corner < face->num_grids; corner++) { + const int grid_index = face->start_grid_index + corner; + unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index]; + for (int y = 0; y < grid_size; y++) { + const float grid_v = (float)y * grid_size_1_inv; + for (int x = 0; x < grid_size; x++) { + const float grid_u = (float)x * grid_size_1_inv; + float u, v; + rotate_corner_to_quad(corner, grid_u, grid_v, &u, &v); + const size_t grid_element_index = (size_t)y * grid_size + x; + const size_t grid_element_offset = + grid_element_index * element_size; + subdiv_ccg_eval_grid_element( + data, + ptex_face_index, u, v, + &grid[grid_element_offset]); + } + } + /* Assign grid's face. */ + grid_faces[grid_index] = &faces[face_index]; + } +} + +static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data, + const int face_index) +{ + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + const int grid_size = subdiv_ccg->grid_size; + const float grid_size_1_inv = 1.0f / (float)(grid_size - 1); + const int element_size = element_size_bytes_get(subdiv_ccg); + SubdivCCGFace *faces = subdiv_ccg->faces; + SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces; + const SubdivCCGFace *face = &faces[face_index]; + for (int corner = 0; corner < face->num_grids; corner++) { + const int grid_index = face->start_grid_index + corner; + unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index]; + for (int y = 0; y < grid_size; y++) { + const float u = 1.0f - ((float)y * grid_size_1_inv); + for (int x = 0; x < grid_size; x++) { + const float v = 1.0f - ((float)x * grid_size_1_inv); + const int ptex_face_index = + data->face_ptex_offset[face_index] + corner; + const size_t grid_element_index = (size_t)y * grid_size + x; + const size_t grid_element_offset = + grid_element_index * element_size; + subdiv_ccg_eval_grid_element( + data, + ptex_face_index, u, v, + &grid[grid_element_offset]); + } + } + /* Assign grid's face. */ + grid_faces[grid_index] = &faces[face_index]; + } +} + +static void subdiv_ccg_eval_grids_task( + void *__restrict userdata_v, + const int face_index, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + CCGEvalGridsData *data = userdata_v; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + SubdivCCGFace *face = &subdiv_ccg->faces[face_index]; + if (face->num_grids == 4) { + subdiv_ccg_eval_regular_grid(data, face_index); + } + else { + subdiv_ccg_eval_special_grid(data, face_index); + } +} + +static bool subdiv_ccg_evaluate_grids( + SubdivCCG *subdiv_ccg, + Subdiv *subdiv, + SubdivCCGMask *mask_evaluator) +{ + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + /* Initialize data passed to all the tasks. */ + CCGEvalGridsData data; + data.subdiv_ccg = subdiv_ccg; + data.subdiv = subdiv; + data.face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); + data.mask_evaluator = mask_evaluator; + /* Threaded grids evaluation. */ + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + BLI_task_parallel_range(0, num_faces, + &data, + subdiv_ccg_eval_grids_task, + ¶llel_range_settings); + /* If displacement is used, need to calculate normals after all final + * coordinates are known. + */ + if (subdiv->displacement_evaluator != NULL) { + BKE_subdiv_ccg_recalc_normals(subdiv_ccg); + } + return true; +} + +/* Initialize face descriptors, assuming memory for them was already + * allocated. + */ +static void subdiv_ccg_init_faces(SubdivCCG *subdiv_ccg) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + const int num_faces = subdiv_ccg->num_faces; + int corner_index = 0; + for (int face_index = 0; face_index < num_faces; face_index++) { + const int num_corners = topology_refiner->getNumFaceVertices( + topology_refiner, face_index); + subdiv_ccg->faces[face_index].num_grids = num_corners; + subdiv_ccg->faces[face_index].start_grid_index = corner_index; + corner_index += num_corners; + } +} + +/* TODO(sergey): Consider making it generic enough to be fit into BLI. */ +typedef struct StaticOrHeapIntStorage { + int static_storage[64]; + int static_storage_size; + int *heap_storage; + int heap_storage_size; +} StaticOrHeapIntStorage; + +static void static_or_heap_storage_init(StaticOrHeapIntStorage *storage) +{ + storage->static_storage_size = + sizeof(storage->static_storage) / sizeof(*storage->static_storage); + storage->heap_storage = NULL; + storage->heap_storage_size = 0; +} + +static int *static_or_heap_storage_get(StaticOrHeapIntStorage *storage, + int size) +{ + /* Requested size small enough to be fit into stack allocated memory. */ + if (size <= storage->static_storage_size) { + return storage->static_storage; + } + /* Make sure heap ius big enough. */ + if (size > storage->heap_storage_size) { + MEM_SAFE_FREE(storage->heap_storage); + storage->heap_storage = MEM_malloc_arrayN( + size, sizeof(int), "int storage"); + storage->heap_storage_size = size; + } + return storage->heap_storage; +} + +static void static_or_heap_storage_free(StaticOrHeapIntStorage *storage) +{ + MEM_SAFE_FREE(storage->heap_storage); +} + +static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg, + const int num_edges) +{ + subdiv_ccg->num_adjacent_edges = num_edges; + subdiv_ccg->adjacent_edges = MEM_calloc_arrayN( + subdiv_ccg->num_adjacent_edges, + sizeof(*subdiv_ccg->adjacent_edges), + "ccg adjacent edges"); +} + +/* Returns storage where boundary elements are to be stored. */ +static CCGElem **subdiv_ccg_adjacent_edge_add_face( + SubdivCCG *subdiv_ccg, + SubdivCCGAdjacentEdge *adjacent_edge, + SubdivCCGFace *face) +{ + const int grid_size = subdiv_ccg->grid_size * 2; + const int adjacent_face_index = adjacent_edge->num_adjacent_faces; + ++adjacent_edge->num_adjacent_faces; + /* Store new adjacent face. */ + adjacent_edge->faces = MEM_reallocN( + adjacent_edge->faces, + adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces)); + adjacent_edge->faces[adjacent_face_index] = face; + /* Allocate memory for the boundary elements. */ + adjacent_edge->boundary_elements = MEM_reallocN( + adjacent_edge->boundary_elements, + adjacent_edge->num_adjacent_faces * + sizeof(*adjacent_edge->boundary_elements)); + adjacent_edge->boundary_elements[adjacent_face_index] = + MEM_malloc_arrayN( + grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary"); + return adjacent_edge->boundary_elements[adjacent_face_index]; +} + +static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + SubdivCCGFace *faces = subdiv_ccg->faces; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + const int num_edges = topology_refiner->getNumEdges(topology_refiner); + const int grid_size = subdiv_ccg->grid_size; + if (num_edges == 0) { + /* Early output, nothing to do in this case. */ + return; + } + subdiv_ccg_allocate_adjacent_edges(subdiv_ccg, num_edges); + /* Initialize storage. */ + StaticOrHeapIntStorage face_vertices_storage; + StaticOrHeapIntStorage face_edges_storage; + static_or_heap_storage_init(&face_vertices_storage); + static_or_heap_storage_init(&face_edges_storage); + /* Key to access elements. */ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + /* Store adjacency for all faces. */ + const int num_faces = subdiv_ccg->num_faces; + for (int face_index = 0; face_index < num_faces; face_index++) { + SubdivCCGFace *face = &faces[face_index]; + const int num_face_grids = face->num_grids; + const int num_face_edges = num_face_grids; + int *face_vertices = static_or_heap_storage_get( + &face_vertices_storage, num_face_edges); + topology_refiner->getFaceVertices( + topology_refiner, face_index, face_vertices); + /* Note that order of edges is same as order of MLoops, which also + * means it's the same as order of grids. + */ + int *face_edges = static_or_heap_storage_get( + &face_edges_storage, num_face_edges); + topology_refiner->getFaceEdges( + topology_refiner, face_index, face_edges); + /* Store grids adjacency for this edge. */ + for (int corner = 0; corner < num_face_edges; corner++) { + const int vertex_index = face_vertices[corner]; + const int edge_index = face_edges[corner]; + int edge_vertices[2]; + topology_refiner->getEdgeVertices( + topology_refiner, edge_index, edge_vertices); + const bool is_edge_flipped = (edge_vertices[0] != vertex_index); + /* Grid which is adjacent to the current corner. */ + const int current_grid_index = face->start_grid_index + corner; + CCGElem *current_grid = subdiv_ccg->grids[current_grid_index]; + /* Grid which is adjacent to the next corner. */ + const int next_grid_index = + face->start_grid_index + (corner + 1) % num_face_grids; + CCGElem *next_grid = subdiv_ccg->grids[next_grid_index]; + /* Add new face to the adjacent edge. */ + SubdivCCGAdjacentEdge *adjacent_edge = + &subdiv_ccg->adjacent_edges[edge_index]; + CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face( + subdiv_ccg, adjacent_edge, face); + /* Fill CCG elements along the edge. */ + int boundary_element_index = 0; + if (is_edge_flipped) { + for (int i = 0; i < grid_size; i++) { + boundary_elements[boundary_element_index++] = + CCG_grid_elem(&key, + next_grid, + grid_size - i - 1, + grid_size - 1); + } + for (int i = 0; i < grid_size; i++) { + boundary_elements[boundary_element_index++] = + CCG_grid_elem(&key, + current_grid, + grid_size - 1, + i); + } + } + else { + for (int i = 0; i < grid_size; i++) { + boundary_elements[boundary_element_index++] = + CCG_grid_elem(&key, + current_grid, + grid_size - 1, + grid_size - i - 1); + } + for (int i = 0; i < grid_size; i++) { + boundary_elements[boundary_element_index++] = + CCG_grid_elem(&key, + next_grid, + i, + grid_size - 1); + } + } + } + } + /* Free possibly heap-allocated storage. */ + static_or_heap_storage_free(&face_vertices_storage); + static_or_heap_storage_free(&face_edges_storage); +} + +static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg, + const int num_vertices) +{ + subdiv_ccg->num_adjacent_vertices = num_vertices; + subdiv_ccg->adjacent_vertices = MEM_calloc_arrayN( + subdiv_ccg->num_adjacent_vertices, + sizeof(*subdiv_ccg->adjacent_vertices), + "ccg adjacent vertices"); +} + +/* Returns storage where corner elements are to be stored. This is a pointer + * to the actual storage. + */ +static CCGElem **subdiv_ccg_adjacent_vertex_add_face( + SubdivCCGAdjacentVertex *adjacent_vertex, + SubdivCCGFace *face) +{ + const int adjacent_face_index = adjacent_vertex->num_adjacent_faces; + ++adjacent_vertex->num_adjacent_faces; + /* Store new adjacent face. */ + adjacent_vertex->faces = MEM_reallocN( + adjacent_vertex->faces, + adjacent_vertex->num_adjacent_faces * + sizeof(*adjacent_vertex->faces)); + adjacent_vertex->faces[adjacent_face_index] = face; + /* Allocate memory for the boundary elements. */ + adjacent_vertex->corner_elements = MEM_reallocN( + adjacent_vertex->corner_elements, + adjacent_vertex->num_adjacent_faces * + sizeof(*adjacent_vertex->corner_elements)); + return &adjacent_vertex->corner_elements[adjacent_face_index]; +} + +static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + SubdivCCGFace *faces = subdiv_ccg->faces; + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + const int num_vertices = + topology_refiner->getNumVertices(topology_refiner); + const int grid_size = subdiv_ccg->grid_size; + if (num_vertices == 0) { + /* Early output, nothing to do in this case. */ + return; + } + subdiv_ccg_allocate_adjacent_vertices(subdiv_ccg, num_vertices); + /* Initialize storage. */ + StaticOrHeapIntStorage face_vertices_storage; + static_or_heap_storage_init(&face_vertices_storage); + /* Key to access elements. */ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + /* Store adjacency for all faces. */ + const int num_faces = subdiv_ccg->num_faces; + for (int face_index = 0; face_index < num_faces; face_index++) { + SubdivCCGFace *face = &faces[face_index]; + const int num_face_grids = face->num_grids; + const int num_face_edges = num_face_grids; + int *face_vertices = static_or_heap_storage_get( + &face_vertices_storage, num_face_edges); + topology_refiner->getFaceVertices( + topology_refiner, face_index, face_vertices); + for (int corner = 0; corner < num_face_edges; corner++) { + const int vertex_index = face_vertices[corner]; + /* Grid which is adjacent to the current corner. */ + const int grid_index = face->start_grid_index + corner; + CCGElem *grid = subdiv_ccg->grids[grid_index]; + /* Add new face to the adjacent edge. */ + SubdivCCGAdjacentVertex *adjacent_vertex = + &subdiv_ccg->adjacent_vertices[vertex_index]; + CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face( + adjacent_vertex, face); + *corner_element = CCG_grid_elem( + &key, grid, grid_size - 1, grid_size - 1); + } + } + /* Free possibly heap-allocated storage. */ + static_or_heap_storage_free(&face_vertices_storage); +} + +static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg) +{ + subdiv_ccg_init_faces_edge_neighborhood(subdiv_ccg); + subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg); +} + +/* ============================================================================= + * Creation / evaluation. + */ + +SubdivCCG *BKE_subdiv_to_ccg( + Subdiv *subdiv, + const SubdivToCCGSettings *settings, + SubdivCCGMask *mask_evaluator) +{ + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg"); + subdiv_ccg->subdiv = subdiv; + subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1); + subdiv_ccg->grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level); + subdiv_ccg_init_layers(subdiv_ccg, settings); + subdiv_ccg_alloc_elements(subdiv_ccg, subdiv); + subdiv_ccg_init_faces(subdiv_ccg); + subdiv_ccg_init_faces_neighborhood(subdiv_ccg); + if (!subdiv_ccg_evaluate_grids(subdiv_ccg, subdiv, mask_evaluator)) { + BKE_subdiv_ccg_destroy(subdiv_ccg); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + return NULL; + } + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + return subdiv_ccg; +} + +Mesh *BKE_subdiv_to_ccg_mesh( + Subdiv *subdiv, + const SubdivToCCGSettings *settings, + const Mesh *coarse_mesh) +{ + /* Make sure evaluator is ready. */ + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) { + if (coarse_mesh->totpoly) { + return false; + } + } + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); + SubdivCCGMask mask_evaluator; + bool has_mask = BKE_subdiv_ccg_mask_init_from_paint( + &mask_evaluator, coarse_mesh); + SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg( + subdiv, settings, has_mask ? &mask_evaluator : NULL); + if (has_mask) { + mask_evaluator.free(&mask_evaluator); + } + if (subdiv_ccg == NULL) { + return NULL; + } + Mesh *result = BKE_mesh_new_nomain_from_template( + coarse_mesh, 0, 0, 0, 0, 0); + result->runtime.subdiv_ccg = subdiv_ccg; + return result; +} + +void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg) +{ + const int num_grids = subdiv_ccg->num_grids; + MEM_SAFE_FREE(subdiv_ccg->grids); + MEM_SAFE_FREE(subdiv_ccg->grids_storage); + MEM_SAFE_FREE(subdiv_ccg->edges); + MEM_SAFE_FREE(subdiv_ccg->vertices); + MEM_SAFE_FREE(subdiv_ccg->grid_flag_mats); + if (subdiv_ccg->grid_hidden != NULL) { + for (int grid_index = 0; grid_index < num_grids; grid_index++) { + MEM_freeN(subdiv_ccg->grid_hidden[grid_index]); + } + MEM_freeN(subdiv_ccg->grid_hidden); + } + if (subdiv_ccg->subdiv != NULL) { + BKE_subdiv_free(subdiv_ccg->subdiv); + } + MEM_SAFE_FREE(subdiv_ccg->faces); + MEM_SAFE_FREE(subdiv_ccg->grid_faces); + /* Free map of adjacent edges. */ + for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) { + SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i]; + for (int face_index = 0; + face_index < adjacent_edge->num_adjacent_faces; + face_index++) + { + MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]); + } + MEM_SAFE_FREE(adjacent_edge->faces); + MEM_SAFE_FREE(adjacent_edge->boundary_elements); + } + MEM_SAFE_FREE(subdiv_ccg->adjacent_edges); + /* Free map of adjacent vertices. */ + for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) { + SubdivCCGAdjacentVertex *adjacent_vertex = + &subdiv_ccg->adjacent_vertices[i]; + MEM_SAFE_FREE(adjacent_vertex->faces); + MEM_SAFE_FREE(adjacent_vertex->corner_elements); + } + MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices); + MEM_freeN(subdiv_ccg); +} + +void BKE_subdiv_ccg_key(CCGKey *key, const SubdivCCG *subdiv_ccg, int level) +{ + key->level = level; + key->elem_size = element_size_bytes_get(subdiv_ccg); + key->grid_size = BKE_subdiv_grid_size_from_level(level); + key->grid_area = key->grid_size * key->grid_size; + key->grid_bytes = key->elem_size * key->grid_area; + + key->normal_offset = subdiv_ccg->normal_offset; + key->mask_offset = subdiv_ccg->mask_offset; + + key->has_normals = subdiv_ccg->has_normal; + key->has_mask = subdiv_ccg->has_mask; +} + +void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg) +{ + BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level); +} + +/* ============================================================================= + * Normals. + */ + +typedef struct RecalcInnerNormalsData { + SubdivCCG *subdiv_ccg; + CCGKey *key; +} RecalcInnerNormalsData; + +typedef struct RecalcInnerNormalsTLSData { + float (*face_normals)[3]; +} RecalcInnerNormalsTLSData; + +/* Evaluate high-res face normals, for faces which corresponds to grid elements + * + * {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}} + * + * The result is stored in normals storage from TLS. + */ +static void subdiv_ccg_recalc_inner_face_normals( + RecalcInnerNormalsData *data, + RecalcInnerNormalsTLSData *tls, + const int grid_index) +{ + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + CCGKey *key = data->key; + const int grid_size = subdiv_ccg->grid_size; + const int grid_size_1 = grid_size - 1; + CCGElem *grid = subdiv_ccg->grids[grid_index]; + if (tls->face_normals == NULL) { + tls->face_normals = MEM_malloc_arrayN( + grid_size_1 * grid_size_1, + 3 * sizeof(float), + "CCG TLS normals"); + } + for (int y = 0; y < grid_size -1; y++) { + for (int x = 0; x < grid_size - 1; x++) { + CCGElem *grid_elements[4] = { + CCG_grid_elem(key, grid, x, y + 1), + CCG_grid_elem(key, grid, x + 1, y + 1), + CCG_grid_elem(key, grid, x + 1, y), + CCG_grid_elem(key, grid, x, y) + }; + float *co[4] = { + CCG_elem_co(key, grid_elements[0]), + CCG_elem_co(key, grid_elements[1]), + CCG_elem_co(key, grid_elements[2]), + CCG_elem_co(key, grid_elements[3]) + }; + const int face_index = y * grid_size_1 + x; + float *face_normal = tls->face_normals[face_index]; + normal_quad_v3(face_normal, co[0], co[1], co[2], co[3]); + } + } +} + +/* Average normals at every grid element, using adjacent faces normals. */ +static void subdiv_ccg_average_inner_face_normals( + RecalcInnerNormalsData *data, + RecalcInnerNormalsTLSData *tls, + const int grid_index) +{ + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + CCGKey *key = data->key; + const int grid_size = subdiv_ccg->grid_size; + const int grid_size_1 = grid_size - 1; + CCGElem *grid = subdiv_ccg->grids[grid_index]; + const float (*face_normals)[3] = tls->face_normals; + for (int y = 0; y < grid_size; y++) { + for (int x = 0; x < grid_size; x++) { + float normal_acc[3] = {0.0f, 0.0f, 0.0f}; + int counter = 0; + /* Accumulate normals of all adjacent faces. */ + if (x < grid_size_1 && y < grid_size_1) { + add_v3_v3(normal_acc, face_normals[y * grid_size_1 + x]); + counter++; + } + if (x >= 1) { + if (y < grid_size_1) { + add_v3_v3(normal_acc, + face_normals[y * grid_size_1 + (x - 1)]); + counter++; + } + if (y >= 1) { + add_v3_v3(normal_acc, + face_normals[(y - 1) * grid_size_1 + (x - 1)]); + counter++; + } + } + if (y >= 1 && x < grid_size_1) { + add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + x]); + counter++; + } + /* Normalize and store. */ + mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y), + normal_acc, + 1.0f / (float)counter); + } + } +} + +static void subdiv_ccg_recalc_inner_normal_task( + void *__restrict userdata_v, + const int grid_index, + const ParallelRangeTLS *__restrict tls_v) +{ + RecalcInnerNormalsData *data = userdata_v; + RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk; + subdiv_ccg_recalc_inner_face_normals(data, tls, grid_index); + subdiv_ccg_average_inner_face_normals(data, tls, grid_index); +} + +static void subdiv_ccg_recalc_inner_normal_finalize( + void *__restrict UNUSED(userdata), + void *__restrict tls_v) +{ + RecalcInnerNormalsTLSData *tls = tls_v; + MEM_SAFE_FREE(tls->face_normals); +} + +/* Recalculate normals which corresponds to non-boundaries elements of grids. */ +static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg) +{ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + RecalcInnerNormalsData data = { + .subdiv_ccg = subdiv_ccg, + .key = &key + }; + RecalcInnerNormalsTLSData tls_data = {NULL}; + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + parallel_range_settings.userdata_chunk = &tls_data; + parallel_range_settings.userdata_chunk_size = sizeof(tls_data); + parallel_range_settings.func_finalize = + subdiv_ccg_recalc_inner_normal_finalize; + BLI_task_parallel_range(0, subdiv_ccg->num_grids, + &data, + subdiv_ccg_recalc_inner_normal_task, + ¶llel_range_settings); +} + +void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg) +{ + if (!subdiv_ccg->has_normal) { + /* Grids don't have normals, can do early output. */ + return; + } + subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg); + BKE_subdiv_ccg_average_grids(subdiv_ccg); +} + +/* ============================================================================= + * Boundary averaging/stitching. + */ + +typedef struct AverageInnerGridsData { + SubdivCCG *subdiv_ccg; + CCGKey *key; +} AverageInnerGridsData; + +static void average_grid_element_value_v3(float a[3], float b[3]) +{ + add_v3_v3(a, b); + mul_v3_fl(a, 0.5f); + copy_v3_v3(b, a); +} + +static void average_grid_element(SubdivCCG *subdiv_ccg, + CCGKey *key, + CCGElem *grid_element_a, + CCGElem *grid_element_b) +{ + average_grid_element_value_v3(CCG_elem_co(key, grid_element_a), + CCG_elem_co(key, grid_element_b)); + if (subdiv_ccg->has_normal) { + average_grid_element_value_v3(CCG_elem_no(key, grid_element_a), + CCG_elem_no(key, grid_element_b)); + } + if (subdiv_ccg->has_mask) { + float mask = + (*CCG_elem_mask(key, grid_element_a) + + *CCG_elem_mask(key, grid_element_b)) * 0.5f; + *CCG_elem_mask(key, grid_element_a) = mask; + *CCG_elem_mask(key, grid_element_b) = mask; + } +} + +static void copy_grid_element(SubdivCCG *subdiv_ccg, + CCGKey *key, + CCGElem *destination, + CCGElem *source) +{ + copy_v3_v3(CCG_elem_co(key, destination), CCG_elem_co(key, source)); + if (subdiv_ccg->has_normal) { + copy_v3_v3(CCG_elem_no(key, destination), CCG_elem_no(key, source)); + } + if (subdiv_ccg->has_mask) { + *CCG_elem_mask(key, destination) = *CCG_elem_mask(key, source); + } +} + +static void subdiv_ccg_average_inner_face_grids( + SubdivCCG *subdiv_ccg, + CCGKey *key, + SubdivCCGFace *face) +{ + CCGElem **grids = subdiv_ccg->grids; + const int num_face_grids = face->num_grids; + const int grid_size = subdiv_ccg->grid_size; + CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1]; + for (int corner = 0; corner < num_face_grids; corner++) { + CCGElem *grid = grids[face->start_grid_index + corner]; + for (int i = 0; i < grid_size; i++) { + CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0); + CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i); + average_grid_element( + subdiv_ccg, key, prev_grid_element, grid_element); + } + prev_grid = grid; + } + +} + +static void subdiv_ccg_average_inner_grids_task( + void *__restrict userdata_v, + const int face_index, + const ParallelRangeTLS *__restrict UNUSED(tls_v)) +{ + AverageInnerGridsData *data = userdata_v; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + CCGKey *key = data->key; + SubdivCCGFace *faces = subdiv_ccg->faces; + SubdivCCGFace *face = &faces[face_index]; + subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face); +} + +typedef struct AverageGridsBoundariesData { + SubdivCCG *subdiv_ccg; + CCGKey *key; +} AverageGridsBoundariesData; + +static void subdiv_ccg_average_grids_boundary( + SubdivCCG *subdiv_ccg, + CCGKey *key, + SubdivCCGAdjacentEdge *adjacent_edge) +{ + const int num_adjacent_faces = adjacent_edge->num_adjacent_faces; + const int grid_size2 = subdiv_ccg->grid_size * 2; + if (num_adjacent_faces == 1) { + /* Nothing to average with. */ + return; + } + /* Incrementall average result to elements of a first adjacent face. + * + * Arguably, this is less precise than accumulating and then diving once, + * but on another hand this is more stable when coordinates are big. + */ + for (int face_index = 1; face_index < num_adjacent_faces; face_index++) { + /* NOTE: We ignore very first and very last elements, they correspond + * to corner vertices, and they can belong to multiple edges. + * The fact, that they can belong to multiple edges means we can't + * safely average them. + * The fact, that they correspond to a corner elements, means they will + * be handled at the upcoming pass over corner elements. + */ + for (int i = 1; i < grid_size2 - 1; i++) { + CCGElem *grid_element_0 = + adjacent_edge->boundary_elements[0][i]; + CCGElem *grid_element_face_index = + adjacent_edge->boundary_elements[face_index][i]; + average_grid_element(subdiv_ccg, + key, + grid_element_0, + grid_element_face_index); + } + } + /* Copy averaged value to all the other faces. */ + for (int face_index = 1; face_index < num_adjacent_faces; face_index++) { + for (int i = 1; i < grid_size2 -1; i++) { + CCGElem *grid_element_0 = + adjacent_edge->boundary_elements[0][i]; + CCGElem *grid_element_face_index = + adjacent_edge->boundary_elements[face_index][i]; + copy_grid_element(subdiv_ccg, + key, + grid_element_face_index, + grid_element_0); + } + } +} + +static void subdiv_ccg_average_grids_boundaries_task( + void *__restrict userdata_v, + const int adjacent_edge_index, + const ParallelRangeTLS *__restrict UNUSED(tls_v)) +{ + AverageGridsBoundariesData *data = userdata_v; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + CCGKey *key = data->key; + SubdivCCGAdjacentEdge *adjacent_edge = + &subdiv_ccg->adjacent_edges[adjacent_edge_index]; + subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge); +} + +typedef struct AverageGridsCornerData { + SubdivCCG *subdiv_ccg; + CCGKey *key; +} AverageGridsCornerData; + +static void subdiv_ccg_average_grids_corners( + SubdivCCG *subdiv_ccg, + CCGKey *key, + SubdivCCGAdjacentVertex *adjacent_vertex) +{ + const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces; + if (num_adjacent_faces == 1) { + /* Nothing to average with. */ + return; + } + /* Incrementall average result to elements of a first adjacent face. + * See comment to the boundary averaging. + */ + for (int face_index = 1; face_index < num_adjacent_faces; face_index++) { + CCGElem *grid_element_0 = + adjacent_vertex->corner_elements[0]; + CCGElem *grid_element_face_index = + adjacent_vertex->corner_elements[face_index]; + average_grid_element(subdiv_ccg, + key, + grid_element_0, + grid_element_face_index); + } + /* Copy averaged value to all the other faces. */ + for (int face_index = 1; face_index < num_adjacent_faces; face_index++) { + CCGElem *grid_element_0 = + adjacent_vertex->corner_elements[0]; + CCGElem *grid_element_face_index = + adjacent_vertex->corner_elements[face_index]; + copy_grid_element(subdiv_ccg, + key, + grid_element_face_index, + grid_element_0); + } +} + +static void subdiv_ccg_average_grids_corners_task( + void *__restrict userdata_v, + const int adjacent_vertex_index, + const ParallelRangeTLS *__restrict UNUSED(tls_v)) +{ + AverageGridsCornerData *data = userdata_v; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + CCGKey *key = data->key; + SubdivCCGAdjacentVertex *adjacent_vertex = + &subdiv_ccg->adjacent_vertices[adjacent_vertex_index]; + subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vertex); +} + +static void subdiv_ccg_average_all_boundaries_and_corners( + SubdivCCG *subdiv_ccg, + CCGKey *key) +{ + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + /* Average grids across coarse edges. */ + AverageGridsBoundariesData boundaries_data = { + .subdiv_ccg = subdiv_ccg, + .key = key, + }; + BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_edges, + &boundaries_data, + subdiv_ccg_average_grids_boundaries_task, + ¶llel_range_settings); + /* Average grids at coarse vertices. */ + AverageGridsCornerData corner_data = { + .subdiv_ccg = subdiv_ccg, + .key = key, + }; + BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_vertices, + &corner_data, + subdiv_ccg_average_grids_corners_task, + ¶llel_range_settings); +} + +void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg) +{ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + /* Average inner boundaries of grids (within one face), across faces + * from different face-corners. + */ + AverageInnerGridsData inner_data = { + .subdiv_ccg = subdiv_ccg, + .key = &key, + }; + BLI_task_parallel_range(0, subdiv_ccg->num_faces, + &inner_data, + subdiv_ccg_average_inner_grids_task, + ¶llel_range_settings); + subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key); +} + +typedef struct StitchFacesInnerGridsData { + SubdivCCG *subdiv_ccg; + CCGKey *key; + struct CCGFace **effected_ccg_faces; +} StitchFacesInnerGridsData; + +static void subdiv_ccg_stitch_face_inner_grids_task( + void *__restrict userdata_v, + const int face_index, + const ParallelRangeTLS *__restrict UNUSED(tls_v)) +{ + StitchFacesInnerGridsData *data = userdata_v; + SubdivCCG *subdiv_ccg = data->subdiv_ccg; + CCGKey *key = data->key; + struct CCGFace **effected_ccg_faces = data->effected_ccg_faces; + struct CCGFace *effected_ccg_face = effected_ccg_faces[face_index]; + SubdivCCGFace *face = (SubdivCCGFace *)effected_ccg_face; + subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face); +} + +void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG *subdiv_ccg, + struct CCGFace **effected_faces, + int num_effected_faces) +{ + CCGKey key; + BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg); + StitchFacesInnerGridsData data = { + .subdiv_ccg = subdiv_ccg, + .key = &key, + .effected_ccg_faces = effected_faces, + }; + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + BLI_task_parallel_range(0, num_effected_faces, + &data, + subdiv_ccg_stitch_face_inner_grids_task, + ¶llel_range_settings); + /* TODO(sergey): Only average elements which are adjacent to modified + * faces. + */ + subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key); +} diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.c b/source/blender/blenkernel/intern/subdiv_ccg_mask.c new file mode 100644 index 00000000000..0da30fb1bf0 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.c @@ -0,0 +1,197 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_ccg_mask.c + * \ingroup bke + */ + +#include "BKE_subdiv_ccg.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_subdiv.h" + +#include "MEM_guardedalloc.h" + +typedef struct PolyCornerIndex { + int poly_index; + int corner; +} PolyCornerIndex; + +typedef struct GridPaintMaskData { + // int grid_size; + const MPoly *mpoly; + const GridPaintMask *grid_paint_mask; + /* Indexed by ptex face index, contains polygon/corner which corresponds + * to it. + * + * NOTE: For quad polygon this is an index of first corner only, since + * there we only have one ptex. + */ + PolyCornerIndex *ptex_poly_corner; +} GridPaintMaskData; + +static int mask_get_grid_and_coord( + SubdivCCGMask *mask_evaluator, + const int ptex_face_index, const float u, const float v, + const GridPaintMask **r_mask_grid, + float *grid_u, float *grid_v) +{ + GridPaintMaskData *data = mask_evaluator->user_data; + const PolyCornerIndex *poly_corner = + &data->ptex_poly_corner[ptex_face_index]; + const MPoly *poly = &data->mpoly[poly_corner->poly_index]; + const int start_grid_index = poly->loopstart + poly_corner->corner; + int corner = 0; + if (poly->totloop == 4) { + float corner_u, corner_v; + corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v); + *r_mask_grid = + &data->grid_paint_mask[start_grid_index + corner]; + BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v); + } + else { + *r_mask_grid = + &data->grid_paint_mask[start_grid_index]; + BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v); + } + return corner; +} + +BLI_INLINE float read_mask_grid(const GridPaintMask *mask_grid, + const float grid_u, const float grid_v) +{ + if (mask_grid->data == NULL) { + return 0; + } + const int grid_size = BKE_subdiv_grid_size_from_level(mask_grid->level); + const int x = (grid_u * (grid_size - 1) + 0.5f); + const int y = (grid_v * (grid_size - 1) + 0.5f); + return mask_grid->data[y * grid_size + x]; +} + +static float eval_mask(SubdivCCGMask *mask_evaluator, + const int ptex_face_index, + const float u, const float v) +{ + const GridPaintMask *mask_grid; + float grid_u, grid_v; + mask_get_grid_and_coord(mask_evaluator, + ptex_face_index, u, v, + &mask_grid, + &grid_u, &grid_v); + return read_mask_grid(mask_grid, grid_u, grid_v); +} + +static void free_mask_data(SubdivCCGMask *mask_evaluator) +{ + GridPaintMaskData *data = mask_evaluator->user_data; + MEM_freeN(data->ptex_poly_corner); + MEM_freeN(data); +} + +/* TODO(sergey): This seems to be generally used information, which almost + * worth adding to a subdiv itself, with possible cache of the value. + */ +static int count_num_ptex_faces(const Mesh *mesh) +{ + int num_ptex_faces = 0; + const MPoly *mpoly = mesh->mpoly; + for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) { + const MPoly *poly = &mpoly[poly_index]; + num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop; + } + return num_ptex_faces; +} + +static void displacement_data_init_mapping(SubdivCCGMask *mask_evaluator, + const Mesh *mesh) +{ + GridPaintMaskData *data = mask_evaluator->user_data; + const MPoly *mpoly = mesh->mpoly; + const int num_ptex_faces = count_num_ptex_faces(mesh); + /* Allocate memory. */ + data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces, + sizeof(*data->ptex_poly_corner), + "ptex poly corner"); + /* Fill in offsets. */ + int ptex_face_index = 0; + PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner; + for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) { + const MPoly *poly = &mpoly[poly_index]; + if (poly->totloop == 4) { + ptex_poly_corner[ptex_face_index].poly_index = poly_index; + ptex_poly_corner[ptex_face_index].corner = 0; + ptex_face_index++; + } + else { + for (int corner = 0; corner < poly->totloop; corner++) { + ptex_poly_corner[ptex_face_index].poly_index = poly_index; + ptex_poly_corner[ptex_face_index].corner = corner; + ptex_face_index++; + } + } + } +} + +static void displacement_init_data(SubdivCCGMask *mask_evaluator, + const Mesh *mesh) +{ + GridPaintMaskData *data = mask_evaluator->user_data; + data->mpoly = mesh->mpoly; + data->grid_paint_mask = + CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); + displacement_data_init_mapping(mask_evaluator, mesh); +} + +static void displacement_init_functions(SubdivCCGMask *mask_evaluator) +{ + mask_evaluator->eval_mask = eval_mask; + mask_evaluator->free = free_mask_data; +} + +bool BKE_subdiv_ccg_mask_init_from_paint( + SubdivCCGMask *mask_evaluator, + const struct Mesh *mesh) +{ + GridPaintMask *grid_paint_mask = + CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK); + if (grid_paint_mask == NULL) { + return false; + } + /* Allocate all required memory. */ + mask_evaluator->user_data = MEM_callocN(sizeof(GridPaintMaskData), + "mask from grid data"); + displacement_init_data(mask_evaluator, mesh); + displacement_init_functions(mask_evaluator); + return true; +} diff --git a/source/blender/blenkernel/intern/subdiv_converter.c b/source/blender/blenkernel/intern/subdiv_converter.c new file mode 100644 index 00000000000..b3eab1565d7 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_converter.c @@ -0,0 +1,77 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_converter.c + * \ingroup bke + */ + +#include "subdiv_converter.h" + +#include "BLI_utildefines.h" + +#include "opensubdiv_converter_capi.h" + +void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter) +{ + if (converter->freeUserData) { + converter->freeUserData(converter); + } +} + +int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings( + const SubdivSettings *settings) +{ + switch (settings->vtx_boundary_interpolation) { + case SUBDIV_VTX_BOUNDARY_NONE: + return OSD_VTX_BOUNDARY_NONE; + case SUBDIV_VTX_BOUNDARY_EDGE_ONLY: + return OSD_VTX_BOUNDARY_EDGE_ONLY; + case SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER: + return OSD_VTX_BOUNDARY_EDGE_AND_CORNER; + } + BLI_assert(!"Unknown vtx boundary interpolation"); + return OSD_VTX_BOUNDARY_EDGE_ONLY; +} + +/*OpenSubdiv_FVarLinearInterpolation*/ int +BKE_subdiv_converter_fvar_linear_from_settings(const SubdivSettings *settings) +{ + switch (settings->fvar_linear_interpolation) { + case SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE: + return OSD_FVAR_LINEAR_INTERPOLATION_NONE; + case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY: + return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY; + case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS: + return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1; + case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE: + return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2; + case SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES: + return OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES; + case SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL: + return OSD_FVAR_LINEAR_INTERPOLATION_ALL; + } + BLI_assert(!"Unknown fvar linear interpolation"); + return OSD_FVAR_LINEAR_INTERPOLATION_NONE; +} diff --git a/source/blender/blenkernel/intern/subdiv_converter.h b/source/blender/blenkernel/intern/subdiv_converter.h new file mode 100644 index 00000000000..17172bc29f7 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_converter.h @@ -0,0 +1,67 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __SUBDIV_CONVERTER_H__ +#define __SUBDIV_CONVERTER_H__ + +/** \file blender/blenkernel/intern/subdiv_converter.h + * \ingroup bke + */ + +#include "BKE_subdiv.h" + +/* NOTE: Was initially used to get proper enumerator types, but this makes + * it tricky to compile without OpenSubdiv. + */ +/* #include "opensubdiv_converter_capi.h" */ + +struct Mesh; +struct OpenSubdiv_Converter; +struct SubdivSettings; + +void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter, + const struct SubdivSettings *settings, + const struct Mesh *mesh); + +/* NOTE: Frees converter data, but not converter itself. This means, that if + * converter was allocated on heap, it is up to the user to free that memory. + */ +void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter); + +/* ============================ INTERNAL HELPERS ============================ */ + +/* TODO(sergey): Find a way to make it OpenSubdiv_VtxBoundaryInterpolation, + * without breaking compilation without OpenSubdiv. + */ +int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings( + const SubdivSettings *settings); + +/* TODO(sergey): Find a way to make it OpenSubdiv_FVarLinearInterpolation, + * without breaking compilation without OpenSubdiv. + */ +int BKE_subdiv_converter_fvar_linear_from_settings( + const SubdivSettings *settings); + +#endif /* __SUBDIV_CONVERTER_H__ */ diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c new file mode 100644 index 00000000000..5941de682f4 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c @@ -0,0 +1,410 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_converter_mesh.c + * \ingroup bke + */ + +#include "subdiv_converter.h" + +#include <string.h> + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_bitmap.h" +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_mesh_mapping.h" +#include "BKE_subdiv.h" + +#include "MEM_guardedalloc.h" + +#include "opensubdiv_capi.h" +#include "opensubdiv_converter_capi.h" + +typedef struct ConverterStorage { + SubdivSettings settings; + const Mesh *mesh; + /* Indexed by loop index, value denotes index of face-varying vertex + * which corresponds to the UV coordinate. + */ + int *loop_uv_indices; + int num_uv_coordinates; + /* Indexed by coarse mesh elements, gives index of corresponding element + * with ignoring all non-manifold entities. + * + * NOTE: This isn't strictly speaking manifold, this is more like non-loose + * geometry index. As in, index of element as if there were no loose edges + * or vertices in the mesh. + */ + int *manifold_vertex_index; + /* Indexed by vertex index from mesh, corresponds to whether this vertex has + * infinite sharpness due to non-manifol topology. + */ + BLI_bitmap *infinite_sharp_vertices_map; + /* Reverse mapping to above. */ + int *manifold_vertex_index_reverse; + int *manifold_edge_index_reverse; + /* Number of non-loose elements. */ + int num_manifold_vertices; + int num_manifold_edges; +} ConverterStorage; + +static OpenSubdiv_SchemeType get_scheme_type( + const OpenSubdiv_Converter *converter) +{ + ConverterStorage *storage = converter->user_data; + if (storage->settings.is_simple) { + return OSD_SCHEME_BILINEAR; + } + else { + return OSD_SCHEME_CATMARK; + } +} + +static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation( + const struct OpenSubdiv_Converter *converter) { + ConverterStorage *storage = converter->user_data; + return BKE_subdiv_converter_vtx_boundary_interpolation_from_settings( + &storage->settings); +} + +static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation( + const OpenSubdiv_Converter *converter) +{ + ConverterStorage *storage = converter->user_data; + return BKE_subdiv_converter_fvar_linear_from_settings(&storage->settings); +} + +static bool specifies_full_topology( + const OpenSubdiv_Converter *UNUSED(converter)) +{ + return false; +} + +static int get_num_faces(const OpenSubdiv_Converter *converter) +{ + ConverterStorage *storage = converter->user_data; + return storage->mesh->totpoly; +} + +static int get_num_edges(const OpenSubdiv_Converter *converter) +{ + ConverterStorage *storage = converter->user_data; + return storage->num_manifold_edges; +} + +static int get_num_vertices(const OpenSubdiv_Converter *converter) +{ + ConverterStorage *storage = converter->user_data; + return storage->num_manifold_vertices; +} + +static int get_num_face_vertices(const OpenSubdiv_Converter *converter, + int manifold_face_index) +{ + ConverterStorage *storage = converter->user_data; + return storage->mesh->mpoly[manifold_face_index].totloop; +} + +static void get_face_vertices(const OpenSubdiv_Converter *converter, + int manifold_face_index, + int *manifold_face_vertices) +{ + ConverterStorage *storage = converter->user_data; + const MPoly *poly = &storage->mesh->mpoly[manifold_face_index]; + const MLoop *mloop = storage->mesh->mloop; + for (int corner = 0; corner < poly->totloop; corner++) { + manifold_face_vertices[corner] = storage->manifold_vertex_index[ + mloop[poly->loopstart + corner].v]; + } +} + +static void get_edge_vertices(const OpenSubdiv_Converter *converter, + int manifold_edge_index, + int *manifold_edge_vertices) +{ + ConverterStorage *storage = converter->user_data; + const int edge_index = + storage->manifold_edge_index_reverse[manifold_edge_index]; + const MEdge *edge = &storage->mesh->medge[edge_index]; + manifold_edge_vertices[0] = storage->manifold_vertex_index[edge->v1]; + manifold_edge_vertices[1] = storage->manifold_vertex_index[edge->v2]; +} + +static float get_edge_sharpness(const OpenSubdiv_Converter *converter, + int manifold_edge_index) +{ + ConverterStorage *storage = converter->user_data; + const int edge_index = + storage->manifold_edge_index_reverse[manifold_edge_index]; + const MEdge *medge = storage->mesh->medge; + const float edge_crease = (float)medge[edge_index].crease / 255.0f; + return edge_crease * edge_crease * 10.0f; +} + + +static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, + int manifold_vertex_index) +{ + ConverterStorage *storage = converter->user_data; + const int vertex_index = + storage->manifold_vertex_index_reverse[manifold_vertex_index]; + return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map, + vertex_index); +} + +static float get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter), + int UNUSED(manifold_vertex_index)) +{ + return 0.0f; +} + +static int get_num_uv_layers(const OpenSubdiv_Converter *converter) +{ + ConverterStorage *storage = converter->user_data; + const Mesh *mesh = storage->mesh; + return CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); +} + +static void precalc_uv_layer(const OpenSubdiv_Converter *converter, + const int layer_index) +{ + ConverterStorage *storage = converter->user_data; + const Mesh *mesh = storage->mesh; + const MPoly *mpoly = mesh->mpoly; + const MLoop *mloop = mesh->mloop; + const MLoopUV *mloopuv = CustomData_get_layer_n( + &mesh->ldata, CD_MLOOPUV, layer_index); + const int num_poly = mesh->totpoly; + const int num_vert = mesh->totvert; + const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT}; + /* Initialize memory required for the operations. */ + if (storage->loop_uv_indices == NULL) { + storage->loop_uv_indices = MEM_malloc_arrayN( + mesh->totloop, sizeof(int), "loop uv vertex index"); + } + UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create( + mpoly, mloop, mloopuv, + num_poly, num_vert, + limit, + false, true); + /* NOTE: First UV vertex is supposed to be always marked as separate. */ + storage->num_uv_coordinates = -1; + for (int vertex_index = 0; vertex_index < num_vert; ++vertex_index) { + const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, + vertex_index); + while (uv_vert != NULL) { + if (uv_vert->separate) { + storage->num_uv_coordinates++; + } + const MPoly *mp = &mpoly[uv_vert->poly_index]; + const int global_loop_index = mp->loopstart + + uv_vert->loop_of_poly_index; + storage->loop_uv_indices[global_loop_index] = + storage->num_uv_coordinates; + uv_vert = uv_vert->next; + } + } + /* So far this value was used as a 0-based index, actual number of UV + * vertices is 1 more. + */ + storage->num_uv_coordinates += 1; + BKE_mesh_uv_vert_map_free(uv_vert_map); +} + +static void finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter)) +{ +} + +static int get_num_uvs(const OpenSubdiv_Converter *converter) +{ + ConverterStorage *storage = converter->user_data; + return storage->num_uv_coordinates; +} + +static int get_face_corner_uv_index(const OpenSubdiv_Converter *converter, + const int face_index, + const int corner) +{ + ConverterStorage *storage = converter->user_data; + const MPoly *mp = &storage->mesh->mpoly[face_index]; + return storage->loop_uv_indices[mp->loopstart + corner]; +} + +static void free_user_data(const OpenSubdiv_Converter *converter) +{ + ConverterStorage *user_data = converter->user_data; + MEM_SAFE_FREE(user_data->loop_uv_indices); + MEM_freeN(user_data->manifold_vertex_index); + MEM_freeN(user_data->infinite_sharp_vertices_map); + MEM_freeN(user_data->manifold_vertex_index_reverse); + MEM_freeN(user_data->manifold_edge_index_reverse); + MEM_freeN(user_data); +} + +static void init_functions(OpenSubdiv_Converter *converter) +{ + converter->getSchemeType = get_scheme_type; + converter->getVtxBoundaryInterpolation = get_vtx_boundary_interpolation; + converter->getFVarLinearInterpolation = get_fvar_linear_interpolation; + converter->specifiesFullTopology = specifies_full_topology; + + converter->getNumFaces = get_num_faces; + converter->getNumEdges = get_num_edges; + converter->getNumVertices = get_num_vertices; + + converter->getNumFaceVertices = get_num_face_vertices; + converter->getFaceVertices = get_face_vertices; + converter->getFaceEdges = NULL; + + converter->getEdgeVertices = get_edge_vertices; + converter->getNumEdgeFaces = NULL; + converter->getEdgeFaces = NULL; + converter->getEdgeSharpness = get_edge_sharpness; + + converter->getNumVertexEdges = NULL; + converter->getVertexEdges = NULL; + converter->getNumVertexFaces = NULL; + converter->getVertexFaces = NULL; + converter->isInfiniteSharpVertex = is_infinite_sharp_vertex; + converter->getVertexSharpness = get_vertex_sharpness; + + converter->getNumUVLayers = get_num_uv_layers; + converter->precalcUVLayer = precalc_uv_layer; + converter->finishUVLayer = finish_uv_layer; + converter->getNumUVCoordinates = get_num_uvs; + converter->getFaceCornerUVIndex = get_face_corner_uv_index; + + converter->freeUserData = free_user_data; +} + +static void initialize_manifold_index_array(const BLI_bitmap *used_map, + const int num_elements, + int **indices_r, + int **indices_reverse_r, + int *num_manifold_elements_r) +{ + int *indices = NULL; + if (indices_r != NULL) { + indices = MEM_malloc_arrayN( + num_elements, sizeof(int), "manifold indices"); + } + int *indices_reverse = NULL; + if (indices_reverse_r != NULL) { + indices_reverse = MEM_malloc_arrayN( + num_elements, sizeof(int), "manifold indices reverse"); + } + int offset = 0; + for (int i = 0; i < num_elements; i++) { + if (BLI_BITMAP_TEST_BOOL(used_map, i)) { + if (indices != NULL) { + indices[i] = i - offset; + } + if (indices_reverse != NULL) { + indices_reverse[i - offset] = i; + } + } + else { + if (indices != NULL) { + indices[i] = -1; + } + offset++; + } + } + if (indices_r != NULL) { + *indices_r = indices; + } + if (indices_reverse_r != NULL) { + *indices_reverse_r = indices_reverse; + } + *num_manifold_elements_r = num_elements - offset; +} + +static void initialize_manifold_indices(ConverterStorage *storage) +{ + const Mesh *mesh = storage->mesh; + const MEdge *medge = mesh->medge; + const MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + /* Set bits of elements which are not loose. */ + BLI_bitmap *vert_used_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map"); + BLI_bitmap *edge_used_map = BLI_BITMAP_NEW(mesh->totedge, "edge used map"); + for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) { + const MPoly *poly = &mpoly[poly_index]; + for (int corner = 0; corner < poly->totloop; corner++) { + const MLoop *loop = &mloop[poly->loopstart + corner]; + BLI_BITMAP_ENABLE(vert_used_map, loop->v); + BLI_BITMAP_ENABLE(edge_used_map, loop->e); + } + } + initialize_manifold_index_array(vert_used_map, + mesh->totvert, + &storage->manifold_vertex_index, + &storage->manifold_vertex_index_reverse, + &storage->num_manifold_vertices); + initialize_manifold_index_array(edge_used_map, + mesh->totedge, + NULL, + &storage->manifold_edge_index_reverse, + &storage->num_manifold_edges); + /* Initialize infinite sharp mapping. */ + storage->infinite_sharp_vertices_map = + BLI_BITMAP_NEW(mesh->totvert, "vert used map"); + for (int edge_index = 0; edge_index < mesh->totedge; edge_index++) { + if (!BLI_BITMAP_TEST_BOOL(edge_used_map, edge_index)) { + const MEdge *edge = &medge[edge_index]; + BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v1); + BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v2); + } + } + /* Free working variables. */ + MEM_freeN(vert_used_map); + MEM_freeN(edge_used_map); +} + +static void init_user_data(OpenSubdiv_Converter *converter, + const SubdivSettings *settings, + const Mesh *mesh) +{ + ConverterStorage *user_data = + MEM_mallocN(sizeof(ConverterStorage), __func__); + user_data->settings = *settings; + user_data->mesh = mesh; + user_data->loop_uv_indices = NULL; + initialize_manifold_indices(user_data); + converter->user_data = user_data; +} + +void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter, + const SubdivSettings *settings, + const Mesh *mesh) +{ + init_functions(converter); + init_user_data(converter, settings, mesh); +} diff --git a/source/blender/blenkernel/intern/subdiv_displacement.c b/source/blender/blenkernel/intern/subdiv_displacement.c new file mode 100644 index 00000000000..a6af6f45e59 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_displacement.c @@ -0,0 +1,46 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_displacement.c + * \ingroup bke + */ + +#include "BKE_subdiv.h" + +#include "BLI_utildefines.h" + +#include "MEM_guardedalloc.h" + +void BKE_subdiv_displacement_detach(Subdiv *subdiv) +{ + if (subdiv->displacement_evaluator == NULL) { + return; + } + if (subdiv->displacement_evaluator->free != NULL) { + subdiv->displacement_evaluator->free(subdiv->displacement_evaluator); + } + MEM_freeN(subdiv->displacement_evaluator); + subdiv->displacement_evaluator = NULL; +} diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c new file mode 100644 index 00000000000..5744ac3ca0d --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c @@ -0,0 +1,358 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_displacement_multires.c + * \ingroup bke + */ + +#include "BKE_subdiv.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_multires.h" + +#include "MEM_guardedalloc.h" + +typedef struct PolyCornerIndex { + int poly_index; + int corner; +} PolyCornerIndex; + +typedef struct MultiresDisplacementData { + int grid_size; + const MPoly *mpoly; + const MDisps *mdisps; + /* Indexed by ptex face index, contains polygon/corner which corresponds + * to it. + * + * NOTE: For quad polygon this is an index of first corner only, since + * there we only have one ptex. + */ + PolyCornerIndex *ptex_poly_corner; +} MultiresDisplacementData; + +/* Denotes which grid to use to average value of the displacement read from the + * grid which corresponds to the ptex face. + */ +typedef enum eAverageWith { + AVERAGE_WITH_NONE, + AVERAGE_WITH_ALL, + AVERAGE_WITH_PREV, + AVERAGE_WITH_NEXT, +} eAverageWith; + +static int displacement_get_grid_and_coord( + SubdivDisplacement *displacement, + const int ptex_face_index, const float u, const float v, + const MDisps **r_displacement_grid, + float *grid_u, float *grid_v) +{ + MultiresDisplacementData *data = displacement->user_data; + const PolyCornerIndex *poly_corner = + &data->ptex_poly_corner[ptex_face_index]; + const MPoly *poly = &data->mpoly[poly_corner->poly_index]; + const int start_grid_index = poly->loopstart + poly_corner->corner; + int corner = 0; + if (poly->totloop == 4) { + float corner_u, corner_v; + corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v); + *r_displacement_grid = &data->mdisps[start_grid_index + corner]; + BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v); + } + else { + *r_displacement_grid = &data->mdisps[start_grid_index]; + BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v); + } + return corner; +} + +static const MDisps *displacement_get_next_grid( + SubdivDisplacement *displacement, + const int ptex_face_index, const int corner) +{ + MultiresDisplacementData *data = displacement->user_data; + const PolyCornerIndex *poly_corner = + &data->ptex_poly_corner[ptex_face_index]; + const MPoly *poly = &data->mpoly[poly_corner->poly_index]; + const int effective_corner = (poly->totloop == 4) ? corner + : poly_corner->corner; + const int next_corner = (effective_corner + 1) % poly->totloop; + return &data->mdisps[poly->loopstart + next_corner]; +} + +static const MDisps *displacement_get_prev_grid( + SubdivDisplacement *displacement, + const int ptex_face_index, const int corner) +{ + MultiresDisplacementData *data = displacement->user_data; + const PolyCornerIndex *poly_corner = + &data->ptex_poly_corner[ptex_face_index]; + const MPoly *poly = &data->mpoly[poly_corner->poly_index]; + const int effective_corner = (poly->totloop == 4) ? corner + : poly_corner->corner; + const int prev_corner = + (effective_corner - 1 + poly->totloop) % poly->totloop; + return &data->mdisps[poly->loopstart + prev_corner]; +} + +BLI_INLINE eAverageWith read_displacement_grid( + const MDisps *displacement_grid, + const int grid_size, + const float grid_u, const float grid_v, + float r_tangent_D[3]) +{ + if (displacement_grid->disps == NULL) { + zero_v3(r_tangent_D); + return AVERAGE_WITH_NONE; + } + const int x = (grid_u * (grid_size - 1) + 0.5f); + const int y = (grid_v * (grid_size - 1) + 0.5f); + copy_v3_v3(r_tangent_D, displacement_grid->disps[y * grid_size + x]); + if (x == 0 && y == 0) { + return AVERAGE_WITH_ALL; + } + else if (x == 0) { + return AVERAGE_WITH_PREV; + } + else if (y == 0) { + return AVERAGE_WITH_NEXT; + } + return AVERAGE_WITH_NONE; +} + +static void average_with_all( + SubdivDisplacement *displacement, + const int ptex_face_index, const int corner, + const float UNUSED(grid_u), const float UNUSED(grid_v), + float r_tangent_D[3]) +{ + MultiresDisplacementData *data = displacement->user_data; + const PolyCornerIndex *poly_corner = + &data->ptex_poly_corner[ptex_face_index]; + const MPoly *poly = &data->mpoly[poly_corner->poly_index]; + for (int current_corner = 0; + current_corner < poly->totloop; + current_corner++) + { + if (current_corner == corner) { + continue; + } + const MDisps *displacement_grid = + &data->mdisps[poly->loopstart + current_corner]; + const float *current_tangent_D = displacement_grid->disps[0]; + r_tangent_D[2] += current_tangent_D[2]; + } + r_tangent_D[2] /= (float)poly->totloop; +} + +static void average_with_next(SubdivDisplacement *displacement, + const int ptex_face_index, const int corner, + const float grid_u, const float UNUSED(grid_v), + float r_tangent_D[3]) +{ + MultiresDisplacementData *data = displacement->user_data; + const int grid_size = data->grid_size; + const MDisps *next_displacement_grid = displacement_get_next_grid( + displacement, ptex_face_index, corner); + float next_tangent_D[3]; + read_displacement_grid(next_displacement_grid, grid_size, + 0.0f, grid_u, + next_tangent_D); + r_tangent_D[2] += next_tangent_D[2]; + r_tangent_D[2] *= 0.5f; +} + +static void average_with_prev(SubdivDisplacement *displacement, + const int ptex_face_index, const int corner, + const float UNUSED(grid_u), const float grid_v, + float r_tangent_D[3]) +{ + MultiresDisplacementData *data = displacement->user_data; + const int grid_size = data->grid_size; + const MDisps *prev_displacement_grid = displacement_get_prev_grid( + displacement, ptex_face_index, corner); + float prev_tangent_D[3]; + read_displacement_grid(prev_displacement_grid, grid_size, + grid_v, 0.0f, + prev_tangent_D); + r_tangent_D[2] += prev_tangent_D[2]; + r_tangent_D[2] *= 0.5f; +} + +static void average_displacement(SubdivDisplacement *displacement, + const int ptex_face_index, const int corner, + eAverageWith average_with, + const float grid_u, const float grid_v, + float r_tangent_D[3]) +{ + switch (average_with) { + case AVERAGE_WITH_ALL: + average_with_all(displacement, + ptex_face_index, corner, + grid_u, grid_v, + r_tangent_D); + break; + case AVERAGE_WITH_PREV: + average_with_prev(displacement, + ptex_face_index, corner, + grid_u, grid_v, + r_tangent_D); + break; + case AVERAGE_WITH_NEXT: + average_with_next(displacement, + ptex_face_index, corner, + grid_u, grid_v, + r_tangent_D); + break; + case AVERAGE_WITH_NONE: + break; + } +} + +static void eval_displacement(SubdivDisplacement *displacement, + const int ptex_face_index, + const float u, const float v, + const float dPdu[3], const float dPdv[3], + float r_D[3]) +{ + MultiresDisplacementData *data = displacement->user_data; + const int grid_size = data->grid_size; + /* Get displacement in tangent space. */ + const MDisps *displacement_grid; + float grid_u, grid_v; + int corner = displacement_get_grid_and_coord(displacement, + ptex_face_index, u, v, + &displacement_grid, + &grid_u, &grid_v); + /* Read displacement from the current displacement grid and see if any + * averaging is needed. + */ + float tangent_D[3]; + eAverageWith average_with = + read_displacement_grid(displacement_grid, grid_size, + grid_u, grid_v, + tangent_D); + average_displacement(displacement, + ptex_face_index, corner, + average_with, grid_u, grid_v, + tangent_D); + /* Convert it to the object space. */ + float tangent_matrix[3][3]; + BKE_multires_construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner); + mul_v3_m3v3(r_D, tangent_matrix, tangent_D); +} + +static void free_displacement(SubdivDisplacement *displacement) +{ + MultiresDisplacementData *data = displacement->user_data; + MEM_freeN(data->ptex_poly_corner); + MEM_freeN(data); +} + +/* TODO(sergey): This seems to be generally used information, which almost + * worth adding to a subdiv itself, with possible cache of the value. + */ +static int count_num_ptex_faces(const Mesh *mesh) +{ + int num_ptex_faces = 0; + const MPoly *mpoly = mesh->mpoly; + for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) { + const MPoly *poly = &mpoly[poly_index]; + num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop; + } + return num_ptex_faces; +} + +static void displacement_data_init_mapping(SubdivDisplacement *displacement, + const Mesh *mesh) +{ + MultiresDisplacementData *data = displacement->user_data; + const MPoly *mpoly = mesh->mpoly; + const int num_ptex_faces = count_num_ptex_faces(mesh); + /* Allocate memory. */ + data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces, + sizeof(*data->ptex_poly_corner), + "ptex poly corner"); + /* Fill in offsets. */ + int ptex_face_index = 0; + PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner; + for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) { + const MPoly *poly = &mpoly[poly_index]; + if (poly->totloop == 4) { + ptex_poly_corner[ptex_face_index].poly_index = poly_index; + ptex_poly_corner[ptex_face_index].corner = 0; + ptex_face_index++; + } + else { + for (int corner = 0; corner < poly->totloop; corner++) { + ptex_poly_corner[ptex_face_index].poly_index = poly_index; + ptex_poly_corner[ptex_face_index].corner = corner; + ptex_face_index++; + } + } + } +} + +static void displacement_init_data(SubdivDisplacement *displacement, + const Mesh *mesh, + const MultiresModifierData *mmd) +{ + MultiresDisplacementData *data = displacement->user_data; + data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl); + data->mpoly = mesh->mpoly; + data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + displacement_data_init_mapping(displacement, mesh); +} + +static void displacement_init_functions(SubdivDisplacement *displacement) +{ + displacement->eval_displacement = eval_displacement; + displacement->free = free_displacement; +} + +void BKE_subdiv_displacement_attach_from_multires( + Subdiv *subdiv, + const Mesh *mesh, + const MultiresModifierData *mmd) +{ + /* Make sure we don't have previously assigned displacement. */ + BKE_subdiv_displacement_detach(subdiv); + /* Allocate all required memory. */ + SubdivDisplacement *displacement = MEM_callocN(sizeof(SubdivDisplacement), + "multires displacement"); + displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData), + "multires displacement data"); + displacement_init_data(displacement, mesh, mmd); + displacement_init_functions(displacement); + /* Finish. */ + subdiv->displacement_evaluator = displacement; +} diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c new file mode 100644 index 00000000000..f4a9e1a95fd --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_eval.c @@ -0,0 +1,394 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_eval.c + * \ingroup bke + */ + +#include "BKE_subdiv_eval.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_bitmap.h" +#include "BLI_math_vector.h" + +#include "BKE_customdata.h" +#include "BKE_subdiv.h" + +#include "MEM_guardedalloc.h" + +#include "opensubdiv_evaluator_capi.h" +#include "opensubdiv_topology_refiner_capi.h" + +bool BKE_subdiv_eval_begin(Subdiv *subdiv) +{ + if (subdiv->topology_refiner == NULL) { + /* Happens on input mesh with just loose geometry, + * or when OpenSubdiv is disabled + */ + return false; + } + else if (subdiv->evaluator == NULL) { + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); + subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner( + subdiv->topology_refiner); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); + if (subdiv->evaluator == NULL) { + return false; + } + } + else { + /* TODO(sergey): Check for topology change. */ + } + return true; +} + +static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh) +{ + const MVert *mvert = mesh->mvert; + const MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + /* Mark vertices which needs new coordinates. */ + /* TODO(sergey): This is annoying to calculate this on every update, + * maybe it's better to cache this mapping. Or make it possible to have + * OpenSubdiv's vertices match mesh ones? + */ + BLI_bitmap *vertex_used_map = + BLI_BITMAP_NEW(mesh->totvert, "vert used map"); + for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) { + const MPoly *poly = &mpoly[poly_index]; + for (int corner = 0; corner < poly->totloop; corner++) { + const MLoop *loop = &mloop[poly->loopstart + corner]; + BLI_BITMAP_ENABLE(vertex_used_map, loop->v); + } + } + for (int vertex_index = 0, manifold_veretx_index = 0; + vertex_index < mesh->totvert; + vertex_index++) + { + if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) { + continue; + } + const MVert *vertex = &mvert[vertex_index]; + subdiv->evaluator->setCoarsePositions( + subdiv->evaluator, + vertex->co, + manifold_veretx_index, 1); + manifold_veretx_index++; + } + MEM_freeN(vertex_used_map); +} + +static void set_face_varying_data_from_uv(Subdiv *subdiv, + const MLoopUV *mloopuv, + const int layer_index) +{ + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; + const int num_faces = topology_refiner->getNumFaces(topology_refiner); + const MLoopUV *mluv = mloopuv; + /* TODO(sergey): OpenSubdiv's C-API converter can change winding of + * loops of a face, need to watch for that, to prevent wrong UVs assigned. + */ + for (int face_index = 0; face_index < num_faces; ++face_index) { + const int num_face_vertices = topology_refiner->getNumFaceVertices( + topology_refiner, face_index); + const int *uv_indicies = topology_refiner->getFaceFVarValueIndices( + topology_refiner, face_index, layer_index); + for (int vertex_index = 0; + vertex_index < num_face_vertices; + vertex_index++, mluv++) + { + evaluator->setFaceVaryingData(evaluator, + layer_index, + mluv->uv, + uv_indicies[vertex_index], + 1); + } + } +} + +bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh) +{ + if (!BKE_subdiv_eval_begin(subdiv)) { + return false; + } + if (subdiv->evaluator == NULL) { + /* NOTE: This situation is supposed to be handled by begin(). */ + BLI_assert(!"Is not supposed to happen"); + return false; + } + /* Set coordinates of base mesh vertices. */ + set_coarse_positions(subdiv, mesh); + /* Set face-varyign data to UV maps. */ + const int num_uv_layers = + CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); + for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) { + const MLoopUV *mloopuv = CustomData_get_layer_n( + &mesh->ldata, CD_MLOOPUV, layer_index); + set_face_varying_data_from_uv(subdiv, mloopuv, layer_index); + } + /* Update evaluator to the new coarse geometry. */ + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE); + subdiv->evaluator->refine(subdiv->evaluator); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE); + return true; +} + +/* ========================== Single point queries ========================== */ + +void BKE_subdiv_eval_limit_point( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3]) +{ + BKE_subdiv_eval_limit_point_and_derivatives(subdiv, + ptex_face_index, + u, v, + r_P, NULL, NULL); +} + +void BKE_subdiv_eval_limit_point_and_derivatives( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3], float r_dPdu[3], float r_dPdv[3]) +{ + subdiv->evaluator->evaluateLimit(subdiv->evaluator, + ptex_face_index, + u, v, + r_P, r_dPdu, r_dPdv); +} + +void BKE_subdiv_eval_limit_point_and_normal( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3], float r_N[3]) +{ + float dPdu[3], dPdv[3]; + BKE_subdiv_eval_limit_point_and_derivatives(subdiv, + ptex_face_index, + u, v, + r_P, dPdu, dPdv); + cross_v3_v3v3(r_N, dPdu, dPdv); + normalize_v3(r_N); +} + +void BKE_subdiv_eval_limit_point_and_short_normal( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3], short r_N[3]) +{ + float N_float[3]; + BKE_subdiv_eval_limit_point_and_normal(subdiv, + ptex_face_index, + u, v, + r_P, N_float); + normal_float_to_short_v3(r_N, N_float); +} + +void BKE_subdiv_eval_face_varying( + Subdiv *subdiv, + const int face_varying_channel, + const int ptex_face_index, + const float u, const float v, + float r_face_varying[2]) +{ + subdiv->evaluator->evaluateFaceVarying(subdiv->evaluator, + face_varying_channel, + ptex_face_index, + u, v, + r_face_varying); +} + +void BKE_subdiv_eval_displacement( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + const float dPdu[3], const float dPdv[3], + float r_D[3]) +{ + if (subdiv->displacement_evaluator == NULL) { + zero_v3(r_D); + return; + } + subdiv->displacement_evaluator->eval_displacement( + subdiv->displacement_evaluator, + ptex_face_index, + u, v, + dPdu, dPdv, + r_D); +} + +void BKE_subdiv_eval_final_point( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3]) +{ + if (subdiv->displacement_evaluator) { + float dPdu[3], dPdv[3], D[3]; + BKE_subdiv_eval_limit_point_and_derivatives( + subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv); + BKE_subdiv_eval_displacement(subdiv, + ptex_face_index, u, v, + dPdu, dPdv, + D); + add_v3_v3(r_P, D); + } + else { + BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P); + } +} + +/* =================== Patch queries at given resolution =================== */ + +/* Move buffer forward by a given number of bytes. */ +static void buffer_apply_offset(void **buffer, const int offset) +{ + *buffer = ((unsigned char *)*buffer) + offset; +} + +/* Write given number of floats to the beginning of given buffer. */ +static void buffer_write_float_value(void **buffer, + const float *values_buffer, int num_values) +{ + memcpy(*buffer, values_buffer, sizeof(float) * num_values); +} + +/* Similar to above, just operates with short values. */ +static void buffer_write_short_value(void **buffer, + const short *values_buffer, int num_values) +{ + memcpy(*buffer, values_buffer, sizeof(short) * num_values); +} + +void BKE_subdiv_eval_limit_patch_resolution_point( + Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *buffer, const int offset, const int stride) +{ + buffer_apply_offset(&buffer, offset); + const float inv_resolution_1 = 1.0f / (float)(resolution - 1); + for (int y = 0; y < resolution; y++) { + const float v = y * inv_resolution_1; + for (int x = 0; x < resolution; x++) { + const float u = x * inv_resolution_1; + BKE_subdiv_eval_limit_point(subdiv, + ptex_face_index, + u, v, + buffer); + buffer_apply_offset(&buffer, stride); + } + } +} + +void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives( + Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *point_buffer, const int point_offset, const int point_stride, + void *du_buffer, const int du_offset, const int du_stride, + void *dv_buffer, const int dv_offset, const int dv_stride) +{ + buffer_apply_offset(&point_buffer, point_offset); + buffer_apply_offset(&du_buffer, du_offset); + buffer_apply_offset(&dv_buffer, dv_offset); + const float inv_resolution_1 = 1.0f / (float)(resolution - 1); + for (int y = 0; y < resolution; y++) { + const float v = y * inv_resolution_1; + for (int x = 0; x < resolution; x++) { + const float u = x * inv_resolution_1; + BKE_subdiv_eval_limit_point_and_derivatives( + subdiv, + ptex_face_index, + u, v, + point_buffer, du_buffer, dv_buffer); + buffer_apply_offset(&point_buffer, point_stride); + buffer_apply_offset(&du_buffer, du_stride); + buffer_apply_offset(&dv_buffer, dv_stride); + } + } +} + +void BKE_subdiv_eval_limit_patch_resolution_point_and_normal( + Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *point_buffer, const int point_offset, const int point_stride, + void *normal_buffer, const int normal_offset, const int normal_stride) +{ + buffer_apply_offset(&point_buffer, point_offset); + buffer_apply_offset(&normal_buffer, normal_offset); + const float inv_resolution_1 = 1.0f / (float)(resolution - 1); + for (int y = 0; y < resolution; y++) { + const float v = y * inv_resolution_1; + for (int x = 0; x < resolution; x++) { + const float u = x * inv_resolution_1; + float normal[3]; + BKE_subdiv_eval_limit_point_and_normal( + subdiv, + ptex_face_index, + u, v, + point_buffer, normal); + buffer_write_float_value(&normal_buffer, normal, 3); + buffer_apply_offset(&point_buffer, point_stride); + buffer_apply_offset(&normal_buffer, normal_stride); + } + } +} + +void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal( + Subdiv *subdiv, + const int ptex_face_index, + const int resolution, + void *point_buffer, const int point_offset, const int point_stride, + void *normal_buffer, const int normal_offset, const int normal_stride) +{ + buffer_apply_offset(&point_buffer, point_offset); + buffer_apply_offset(&normal_buffer, normal_offset); + const float inv_resolution_1 = 1.0f / (float)(resolution - 1); + for (int y = 0; y < resolution; y++) { + const float v = y * inv_resolution_1; + for (int x = 0; x < resolution; x++) { + const float u = x * inv_resolution_1; + short normal[3]; + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + u, v, + point_buffer, normal); + buffer_write_short_value(&normal_buffer, normal, 3); + buffer_apply_offset(&point_buffer, point_stride); + buffer_apply_offset(&normal_buffer, normal_stride); + } + } +} diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c new file mode 100644 index 00000000000..511536c31b5 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_foreach.c @@ -0,0 +1,2038 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_foreach.c + * \ingroup bke + */ + +#include "BKE_subdiv_foreach.h" + +#include "atomic_ops.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_key_types.h" + +#include "BLI_alloca.h" +#include "BLI_bitmap.h" +#include "BLI_math_vector.h" +#include "BLI_task.h" + +#include "BKE_mesh.h" +#include "BKE_key.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_mesh.h" + +#include "MEM_guardedalloc.h" + +/* ============================================================================= + * General helpers. + */ + +/* Number of ptex faces for a given polygon. */ +BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly) +{ + return (poly->totloop == 4) ? 1 : poly->totloop; +} + +BLI_INLINE int num_edges_per_ptex_face_get(const int resolution) +{ + return 2 * (resolution - 1) * resolution; +} + +BLI_INLINE int num_inner_edges_per_ptex_face_get(const int resolution) +{ + if (resolution < 2) { + return 0; + } + return (resolution - 2) * resolution + + (resolution - 1) * (resolution - 1); +} + +/* Number of subdivision polygons per ptex face. */ +BLI_INLINE int num_polys_per_ptex_get(const int resolution) +{ + return (resolution - 1) * (resolution - 1); +} + +/* Subdivision resolution per given polygon's ptex faces. */ +BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution) +{ + return (poly->totloop == 4) ? (resolution) + : ((resolution >> 1) + 1); +} + +/* ============================================================================= + * Context which is passed to all threaded tasks. + */ + +typedef struct SubdivForeachTaskContext { + const Mesh *coarse_mesh; + const SubdivToMeshSettings *settings; + /* Callbacks. */ + const SubdivForeachContext *foreach_context; + /* Counters of geometry in subdivided mesh, initialized as a part of + * offsets calculation. + */ + int num_subdiv_vertices; + int num_subdiv_edges; + int num_subdiv_loops; + int num_subdiv_polygons; + /* Offsets of various geometry in the subdivision mesh arrays. */ + int vertices_corner_offset; + int vertices_edge_offset; + int vertices_inner_offset; + int edge_boundary_offset; + int edge_inner_offset; + /* Indexed by coarse polygon index, indicates offset in subdivided mesh + * vertices, edges and polygons arrays, where first element of the poly + * begins. + */ + int *subdiv_vertex_offset; + int *subdiv_edge_offset; + int *subdiv_polygon_offset; + /* Indexed by base face index, element indicates total number of ptex faces + * created for preceding base faces. + */ + int *face_ptex_offset; + /* Bitmap indicating whether vertex was used already or not. + * - During patch evaluation indicates whether coarse vertex was already + * evaluated and its position on limit is already known. + */ + BLI_bitmap *coarse_vertices_used_map; + /* Bitmap indicating whether edge was used already or not. This includes: + * - During context initialization it indicates whether subdivided vertices + * for corresponding edge were already calculated or not. + * - During patch evaluation it indicates whether vertices along this edge + * were already evaluated. + */ + BLI_bitmap *coarse_edges_used_map; +} SubdivForeachTaskContext; + +/* NOTE: Expects edge map to be zeroed. */ +static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx) +{ + /* Reset counters. */ + ctx->num_subdiv_vertices = 0; + ctx->num_subdiv_edges = 0; + ctx->num_subdiv_loops = 0; + ctx->num_subdiv_polygons = 0; + /* Static geometry counters. */ + const int resolution = ctx->settings->resolution; + const int no_quad_patch_resolution = ((resolution >> 1) + 1); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_inner_vertices_per_quad = (resolution - 2) * (resolution - 2); + const int num_inner_vertices_per_noquad_patch = + (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 2); + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + ctx->num_subdiv_vertices = coarse_mesh->totvert; + ctx->num_subdiv_edges = + coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1); + /* Calculate extra vertices and edges createdd by non-loose geometry. */ + for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner]; + const bool is_edge_used = + BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e); + /* Edges which aren't counted yet. */ + if (!is_edge_used) { + BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e); + ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge; + } + } + /* Inner vertices of polygon. */ + if (num_ptex_faces_per_poly == 1) { + ctx->num_subdiv_vertices += num_inner_vertices_per_quad; + ctx->num_subdiv_edges += + num_edges_per_ptex_face_get(resolution - 2) + + 4 * num_subdiv_vertices_per_coarse_edge; + ctx->num_subdiv_polygons += num_polys_per_ptex_get(resolution); + } + else { + ctx->num_subdiv_vertices += + 1 + + num_ptex_faces_per_poly * (no_quad_patch_resolution - 2) + + num_ptex_faces_per_poly * num_inner_vertices_per_noquad_patch; + ctx->num_subdiv_edges += + num_ptex_faces_per_poly * + (num_inner_edges_per_ptex_face_get( + no_quad_patch_resolution - 1) + + (no_quad_patch_resolution - 2) + + num_subdiv_vertices_per_coarse_edge); + if (no_quad_patch_resolution >= 3) { + ctx->num_subdiv_edges += coarse_poly->totloop; + } + ctx->num_subdiv_polygons += + num_ptex_faces_per_poly * + num_polys_per_ptex_get(no_quad_patch_resolution); + } + } + /* Calculate extra vertices createdd by loose edges. */ + for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) { + if (!BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, edge_index)) { + ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge; + } + } + ctx->num_subdiv_loops = ctx->num_subdiv_polygons * 4; +} + +static void subdiv_foreach_ctx_init_offsets(SubdivForeachTaskContext *ctx) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const int resolution = ctx->settings->resolution; + const int resolution_2 = resolution - 2; + const int resolution_2_squared = resolution_2 * resolution_2; + const int no_quad_patch_resolution = ((resolution >> 1) + 1); + const int num_irregular_vertices_per_patch = + (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 1); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + /* Constant offsets in arrays. */ + ctx->vertices_corner_offset = 0; + ctx->vertices_edge_offset = coarse_mesh->totvert; + ctx->vertices_inner_offset = + ctx->vertices_edge_offset + + coarse_mesh->totedge * num_subdiv_vertices_per_coarse_edge; + ctx->edge_boundary_offset = 0; + ctx->edge_inner_offset = + ctx->edge_boundary_offset + + coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge; + /* "Indexed" offsets. */ + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + int vertex_offset = 0; + int edge_offset = 0; + int polygon_offset = 0; + for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + ctx->subdiv_vertex_offset[poly_index] = vertex_offset; + ctx->subdiv_edge_offset[poly_index] = edge_offset; + ctx->subdiv_polygon_offset[poly_index] = polygon_offset; + if (num_ptex_faces_per_poly == 1) { + vertex_offset += resolution_2_squared; + edge_offset += num_edges_per_ptex_face_get(resolution - 2) + + 4 * num_subdiv_vertices_per_coarse_edge; + polygon_offset += num_polys_per_ptex_get(resolution); + } + else { + vertex_offset += + 1 + + num_ptex_faces_per_poly * num_irregular_vertices_per_patch; + edge_offset += + num_ptex_faces_per_poly * + (num_inner_edges_per_ptex_face_get( + no_quad_patch_resolution - 1) + + (no_quad_patch_resolution - 2) + + num_subdiv_vertices_per_coarse_edge); + if (no_quad_patch_resolution >= 3) { + edge_offset += coarse_poly->totloop; + } + polygon_offset += + num_ptex_faces_per_poly * + num_polys_per_ptex_get(no_quad_patch_resolution); + } + } +} + +static void subdiv_foreach_ctx_init(Subdiv *subdiv, + SubdivForeachTaskContext *ctx) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + /* Allocate maps and offsets. */ + ctx->coarse_vertices_used_map = + BLI_BITMAP_NEW(coarse_mesh->totvert, "vertices used map"); + ctx->coarse_edges_used_map = + BLI_BITMAP_NEW(coarse_mesh->totedge, "edges used map"); + ctx->subdiv_vertex_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_vertex_offset), + "vertex_offset"); + ctx->subdiv_edge_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_edge_offset), + "subdiv_edge_offset"); + ctx->subdiv_polygon_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_polygon_offset), + "subdiv_edge_offset"); + /* Initialize all offsets. */ + subdiv_foreach_ctx_init_offsets(ctx); + /* Calculate number of geometry in the result subdivision mesh. */ + subdiv_foreach_ctx_count(ctx); + /* Re-set maps which were used at this step. */ + BLI_BITMAP_SET_ALL(ctx->coarse_edges_used_map, false, coarse_mesh->totedge); + ctx->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); +} + +static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx) +{ + MEM_freeN(ctx->coarse_vertices_used_map); + MEM_freeN(ctx->coarse_edges_used_map); + MEM_freeN(ctx->subdiv_vertex_offset); + MEM_freeN(ctx->subdiv_edge_offset); + MEM_freeN(ctx->subdiv_polygon_offset); +} + +/* ============================================================================= + * Vertex traversal process. + */ + +/* Traversal of corner vertices. They are coming from coarse vertices. */ + +static void subdiv_foreach_corner_vertices_regular_do( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly, + SubdivForeachVertexFromCornerCb vertex_corner, + bool check_usage) +{ + const float weights[4][2] = {{0.0f, 0.0f}, + {1.0f, 0.0f}, + {1.0f, 1.0f}, + {0.0f, 1.0f}}; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + if (check_usage && + BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, + coarse_loop->v)) + { + continue; + } + const int coarse_vertex_index = coarse_loop->v; + const int subdiv_vertex_index = + ctx->vertices_corner_offset + coarse_vertex_index; + const float u = weights[corner][0]; + const float v = weights[corner][1]; + vertex_corner( + ctx->foreach_context, + tls, + ptex_face_index, + u, v, + coarse_vertex_index, + coarse_poly_index, + 0, + subdiv_vertex_index); + } +} + +static void subdiv_foreach_corner_vertices_regular( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_corner_vertices_regular_do( + ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true); +} + +static void subdiv_foreach_corner_vertices_special_do( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly, + SubdivForeachVertexFromCornerCb vertex_corner, + bool check_usage) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly; + int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index]; + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, ptex_face_index++) + { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + if (check_usage && + BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, + coarse_loop->v)) + { + continue; + } + const int coarse_vertex_index = coarse_loop->v; + const int subdiv_vertex_index = + ctx->vertices_corner_offset + coarse_vertex_index; + vertex_corner( + ctx->foreach_context, + tls, + ptex_face_index, + 0.0f, 0.0f, + coarse_vertex_index, + coarse_poly_index, + corner, + subdiv_vertex_index); + } +} + +static void subdiv_foreach_corner_vertices_special( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_corner_vertices_special_do( + ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true); +} + +static void subdiv_foreach_corner_vertices(SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + if (coarse_poly->totloop == 4) { + subdiv_foreach_corner_vertices_regular(ctx, tls, coarse_poly); + } + else { + subdiv_foreach_corner_vertices_special(ctx, tls, coarse_poly); + } +} + +static void subdiv_foreach_every_corner_vertices_regular( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_corner_vertices_regular_do( + ctx, tls, coarse_poly, + ctx->foreach_context->vertex_every_corner, + false); +} + +static void subdiv_foreach_every_corner_vertices_special( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_corner_vertices_special_do( + ctx, tls, coarse_poly, + ctx->foreach_context->vertex_every_corner, + false); +} + +static void subdiv_foreach_every_corner_vertices(SubdivForeachTaskContext *ctx) +{ + if (ctx->foreach_context->vertex_every_corner == NULL) { + return; + } + const SubdivForeachContext *foreach_context = ctx->foreach_context; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + void *tls = NULL; + if (foreach_context->user_data_tls_size != 0) { + tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls"); + memcpy(tls, + foreach_context->user_data_tls, + foreach_context->user_data_tls_size); + } + for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + if (coarse_poly->totloop == 4) { + subdiv_foreach_every_corner_vertices_regular(ctx, tls, coarse_poly); + } + else { + subdiv_foreach_every_corner_vertices_special(ctx, tls, coarse_poly); + } + } + if (tls != NULL) { + MEM_freeN(tls); + } +} + +/* Traverse of edge vertices. They are coming from coarse edges. */ + +static void subdiv_foreach_edge_vertices_regular_do( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly, + SubdivForeachVertexFromEdgeCb vertex_edge, + bool check_usage) +{ + const int resolution = ctx->settings->resolution; + const int resolution_1 = resolution - 1; + const float inv_resolution_1 = 1.0f / (float)resolution_1; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int coarse_poly_index = coarse_poly - coarse_mpoly; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const int coarse_edge_index = coarse_loop->e; + if (check_usage && + BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, + coarse_edge_index)) + { + continue; + } + const MEdge *coarse_edge = &coarse_medge[coarse_edge_index]; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int subdiv_vertex_index = + ctx->vertices_edge_offset + + coarse_edge_index * num_subdiv_vertices_per_coarse_edge; + for (int vertex_index = 0; + vertex_index < num_subdiv_vertices_per_coarse_edge; + vertex_index++, subdiv_vertex_index++) + { + float fac = (vertex_index + 1) * inv_resolution_1; + if (flip) { + fac = 1.0f - fac; + } + if (corner >= 2) { + fac = 1.0f - fac; + } + float u, v; + if ((corner & 1) == 0) { + u = fac; + v = (corner == 2) ? 1.0f : 0.0f; + } + else { + u = (corner == 1) ? 1.0f : 0.0f; + v = fac; + } + vertex_edge( + ctx->foreach_context, + tls, + ptex_face_index, + u, v, + coarse_edge_index, + coarse_poly_index, + 0, + subdiv_vertex_index); + } + } +} + +static void subdiv_foreach_edge_vertices_regular( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_edge_vertices_regular_do( + ctx, tls, coarse_poly, + ctx->foreach_context->vertex_edge, + true); +} + +static void subdiv_foreach_edge_vertices_special_do( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly, + SubdivForeachVertexFromEdgeCb vertex_edge, + bool check_usage) +{ + const int resolution = ctx->settings->resolution; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1); + const float inv_ptex_resolution_1 = + 1.0f / (float)(num_vertices_per_ptex_edge - 1); + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int coarse_poly_index = coarse_poly - coarse_mpoly; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_start_index = ctx->face_ptex_offset[poly_index]; + int ptex_face_index = ptex_face_start_index; + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, ptex_face_index++) + { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const int coarse_edge_index = coarse_loop->e; + if (check_usage && + BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, + coarse_edge_index)) + { + continue; + } + const MEdge *coarse_edge = &coarse_medge[coarse_edge_index]; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int subdiv_vertex_index = + ctx->vertices_edge_offset + + coarse_edge_index * num_subdiv_vertices_per_coarse_edge; + int veretx_delta = 1; + if (flip) { + subdiv_vertex_index += num_subdiv_vertices_per_coarse_edge - 1; + veretx_delta = -1; + } + for (int vertex_index = 1; + vertex_index < num_vertices_per_ptex_edge; + vertex_index++, subdiv_vertex_index += veretx_delta) + { + const float u = vertex_index * inv_ptex_resolution_1; + vertex_edge( + ctx->foreach_context, + tls, + ptex_face_index, + u, 0.0f, + coarse_edge_index, + coarse_poly_index, + corner, + subdiv_vertex_index); + } + const int next_ptex_face_index = + ptex_face_start_index + (corner + 1) % coarse_poly->totloop; + for (int vertex_index = 1; + vertex_index < num_vertices_per_ptex_edge - 1; + vertex_index++, subdiv_vertex_index += veretx_delta) + { + const float v = 1.0f - vertex_index * inv_ptex_resolution_1; + vertex_edge( + ctx->foreach_context, + tls, + next_ptex_face_index, + 0.0f, v, + coarse_edge_index, + coarse_poly_index, + corner, + subdiv_vertex_index); + } + } +} + +static void subdiv_foreach_edge_vertices_special( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_edge_vertices_special_do( + ctx, tls, coarse_poly, + ctx->foreach_context->vertex_edge, + true); +} + +static void subdiv_foreach_edge_vertices( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + if (coarse_poly->totloop == 4) { + subdiv_foreach_edge_vertices_regular(ctx, tls, coarse_poly); + } + else { + subdiv_foreach_edge_vertices_special(ctx, tls, coarse_poly); + } +} + +static void subdiv_foreach_every_edge_vertices_regular( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_edge_vertices_regular_do( + ctx, tls, coarse_poly, + ctx->foreach_context->vertex_every_edge, + false); +} + +static void subdiv_foreach_every_edge_vertices_special( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + subdiv_foreach_edge_vertices_special_do( + ctx, tls, coarse_poly, + ctx->foreach_context->vertex_every_edge, + false); +} + +static void subdiv_foreach_every_edge_vertices(SubdivForeachTaskContext *ctx) +{ + if (ctx->foreach_context->vertex_every_edge == NULL) { + return; + } + const SubdivForeachContext *foreach_context = ctx->foreach_context; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + void *tls = NULL; + if (foreach_context->user_data_tls_size != 0) { + tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls"); + memcpy(tls, + foreach_context->user_data_tls, + foreach_context->user_data_tls_size); + } + for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + if (coarse_poly->totloop == 4) { + subdiv_foreach_every_edge_vertices_regular(ctx, tls, coarse_poly); + } + else { + subdiv_foreach_every_edge_vertices_special(ctx, tls, coarse_poly); + } + } + if (tls != NULL) { + MEM_freeN(tls); + } +} + +/* Traversal of inner vertices, they are coming from ptex patches. */ + +static void subdiv_foreach_inner_vertices_regular( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + const int resolution = ctx->settings->resolution; + const float inv_resolution_1 = 1.0f / (float)(resolution - 1); + const Mesh *coarse_mesh = ctx->coarse_mesh; + const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index]; + const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index]; + int subdiv_vertex_index = + ctx->vertices_inner_offset + start_vertex_index; + for (int y = 1; y < resolution - 1; y++) { + const float v = y * inv_resolution_1; + for (int x = 1; x < resolution - 1; x++, subdiv_vertex_index++) { + const float u = x * inv_resolution_1; + ctx->foreach_context->vertex_inner( + ctx->foreach_context, + tls, + ptex_face_index, + u, v, + coarse_poly_index, 0, + subdiv_vertex_index); + } + } +} + +static void subdiv_foreach_inner_vertices_special( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + const int resolution = ctx->settings->resolution; + const int ptex_face_resolution = ptex_face_resolution_get( + coarse_poly, resolution); + const float inv_ptex_face_resolution_1 = + 1.0f / (float)(ptex_face_resolution - 1); + const Mesh *coarse_mesh = ctx->coarse_mesh; + const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly; + int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index]; + const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index]; + int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index; + ctx->foreach_context->vertex_inner( + ctx->foreach_context, + tls, + ptex_face_index, + 1.0f, 1.0f, + coarse_poly_index, 0, + subdiv_vertex_index); + subdiv_vertex_index++; + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, ptex_face_index++) + { + for (int y = 1; y < ptex_face_resolution - 1; y++) { + const float v = y * inv_ptex_face_resolution_1; + for (int x = 1; + x < ptex_face_resolution; x++, + subdiv_vertex_index++) + { + const float u = x * inv_ptex_face_resolution_1; + ctx->foreach_context->vertex_inner( + ctx->foreach_context, + tls, + ptex_face_index, + u, v, + coarse_poly_index, corner, + subdiv_vertex_index); + } + } + } +} + +static void subdiv_foreach_inner_vertices( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + if (coarse_poly->totloop == 4) { + subdiv_foreach_inner_vertices_regular(ctx, tls, coarse_poly); + } + else { + subdiv_foreach_inner_vertices_special(ctx, tls, coarse_poly); + } +} + +/* Traverse all vertices which are emitted from given coarse polygon. */ +static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx, + void *tls, + const int poly_index) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + if (ctx->foreach_context->vertex_corner != NULL) { + subdiv_foreach_corner_vertices(ctx, tls, coarse_poly); + } + if (ctx->foreach_context->vertex_edge != NULL) { + subdiv_foreach_edge_vertices(ctx, tls, coarse_poly); + } + if (ctx->foreach_context->vertex_inner != NULL) { + subdiv_foreach_inner_vertices(ctx, tls, coarse_poly); + } +} + +/* ============================================================================= + * Edge traversal process. + */ + +/* TODO(sergey): Coarse edge are always NONE, consider getting rid of it. */ +static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx, + void *tls, + const int coarse_edge_index, + const int start_subdiv_edge_index, + const int start_vertex_index, + const int num_edges_per_row) +{ + int subdiv_edge_index = start_subdiv_edge_index; + int vertex_index = start_vertex_index; + for (int edge_index = 0; + edge_index < num_edges_per_row - 1; + edge_index++, subdiv_edge_index++) + { + const int v1 = vertex_index; + const int v2 = vertex_index + 1; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + coarse_edge_index, + subdiv_edge_index, + v1, v2); + vertex_index += 1; + } + return subdiv_edge_index; +} + +/* TODO(sergey): Coarse edges are always NONE, consider getting rid of them. */ +static int subdiv_foreach_edges_column(SubdivForeachTaskContext *ctx, + void *tls, + const int coarse_start_edge_index, + const int coarse_end_edge_index, + const int start_subdiv_edge_index, + const int start_vertex_index, + const int num_edges_per_row) +{ + int subdiv_edge_index = start_subdiv_edge_index; + int vertex_index = start_vertex_index; + for (int edge_index = 0; + edge_index < num_edges_per_row; + edge_index++, subdiv_edge_index++) + { + int coarse_edge_index = ORIGINDEX_NONE; + if (edge_index == 0) { + coarse_edge_index = coarse_start_edge_index; + } + else if (edge_index == num_edges_per_row - 1) { + coarse_edge_index = coarse_end_edge_index; + } + const int v1 = vertex_index; + const int v2 = vertex_index + num_edges_per_row; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + coarse_edge_index, + subdiv_edge_index, + v1, v2); + vertex_index += 1; + } + return subdiv_edge_index; +} + +/* Defines edges between inner vertices of patch, and also edges to the + * boundary. + */ + +/* Consider a subdivision of base face at level 1: + * + * y + * ^ + * | (6) ---- (7) ---- (8) + * | | | | + * | (3) ---- (4) ---- (5) + * | | | | + * | (0) ---- (1) ---- (2) + * o---------------------------> x + * + * This is illustrate which parts of geometry is created by code below. + */ + +static void subdiv_foreach_edges_all_patches_regular( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int poly_index = coarse_poly - coarse_mpoly; + const int resolution = ctx->settings->resolution; + const int start_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[poly_index]; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + int subdiv_edge_index = + ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index]; + /* Traverse bottom row of edges (0-1, 1-2). */ + subdiv_edge_index = subdiv_foreach_edges_row( + ctx, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + start_vertex_index, + resolution - 2); + /* Traverse remaining edges. */ + for (int row = 0; row < resolution - 3; row++) { + const int start_row_vertex_index = + start_vertex_index + row * (resolution - 2); + /* Traverse vertical columns. + * + * At first iteration it will be edges (0-3. 1-4, 2-5), then it + * will be (3-6, 4-7, 5-8) and so on. + */ + subdiv_edge_index = subdiv_foreach_edges_column( + ctx, + tls, + ORIGINDEX_NONE, + ORIGINDEX_NONE, + subdiv_edge_index, + start_row_vertex_index, + resolution - 2); + /* Create horizontal edge row. + * + * At first iteration it will be edges (3-4, 4-5), then it will be + * (6-7, 7-8) and so on. + */ + subdiv_edge_index = subdiv_foreach_edges_row( + ctx, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + start_row_vertex_index + resolution - 2, + resolution - 2); + } + /* Connect inner part of patch to boundary. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index = start_vertex_index; + int side_stride = 0; + /* Calculate starting veretx of corresponding inner part of ptex. */ + if (corner == 0) { + side_stride = 1; + } + else if (corner == 1) { + side_start_index += resolution - 3; + side_stride = resolution - 2; + } + else if (corner == 2) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + num_subdiv_vertices_per_coarse_edge - 1; + side_stride = -1; + } + else if (corner == 3) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + (num_subdiv_vertices_per_coarse_edge - 1); + side_stride = -(resolution - 2); + } + for (int i = 0; i < resolution - 2; i++, subdiv_edge_index++) { + const int v1 = (flip) + ? (start_edge_vertex + (resolution - i - 3)) + : (start_edge_vertex + i); + const int v2 = side_start_index + side_stride * i; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + v1, v2); + } + } +} + +static void subdiv_foreach_edges_all_patches_special( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int poly_index = coarse_poly - coarse_mpoly; + const int resolution = ctx->settings->resolution; + const int ptex_face_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int ptex_face_inner_resolution = ptex_face_resolution - 2; + const int num_inner_vertices_per_ptex = + (ptex_face_resolution - 1) * (ptex_face_resolution - 2); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int center_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[poly_index]; + const int start_vertex_index = center_vertex_index + 1; + int subdiv_edge_index = + ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index]; + /* Traverse inner ptex edges. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const int start_ptex_face_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex; + /* Similar steps to regular patch case. */ + subdiv_edge_index = subdiv_foreach_edges_row( + ctx, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + start_ptex_face_vertex_index, + ptex_face_inner_resolution + 1); + for (int row = 0; row < ptex_face_inner_resolution - 1; row++) { + const int start_row_vertex_index = + start_ptex_face_vertex_index + + row * (ptex_face_inner_resolution + 1); + subdiv_edge_index = subdiv_foreach_edges_column( + ctx, + tls, + ORIGINDEX_NONE, + ORIGINDEX_NONE, + subdiv_edge_index, + start_row_vertex_index, + ptex_face_inner_resolution + 1); + subdiv_edge_index = subdiv_foreach_edges_row( + ctx, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + start_row_vertex_index + ptex_face_inner_resolution + 1, + ptex_face_inner_resolution + 1); + } + } + /* Create connections between ptex faces. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const int next_corner = (corner + 1) % coarse_poly->totloop; + int current_patch_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex + + ptex_face_inner_resolution; + int next_path_vertex_index = + start_vertex_index + next_corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - ptex_face_resolution + 1; + for (int row = 0; + row < ptex_face_inner_resolution; + row++, subdiv_edge_index++) + { + const int v1 = current_patch_vertex_index; + const int v2 = next_path_vertex_index; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + v1, v2); + current_patch_vertex_index += ptex_face_inner_resolution + 1; + next_path_vertex_index += 1; + } + } + /* Create edges from center. */ + if (ptex_face_resolution >= 3) { + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, subdiv_edge_index++) + { + const int current_patch_end_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - 1; + const int v1 = center_vertex_index; + const int v2 = current_patch_end_vertex_index; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + v1, v2); + } + } + /* Connect inner path of patch to boundary. */ + const MLoop *prev_coarse_loop = + &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + { + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index; + if (ptex_face_resolution >= 3) { + side_start_index = + start_vertex_index + num_inner_vertices_per_ptex * corner; + } + else { + side_start_index = center_vertex_index; + } + for (int i = 0; i < ptex_face_resolution - 1; + i++, + subdiv_edge_index++) + { + const int v1 = (flip) + ? (start_edge_vertex + (resolution - i - 3)) + : (start_edge_vertex + i); + const int v2 = side_start_index + i; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + v1, v2); + } + } + if (ptex_face_resolution >= 3) { + const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index = + start_vertex_index + num_inner_vertices_per_ptex * corner; + for (int i = 0; + i < ptex_face_resolution - 2; + i++, subdiv_edge_index++) + { + const int v1 = (flip) + ? (start_edge_vertex + (resolution - i - 3)) + : (start_edge_vertex + i); + const int v2 = side_start_index + + (ptex_face_inner_resolution + 1) * i; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + ORIGINDEX_NONE, + subdiv_edge_index, + v1, v2); + } + } + prev_coarse_loop = coarse_loop; + } +} + +static void subdiv_foreach_edges_all_patches( + SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + if (coarse_poly->totloop == 4) { + subdiv_foreach_edges_all_patches_regular(ctx, tls, coarse_poly); + } + else { + subdiv_foreach_edges_all_patches_special(ctx, tls, coarse_poly); + } +} + +static void subdiv_foreach_edges(SubdivForeachTaskContext *ctx, + void *tls, + int poly_index) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + subdiv_foreach_edges_all_patches(ctx, tls, coarse_poly); +} + +static void subdiv_foreach_boundary_edges( + SubdivForeachTaskContext *ctx, + void *tls, + int coarse_edge_index) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MEdge *coarse_edge = &coarse_medge[coarse_edge_index]; + const int resolution = ctx->settings->resolution; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + int subdiv_edge_index = + ctx->edge_boundary_offset + + coarse_edge_index * num_subdiv_edges_per_coarse_edge; + int last_vertex_index = ctx->vertices_corner_offset + coarse_edge->v1; + for (int i = 0; + i < num_subdiv_edges_per_coarse_edge - 1; + i++, subdiv_edge_index++) + { + const int v1 = last_vertex_index; + const int v2 = + ctx->vertices_edge_offset + + coarse_edge_index * num_subdiv_vertices_per_coarse_edge + + i; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + coarse_edge_index, + subdiv_edge_index, + v1, v2); + last_vertex_index = v2; + } + const int v1 = last_vertex_index; + const int v2 = ctx->vertices_corner_offset + coarse_edge->v2; + ctx->foreach_context->edge( + ctx->foreach_context, + tls, + coarse_edge_index, + subdiv_edge_index, + v1, v2); +} + +/* ============================================================================= + * Loops traversal. + */ + +static void rotate_indices(const int rot, int *a, int *b, int *c, int *d) +{ + int values[4] = {*a, *b, *c, *d}; + *a = values[(0 - rot + 4) % 4]; + *b = values[(1 - rot + 4) % 4]; + *c = values[(2 - rot + 4) % 4]; + *d = values[(3 - rot + 4) % 4]; +} + +static void subdiv_foreach_loops_of_poly( + SubdivForeachTaskContext *ctx, + void *tls, + int subdiv_loop_start_index, + const int ptex_face_index, + const int coarse_poly_index, + const int coarse_corner_index, + const int rotation, + /*const*/ int v0, /*const*/ int e0, + /*const*/ int v1, /*const*/ int e1, + /*const*/ int v2, /*const*/ int e2, + /*const*/ int v3, /*const*/ int e3, + const float u, const float v, + const float du, const float dv) +{ + rotate_indices(rotation, &v0, &v1, &v2, &v3); + rotate_indices(rotation, &e0, &e1, &e2, &e3); + ctx->foreach_context->loop( + ctx->foreach_context, + tls, + ptex_face_index, u, v, + ORIGINDEX_NONE, + coarse_poly_index, + coarse_corner_index, + subdiv_loop_start_index + 0, + v0, e0); + ctx->foreach_context->loop( + ctx->foreach_context, + tls, + ptex_face_index, u + du, v, + ORIGINDEX_NONE, + coarse_poly_index, + coarse_corner_index, + subdiv_loop_start_index + 1, + v1, e1); + ctx->foreach_context->loop( + ctx->foreach_context, + tls, + ptex_face_index, u + du, v + dv, + ORIGINDEX_NONE, + coarse_poly_index, + coarse_corner_index, + subdiv_loop_start_index + 2, + v2, e2); + ctx->foreach_context->loop( + ctx->foreach_context, + tls, + ptex_face_index, u, v + dv, + ORIGINDEX_NONE, + coarse_poly_index, + coarse_corner_index, + subdiv_loop_start_index + 3, + v3, e3); +} + +static void subdiv_foreach_loops_regular(SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + const int resolution = ctx->settings->resolution; + /* Base/coarse mesh information. */ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int coarse_poly_index = coarse_poly - coarse_mpoly; + const int ptex_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int ptex_inner_resolution = ptex_resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1); + const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index]; + const int start_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[coarse_poly_index]; + const int start_edge_index = + ctx->edge_inner_offset + + ctx->subdiv_edge_offset[coarse_poly_index]; + const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index]; + const int start_loop_index = 4 * start_poly_index; + const float du = inv_ptex_resolution_1; + const float dv = inv_ptex_resolution_1; + /* Hi-poly subdivided mesh. */ + int subdiv_loop_index = start_loop_index; + /* Loops for inner part of ptex. */ + for (int y = 1; y < ptex_resolution - 2; y++) { + const float v = y * inv_ptex_resolution_1; + const int inner_y = y - 1; + for (int x = 1; x < ptex_resolution - 2; x++, subdiv_loop_index += 4) { + const int inner_x = x - 1; + const float u = x * inv_ptex_resolution_1; + /* Vertex indices ordered counter-clockwise. */ + const int v0 = start_vertex_index + + (inner_y * ptex_inner_resolution + inner_x); + const int v1 = v0 + 1; + const int v2 = v0 + ptex_inner_resolution + 1; + const int v3 = v0 + ptex_inner_resolution; + /* Edge indices ordered counter-clockwise. */ + const int e0 = start_edge_index + + (inner_y * (2 * ptex_inner_resolution - 1) + inner_x); + const int e1 = e0 + ptex_inner_resolution; + const int e2 = e0 + (2 * ptex_inner_resolution - 1); + const int e3 = e0 + ptex_inner_resolution - 1; + subdiv_foreach_loops_of_poly( + ctx, tls, subdiv_loop_index, ptex_face_index, + coarse_poly_index, 0, + 0, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + } + } + /* Loops for faces connecting inner ptex part with boundary. */ + const MLoop *prev_coarse_loop = + &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index = start_vertex_index; + int side_stride = 0; + int v0 = ctx->vertices_corner_offset + coarse_loop->v; + int v3, e3; + int e2_offset, e2_stride; + float u, v, delta_u, delta_v; + if (prev_coarse_loop->v == prev_coarse_edge->v1) { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - 1; + } + else { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge; + } + /* Calculate starting veretx of corresponding inner part of ptex. */ + if (corner == 0) { + side_stride = 1; + e2_offset = 0; + e2_stride = 1; + u = 0.0f; + v = 0.0f; + delta_u = du; + delta_v = 0.0f; + } + else if (corner == 1) { + side_start_index += resolution - 3; + side_stride = resolution - 2; + e2_offset = 2 * num_subdiv_edges_per_coarse_edge - 4; + e2_stride = 2 * num_subdiv_edges_per_coarse_edge - 3; + u = 1.0f - du; + v = 0; + delta_u = 0.0f; + delta_v = dv; + } + else if (corner == 2) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + num_subdiv_vertices_per_coarse_edge - 1; + side_stride = -1; + e2_offset = num_edges_per_ptex_face_get(resolution - 2) - 1; + e2_stride = -1; + u = 1.0f - du; + v = 1.0f - dv; + delta_u = -du; + delta_v = 0.0f; + } + else if (corner == 3) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + (num_subdiv_vertices_per_coarse_edge - 1); + side_stride = -(resolution - 2); + e2_offset = num_edges_per_ptex_face_get(resolution - 2) - + (2 * num_subdiv_edges_per_coarse_edge - 3); + e2_stride = -(2 * num_subdiv_edges_per_coarse_edge - 3); + u = 0.0f; + v = 1.0f - dv; + delta_u = 0.0f; + delta_v = -dv; + } + for (int i = 0; i < resolution - 2; i++, subdiv_loop_index += 4) { + int v1; + if (flip) { + v1 = start_edge_vertex + (resolution - i - 3); + } + else { + v1 = start_edge_vertex + i; + } + const int v2 = side_start_index + side_stride * i; + int e0; + if (flip) { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - i - 1; + } + else { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + i; + } + int e1 = start_edge_index + + num_edges_per_ptex_face_get(resolution - 2) + + corner * num_subdiv_vertices_per_coarse_edge + + i; + int e2; + if (i == 0) { + e2 = start_edge_index + + num_edges_per_ptex_face_get(resolution - 2) + + ((corner - 1 + coarse_poly->totloop) % + coarse_poly->totloop) * + num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + } + else { + e2 = start_edge_index + e2_offset + e2_stride * (i - 1); + } + subdiv_foreach_loops_of_poly( + ctx, tls, subdiv_loop_index, ptex_face_index, + coarse_poly_index, corner, + corner, + v0, e0, v1, e1, v2, e2, v3, e3, + u + delta_u * i, v + delta_v * i, du, dv); + v0 = v1; + v3 = v2; + e3 = e1; + } + prev_coarse_loop = coarse_loop; + } +} + +static void subdiv_foreach_loops_special(SubdivForeachTaskContext *ctx, + void *tls, + const MPoly *coarse_poly) +{ + const int resolution = ctx->settings->resolution; + /* Base/coarse mesh information. */ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int coarse_poly_index = coarse_poly - coarse_mpoly; + const int ptex_face_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int ptex_face_inner_resolution = ptex_face_resolution - 2; + const float inv_ptex_resolution_1 = + 1.0f / (float)(ptex_face_resolution - 1); + const int num_inner_vertices_per_ptex = + (ptex_face_resolution - 1) * (ptex_face_resolution - 2); + const int num_inner_edges_per_ptex_face = + num_inner_edges_per_ptex_face_get( + ptex_face_inner_resolution + 1); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index]; + const int center_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[coarse_poly_index]; + const int start_vertex_index = center_vertex_index + 1; + const int start_inner_vertex_index = center_vertex_index + 1; + const int start_edge_index = ctx->edge_inner_offset + + ctx->subdiv_edge_offset[coarse_poly_index]; + const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index]; + const int start_loop_index = 4 * start_poly_index; + const float du = inv_ptex_resolution_1; + const float dv = inv_ptex_resolution_1; + /* Hi-poly subdivided mesh. */ + int subdiv_loop_index = start_loop_index; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const int corner_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex; + const int corner_edge_index = + start_edge_index + corner * num_inner_edges_per_ptex_face; + for (int y = 1; y < ptex_face_inner_resolution; y++) { + const float v = y * inv_ptex_resolution_1; + const int inner_y = y - 1; + for (int x = 1; + x < ptex_face_inner_resolution + 1; + x++, subdiv_loop_index += 4) + { + const int inner_x = x - 1; + const float u = x * inv_ptex_resolution_1; + /* Vertex indices ordered counter-clockwise. */ + const int v0 = + corner_vertex_index + + (inner_y * (ptex_face_inner_resolution + 1) + inner_x); + const int v1 = v0 + 1; + const int v2 = v0 + ptex_face_inner_resolution + 2; + const int v3 = v0 + ptex_face_inner_resolution + 1; + /* Edge indices ordered counter-clockwise. */ + const int e0 = corner_edge_index + + (inner_y * (2 * ptex_face_inner_resolution + 1) + inner_x); + const int e1 = e0 + ptex_face_inner_resolution + 1; + const int e2 = e0 + (2 * ptex_face_inner_resolution + 1); + const int e3 = e0 + ptex_face_inner_resolution; + subdiv_foreach_loops_of_poly( + ctx, tls, subdiv_loop_index, ptex_face_index + corner, + coarse_poly_index, corner, + 0, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + } + } + } + /* Create connections between ptex faces. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const int next_corner = (corner + 1) % coarse_poly->totloop; + const int corner_edge_index = + start_edge_index + corner * num_inner_edges_per_ptex_face; + const int next_corner_edge_index = + start_edge_index + next_corner * num_inner_edges_per_ptex_face; + int current_patch_vertex_index = + start_inner_vertex_index + + corner * num_inner_vertices_per_ptex + + ptex_face_inner_resolution; + int next_path_vertex_index = + start_inner_vertex_index + + next_corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - ptex_face_resolution + 1; + int v0 = current_patch_vertex_index; + int v1 = next_path_vertex_index; + current_patch_vertex_index += ptex_face_inner_resolution + 1; + next_path_vertex_index += 1; + int e0 = start_edge_index + + coarse_poly->totloop * num_inner_edges_per_ptex_face + + corner * (ptex_face_resolution - 2); + int e1 = next_corner_edge_index + num_inner_edges_per_ptex_face - + ptex_face_resolution + 2; + int e3 = corner_edge_index + 2 * ptex_face_resolution - 4; + for (int row = 1; + row < ptex_face_inner_resolution; + row++, subdiv_loop_index += 4) + { + const int v2 = next_path_vertex_index; + const int v3 = current_patch_vertex_index; + const int e2 = e0 + 1; + const float u = row * du; + const float v = 1.0f - dv; + subdiv_foreach_loops_of_poly( + ctx, tls, subdiv_loop_index, ptex_face_index + next_corner, + coarse_poly_index, next_corner, + 3, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + current_patch_vertex_index += ptex_face_inner_resolution + 1; + next_path_vertex_index += 1; + v0 = v3; + v1 = v2; + e0 = e2; + e1 += 1; + e3 += 2 * ptex_face_resolution - 3; + } + } + /* Create loops from center. */ + if (ptex_face_resolution >= 3) { + const int start_center_edge_index = + start_edge_index + + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution) * coarse_poly->totloop; + const int start_boundary_edge = + start_edge_index + + coarse_poly->totloop * num_inner_edges_per_ptex_face + + ptex_face_inner_resolution - 1; + for (int corner = 0, prev_corner = coarse_poly->totloop - 1; + corner < coarse_poly->totloop; + prev_corner = corner, corner++, subdiv_loop_index += 4) + { + const int corner_edge_index = + start_edge_index + + corner * num_inner_edges_per_ptex_face; + const int current_patch_end_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - 1; + const int prev_current_patch_end_vertex_index = + start_vertex_index + prev_corner * + num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - 1; + const int v0 = center_vertex_index; + const int v1 = prev_current_patch_end_vertex_index; + const int v2 = current_patch_end_vertex_index - 1; + const int v3 = current_patch_end_vertex_index; + const int e0 = start_center_edge_index + prev_corner; + const int e1 = start_boundary_edge + + prev_corner * (ptex_face_inner_resolution); + const int e2 = corner_edge_index + + num_inner_edges_per_ptex_face - 1; + const int e3 = start_center_edge_index + corner; + const float u = 1.0f - du; + const float v = 1.0f - dv; + subdiv_foreach_loops_of_poly( + ctx, tls, subdiv_loop_index, + ptex_face_index + corner, + coarse_poly_index, corner, + 2, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + } + } + /* Loops for faces connecting inner ptex part with boundary. */ + const MLoop *prev_coarse_loop = + &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1]; + for (int prev_corner = coarse_poly->totloop - 1, corner = 0; + corner < coarse_poly->totloop; + prev_corner = corner, corner++) + { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e]; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const int corner_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex; + const int corner_edge_index = + start_edge_index + corner * num_inner_edges_per_ptex_face; + /* Create loops for polygons along U axis. */ + int v0 = ctx->vertices_corner_offset + coarse_loop->v; + int v3, e3; + if (prev_coarse_loop->v == prev_coarse_edge->v1) { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - 1; + } + else { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge; + } + for (int i = 0; + i <= ptex_face_inner_resolution; + i++, subdiv_loop_index += 4) + { + int v1; + if (flip) { + v1 = start_edge_vertex + (resolution - i - 3); + } + else { + v1 = start_edge_vertex + i; + } + int v2; + if (ptex_face_inner_resolution >= 1) { + v2 = corner_vertex_index + i; + } + else { + v2 = center_vertex_index; + } + int e0; + if (flip) { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - i - 1; + } + else { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + i; + } + int e1 = start_edge_index + + corner * (2 * ptex_face_inner_resolution + 1); + if (ptex_face_resolution >= 3) { + e1 += coarse_poly->totloop * (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + i; + } + int e2 = 0; + if (i == 0 && ptex_face_resolution >= 3) { + e2 = start_edge_index + + coarse_poly->totloop * + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + corner * (2 * ptex_face_inner_resolution + 1) + + ptex_face_inner_resolution + 1; + } + else if (i == 0 && ptex_face_resolution < 3) { + e2 = start_edge_index + + prev_corner * (2 * ptex_face_inner_resolution + 1); + } + else { + e2 = corner_edge_index + i - 1; + } + const float u = du * i; + const float v = 0.0f; + subdiv_foreach_loops_of_poly( + ctx, tls, subdiv_loop_index, ptex_face_index + corner, + coarse_poly_index, corner, + 0, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + v0 = v1; + v3 = v2; + e3 = e1; + } + /* Create loops for polygons along V axis. */ + const bool flip_prev = (prev_coarse_edge->v2 == coarse_loop->v); + v0 = corner_vertex_index; + if (prev_coarse_loop->v == prev_coarse_edge->v1) { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + } + else { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + } + e3 = start_edge_index + + coarse_poly->totloop * + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + corner * (2 * ptex_face_inner_resolution + 1) + + ptex_face_inner_resolution + 1; + for (int i = 0; + i <= ptex_face_inner_resolution - 1; + i++, subdiv_loop_index += 4) + { + int v1; + int e0, e1; + if (i == ptex_face_inner_resolution - 1) { + v1 = start_vertex_index + + prev_corner * num_inner_vertices_per_ptex + + ptex_face_inner_resolution; + e1 = start_edge_index + + coarse_poly->totloop * + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + prev_corner * (2 * ptex_face_inner_resolution + 1) + + ptex_face_inner_resolution; + e0 = start_edge_index + + coarse_poly->totloop * num_inner_edges_per_ptex_face + + prev_corner * ptex_face_inner_resolution; + } + else { + v1 = v0 + ptex_face_inner_resolution + 1; + e0 = corner_edge_index + ptex_face_inner_resolution + + i * (2 * ptex_face_inner_resolution + 1); + e1 = e3 + 1; + } + int v2 = flip_prev ? v3 - 1 : v3 + 1; + int e2; + if (flip_prev) { + e2 = ctx->edge_boundary_offset + + prev_coarse_loop->e * + num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - 2 - i; + } + else { + e2 = ctx->edge_boundary_offset + + prev_coarse_loop->e * + num_subdiv_edges_per_coarse_edge + 1 + i; + } + const float u = 0.0f; + const float v = du * (i + 1); + subdiv_foreach_loops_of_poly( + ctx, tls, subdiv_loop_index, ptex_face_index + corner, + coarse_poly_index, corner, + 1, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + v0 = v1; + v3 = v2; + e3 = e1; + } + prev_coarse_loop = coarse_loop; + } +} + +static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx, + void *tls, + int poly_index) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + if (coarse_poly->totloop == 4) { + subdiv_foreach_loops_regular(ctx, tls, coarse_poly); + } + else { + subdiv_foreach_loops_special(ctx, tls, coarse_poly); + } +} + +/* ============================================================================= + * Polygons traverse process. + */ + +static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, + void *tls, + int poly_index) +{ + const int resolution = ctx->settings->resolution; + const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; + /* Base/coarse mesh information. */ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + const int ptex_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution); + const int num_loops_per_ptex = 4 * num_polys_per_ptex; + const int start_loop_index = 4 * start_poly_index; + /* Hi-poly subdivided mesh. */ + int subdiv_polyon_index = start_poly_index; + for (int ptex_of_poly_index = 0; + ptex_of_poly_index < num_ptex_faces_per_poly; + ptex_of_poly_index++) + { + for (int subdiv_poly_index = 0; + subdiv_poly_index < num_polys_per_ptex; + subdiv_poly_index++, subdiv_polyon_index++) + { + const int loopstart = start_loop_index + + (ptex_of_poly_index * num_loops_per_ptex) + + (subdiv_poly_index * 4); + ctx->foreach_context->poly( + ctx->foreach_context, + tls, + poly_index, + subdiv_polyon_index, + loopstart, 4); + } + } +} + +/* ============================================================================= + * Loose elements traverse process. + */ + +static void subdiv_foreach_loose_vertices_task( + void *__restrict userdata, + const int coarse_vertex_index, + const ParallelRangeTLS *__restrict tls) +{ + SubdivForeachTaskContext *ctx = userdata; + if (BLI_BITMAP_TEST_BOOL(ctx->coarse_vertices_used_map, + coarse_vertex_index)) + { + /* Vertex is not loose, was handled when handling polygons. */ + return; + } + const int subdiv_vertex_index = + ctx->vertices_corner_offset + coarse_vertex_index; + ctx->foreach_context->vertex_loose( + ctx->foreach_context, + tls->userdata_chunk, + coarse_vertex_index, + subdiv_vertex_index); +} + +static void subdiv_foreach_vertices_of_loose_edges_task( + void *__restrict userdata, + const int coarse_edge_index, + const ParallelRangeTLS *__restrict tls) +{ + SubdivForeachTaskContext *ctx = userdata; + if (BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, coarse_edge_index)) { + /* Vertex is not loose, was handled when handling polygons. */ + return; + } + const int resolution = ctx->settings->resolution; + const int resolution_1 = resolution - 1; + const float inv_resolution_1 = 1.0f / (float)resolution_1; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index]; + /* Subdivion vertices which corresponds to edge's v1 and v2. */ + const int subdiv_v1_index = + ctx->vertices_corner_offset + coarse_edge->v1; + const int subdiv_v2_index = + ctx->vertices_corner_offset + coarse_edge->v2; + /* First subdivided inner vertex of the edge. */ + const int subdiv_start_vertex = + ctx->vertices_edge_offset + + coarse_edge_index * num_subdiv_vertices_per_coarse_edge; + /* Perform interpolation. */ + for (int i = 0; i < resolution; i++) { + const float u = i * inv_resolution_1; + int subdiv_vertex_index; + if (i == 0) { + subdiv_vertex_index = subdiv_v1_index; + } + else if (i == resolution - 1) { + subdiv_vertex_index = subdiv_v2_index; + } + else { + subdiv_vertex_index = subdiv_start_vertex + (i - 1); + } + ctx->foreach_context->vertex_of_loose_edge( + ctx->foreach_context, + tls->userdata_chunk, + coarse_edge_index, + u, + subdiv_vertex_index); + } +} + +/* ============================================================================= + * Subdivision process entry points. + */ + +static void subdiv_foreach_task( + void *__restrict userdata, + const int poly_index, + const ParallelRangeTLS *__restrict tls) +{ + SubdivForeachTaskContext *ctx = userdata; + /* Traverse hi-poly vertex coordinates and normals. */ + subdiv_foreach_vertices(ctx, tls->userdata_chunk, poly_index); + /* Traverse mesh geometry for the given base poly index. */ + if (ctx->foreach_context->edge != NULL) { + subdiv_foreach_edges(ctx, tls->userdata_chunk, poly_index); + } + if (ctx->foreach_context->loop != NULL) { + subdiv_foreach_loops(ctx, tls->userdata_chunk, poly_index); + } + if (ctx->foreach_context->poly != NULL) { + subdiv_foreach_polys(ctx, tls->userdata_chunk, poly_index); + } +} + +static void subdiv_foreach_boundary_edges_task( + void *__restrict userdata, + const int edge_index, + const ParallelRangeTLS *__restrict tls) +{ + SubdivForeachTaskContext *ctx = userdata; + subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index); +} + +static void subdiv_foreach_finalize(void *__restrict userdata, + void *__restrict userdata_chunk) +{ + SubdivForeachTaskContext *ctx = userdata; + ctx->foreach_context->user_data_tls_free(userdata_chunk); +} + +bool BKE_subdiv_foreach_subdiv_geometry( + Subdiv *subdiv, + const SubdivForeachContext *context, + const SubdivToMeshSettings *mesh_settings, + const Mesh *coarse_mesh) +{ + SubdivForeachTaskContext ctx = {0}; + ctx.coarse_mesh = coarse_mesh; + ctx.settings = mesh_settings; + ctx.foreach_context = context; + subdiv_foreach_ctx_init(subdiv, &ctx); + if (context->topology_info != NULL) { + if (!context->topology_info(context, + ctx.num_subdiv_vertices, + ctx.num_subdiv_edges, + ctx.num_subdiv_loops, + ctx.num_subdiv_polygons)) + { + subdiv_foreach_ctx_free(&ctx); + return false; + } + } + /* Single threaded passes to average displacement on the corner vertices + * and boundary edges. + */ + subdiv_foreach_every_corner_vertices(&ctx); + subdiv_foreach_every_edge_vertices(&ctx); + /* Threaded traversal of the rest of topology. */ + ParallelRangeSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + parallel_range_settings.userdata_chunk = context->user_data_tls; + parallel_range_settings.userdata_chunk_size = context->user_data_tls_size; + if (context->user_data_tls_free != NULL) { + parallel_range_settings.func_finalize = subdiv_foreach_finalize; + } + BLI_task_parallel_range(0, coarse_mesh->totpoly, + &ctx, + subdiv_foreach_task, + ¶llel_range_settings); + if (context->vertex_loose != NULL) { + BLI_task_parallel_range(0, coarse_mesh->totvert, + &ctx, + subdiv_foreach_loose_vertices_task, + ¶llel_range_settings); + } + if (context->vertex_of_loose_edge != NULL) { + BLI_task_parallel_range(0, coarse_mesh->totedge, + &ctx, + subdiv_foreach_vertices_of_loose_edges_task, + ¶llel_range_settings); + } + if (context->edge != NULL) { + BLI_task_parallel_range(0, coarse_mesh->totedge, + &ctx, + subdiv_foreach_boundary_edges_task, + ¶llel_range_settings); + } + subdiv_foreach_ctx_free(&ctx); + return true; +} diff --git a/source/blender/blenkernel/intern/subdiv_inline.h b/source/blender/blenkernel/intern/subdiv_inline.h new file mode 100644 index 00000000000..7eebde48bdc --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_inline.h @@ -0,0 +1,80 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_inline.h + * \ingroup bke + */ + +#ifndef __SUBDIV_INLINE_H__ +#define __SUBDIV_INLINE_H__ + +#include "BLI_assert.h" +#include "BLI_compiler_compat.h" + +#include "BKE_subdiv.h" + +BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv( + const float ptex_u, const float ptex_v, + float *r_grid_u, float *r_grid_v) +{ + *r_grid_u = 1.0f - ptex_v; + *r_grid_v = 1.0f - ptex_u; +} + +BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level) +{ + return (1 << (level - 1)) + 1; +} + +BLI_INLINE int BKE_subdiv_rotate_quad_to_corner( + const float u, const float v, + float *r_u, float *r_v) +{ + int corner; + if (u <= 0.5f && v <= 0.5f) { + corner = 0; + *r_u = 2.0f * u; + *r_v = 2.0f * v; + } + else if (u > 0.5f && v <= 0.5f) { + corner = 1; + *r_u = 2.0f * v; + *r_v = 2.0f * (1.0f - u); + } + else if (u > 0.5f && v > 0.5f) { + corner = 2; + *r_u = 2.0f * (1.0f - u); + *r_v = 2.0f * (1.0f - v); + } + else { + BLI_assert(u <= 0.5f && v >= 0.5f); + corner = 3; + *r_u = 2.0f * (1.0f - v); + *r_v = 2.0f * u; + } + return corner; +} + +#endif /* __SUBDIV_INLINE_H__ */ diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c new file mode 100644 index 00000000000..d8d4014b3cd --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -0,0 +1,1148 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_mesh.c + * \ingroup bke + */ + +#include "BKE_subdiv_mesh.h" + +#include "atomic_ops.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_key_types.h" + +#include "BLI_alloca.h" +#include "BLI_bitmap.h" +#include "BLI_math_vector.h" +#include "BLI_task.h" + +#include "BKE_mesh.h" +#include "BKE_key.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_eval.h" +#include "BKE_subdiv_foreach.h" + +#include "MEM_guardedalloc.h" + +/* ============================================================================= + * Subdivision context. + */ + +typedef struct SubdivMeshContext { + const Mesh *coarse_mesh; + Subdiv *subdiv; + Mesh *subdiv_mesh; + /* Cached custom data arrays for fastter access. */ + int *vert_origindex; + int *edge_origindex; + int *loop_origindex; + int *poly_origindex; + /* UV layers interpolation. */ + int num_uv_layers; + MLoopUV *uv_layers[MAX_MTFACE]; +} SubdivMeshContext; + +static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx) +{ + Mesh *subdiv_mesh = ctx->subdiv_mesh; + ctx->num_uv_layers = + CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV); + for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) { + ctx->uv_layers[layer_index] = CustomData_get_layer_n( + &subdiv_mesh->ldata, CD_MLOOPUV, layer_index); + } +} + +static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx) +{ + Mesh *subdiv_mesh = ctx->subdiv_mesh; + /* Pointers to original indices layers. */ + ctx->vert_origindex = CustomData_get_layer( + &subdiv_mesh->vdata, CD_ORIGINDEX); + ctx->edge_origindex = CustomData_get_layer( + &subdiv_mesh->edata, CD_ORIGINDEX); + ctx->loop_origindex = CustomData_get_layer( + &subdiv_mesh->ldata, CD_ORIGINDEX); + ctx->poly_origindex = CustomData_get_layer( + &subdiv_mesh->pdata, CD_ORIGINDEX); + /* UV layers interpolation. */ + subdiv_mesh_ctx_cache_uv_layers(ctx); +} + +/* ============================================================================= + * Loop custom data copy helpers. + */ + +typedef struct LoopsOfPtex { + /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */ + const MLoop *first_loop; + /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */ + const MLoop *last_loop; + /* For quad coarse faces only. */ + const MLoop *second_loop; + const MLoop *third_loop; +} LoopsOfPtex; + +static void loops_of_ptex_get( + const SubdivMeshContext *ctx, + LoopsOfPtex *loops_of_ptex, + const MPoly *coarse_poly, + const int ptex_of_poly_index) +{ + const MLoop *coarse_mloop = ctx->coarse_mesh->mloop; + const int first_ptex_loop_index = + coarse_poly->loopstart + ptex_of_poly_index; + /* Loop which look in the (opposite) V direction of the current + * ptex face. + * + * TODO(sergey): Get rid of using module on every iteration. + */ + const int last_ptex_loop_index = + coarse_poly->loopstart + + (ptex_of_poly_index + coarse_poly->totloop - 1) % + coarse_poly->totloop; + loops_of_ptex->first_loop = &coarse_mloop[first_ptex_loop_index]; + loops_of_ptex->last_loop = &coarse_mloop[last_ptex_loop_index]; + if (coarse_poly->totloop == 4) { + loops_of_ptex->second_loop = loops_of_ptex->first_loop + 1; + loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2; + } + else { + loops_of_ptex->second_loop = NULL; + loops_of_ptex->third_loop = NULL; + } +} + +/* ============================================================================= + * Vertex custom data interpolation helpers. + */ + +/* TODO(sergey): Somehow de-duplicate with loops storage, without too much + * exception cases all over the code. + */ + +typedef struct VerticesForInterpolation { + /* This field points to a vertex data which is to be used for interpolation. + * The idea is to avoid unnecessary allocations for regular faces, where + * we can simply + */ + const CustomData *vertex_data; + /* Vertices data calculated for ptex corners. There are always 4 elements + * in this custom data, aligned the following way: + * + * index 0 -> uv (0, 0) + * index 1 -> uv (0, 1) + * index 2 -> uv (1, 1) + * index 3 -> uv (1, 0) + * + * Is allocated for non-regular faces (triangles and n-gons). + */ + CustomData vertex_data_storage; + bool vertex_data_storage_allocated; + /* Infices within vertex_data to interpolate for. The indices are aligned + * with uv coordinates in a similar way as indices in loop_data_storage. + */ + int vertex_indices[4]; +} VerticesForInterpolation; + +static void vertex_interpolation_init( + const SubdivMeshContext *ctx, + VerticesForInterpolation *vertex_interpolation, + const MPoly *coarse_poly) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MLoop *coarse_mloop = coarse_mesh->mloop; + if (coarse_poly->totloop == 4) { + vertex_interpolation->vertex_data = &coarse_mesh->vdata; + vertex_interpolation->vertex_indices[0] = + coarse_mloop[coarse_poly->loopstart + 0].v; + vertex_interpolation->vertex_indices[1] = + coarse_mloop[coarse_poly->loopstart + 1].v; + vertex_interpolation->vertex_indices[2] = + coarse_mloop[coarse_poly->loopstart + 2].v; + vertex_interpolation->vertex_indices[3] = + coarse_mloop[coarse_poly->loopstart + 3].v; + vertex_interpolation->vertex_data_storage_allocated = false; + } + else { + vertex_interpolation->vertex_data = + &vertex_interpolation->vertex_data_storage; + /* Allocate storage for loops corresponding to ptex corners. */ + CustomData_copy(&ctx->coarse_mesh->vdata, + &vertex_interpolation->vertex_data_storage, + CD_MASK_EVERYTHING, + CD_CALLOC, + 4); + /* Initialize indices. */ + vertex_interpolation->vertex_indices[0] = 0; + vertex_interpolation->vertex_indices[1] = 1; + vertex_interpolation->vertex_indices[2] = 2; + vertex_interpolation->vertex_indices[3] = 3; + vertex_interpolation->vertex_data_storage_allocated = true; + /* Interpolate center of poly right away, it stays unchanged for all + * ptex faces. + */ + const float weight = 1.0f / (float)coarse_poly->totloop; + float *weights = BLI_array_alloca(weights, coarse_poly->totloop); + int *indices = BLI_array_alloca(indices, coarse_poly->totloop); + for (int i = 0; i < coarse_poly->totloop; ++i) { + weights[i] = weight; + indices[i] = coarse_mloop[coarse_poly->loopstart + i].v; + } + CustomData_interp(&coarse_mesh->vdata, + &vertex_interpolation->vertex_data_storage, + indices, + weights, NULL, + coarse_poly->totloop, + 2); + } +} + +static void vertex_interpolation_from_corner( + const SubdivMeshContext *ctx, + VerticesForInterpolation *vertex_interpolation, + const MPoly *coarse_poly, + const int corner) +{ + if (coarse_poly->totloop == 4) { + /* Nothing to do, all indices and data is already assigned. */ + } + else { + const CustomData *vertex_data = &ctx->coarse_mesh->vdata; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MLoop *coarse_mloop = coarse_mesh->mloop; + LoopsOfPtex loops_of_ptex; + loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner); + /* Ptex face corner corresponds to a poly loop with same index. */ + CustomData_copy_data( + vertex_data, + &vertex_interpolation->vertex_data_storage, + coarse_mloop[coarse_poly->loopstart + corner].v, + 0, + 1); + /* Interpolate remaining ptex face corners, which hits loops + * middle points. + * + * TODO(sergey): Re-use one of interpolation results from previous + * iteration. + */ + const float weights[2] = {0.5f, 0.5f}; + const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop; + const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop; + const int first_indices[2] = { + coarse_mloop[first_loop_index].v, + coarse_mloop[coarse_poly->loopstart + + (first_loop_index - coarse_poly->loopstart + 1) % + coarse_poly->totloop].v}; + const int last_indices[2] = {coarse_mloop[first_loop_index].v, + coarse_mloop[last_loop_index].v}; + CustomData_interp(vertex_data, + &vertex_interpolation->vertex_data_storage, + first_indices, + weights, NULL, + 2, + 1); + CustomData_interp(vertex_data, + &vertex_interpolation->vertex_data_storage, + last_indices, + weights, NULL, + 2, + 3); + } +} + +static void vertex_interpolation_end( + VerticesForInterpolation *vertex_interpolation) +{ + if (vertex_interpolation->vertex_data_storage_allocated) { + CustomData_free(&vertex_interpolation->vertex_data_storage, 4); + } +} + +/* ============================================================================= + * Loop custom data interpolation helpers. + */ + +typedef struct LoopsForInterpolation { + /* This field points to a loop data which is to be used for interpolation. + * The idea is to avoid unnecessary allocations for regular faces, where + * we can simply + */ + const CustomData *loop_data; + /* Loops data calculated for ptex corners. There are always 4 elements + * in this custom data, aligned the following way: + * + * index 0 -> uv (0, 0) + * index 1 -> uv (0, 1) + * index 2 -> uv (1, 1) + * index 3 -> uv (1, 0) + * + * Is allocated for non-regular faces (triangles and n-gons). + */ + CustomData loop_data_storage; + bool loop_data_storage_allocated; + /* Infices within loop_data to interpolate for. The indices are aligned with + * uv coordinates in a similar way as indices in loop_data_storage. + */ + int loop_indices[4]; +} LoopsForInterpolation; + +static void loop_interpolation_init( + const SubdivMeshContext *ctx, + LoopsForInterpolation *loop_interpolation, + const MPoly *coarse_poly) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + if (coarse_poly->totloop == 4) { + loop_interpolation->loop_data = &coarse_mesh->ldata; + loop_interpolation->loop_indices[0] = coarse_poly->loopstart + 0; + loop_interpolation->loop_indices[1] = coarse_poly->loopstart + 1; + loop_interpolation->loop_indices[2] = coarse_poly->loopstart + 2; + loop_interpolation->loop_indices[3] = coarse_poly->loopstart + 3; + loop_interpolation->loop_data_storage_allocated = false; + } + else { + loop_interpolation->loop_data = &loop_interpolation->loop_data_storage; + /* Allocate storage for loops corresponding to ptex corners. */ + CustomData_copy(&ctx->coarse_mesh->ldata, + &loop_interpolation->loop_data_storage, + CD_MASK_EVERYTHING, + CD_CALLOC, + 4); + /* Initialize indices. */ + loop_interpolation->loop_indices[0] = 0; + loop_interpolation->loop_indices[1] = 1; + loop_interpolation->loop_indices[2] = 2; + loop_interpolation->loop_indices[3] = 3; + loop_interpolation->loop_data_storage_allocated = true; + /* Interpolate center of poly right away, it stays unchanged for all + * ptex faces. + */ + const float weight = 1.0f / (float)coarse_poly->totloop; + float *weights = BLI_array_alloca(weights, coarse_poly->totloop); + int *indices = BLI_array_alloca(indices, coarse_poly->totloop); + for (int i = 0; i < coarse_poly->totloop; ++i) { + weights[i] = weight; + indices[i] = coarse_poly->loopstart + i; + } + CustomData_interp(&coarse_mesh->ldata, + &loop_interpolation->loop_data_storage, + indices, + weights, NULL, + coarse_poly->totloop, + 2); + } +} + +static void loop_interpolation_from_corner( + const SubdivMeshContext *ctx, + LoopsForInterpolation *loop_interpolation, + const MPoly *coarse_poly, + const int corner) +{ + if (coarse_poly->totloop == 4) { + /* Nothing to do, all indices and data is already assigned. */ + } + else { + const CustomData *loop_data = &ctx->coarse_mesh->ldata; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MLoop *coarse_mloop = coarse_mesh->mloop; + LoopsOfPtex loops_of_ptex; + loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner); + /* Ptex face corner corresponds to a poly loop with same index. */ + CustomData_free_elem(&loop_interpolation->loop_data_storage, 0, 1); + CustomData_copy_data(loop_data, + &loop_interpolation->loop_data_storage, + coarse_poly->loopstart + corner, + 0, + 1); + /* Interpolate remaining ptex face corners, which hits loops + * middle points. + * + * TODO(sergey): Re-use one of interpolation results from previous + * iteration. + */ + const float weights[2] = {0.5f, 0.5f}; + const int first_indices[2] = { + loops_of_ptex.first_loop - coarse_mloop, + (loops_of_ptex.first_loop + 1 - coarse_mloop) % + coarse_poly->totloop}; + const int last_indices[2] = { + loops_of_ptex.last_loop - coarse_mloop, + loops_of_ptex.first_loop - coarse_mloop}; + CustomData_interp(loop_data, + &loop_interpolation->loop_data_storage, + first_indices, + weights, NULL, + 2, + 1); + CustomData_interp(loop_data, + &loop_interpolation->loop_data_storage, + last_indices, + weights, NULL, + 2, + 3); + } +} + +static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) +{ + if (loop_interpolation->loop_data_storage_allocated) { + CustomData_free(&loop_interpolation->loop_data_storage, 4); + } +} + +/* ============================================================================= + * TLS. + */ + +typedef struct SubdivMeshTLS { + bool vertex_interpolation_initialized; + VerticesForInterpolation vertex_interpolation; + const MPoly *vertex_interpolation_coarse_poly; + int vertex_interpolation_coarse_corner; + + bool loop_interpolation_initialized; + LoopsForInterpolation loop_interpolation; + const MPoly *loop_interpolation_coarse_poly; + int loop_interpolation_coarse_corner; +} SubdivMeshTLS; + +static void subdiv_mesh_tls_free(void *tls_v) +{ + SubdivMeshTLS *tls = tls_v; + if (tls->vertex_interpolation_initialized) { + vertex_interpolation_end(&tls->vertex_interpolation); + } + if (tls->loop_interpolation_initialized) { + loop_interpolation_end(&tls->loop_interpolation); + } +} + +/* ============================================================================= + * Evaluation helper functions. + */ + +static void eval_final_point_and_vertex_normal( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + float r_P[3], short r_N[3]) +{ + if (subdiv->displacement_evaluator == NULL) { + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, ptex_face_index, u, v, r_P, r_N); + } + else { + BKE_subdiv_eval_final_point( + subdiv, ptex_face_index, u, v, r_P); + } +} + +/* ============================================================================= + * Displacement helpers + */ + +static void subdiv_accumulate_vertex_displacement( + Subdiv *subdiv, + const int ptex_face_index, + const float u, const float v, + MVert *subdiv_vert) +{ + float dummy_P[3], dPdu[3], dPdv[3], D[3]; + BKE_subdiv_eval_limit_point_and_derivatives( + subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv); + BKE_subdiv_eval_displacement(subdiv, + ptex_face_index, u, v, + dPdu, dPdv, + D); + add_v3_v3(subdiv_vert->co, D); + if (subdiv_vert->flag & ME_VERT_TMP_TAG) { + mul_v3_fl(subdiv_vert->co, 0.5f); + } + subdiv_vert->flag |= ME_VERT_TMP_TAG; +} + +/* ============================================================================= + * Callbacks. + */ + +static bool subdiv_mesh_topology_info( + const SubdivForeachContext *foreach_context, + const int num_vertices, + const int num_edges, + const int num_loops, + const int num_polygons) +{ + SubdivMeshContext *subdiv_context = foreach_context->user_data; + subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template( + subdiv_context->coarse_mesh, + num_vertices, + num_edges, + 0, + num_loops, + num_polygons); + subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context); + return true; +} + +/* ============================================================================= + * Vertex subdivision process. + */ + +static void subdiv_vertex_data_copy( + const SubdivMeshContext *ctx, + const MVert *coarse_vertex, + MVert *subdiv_vertex) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert; + const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert; + subdiv_vertex->flag &= ~ME_VERT_TMP_TAG; + CustomData_copy_data(&coarse_mesh->vdata, + &ctx->subdiv_mesh->vdata, + coarse_vertex_index, + subdiv_vertex_index, + 1); +} + +static void subdiv_vertex_data_interpolate( + const SubdivMeshContext *ctx, + MVert *subdiv_vertex, + const VerticesForInterpolation *vertex_interpolation, + const float u, const float v) +{ + const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert; + const float weights[4] = {(1.0f - u) * (1.0f - v), + u * (1.0f - v), + u * v, + (1.0f - u) * v}; + subdiv_vertex->flag &= ~ME_VERT_TMP_TAG; + CustomData_interp(vertex_interpolation->vertex_data, + &ctx->subdiv_mesh->vdata, + vertex_interpolation->vertex_indices, + weights, NULL, + 4, + subdiv_vertex_index); + if (ctx->vert_origindex != NULL) { + ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; + } +} + +static void evaluate_vertex_and_apply_displacement_copy( + const SubdivMeshContext *ctx, + const int ptex_face_index, + const float u, const float v, + const MVert *coarse_vert, + MVert *subdiv_vert) +{ + /* Displacement is accumulated in subdiv vertex position. + * need to back it up before copying data from original vertex. + */ + float D[3]; + copy_v3_v3(D, subdiv_vert->co); + subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert); + BKE_subdiv_eval_limit_point_and_short_normal( + ctx->subdiv, + ptex_face_index, + u, v, + subdiv_vert->co, subdiv_vert->no); + /* Apply displacement. */ + add_v3_v3(subdiv_vert->co, D); +} + +static void evaluate_vertex_and_apply_displacement_interpolate( + const SubdivMeshContext *ctx, + const int ptex_face_index, + const float u, const float v, + VerticesForInterpolation *vertex_interpolation, + MVert *subdiv_vert) +{ + /* Displacement is accumulated in subdiv vertex position. + * need to back it up before copying data from original vertex. + */ + float D[3]; + copy_v3_v3(D, subdiv_vert->co); + subdiv_vertex_data_interpolate(ctx, + subdiv_vert, + vertex_interpolation, + u, v); + BKE_subdiv_eval_limit_point_and_short_normal( + ctx->subdiv, + ptex_face_index, + u, v, + subdiv_vert->co, subdiv_vert->no); + /* Apply displacement. */ + add_v3_v3(subdiv_vert->co, D); +} + +static void subdiv_mesh_vertex_every_corner_or_edge( + const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int ptex_face_index, + const float u, const float v, + const int subdiv_vertex_index) +{ + SubdivMeshContext *ctx = foreach_context->user_data; + Subdiv *subdiv = ctx->subdiv; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index]; + subdiv_accumulate_vertex_displacement( + subdiv, ptex_face_index, u, v, subdiv_vert); +} + +static void subdiv_mesh_vertex_every_corner( + const SubdivForeachContext *foreach_context, + void *tls, + const int ptex_face_index, + const float u, const float v, + const int UNUSED(coarse_vertex_index), + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int subdiv_vertex_index) +{ + subdiv_mesh_vertex_every_corner_or_edge( + foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index); +} + +static void subdiv_mesh_vertex_every_edge( + const SubdivForeachContext *foreach_context, + void *tls, + const int ptex_face_index, + const float u, const float v, + const int UNUSED(coarse_edge_index), + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int subdiv_vertex_index) +{ + subdiv_mesh_vertex_every_corner_or_edge( + foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index); +} + +static void subdiv_mesh_vertex_corner( + const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int ptex_face_index, + const float u, const float v, + const int coarse_vertex_index, + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int subdiv_vertex_index) +{ + BLI_assert(coarse_vertex_index != ORIGINDEX_NONE); + SubdivMeshContext *ctx = foreach_context->user_data; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MVert *coarse_mvert = coarse_mesh->mvert; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + const MVert *coarse_vert = &coarse_mvert[coarse_vertex_index]; + MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index]; + evaluate_vertex_and_apply_displacement_copy( + ctx, ptex_face_index, u, v, coarse_vert, subdiv_vert); +} + +static void subdiv_mesh_ensure_vertex_interpolation( + SubdivMeshContext *ctx, + SubdivMeshTLS *tls, + const MPoly *coarse_poly, + const int coarse_corner) +{ + /* Check whether we've moved to another corner or polygon. */ + if (tls->vertex_interpolation_initialized) { + if (tls->vertex_interpolation_coarse_poly != coarse_poly || + tls->vertex_interpolation_coarse_corner != coarse_corner) + { + vertex_interpolation_end(&tls->vertex_interpolation); + tls->vertex_interpolation_initialized = false; + } + } + /* Initialize the interpolation. */ + if (!tls->vertex_interpolation_initialized) { + vertex_interpolation_init(ctx, &tls->vertex_interpolation, coarse_poly); + } + /* Update it for a new corner if needed. */ + if (!tls->vertex_interpolation_initialized || + tls->vertex_interpolation_coarse_corner != coarse_corner) + { + vertex_interpolation_from_corner( + ctx, &tls->vertex_interpolation, coarse_poly, coarse_corner); + } + /* Store settings used for the current state of interpolator. */ + tls->vertex_interpolation_initialized = true; + tls->vertex_interpolation_coarse_poly = coarse_poly; + tls->vertex_interpolation_coarse_corner = coarse_corner; +} + +static void subdiv_mesh_vertex_edge( + const SubdivForeachContext *foreach_context, + void *tls_v, + const int ptex_face_index, + const float u, const float v, + const int UNUSED(coarse_edge_index), + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index) +{ + SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshTLS *tls = tls_v; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index]; + subdiv_mesh_ensure_vertex_interpolation( + ctx, tls, coarse_poly, coarse_corner); + evaluate_vertex_and_apply_displacement_interpolate( + ctx, + ptex_face_index, u, v, + &tls->vertex_interpolation, + subdiv_vert); +} + +static void subdiv_mesh_vertex_inner( + const SubdivForeachContext *foreach_context, + void *tls_v, + const int ptex_face_index, + const float u, const float v, + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_vertex_index) +{ + SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshTLS *tls = tls_v; + Subdiv *subdiv = ctx->subdiv; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index]; + subdiv_mesh_ensure_vertex_interpolation( + ctx, tls, coarse_poly, coarse_corner); + subdiv_vertex_data_interpolate( + ctx, subdiv_vert, &tls->vertex_interpolation, u, v); + eval_final_point_and_vertex_normal( + subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no); +} + +/* ============================================================================= + * Edge subdivision process. + */ + +static void subdiv_copy_edge_data( + SubdivMeshContext *ctx, + MEdge *subdiv_edge, + const MEdge *coarse_edge) +{ + const int subdiv_edge_index = subdiv_edge - ctx->subdiv_mesh->medge; + if (coarse_edge == NULL) { + subdiv_edge->crease = 0; + subdiv_edge->bweight = 0; + subdiv_edge->flag = 0; + if (ctx->edge_origindex != NULL) { + ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE; + } + return; + } + const int coarse_edge_index = coarse_edge - ctx->coarse_mesh->medge; + CustomData_copy_data(&ctx->coarse_mesh->edata, + &ctx->subdiv_mesh->edata, + coarse_edge_index, + subdiv_edge_index, + 1); +} + +static void subdiv_mesh_edge( + const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int coarse_edge_index, + const int subdiv_edge_index, + const int subdiv_v1, const int subdiv_v2) +{ + SubdivMeshContext *ctx = foreach_context->user_data; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MEdge *subdiv_medge = subdiv_mesh->medge; + MEdge *subdiv_edge = &subdiv_medge[subdiv_edge_index]; + if (coarse_edge_index != ORIGINDEX_NONE) { + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MEdge *coarse_edge = &coarse_medge[coarse_edge_index]; + subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge); + } + subdiv_edge->v1 = subdiv_v1; + subdiv_edge->v2 = subdiv_v2; +} + +/* ============================================================================= + * Loops creation/interpolation. + */ + +static void subdiv_interpolate_loop_data( + const SubdivMeshContext *ctx, + MLoop *subdiv_loop, + const LoopsForInterpolation *loop_interpolation, + const float u, const float v) +{ + const int subdiv_loop_index = subdiv_loop - ctx->subdiv_mesh->mloop; + const float weights[4] = {(1.0f - u) * (1.0f - v), + u * (1.0f - v), + u * v, + (1.0f - u) * v}; + CustomData_interp(loop_interpolation->loop_data, + &ctx->subdiv_mesh->ldata, + loop_interpolation->loop_indices, + weights, NULL, + 4, + subdiv_loop_index); + /* TODO(sergey): Set ORIGINDEX. */ +} + +static void subdiv_eval_uv_layer(SubdivMeshContext *ctx, + MLoop *subdiv_loop, + const int ptex_face_index, + const float u, const float v) +{ + if (ctx->num_uv_layers == 0) { + return; + } + Subdiv *subdiv = ctx->subdiv; + const int mloop_index = subdiv_loop - ctx->subdiv_mesh->mloop; + for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) { + MLoopUV *subdiv_loopuv = &ctx->uv_layers[layer_index][mloop_index]; + BKE_subdiv_eval_face_varying(subdiv, + layer_index, + ptex_face_index, + u, v, + subdiv_loopuv->uv); + } +} + +static void subdiv_mesh_ensure_loop_interpolation( + SubdivMeshContext *ctx, + SubdivMeshTLS *tls, + const MPoly *coarse_poly, + const int coarse_corner) +{ + /* Check whether we've moved to another corner or polygon. */ + if (tls->loop_interpolation_initialized) { + if (tls->loop_interpolation_coarse_poly != coarse_poly || + tls->loop_interpolation_coarse_corner != coarse_corner) + { + loop_interpolation_end(&tls->loop_interpolation); + tls->loop_interpolation_initialized = false; + } + } + /* Initialize the interpolation. */ + if (!tls->loop_interpolation_initialized) { + loop_interpolation_init(ctx, &tls->loop_interpolation, coarse_poly); + } + /* Update it for a new corner if needed. */ + if (!tls->loop_interpolation_initialized || + tls->loop_interpolation_coarse_corner != coarse_corner) + { + loop_interpolation_from_corner( + ctx, &tls->loop_interpolation, coarse_poly, coarse_corner); + } + /* Store settings used for the current state of interpolator. */ + tls->loop_interpolation_initialized = true; + tls->loop_interpolation_coarse_poly = coarse_poly; + tls->loop_interpolation_coarse_corner = coarse_corner; +} + +static void subdiv_mesh_loop( + const SubdivForeachContext *foreach_context, + void *tls_v, + const int ptex_face_index, + const float u, const float v, + const int UNUSED(coarse_loop_index), + const int coarse_poly_index, + const int coarse_corner, + const int subdiv_loop_index, + const int subdiv_vertex_index, const int subdiv_edge_index) +{ + SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshTLS *tls = tls_v; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MLoop *subdiv_mloop = subdiv_mesh->mloop; + MLoop *subdiv_loop = &subdiv_mloop[subdiv_loop_index]; + subdiv_mesh_ensure_loop_interpolation( + ctx, tls, coarse_poly, coarse_corner); + subdiv_interpolate_loop_data( + ctx, subdiv_loop, &tls->loop_interpolation, u, v); + subdiv_eval_uv_layer(ctx, subdiv_loop, ptex_face_index, u, v); + subdiv_loop->v = subdiv_vertex_index; + subdiv_loop->e = subdiv_edge_index; +} + +/* ============================================================================= + * Polygons subdivision process. + */ + +static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, + MPoly *subdiv_poly, + const MPoly *coarse_poly) +{ + const int coarse_poly_index = coarse_poly - ctx->coarse_mesh->mpoly; + const int subdiv_poly_index = subdiv_poly - ctx->subdiv_mesh->mpoly; + CustomData_copy_data(&ctx->coarse_mesh->pdata, + &ctx->subdiv_mesh->pdata, + coarse_poly_index, + subdiv_poly_index, + 1); +} + +static void subdiv_mesh_poly( + const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int coarse_poly_index, + const int subdiv_poly_index, + const int start_loop_index, const int num_loops) +{ + BLI_assert(coarse_poly_index != ORIGINDEX_NONE); + SubdivMeshContext *ctx = foreach_context->user_data; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MPoly *subdiv_mpoly = subdiv_mesh->mpoly; + MPoly *subdiv_poly = &subdiv_mpoly[subdiv_poly_index]; + subdiv_copy_poly_data(ctx, subdiv_poly, coarse_poly); + subdiv_poly->loopstart = start_loop_index; + subdiv_poly->totloop = num_loops; +} + +/* ============================================================================= + * Loose elements subdivision process. + */ + +static void subdiv_mesh_vertex_loose( + const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int coarse_vertex_index, + const int subdiv_vertex_index) +{ + SubdivMeshContext *ctx = foreach_context->user_data; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MVert *coarse_mvert = coarse_mesh->mvert; + const MVert *coarse_vertex = &coarse_mvert[coarse_vertex_index]; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index]; + subdiv_vertex_data_copy(ctx, coarse_vertex, subdiv_vertex); +} + +/* Get neighbor edges of the given one. + * - neighbors[0] is an edge adjacent to edge->v1. + * - neighbors[1] is an edge adjacent to edge->v1. + */ +static void find_edge_neighbors(const SubdivMeshContext *ctx, + const MEdge *edge, + const MEdge *neighbors[2]) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + neighbors[0] = NULL; + neighbors[1] = NULL; + for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) { + const MEdge *current_edge = &coarse_medge[edge_index]; + if (current_edge == edge) { + continue; + } + if (ELEM(edge->v1, current_edge->v1, current_edge->v2)) { + neighbors[0] = current_edge; + } + if (ELEM(edge->v2, current_edge->v1, current_edge->v2)) { + neighbors[1] = current_edge; + } + } +} + +static void points_for_loose_edges_interpolation_get( + SubdivMeshContext *ctx, + const MEdge *coarse_edge, + const MEdge *neighbors[2], + float points_r[4][3]) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MVert *coarse_mvert = coarse_mesh->mvert; + /* Middle points corresponds to the edge. */ + copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co); + copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co); + /* Start point, duplicate from edge start if no neighbor. */ + if (neighbors[0] != NULL) { + if (neighbors[0]->v1 == coarse_edge->v1) { + copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v2].co); + } + else { + copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v1].co); + } + } + else { + sub_v3_v3v3(points_r[0], points_r[1], points_r[2]); + add_v3_v3(points_r[0], points_r[1]); + } + /* End point, duplicate from edge end if no neighbor. */ + if (neighbors[1] != NULL) { + if (neighbors[1]->v1 == coarse_edge->v2) { + copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v2].co); + } + else { + copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v1].co); + } + } + else { + sub_v3_v3v3(points_r[3], points_r[2], points_r[1]); + add_v3_v3(points_r[3], points_r[2]); + } +} + +static void subdiv_mesh_vertex_of_loose_edge( + const struct SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int coarse_edge_index, + const float u, + const int subdiv_vertex_index) +{ + SubdivMeshContext *ctx = foreach_context->user_data; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index]; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + /* Find neighbors of the current loose edge. */ + const MEdge *neighbors[2]; + find_edge_neighbors(ctx, coarse_edge, neighbors); + /* Get points for b-spline interpolation. */ + float points[4][3]; + points_for_loose_edges_interpolation_get( + ctx, coarse_edge, neighbors, points); + /* Perform interpolation. */ + float weights[4]; + key_curve_position_weights(u, weights, KEY_BSPLINE); + + MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index]; + interp_v3_v3v3v3v3(subdiv_vertex->co, + points[0], + points[1], + points[2], + points[3], + weights); + /* Reset flags and such. */ + subdiv_vertex->flag = 0; + subdiv_vertex->bweight = 0.0f; + /* Reset normal. */ + subdiv_vertex->no[0] = 0.0f; + subdiv_vertex->no[1] = 0.0f; + subdiv_vertex->no[2] = 1.0f; +} + +/* ============================================================================= + * Initialization. + */ + +static void setup_foreach_callbacks(SubdivForeachContext *foreach_context, + const Subdiv *subdiv) +{ + memset(foreach_context, 0, sizeof(*foreach_context)); + /* General information. */ + foreach_context->topology_info = subdiv_mesh_topology_info; + /* Every boundary geometry. Used for dispalcement averaging. */ + if (subdiv->displacement_evaluator != NULL) { + foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner; + foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge; + } + else { + foreach_context->vertex_every_corner = NULL; + foreach_context->vertex_every_edge = NULL; + } + foreach_context->vertex_corner = subdiv_mesh_vertex_corner; + foreach_context->vertex_edge = subdiv_mesh_vertex_edge; + foreach_context->vertex_inner = subdiv_mesh_vertex_inner; + foreach_context->edge = subdiv_mesh_edge; + foreach_context->loop = subdiv_mesh_loop; + foreach_context->poly = subdiv_mesh_poly; + foreach_context->vertex_loose = subdiv_mesh_vertex_loose; + foreach_context->vertex_of_loose_edge = subdiv_mesh_vertex_of_loose_edge; + foreach_context->user_data_tls_free = subdiv_mesh_tls_free; +} + +/* ============================================================================= + * Public entry point. + */ + +Mesh *BKE_subdiv_to_mesh( + Subdiv *subdiv, + const SubdivToMeshSettings *settings, + const Mesh *coarse_mesh) +{ + BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); + /* Make sure evaluator is up to date with possible new topology, and that + * is is refined for the new positions of coarse vertices. + */ + if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) { + /* This could happen in two situations: + * - OpenSubdiv is disabled. + * - Something totally bad happened, and OpenSubdiv rejected our + * topology. + * In either way, we can't safely continue. + */ + if (coarse_mesh->totpoly) { + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); + return NULL; + } + } + /* Initialize subdivion mesh creation context/ */ + SubdivMeshContext subdiv_context = {0}; + subdiv_context.coarse_mesh = coarse_mesh; + subdiv_context.subdiv = subdiv; + /* Multi-threaded traversal/evaluation. */ + BKE_subdiv_stats_begin(&subdiv->stats, + SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); + SubdivForeachContext foreach_context; + setup_foreach_callbacks(&foreach_context, subdiv); + SubdivMeshTLS tls = {0}; + foreach_context.user_data = &subdiv_context; + foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS); + foreach_context.user_data_tls = &tls; + BKE_subdiv_foreach_subdiv_geometry(subdiv, + &foreach_context, + settings, + coarse_mesh); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); + Mesh *result = subdiv_context.subdiv_mesh; + // BKE_mesh_validate(result, true, true); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); + if (subdiv->displacement_evaluator != NULL) { + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } + return result; +} diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c new file mode 100644 index 00000000000..a0cd1d909b7 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_stats.c @@ -0,0 +1,92 @@ +/* + * ***** 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) 2018 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/subdiv_stats.c + * \ingroup bke + */ + +#include "BKE_subdiv.h" + +#include <stdio.h> + +#include "PIL_time.h" + +void BKE_subdiv_stats_init(SubdivStats *stats) +{ + stats->topology_refiner_creation_time = 0.0; + stats->subdiv_to_mesh_time = 0.0; + stats->subdiv_to_mesh_geometry_time = 0.0; + stats->evaluator_creation_time = 0.0; + stats->evaluator_refine_time = 0.0; + stats->subdiv_to_ccg_time = 0.0; + stats->subdiv_to_ccg_elements_time = 0.0; +} + +void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value) +{ + stats->begin_timestamp_[value] = PIL_check_seconds_timer(); +} + +void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value) +{ + stats->values_[value] = + PIL_check_seconds_timer() - stats->begin_timestamp_[value]; +} + +void BKE_subdiv_stats_print(const SubdivStats *stats) +{ +#define STATS_PRINT_TIME(stats, value, description) \ + do { \ + if ((stats)->value > 0.0) { \ + printf(" %s: %f (sec)\n", description, (stats)->value); \ + } \ + } while (false) + + printf("Subdivision surface statistics:\n"); + + STATS_PRINT_TIME(stats, + topology_refiner_creation_time, + "Topology refiner creation time"); + STATS_PRINT_TIME(stats, + subdiv_to_mesh_time, + "Subdivision to mesh time"); + STATS_PRINT_TIME(stats, + subdiv_to_mesh_geometry_time, + " Geometry time"); + STATS_PRINT_TIME(stats, + evaluator_creation_time, + "Evaluator creation time"); + STATS_PRINT_TIME(stats, + evaluator_refine_time, + "Evaluator refine time"); + STATS_PRINT_TIME(stats, + subdiv_to_ccg_time, + "Subdivision to CCG time"); + STATS_PRINT_TIME(stats, + subdiv_to_ccg_elements_time, + " Elements time"); + +#undef STATS_PRINT_TIME +} diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 3c4e1f92344..bba3e97cad7 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -69,6 +69,7 @@ #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" #include "BKE_multires.h" +#include "BKE_object.h" #include "BKE_paint.h" #include "BKE_scene.h" #include "BKE_subsurf.h" @@ -77,12 +78,6 @@ # include "BLI_array.h" #endif -#include "GPU_draw.h" -#include "GPU_glew.h" -#include "GPU_buffers.h" -#include "GPU_shader.h" -#include "GPU_basic_shader.h" - #include "CCGSubSurf.h" #ifdef WITH_OPENSUBDIV @@ -1050,43 +1045,6 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med) int gridSideEdges; int gridInternalEdges; - /* code added in bmesh but works correctly without, commenting - campbell */ -#if 0 - int lasti, previ; - i = lastface; - lasti = 0; - while (1) { - previ = i; - if (ccgdm->faceMap[i].startEdge >= edgeNum) { - i -= fabsf(i - lasti) / 2.0f; - } - else if (ccgdm->faceMap[i].startEdge < edgeNum) { - i += fabsf(i - lasti) / 2.0f; - } - else { - break; - } - - if (i < 0) { - i = 0; - break; - } - - if (i > lastface) { - i = lastface; - break; - - } - - if (i == lasti) - break; - - lasti = previ; - } - - i = i > 0 ? i - 1 : i; -#endif - i = 0; while (i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) { i++; @@ -1766,47 +1724,7 @@ static void ccgDM_foreachMappedLoop( } } -static void ccgDM_drawVerts(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - int edgeSize = ccgSubSurf_getEdgeSize(ss); - int gridSize = ccgSubSurf_getGridSize(ss); - CCGVertIterator vi; - CCGEdgeIterator ei; - CCGFaceIterator fi; - - glBegin(GL_POINTS); - for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) { - CCGVert *v = ccgVertIterator_getCurrent(&vi); - glVertex3fv(ccgSubSurf_getVertData(ss, v)); - } - - for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); - int x; - - for (x = 1; x < edgeSize - 1; x++) - glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x)); - } - - for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) { - CCGFace *f = ccgFaceIterator_getCurrent(&fi); - int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - - glVertex3fv(ccgSubSurf_getFaceCenterData(f)); - for (S = 0; S < numVerts; S++) - for (x = 1; x < gridSize - 1; x++) - glVertex3fv(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); - for (S = 0; S < numVerts; S++) - for (y = 1; y < gridSize - 1; y++) - for (x = 1; x < gridSize - 1; x++) - glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y)); - } - glEnd(); -} - -static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm) +static void UNUSED_FUNCTION(ccgdm_pbvh_update)(CCGDerivedMesh *ccgdm) { if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) { CCGFace **faces; @@ -1821,2179 +1739,6 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm) } } -static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges) -{ - GPUDrawObject *gdo; - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - /* TODO(sergey): We currently only support all edges drawing. */ - if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) { - ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1); - } - return; - } -#endif - - ccgdm_pbvh_update(ccgdm); - -/* old debug feature for edges, unsupported for now */ -#if 0 - int useAging = 0; - - if (!(G.f & G_BACKBUFSEL)) { - CCGSubSurf *ss = ccgdm->ss; - ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); - - /* it needs some way to upload this to VBO now */ - if (useAging) { - int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4; - glColor3ub(0, ageCol > 0 ? ageCol : 0, 0); - } - } -#endif - - GPU_edge_setup(dm); - gdo = dm->drawObject; - if (gdo->edges && gdo->points) { - if (drawAllEdges && drawLooseEdges) { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, (gdo->totedge - gdo->totinterior) * 2); - } - else if (drawAllEdges) { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2); - } - else { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2); - GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, gdo->tot_loose_edge_drawn * 2); - } - } - - if (gdo->edges && ccgdm->drawInteriorEdges) { - GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->interior_offset * 2, gdo->totinterior * 2); - } - GPU_buffers_unbind(); -} - -static void ccgDM_drawLooseEdges(DerivedMesh *dm) -{ - int start; - int count; - -#ifdef WITH_OPENSUBDIV - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - if (ccgdm->useGpuBackend) { - /* TODO(sergey): Needs implementation. */ - return; - } -#endif - - GPU_edge_setup(dm); - - start = (dm->drawObject->loose_edge_offset * 2); - count = (dm->drawObject->interior_offset - dm->drawObject->loose_edge_offset) * 2; - - if (count) { - GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count); - } - - GPU_buffers_unbind(); -} - -static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3]) -{ - float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; - float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; - - no[0] = b_dY * a_cZ - b_dZ * a_cY; - no[1] = b_dZ * a_cX - b_dX * a_cZ; - no[2] = b_dX * a_cY - b_dY * a_cX; - - normalize_v3(no); -} - - -static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d) -{ - float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; - float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; - float no[3]; - - no[0] = b_dY * a_cZ - b_dZ * a_cY; - no[1] = b_dZ * a_cX - b_dX * a_cZ; - no[2] = b_dX * a_cY - b_dY * a_cX; - - /* don't normalize, GL_NORMALIZE is enabled */ - glNormal3fv(no); -} - -/* Only used by non-editmesh types */ -static void ccgDM_buffer_copy_normal( - DerivedMesh *dm, short *varray) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - DMFlagMat *faceFlags = ccgdm->faceFlags; - int i, totface = ccgSubSurf_getNumFaces(ss); - int shademodel; - int start = 0; - - /* we are in sculpt mode, disable loop normals (since they won't get updated) */ - if (ccgdm->pbvh) - lnors = NULL; - - CCG_key_top_level(&key, ss); - - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - const float (*ln)[3] = NULL; - - if (faceFlags) { - shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT; - } - else { - shademodel = GL_SMOOTH; - } - - if (lnors) { - ln = lnors; - lnors += gridFaces * gridFaces * numVerts * 4; - } - - for (S = 0; S < numVerts; S++) { - CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); - - if (ln) { - /* Can't use quad strips here... */ - for (y = 0; y < gridFaces; y ++) { - for (x = 0; x < gridFaces; x ++) { - normal_float_to_short_v3(&varray[start + 0], ln[0]); - normal_float_to_short_v3(&varray[start + 4], ln[3]); - normal_float_to_short_v3(&varray[start + 8], ln[2]); - normal_float_to_short_v3(&varray[start + 12], ln[1]); - - start += 16; - ln += 4; - } - } - } - else if (shademodel == GL_SMOOTH) { - for (y = 0; y < gridFaces; y ++) { - for (x = 0; x < gridFaces; x ++) { - float *a = CCG_grid_elem_no(&key, faceGridData, x, y ); - float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y); - float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1); - float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1); - - normal_float_to_short_v3(&varray[start], a); - normal_float_to_short_v3(&varray[start + 4], b); - normal_float_to_short_v3(&varray[start + 8], c); - normal_float_to_short_v3(&varray[start + 12], d); - - start += 16; - } - } - } - else { - for (y = 0; y < gridFaces; y ++) { - for (x = 0; x < gridFaces; x ++) { - float f_no[3]; - short f_no_s[3]; - - float *a = CCG_grid_elem_co(&key, faceGridData, x, y ); - float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y ); - float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - ccgDM_NormalFast(a, b, c, d, f_no); - normal_float_to_short_v3(f_no_s, f_no); - - copy_v3_v3_short(&varray[start], f_no_s); - copy_v3_v3_short(&varray[start + 4], f_no_s); - copy_v3_v3_short(&varray[start + 8], f_no_s); - copy_v3_v3_short(&varray[start + 12], f_no_s); - - start += 16; - } - } - } - } - } -} - -typedef struct FaceCount { - unsigned int i_visible; - unsigned int i_hidden; - unsigned int i_tri_visible; - unsigned int i_tri_hidden; -} FaceCount; - - -/* Only used by non-editmesh types */ -static void ccgDM_buffer_copy_triangles( - DerivedMesh *dm, unsigned int *varray, - const int *mat_orig_to_new) -{ - GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials; - const int gpu_totmat = dm->drawObject->totmaterial; - const short dm_totmat = dm->totmat; - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - DMFlagMat *faceFlags = ccgdm->faceFlags; - int i, totface = ccgSubSurf_getNumFaces(ss); - short mat_nr = -1; - int start; - int totloops = 0; - FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount"); - - CCG_key_top_level(&key, ss); - - for (i = 0; i < gpu_totmat; i++) { - fc[i].i_visible = 0; - fc[i].i_tri_visible = 0; - fc[i].i_hidden = gpumaterials[i].totpolys - 1; - fc[i].i_tri_hidden = gpumaterials[i].totelements - 1; - } - - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - bool is_hidden; - int mati; - - if (faceFlags) { - mat_nr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat); - is_hidden = (faceFlags[index].flag & ME_HIDE) != 0; - } - else { - mat_nr = 0; - is_hidden = false; - } - mati = mat_orig_to_new[mat_nr]; - gpumat = dm->drawObject->materials + mati; - - if (is_hidden) { - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - start = gpumat->start + fc[mati].i_tri_hidden; - - varray[start--] = totloops; - varray[start--] = totloops + 2; - varray[start--] = totloops + 3; - - varray[start--] = totloops; - varray[start--] = totloops + 1; - varray[start--] = totloops + 2; - - fc[mati].i_tri_hidden -= 6; - - totloops += 4; - } - } - } - gpumat->polys[fc[mati].i_hidden--] = i; - } - else { - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - start = gpumat->start + fc[mati].i_tri_visible; - - varray[start++] = totloops + 3; - varray[start++] = totloops + 2; - varray[start++] = totloops; - - varray[start++] = totloops + 2; - varray[start++] = totloops + 1; - varray[start++] = totloops; - - fc[mati].i_tri_visible += 6; - - totloops += 4; - } - } - } - gpumat->polys[fc[mati].i_visible++] = i; - } - } - - /* set the visible polygons */ - for (i = 0; i < gpu_totmat; i++) { - gpumaterials[i].totvisiblepolys = fc[i].i_visible; - } - - MEM_freeN(fc); -} - - -/* Only used by non-editmesh types */ -static void ccgDM_buffer_copy_vertex( - DerivedMesh *dm, void *varray_p) -{ - float *varray = varray_p; - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - int i, totface = ccgSubSurf_getNumFaces(ss); - int totedge = ccgSubSurf_getNumEdges(ss); - int start = 0; - int edgeSize = ccgSubSurf_getEdgeSize(ss); - - CCG_key_top_level(&key, ss); - - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++) { - CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *a = CCG_grid_elem_co(&key, faceGridData, x, y); - float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y); - float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - copy_v3_v3(&varray[start], a); - copy_v3_v3(&varray[start + 3], b); - copy_v3_v3(&varray[start + 6], c); - copy_v3_v3(&varray[start + 9], d); - - start += 12; - } - } - } - } - - /* upload loose points */ - for (i = 0; i < totedge; i++) { - CCGEdge *e = ccgdm->edgeMap[i].edge; - CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); - - if (!ccgSubSurf_getEdgeNumFaces(e)) { - int j = 0; - for (j = 0; j < edgeSize; j++) { - copy_v3_v3(&varray[start], CCG_elem_offset_co(&key, edgeData, j)); - start += 3; - } - } - } -} - -/* Only used by non-editmesh types */ -static void ccgDM_buffer_copy_color( - DerivedMesh *dm, unsigned char *varray, - const void *user_data) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - const unsigned char *mloopcol = user_data; - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - int i, totface = ccgSubSurf_getNumFaces(ss); - int start = 0; - int iface = 0; - - CCG_key_top_level(&key, ss); - - - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - copy_v4_v4_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]); - copy_v4_v4_uchar(&varray[start + 4], &mloopcol[iface * 16 + 12]); - copy_v4_v4_uchar(&varray[start + 8], &mloopcol[iface * 16 + 8]); - copy_v4_v4_uchar(&varray[start + 12], &mloopcol[iface * 16 + 4]); - - start += 16; - iface++; - } - } - } - } -} - -static void ccgDM_buffer_copy_uv( - DerivedMesh *dm, void *varray_p) -{ - float *varray = varray_p; - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - MLoopUV *mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV); - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - int i, totface = ccgSubSurf_getNumFaces(ss); - int start = 0; - - CCG_key_top_level(&key, ss); - - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - copy_v2_v2(&varray[start + 0], mloopuv[0].uv); - copy_v2_v2(&varray[start + 2], mloopuv[3].uv); - copy_v2_v2(&varray[start + 4], mloopuv[2].uv); - copy_v2_v2(&varray[start + 6], mloopuv[1].uv); - - mloopuv += 4; - start += 8; - } - } - } - } -} - -static void ccgDM_buffer_copy_uv_texpaint( - DerivedMesh *dm, float *varray) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - int i, totface = ccgSubSurf_getNumFaces(ss); - int start = 0; - DMFlagMat *faceFlags = ccgdm->faceFlags; - int dm_totmat = dm->totmat; - MLoopUV **mloopuv_base; - MLoopUV *stencil_base; - int stencil; - - CCG_key_top_level(&key, ss); - - /* should have been checked for before, reassert */ - BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV)); - mloopuv_base = MEM_mallocN(dm_totmat * sizeof(*mloopuv_base), "texslots"); - - for (i = 0; i < dm_totmat; i++) { - mloopuv_base[i] = DM_paint_uvlayer_active_get(dm, i); - } - - stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV); - stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil); - - start = 0; - - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - int matnr; - - if (faceFlags) { - matnr = faceFlags[index].mat_nr; - } - else { - matnr = 0; - } - - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - /* divide by 4, gives us current loop-index */ - unsigned int i_ml = start / 4; - copy_v2_v2(&varray[start + 0], mloopuv_base[matnr][i_ml + 0].uv); - copy_v2_v2(&varray[start + 2], stencil_base[i_ml + 0].uv); - copy_v2_v2(&varray[start + 4], mloopuv_base[matnr][i_ml + 3].uv); - copy_v2_v2(&varray[start + 6], stencil_base[i_ml + 3].uv); - copy_v2_v2(&varray[start + 8], mloopuv_base[matnr][i_ml + 2].uv); - copy_v2_v2(&varray[start + 10], stencil_base[i_ml + 2].uv); - copy_v2_v2(&varray[start + 12], mloopuv_base[matnr][i_ml + 1].uv); - copy_v2_v2(&varray[start + 14], stencil_base[i_ml + 1].uv); - start += 16; - } - } - } - } - - MEM_freeN(mloopuv_base); -} - -static void ccgDM_buffer_copy_uvedge( - DerivedMesh *dm, float *varray) -{ - int i, totpoly; - int start; - const MLoopUV *mloopuv; -#ifndef USE_LOOP_LAYOUT_FAST - const MPoly *mpoly = dm->getPolyArray(dm); -#endif - - if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) { - return; - } - - totpoly = dm->getNumPolys(dm); - start = 0; - -#ifndef USE_LOOP_LAYOUT_FAST - for (i = 0; i < totpoly; i++, mpoly++) { - for (j = 0; j < mpoly->totloop; j++) { - copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv); - copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv); - start += 4; - } - } -#else - for (i = 0; i < totpoly; i++) { - copy_v2_v2(&varray[start + 0], mloopuv[(i * 4) + 0].uv); - copy_v2_v2(&varray[start + 2], mloopuv[(i * 4) + 1].uv); - - copy_v2_v2(&varray[start + 4], mloopuv[(i * 4) + 1].uv); - copy_v2_v2(&varray[start + 6], mloopuv[(i * 4) + 2].uv); - - copy_v2_v2(&varray[start + 8], mloopuv[(i * 4) + 2].uv); - copy_v2_v2(&varray[start + 10], mloopuv[(i * 4) + 3].uv); - - copy_v2_v2(&varray[start + 12], mloopuv[(i * 4) + 3].uv); - copy_v2_v2(&varray[start + 14], mloopuv[(i * 4) + 0].uv); - - start += 16; - } -#endif -} - -static void ccgDM_buffer_copy_edge( - DerivedMesh *dm, unsigned int *varray) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - /* getEdgeSuze returns num of verts, edges is one less */ - int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss) - 1; - int totedge = ccgSubSurf_getNumEdges(ss); - int grid_face_side = ccgSubSurf_getGridSize(ss) - 1; - int totface = ccgSubSurf_getNumFaces(ss); - unsigned int index_start; - unsigned int tot_interior = 0; - unsigned int grid_tot_face = grid_face_side * grid_face_side; - - unsigned int iloose, inorm, iloosehidden, inormhidden; - unsigned int tot_loose_hidden = 0, tot_loose = 0; - unsigned int tot_hidden = 0, tot = 0; - unsigned int iloosevert; - /* int tot_interior = 0; */ - - /* first, handle hidden/loose existing edges, then interior edges */ - for (j = 0; j < totedge; j++) { - CCGEdge *e = ccgdm->edgeMap[j].edge; - - if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) { - if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose_hidden++; - else tot_hidden++; - } - else { - if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose++; - else tot++; - } - } - - inorm = 0; - inormhidden = tot * edgeSize; - iloose = (tot + tot_hidden) * edgeSize; - iloosehidden = (tot + tot_hidden + tot_loose) * edgeSize; - iloosevert = dm->drawObject->tot_loop_verts; - - /* part one, handle all normal edges */ - for (j = 0; j < totedge; j++) { - CCGFace *f; - int fhandle = 0; - int totvert = 0; - unsigned int S = 0; - CCGEdge *e = ccgdm->edgeMap[j].edge; - bool isloose = !ccgSubSurf_getEdgeNumFaces(e); - - if (!isloose) { - CCGVert *v1, *v2; - CCGVert *ev1 = ccgSubSurf_getEdgeVert0(e); - CCGVert *ev2 = ccgSubSurf_getEdgeVert1(e); - - f = ccgSubSurf_getEdgeFace(e, 0); - fhandle = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - totvert = ccgSubSurf_getFaceNumVerts(f); - - /* find the index of vertices in the face */ - for (i = 0; i < totvert; i++) { - v1 = ccgSubSurf_getFaceVert(f, i); - v2 = ccgSubSurf_getFaceVert(f, (i + 1) % totvert); - - if ((ev1 == v1 && ev2 == v2) || (ev1 == v2 && ev2 == v1)) { - S = i; - break; - } - } - } - - if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) { - if (isloose) { - for (i = 0; i < edgeSize; i++) { - varray[iloosehidden * 2] = iloosevert; - varray[iloosehidden * 2 + 1] = iloosevert + 1; - iloosehidden++; - iloosevert++; - } - /* we are through with this loose edge and moving to the next, so increase by one */ - iloosevert++; - } - else { - index_start = ccgdm->faceMap[fhandle].startFace; - - for (i = 0; i < grid_face_side; i++) { - varray[inormhidden * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1; - varray[inormhidden * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2; - varray[inormhidden * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2; - varray[inormhidden * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3; - inormhidden += 2; - } - } - } - else { - if (isloose) { - for (i = 0; i < edgeSize; i++) { - varray[iloose * 2] = iloosevert; - varray[iloose * 2 + 1] = iloosevert + 1; - iloose++; - iloosevert++; - } - /* we are through with this loose edge and moving to the next, so increase by one */ - iloosevert++; - } - else { - index_start = ccgdm->faceMap[fhandle].startFace; - - for (i = 0; i < grid_face_side; i++) { - varray[inorm * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1; - varray[inorm * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2; - varray[inorm * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2; - varray[inorm * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3; - inorm += 2; - } - } - } - } - - /* part two, handle interior edges */ - inorm = totedge * grid_face_side * 2; - - index_start = 0; - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - unsigned int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - - for (S = 0; S < numVerts; S++) { - for (x = 1; x < grid_face_side; x++) { - for (y = 0; y < grid_face_side; y++) { - unsigned int tmp = (index_start + x * grid_face_side + y) * 4; - varray[inorm * 2] = tmp; - varray[inorm * 2 + 1] = tmp + 1; - inorm++; - } - } - for (x = 0; x < grid_face_side; x++) { - for (y = 0; y < grid_face_side; y++) { - unsigned int tmp = (index_start + x * grid_face_side + y) * 4; - varray[inorm * 2] = tmp + 3; - varray[inorm * 2 + 1] = tmp; - inorm++; - } - } - - tot_interior += grid_face_side * (2 * grid_face_side - 1); - index_start += grid_tot_face; - } - } - - dm->drawObject->tot_loose_edge_drawn = tot_loose * edgeSize; - dm->drawObject->loose_edge_offset = (tot + tot_hidden) * edgeSize; - dm->drawObject->tot_edge_drawn = tot * edgeSize; - - dm->drawObject->interior_offset = totedge * edgeSize; - dm->drawObject->totinterior = tot_interior; -} - -static void ccgDM_copy_gpu_data( - DerivedMesh *dm, int type, void *varray_p, - const int *mat_orig_to_new, const void *user_data) -{ - /* 'varray_p' cast is redundant but include for self-documentation */ - switch (type) { - case GPU_BUFFER_VERTEX: - ccgDM_buffer_copy_vertex(dm, (float *)varray_p); - break; - case GPU_BUFFER_NORMAL: - ccgDM_buffer_copy_normal(dm, (short *)varray_p); - break; - case GPU_BUFFER_UV: - ccgDM_buffer_copy_uv(dm, (float *)varray_p); - break; - case GPU_BUFFER_UV_TEXPAINT: - ccgDM_buffer_copy_uv_texpaint(dm, (float *)varray_p); - break; - case GPU_BUFFER_COLOR: - ccgDM_buffer_copy_color(dm, (unsigned char *)varray_p, user_data); - break; - case GPU_BUFFER_UVEDGE: - ccgDM_buffer_copy_uvedge(dm, (float *)varray_p); - break; - case GPU_BUFFER_EDGE: - ccgDM_buffer_copy_edge(dm, (unsigned int *)varray_p); - break; - case GPU_BUFFER_TRIANGLES: - ccgDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new); - break; - default: - break; - } -} - -static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - GPUDrawObject *gdo; - DMFlagMat *faceFlags = ccgdm->faceFlags; - int gridFaces = ccgSubSurf_getGridSize(ss) - 1; - const short dm_totmat = (faceFlags) ? dm->totmat : 1; - GPUBufferMaterial *matinfo; - int i; - unsigned int tot_internal_edges = 0; - int edgeVerts = ccgSubSurf_getEdgeSize(ss); - int edgeSize = edgeVerts - 1; - - int totedge = ccgSubSurf_getNumEdges(ss); - int totface = ccgSubSurf_getNumFaces(ss); - - /* object contains at least one material (default included) so zero means uninitialized dm */ - BLI_assert(dm_totmat != 0); - - matinfo = MEM_callocN(sizeof(*matinfo) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new"); - - if (faceFlags) { - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - const short new_matnr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat); - matinfo[new_matnr].totelements += numVerts * gridFaces * gridFaces * 6; - matinfo[new_matnr].totloops += numVerts * gridFaces * gridFaces * 4; - matinfo[new_matnr].totpolys++; - tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1); - } - } - else { - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - matinfo[0].totelements += numVerts * gridFaces * gridFaces * 6; - matinfo[0].totloops += numVerts * gridFaces * gridFaces * 4; - matinfo[0].totpolys++; - tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1); - } - } - - /* create the GPUDrawObject */ - gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject"); - gdo->totvert = 0; /* used to count indices, doesn't really matter for ccgsubsurf */ - gdo->totedge = (totedge * edgeSize + tot_internal_edges); - - GPU_buffer_material_finalize(gdo, matinfo, dm_totmat); - - /* store total number of points used for triangles */ - gdo->tot_triangle_point = ccgSubSurf_getNumFinalFaces(ss) * 6; - gdo->tot_loop_verts = ccgSubSurf_getNumFinalFaces(ss) * 4; - - /* finally, count loose points */ - for (i = 0; i < totedge; i++) { - CCGEdge *e = ccgdm->edgeMap[i].edge; - - if (!ccgSubSurf_getEdgeNumFaces(e)) - gdo->tot_loose_point += edgeVerts; - } - - return gdo; -} - -/* Only used by non-editmesh types */ -static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial) -{ - int a; - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - - ccgdm_pbvh_update(ccgdm); - - if (ccgdm->pbvh && ccgdm->multires.mmd) { - if (BKE_pbvh_has_faces(ccgdm->pbvh)) { - BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, - setMaterial, false, fast); - } - - return; - } - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - CCGSubSurf *ss = ccgdm->ss; - const DMFlagMat *faceFlags = ccgdm->faceFlags; - const int level = ccgSubSurf_getSubdivisionLevels(ss); - const int face_side = 1 << level; - const int grid_side = 1 << (level - 1); - const int face_patches = face_side * face_side; - const int grid_patches = grid_side * grid_side; - const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); - int i, current_patch = 0; - int mat_nr = -1; - bool draw_smooth = false; - int start_draw_patch = -1, num_draw_patches = 0; - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) { - return; - } - if (setMaterial == NULL) { - ccgSubSurf_drawGLMesh(ss, - true, - -1, - -1); - return; - } - for (i = 0; i < num_base_faces; ++i) { - const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); - const int num_patches = (num_face_verts == 4) ? face_patches - : num_face_verts * grid_patches; - int new_matnr; - bool new_draw_smooth; - if (faceFlags) { - new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH); - new_matnr = (faceFlags[i].mat_nr + 1); - } - else { - new_draw_smooth = true; - new_matnr = 1; - } - if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) { - if (num_draw_patches != 0) { - bool do_draw = setMaterial(mat_nr, NULL); - if (do_draw) { - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - } - start_draw_patch = current_patch; - num_draw_patches = num_patches; - mat_nr = new_matnr; - draw_smooth = new_draw_smooth; - } - else { - num_draw_patches += num_patches; - } - current_patch += num_patches; - } - if (num_draw_patches != 0) { - bool do_draw = setMaterial(mat_nr, NULL); - if (do_draw) { - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - } - glShadeModel(GL_SMOOTH); - return; - } -#endif - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - for (a = 0; a < dm->drawObject->totmaterial; a++) { - if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) { - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start, - dm->drawObject->materials[a].totelements); - } - } - GPU_buffers_unbind(); -} - -typedef struct { - DMVertexAttribs attribs; - int numdata; - - GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/ -} GPUMaterialConv; - -/* Only used by non-editmesh types */ -static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, - DMSetMaterial setMaterial, - DMSetDrawOptions setDrawOptions, - void *userData) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - GPUVertexAttribs gattribs; - int a, b; - const DMFlagMat *faceFlags = ccgdm->faceFlags; - unsigned char *varray; - size_t max_element_size = 0; - int tot_loops = 0; - int totpoly = ccgSubSurf_getNumFaces(ss); - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - int edgeSize = ccgSubSurf_getEdgeSize(ss); - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - const int level = ccgSubSurf_getSubdivisionLevels(ss); - const int face_side = 1 << level; - const int grid_side = 1 << (level - 1); - const int face_patches = face_side * face_side; - const int grid_patches = grid_side * grid_side; - const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); - int i, current_patch = 0; - int mat_nr = -1; - bool draw_smooth = false; - int start_draw_patch = -1, num_draw_patches = 0; - GPU_draw_update_fvar_offset(dm); - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) { - return; - } - for (i = 0; i < num_base_faces; ++i) { - const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); - const int num_patches = (num_face_verts == 4) ? face_patches - : num_face_verts * grid_patches; - int new_matnr; - bool new_draw_smooth; - - if (faceFlags) { - new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH); - new_matnr = (faceFlags[i].mat_nr + 1); - } - else { - new_draw_smooth = true; - new_matnr = 1; - } - if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) { - if (num_draw_patches != 0) { - bool do_draw = setMaterial(mat_nr, &gattribs); - if (do_draw) { - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - } - start_draw_patch = current_patch; - num_draw_patches = num_patches; - mat_nr = new_matnr; - draw_smooth = new_draw_smooth; - } - else { - num_draw_patches += num_patches; - } - current_patch += num_patches; - } - if (num_draw_patches != 0) { - bool do_draw = setMaterial(mat_nr, &gattribs); - if (do_draw) { - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - } - glShadeModel(GL_SMOOTH); - return; - } -#endif - - CCG_key_top_level(&key, ss); - ccgdm_pbvh_update(ccgdm); - - if (setDrawOptions != NULL) { - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - DMVertexAttribs attribs = {{{NULL}}}; - int i; - int matnr = -1; - int do_draw = 0; - -#define PASSATTRIB(dx, dy, vert) { \ - if (attribs.totorco) \ - index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \ - else \ - index = 0; \ - DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \ - DM_draw_attrib_vertex_uniforms(&attribs); \ -} (void)0 - - totpoly = ccgSubSurf_getNumFaces(ss); - for (a = 0, i = 0; i < totpoly; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - const float (*ln)[3] = NULL; - int S, x, y, drawSmooth; - int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - int origIndex = ccgDM_getFaceMapIndex(ss, f); - - int numVerts = ccgSubSurf_getFaceNumVerts(f); - int new_matnr; - - if (faceFlags) { - drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH)); - new_matnr = faceFlags[index].mat_nr + 1; - } - else { - drawSmooth = 1; - new_matnr = 1; - } - - if (lnors) { - ln = lnors; - lnors += (gridFaces * gridFaces * numVerts) * 4; - } - - if (new_matnr != matnr) { - do_draw = setMaterial(matnr = new_matnr, &gattribs); - if (do_draw) - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - } - - if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) && - (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP))) - { - a += gridFaces * gridFaces * numVerts; - continue; - } - - glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT); - for (S = 0; S < numVerts; S++) { - CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); - CCGElem *vda, *vdb; - - if (ln) { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); - float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); - float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - PASSATTRIB(0, 1, 1); - glNormal3fv(ln[1]); - glVertex3fv(dco); - PASSATTRIB(1, 1, 2); - glNormal3fv(ln[2]); - glVertex3fv(cco); - PASSATTRIB(1, 0, 3); - glNormal3fv(ln[3]); - glVertex3fv(bco); - PASSATTRIB(0, 0, 0); - glNormal3fv(ln[0]); - glVertex3fv(aco); - - ln += 4; - a++; - } - } - glEnd(); - } - else if (drawSmooth) { - for (y = 0; y < gridFaces; y++) { - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridFaces; x++) { - vda = CCG_grid_elem(&key, faceGridData, x, y + 0); - vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); - - PASSATTRIB(0, 0, 0); - glNormal3fv(CCG_elem_no(&key, vda)); - glVertex3fv(CCG_elem_co(&key, vda)); - - PASSATTRIB(0, 1, 1); - glNormal3fv(CCG_elem_no(&key, vdb)); - glVertex3fv(CCG_elem_co(&key, vdb)); - - if (x != gridFaces - 1) - a++; - } - - vda = CCG_grid_elem(&key, faceGridData, x, y + 0); - vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); - - PASSATTRIB(0, 0, 3); - glNormal3fv(CCG_elem_no(&key, vda)); - glVertex3fv(CCG_elem_co(&key, vda)); - - PASSATTRIB(0, 1, 2); - glNormal3fv(CCG_elem_no(&key, vdb)); - glVertex3fv(CCG_elem_co(&key, vdb)); - - glEnd(); - - a++; - } - } - else { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *aco = CCG_grid_elem_co(&key, faceGridData, x, y); - float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y); - float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - ccgDM_glNormalFast(aco, bco, cco, dco); - - PASSATTRIB(0, 1, 1); - glVertex3fv(dco); - PASSATTRIB(1, 1, 2); - glVertex3fv(cco); - PASSATTRIB(1, 0, 3); - glVertex3fv(bco); - PASSATTRIB(0, 0, 0); - glVertex3fv(aco); - - a++; - } - } - glEnd(); - } - } - } - - glShadeModel(GL_SMOOTH); -#undef PASSATTRIB - } - else { - GPUMaterialConv *matconv; - size_t offset; - int *mat_orig_to_new; - int tot_active_mat; - GPUBuffer *buffer = NULL; - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - - tot_active_mat = dm->drawObject->totmaterial; - - matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat, - "cdDM_drawMappedFacesGLSL.matconv"); - mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, - "cdDM_drawMappedFacesGLSL.mat_orig_to_new"); - - /* part one, check what attributes are needed per material */ - for (a = 0; a < tot_active_mat; a++) { - int new_matnr; - int do_draw; - - new_matnr = dm->drawObject->materials[a].mat_nr; - - /* map from original material index to new - * GPUBufferMaterial index */ - mat_orig_to_new[new_matnr] = a; - do_draw = setMaterial(new_matnr + 1, &gattribs); - - if (do_draw) { - int numdata = 0; - DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs); - - if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index; - matconv[a].datatypes[numdata].size = 3; - matconv[a].datatypes[numdata].type = GL_FLOAT; - numdata++; - } - for (b = 0; b < matconv[a].attribs.tottface; b++) { - if (matconv[a].attribs.tface[b].array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index; - matconv[a].datatypes[numdata].size = 2; - matconv[a].datatypes[numdata].type = GL_FLOAT; - numdata++; - } - } - for (b = 0; b < matconv[a].attribs.totmcol; b++) { - if (matconv[a].attribs.mcol[b].array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index; - matconv[a].datatypes[numdata].size = 4; - matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE; - numdata++; - } - } - for (b = 0; b < matconv[a].attribs.tottang; b++) { - if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) { - matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index; - matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index; - matconv[a].datatypes[numdata].size = 4; - matconv[a].datatypes[numdata].type = GL_FLOAT; - numdata++; - } - } - if (numdata != 0) { - matconv[a].numdata = numdata; - max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size); - } - } - } - - /* part two, generate and fill the arrays with the data */ - if (max_element_size > 0) { - buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts); - - varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY); - if (varray == NULL) { - GPU_buffers_unbind(); - GPU_buffer_free(buffer); - MEM_freeN(mat_orig_to_new); - MEM_freeN(matconv); - fprintf(stderr, "Out of memory, can't draw object\n"); - return; - } - - for (a = 0; a < totpoly; a++) { - CCGFace *f = ccgdm->faceMap[a].face; - int orig_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - int i; - - if (faceFlags) { - i = mat_orig_to_new[faceFlags[orig_index].mat_nr]; - } - else { - i = mat_orig_to_new[0]; - } - - if (matconv[i].numdata != 0) { - for (S = 0; S < numVerts; S++) { - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - - offset = tot_loops * max_element_size; - - if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) { - int index; - - index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize); - copy_v3_v3((float *)&varray[offset], - (float *)matconv[i].attribs.orco.array[index]); - index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize); - copy_v3_v3((float *)&varray[offset + max_element_size], - (float *)matconv[i].attribs.orco.array[index]); - index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize); - copy_v3_v3((float *)&varray[offset + 2 * max_element_size], - (float *)matconv[i].attribs.orco.array[index]); - index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize); - copy_v3_v3((float *)&varray[offset + 3 * max_element_size], - (float *)matconv[i].attribs.orco.array[index]); - - offset += sizeof(float) * 3; - } - for (b = 0; b < matconv[i].attribs.tottface; b++) { - if (matconv[i].attribs.tface[b].array) { - const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops; - - copy_v2_v2((float *)&varray[offset], mloopuv[0].uv); - copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv); - copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv); - copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv); - - offset += sizeof(float) * 2; - } - } - for (b = 0; b < matconv[i].attribs.totmcol; b++) { - if (matconv[i].attribs.mcol[b].array) { - const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops; - - copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r); - copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r); - copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r); - copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r); - - offset += sizeof(unsigned char) * 4; - } - } - for (b = 0; b < matconv[i].attribs.tottang; b++) { - if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) { - const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops; - - copy_v4_v4((float *)&varray[offset], looptang[0]); - copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]); - copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]); - copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]); - - offset += sizeof(float) * 4; - } - } - - tot_loops += 4; - } - } - } - } - else { - tot_loops += 4 * numVerts * gridFaces * gridFaces; - } - } - GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY); - } - - for (a = 0; a < tot_active_mat; a++) { - int new_matnr; - int do_draw; - - new_matnr = dm->drawObject->materials[a].mat_nr; - - do_draw = setMaterial(new_matnr + 1, &gattribs); - - if (do_draw) { - if (matconv[a].numdata) { - GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size); - } - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, - dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements); - if (matconv[a].numdata) { - GPU_interleaved_attrib_unbind(); - } - } - } - - GPU_buffers_unbind(); - if (buffer) - GPU_buffer_free(buffer); - - MEM_freeN(mat_orig_to_new); - MEM_freeN(matconv); - } -} - -static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial) -{ - dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL); -} - -/* Only used by non-editmesh types */ -static void ccgDM_drawMappedFacesMat(DerivedMesh *dm, - void (*setMaterial)(void *userData, int matnr, void *attribs), - bool (*setFace)(void *userData, int index), void *userData) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - GPUVertexAttribs gattribs; - DMVertexAttribs attribs = {{{NULL}}}; - int gridSize = ccgSubSurf_getGridSize(ss); - int gridFaces = gridSize - 1; - int edgeSize = ccgSubSurf_getEdgeSize(ss); - DMFlagMat *faceFlags = ccgdm->faceFlags; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - int a, i, numVerts, matnr, totface; - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - const int level = ccgSubSurf_getSubdivisionLevels(ss); - const int face_side = 1 << level; - const int grid_side = 1 << (level - 1); - const int face_patches = face_side * face_side; - const int grid_patches = grid_side * grid_side; - const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); - int current_patch = 0; - int mat_nr = -1; - bool draw_smooth = false; - int start_draw_patch = -1, num_draw_patches = 0; - GPU_draw_update_fvar_offset(dm); - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) { - return; - } - for (i = 0; i < num_base_faces; ++i) { - const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); - const int num_patches = (num_face_verts == 4) ? face_patches - : num_face_verts * grid_patches; - int new_matnr; - bool new_draw_smooth; - - if (faceFlags) { - new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH); - new_matnr = (faceFlags[i].mat_nr + 1); - } - else { - new_draw_smooth = true; - new_matnr = 1; - } - if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) { - if (num_draw_patches != 0) { - setMaterial(userData, mat_nr, &gattribs); - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - start_draw_patch = current_patch; - num_draw_patches = num_patches; - mat_nr = new_matnr; - draw_smooth = new_draw_smooth; - } - else { - num_draw_patches += num_patches; - } - current_patch += num_patches; - } - if (num_draw_patches != 0) { - setMaterial(userData, mat_nr, &gattribs); - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - glShadeModel(GL_SMOOTH); - return; - } -#endif - - CCG_key_top_level(&key, ss); - ccgdm_pbvh_update(ccgdm); - - matnr = -1; - -#define PASSATTRIB(dx, dy, vert) { \ - if (attribs.totorco) \ - index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \ - else \ - index = 0; \ - DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \ - DM_draw_attrib_vertex_uniforms(&attribs); \ -} (void)0 - - totface = ccgSubSurf_getNumFaces(ss); - for (a = 0, i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - const float (*ln)[3] = NULL; - int S, x, y, drawSmooth; - int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - int origIndex = ccgDM_getFaceMapIndex(ss, f); - int new_matnr; - - numVerts = ccgSubSurf_getFaceNumVerts(f); - - /* get flags */ - if (faceFlags) { - drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH)); - new_matnr = faceFlags[index].mat_nr + 1; - } - else { - drawSmooth = 1; - new_matnr = 1; - } - - if (lnors) { - ln = lnors; - lnors += (gridFaces * gridFaces * numVerts) * 4; - } - - /* material */ - if (new_matnr != matnr) { - setMaterial(userData, matnr = new_matnr, &gattribs); - DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); - } - - /* face hiding */ - if ((setFace && (origIndex != ORIGINDEX_NONE) && !setFace(userData, origIndex))) { - a += gridFaces * gridFaces * numVerts; - continue; - } - - /* draw face*/ - glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT); - for (S = 0; S < numVerts; S++) { - CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); - CCGElem *vda, *vdb; - - if (ln) { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0); - float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); - float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - PASSATTRIB(0, 1, 1); - glNormal3fv(ln[1]); - glVertex3fv(dco); - PASSATTRIB(1, 1, 2); - glNormal3fv(ln[2]); - glVertex3fv(cco); - PASSATTRIB(1, 0, 3); - glNormal3fv(ln[3]); - glVertex3fv(bco); - PASSATTRIB(0, 0, 0); - glNormal3fv(ln[0]); - glVertex3fv(aco); - - ln += 4; - a++; - } - } - glEnd(); - } - else if (drawSmooth) { - for (y = 0; y < gridFaces; y++) { - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridFaces; x++) { - vda = CCG_grid_elem(&key, faceGridData, x, y); - vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); - - PASSATTRIB(0, 0, 0); - glNormal3fv(CCG_elem_no(&key, vda)); - glVertex3fv(CCG_elem_co(&key, vda)); - - PASSATTRIB(0, 1, 1); - glNormal3fv(CCG_elem_no(&key, vdb)); - glVertex3fv(CCG_elem_co(&key, vdb)); - - if (x != gridFaces - 1) - a++; - } - - vda = CCG_grid_elem(&key, faceGridData, x, y + 0); - vdb = CCG_grid_elem(&key, faceGridData, x, y + 1); - - PASSATTRIB(0, 0, 3); - glNormal3fv(CCG_elem_no(&key, vda)); - glVertex3fv(CCG_elem_co(&key, vda)); - - PASSATTRIB(0, 1, 2); - glNormal3fv(CCG_elem_no(&key, vdb)); - glVertex3fv(CCG_elem_co(&key, vdb)); - - glEnd(); - - a++; - } - } - else { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0); - float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); - float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - ccgDM_glNormalFast(aco, bco, cco, dco); - - PASSATTRIB(0, 1, 1); - glVertex3fv(dco); - PASSATTRIB(1, 1, 2); - glVertex3fv(cco); - PASSATTRIB(1, 0, 3); - glVertex3fv(bco); - PASSATTRIB(0, 0, 0); - glVertex3fv(aco); - - a++; - } - } - glEnd(); - } - } - } - - glShadeModel(GL_SMOOTH); -#undef PASSATTRIB -} - -static void ccgDM_drawFacesTex_common(DerivedMesh *dm, - DMSetDrawOptionsTex drawParams, - DMSetDrawOptionsMappedTex drawParamsMapped, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - int colType; - const MLoopCol *mloopcol = NULL; - MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); - DMFlagMat *faceFlags = ccgdm->faceFlags; - DMDrawOption draw_option; - int i, totpoly; - bool flush; - const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0; - const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0; - unsigned int next_actualFace; - unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1; - int mat_index; - int tot_element, start_element, tot_drawn; - - if (use_colors) { - colType = CD_TEXTURE_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - if (!mloopcol) { - colType = CD_PREVIEW_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - if (!mloopcol) { - colType = CD_MLOOPCOL; - mloopcol = dm->getLoopDataArray(dm, colType); - } - } - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV); - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) { - return; - } - if (drawParams == NULL) { - ccgSubSurf_drawGLMesh(ss, true, -1, -1); - return; - } - const int level = ccgSubSurf_getSubdivisionLevels(ss); - const int face_side = 1 << level; - const int grid_side = 1 << (level - 1); - const int face_patches = face_side * face_side; - const int grid_patches = grid_side * grid_side; - const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss); - int current_patch = 0; - int mat_nr = -1; - int start_draw_patch = 0, num_draw_patches = 0; - bool draw_smooth = false; - for (i = 0; i < num_base_faces; ++i) { - const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i); - const int num_patches = (num_face_verts == 4) ? face_patches - : num_face_verts * grid_patches; - if (faceFlags) { - mat_nr = faceFlags[i].mat_nr; - draw_smooth = (faceFlags[i].flag & ME_SMOOTH); - } - else { - mat_nr = 0; - draw_smooth = false; - } - - if (drawParams != NULL) { - MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL; - draw_option = drawParams(tp, (mloopcol != NULL), mat_nr); - } - else { - draw_option = (drawParamsMapped) - ? drawParamsMapped(userData, i, mat_nr) - : DM_DRAW_OPTION_NORMAL; - } - - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1); - - const int next_face = min_ii(i + 1, num_base_faces - 1); - if (!flush && compareDrawOptions) { - flush |= compareDrawOptions(userData, i, next_face) == 0; - } - if (!flush && faceFlags) { - bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH); - flush |= (new_draw_smooth != draw_smooth); - } - - current_patch += num_patches; - - if (flush) { - if (draw_option != DM_DRAW_OPTION_SKIP) { - num_draw_patches += num_patches; - } - if (num_draw_patches != 0) { - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, - true, - start_draw_patch, - num_draw_patches); - } - start_draw_patch = current_patch; - num_draw_patches = 0; - } - else { - num_draw_patches += num_patches; - } - } - glShadeModel(GL_SMOOTH); - return; - } -#endif - - CCG_key_top_level(&key, ss); - ccgdm_pbvh_update(ccgdm); - - GPU_vertex_setup(dm); - GPU_normal_setup(dm); - GPU_triangle_setup(dm); - if (flag & DM_DRAW_USE_TEXPAINT_UV) - GPU_texpaint_uv_setup(dm); - else - GPU_uv_setup(dm); - if (mloopcol) { - GPU_color_setup(dm, colType); - } - - next_actualFace = 0; - - /* lastFlag = 0; */ /* UNUSED */ - for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) { - GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index; - next_actualFace = bufmat->polys[0]; - totpoly = bufmat->totpolys; - - tot_element = 0; - tot_drawn = 0; - start_element = 0; - - for (i = 0; i < totpoly; i++) { - int polyindex = bufmat->polys[i]; - CCGFace *f = ccgdm->faceMap[polyindex].face; - int numVerts = ccgSubSurf_getFaceNumVerts(f); - int index = ccgDM_getFaceMapIndex(ss, f); - int orig_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - int mat_nr; - int facequads = numVerts * gridFaces * gridFaces; - int actualFace = ccgdm->faceMap[polyindex].startFace; - - if (i != totpoly - 1) { - polyindex = bufmat->polys[i + 1]; - next_actualFace = ccgdm->faceMap[polyindex].startFace; - } - - if (faceFlags) { - mat_nr = faceFlags[orig_index].mat_nr; - } - else { - mat_nr = 0; - } - - if (drawParams) { - MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL; - draw_option = drawParams(tp, (mloopcol != NULL), mat_nr); - } - else if (index != ORIGINDEX_NONE) - draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL; - else - draw_option = DM_DRAW_OPTION_NORMAL; - - /* flush buffer if current triangle isn't drawable or it's last triangle */ - flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1); - - if (!flush && compareDrawOptions) { - /* also compare draw options and flush buffer if they're different - * need for face selection highlight in edit mode */ - flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; - } - - tot_element += facequads * 6; - - if (flush) { - if (draw_option != DM_DRAW_OPTION_SKIP) - tot_drawn += facequads * 6; - - if (tot_drawn) { - if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL) - GPU_color_switch(1); - else - GPU_color_switch(0); - - GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn); - tot_drawn = 0; - } - - start_element = tot_element; - } - else { - tot_drawn += facequads * 6; - } - } - } - - - GPU_buffers_unbind(); -} - -static void ccgDM_drawFacesTex(DerivedMesh *dm, - DMSetDrawOptionsTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag); -} - -static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, - DMSetDrawOptionsMappedTex setDrawOptions, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); -} - -/* same as cdDM_drawUVEdges */ -static void ccgDM_drawUVEdges(DerivedMesh *dm) -{ - MPoly *mpoly = dm->getPolyArray(dm); - int totpoly = dm->getNumPolys(dm); - int prevstart = 0; - bool prevdraw = true; - int curpos = 0; - int i; - - GPU_uvedge_setup(dm); - for (i = 0; i < totpoly; i++, mpoly++) { - const bool draw = (mpoly->flag & ME_HIDE) == 0; - - if (prevdraw != draw) { - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - prevstart = curpos; - } - - curpos += 2 * mpoly->totloop; - prevdraw = draw; - } - if (prevdraw && (curpos != prevstart)) { - glDrawArrays(GL_LINES, prevstart, curpos - prevstart); - } - GPU_buffers_unbind(); -} - -static void ccgDM_drawMappedFaces(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - DMSetMaterial setMaterial, - DMCompareDrawOptions compareDrawOptions, - void *userData, DMDrawFlag flag) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - MLoopCol *mloopcol = NULL; - const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); - int i, gridSize = ccgSubSurf_getGridSize(ss); - DMFlagMat *faceFlags = ccgdm->faceFlags; - int useColors = flag & DM_DRAW_USE_COLORS; - int gridFaces = gridSize - 1, totface; - int prev_mat_nr = -1; - - if (ccgdm->pbvh) { - if (G.debug_value == 14) - BKE_pbvh_draw_BB(ccgdm->pbvh); - } - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - int new_matnr; - bool draw_smooth, do_draw = true; - if (setDrawOptions == NULL) { - /* TODO(sergey): This is for cases when vertex colors or weights - * are visualising. Currently we don't have CD layers for this data - * and here we only make it so there's no garbage displayed. - * - * In the future we'll either need to have CD for this data or pass - * this data as face-varying or vertex-varying data in OSD mesh. - */ - glColor3f(0.8f, 0.8f, 0.8f); - } - if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) { - return; - } - if (faceFlags) { - draw_smooth = (faceFlags[0].flag & ME_SMOOTH); - new_matnr = (faceFlags[0].mat_nr + 1); - } - else { - draw_smooth = true; - new_matnr = 1; - } - if (setMaterial) { - setMaterial(new_matnr, NULL); - } - if (setDrawOptions) { - if (setDrawOptions(userData, 0) == DM_DRAW_OPTION_SKIP) { - do_draw = false; - } - } - if (do_draw) { - glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT); - ccgSubSurf_drawGLMesh(ss, true, -1, -1); - glShadeModel(GL_SMOOTH); - } - return; - } -#endif - - CCG_key_top_level(&key, ss); - - /* currently unused -- each original face is handled separately */ - (void)compareDrawOptions; - - if (useColors) { - mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL); - if (!mloopcol) - mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL); - } - - totface = ccgSubSurf_getNumFaces(ss); - for (i = 0; i < totface; i++) { - CCGFace *f = ccgdm->faceMap[i].face; - int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); - int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f); - int origIndex; - unsigned char *cp = NULL; - const float (*ln)[3] = NULL; - - origIndex = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f)); - - if (flag & DM_DRAW_ALWAYS_SMOOTH) drawSmooth = 1; - else if (faceFlags) drawSmooth = (lnors || (faceFlags[origIndex].flag & ME_SMOOTH)); - else drawSmooth = 1; - - if (mloopcol) { - cp = (unsigned char *)mloopcol; - mloopcol += gridFaces * gridFaces * numVerts * 4; - } - - if (lnors) { - ln = lnors; - lnors += (gridFaces * gridFaces * numVerts) * 4; - } - - { - DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL; - - if (setMaterial) { - int mat_nr = faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1; - - if (mat_nr != prev_mat_nr) { - setMaterial(mat_nr, NULL); /* XXX, no faceFlags no material */ - prev_mat_nr = mat_nr; - } - } - - if (setDrawOptions && (index != ORIGINDEX_NONE)) - draw_option = setDrawOptions(userData, index); - - if (draw_option != DM_DRAW_OPTION_SKIP) { - if (draw_option == DM_DRAW_OPTION_STIPPLE) { - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE); - } - - for (S = 0; S < numVerts; S++) { - CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S); - if (ln) { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0); - float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); - float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - if (cp) glColor4ubv(&cp[4]); - glNormal3fv(ln[1]); - glVertex3fv(d); - if (cp) glColor4ubv(&cp[8]); - glNormal3fv(ln[2]); - glVertex3fv(c); - if (cp) glColor4ubv(&cp[12]); - glNormal3fv(ln[3]); - glVertex3fv(b); - if (cp) glColor4ubv(&cp[0]); - glNormal3fv(ln[0]); - glVertex3fv(a); - - if (cp) cp += 16; - ln += 4; - } - } - glEnd(); - } - else if (drawSmooth) { - for (y = 0; y < gridFaces; y++) { - CCGElem *a, *b; - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridFaces; x++) { - a = CCG_grid_elem(&key, faceGridData, x, y + 0); - b = CCG_grid_elem(&key, faceGridData, x, y + 1); - - if (cp) glColor4ubv(&cp[0]); - glNormal3fv(CCG_elem_no(&key, a)); - glVertex3fv(CCG_elem_co(&key, a)); - if (cp) glColor4ubv(&cp[4]); - glNormal3fv(CCG_elem_no(&key, b)); - glVertex3fv(CCG_elem_co(&key, b)); - - if (x != gridFaces - 1) { - if (cp) cp += 16; - } - } - - a = CCG_grid_elem(&key, faceGridData, x, y + 0); - b = CCG_grid_elem(&key, faceGridData, x, y + 1); - - if (cp) glColor4ubv(&cp[12]); - glNormal3fv(CCG_elem_no(&key, a)); - glVertex3fv(CCG_elem_co(&key, a)); - if (cp) glColor4ubv(&cp[8]); - glNormal3fv(CCG_elem_no(&key, b)); - glVertex3fv(CCG_elem_co(&key, b)); - - if (cp) cp += 16; - - glEnd(); - } - } - else { - glBegin(GL_QUADS); - for (y = 0; y < gridFaces; y++) { - for (x = 0; x < gridFaces; x++) { - float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0); - float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0); - float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1); - float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1); - - ccgDM_glNormalFast(a, b, c, d); - - if (cp) glColor4ubv(&cp[4]); - glVertex3fv(d); - if (cp) glColor4ubv(&cp[8]); - glVertex3fv(c); - if (cp) glColor4ubv(&cp[12]); - glVertex3fv(b); - if (cp) glColor4ubv(&cp[0]); - glVertex3fv(a); - - if (cp) cp += 16; - } - } - glEnd(); - } - } - if (draw_option == DM_DRAW_OPTION_STIPPLE) - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - } - } -} - -static void ccgDM_drawMappedEdges(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - void *userData) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGEdgeIterator ei; - CCGKey key; - int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - /* TODO(sergey): Only draw edges from base mesh. */ - if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) { - if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) { - ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1); - } - } - return; - } -#endif - - CCG_key_top_level(&key, ss); - ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); - - for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); - CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); - int index = ccgDM_getEdgeMapIndex(ss, e); - - glBegin(GL_LINE_STRIP); - if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) { - if (useAging && !(G.f & G_BACKBUFSEL)) { - int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4; - glColor3ub(0, ageCol > 0 ? ageCol : 0, 0); - } - - for (i = 0; i < edgeSize - 1; i++) { - glVertex3fv(CCG_elem_offset_co(&key, edgeData, i)); - glVertex3fv(CCG_elem_offset_co(&key, edgeData, i + 1)); - } - } - glEnd(); - } -} - -static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, - DMSetDrawOptions setDrawOptions, - DMSetDrawInterpOptions setDrawInterpOptions, - void *userData) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGKey key; - CCGEdgeIterator ei; - int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss); - -#ifdef WITH_OPENSUBDIV - if (ccgdm->useGpuBackend) { - BLI_assert(!"Not currently supported"); - return; - } -#endif - - CCG_key_top_level(&key, ss); - ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL); - - for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) { - CCGEdge *e = ccgEdgeIterator_getCurrent(&ei); - CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e); - int index = ccgDM_getEdgeMapIndex(ss, e); - - glBegin(GL_LINE_STRIP); - if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) { - for (i = 0; i < edgeSize; i++) { - setDrawInterpOptions(userData, index, (float) i / (edgeSize - 1)); - - if (useAging && !(G.f & G_BACKBUFSEL)) { - int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4; - glColor3ub(0, ageCol > 0 ? ageCol : 0, 0); - } - - glVertex3fv(CCG_elem_offset_co(&key, edgeData, i)); - } - } - glEnd(); - } -} - static void ccgDM_foreachMappedFaceCenter( DerivedMesh *dm, void (*func)(void *userData, int index, const float co[3], const float no[3]), @@ -4036,7 +1781,7 @@ static void ccgDM_release(DerivedMesh *dm) if (ccgdm->multires.mmd) { if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED) - multires_modifier_update_mdisps(dm); + multires_modifier_update_mdisps(dm, NULL); if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED) multires_modifier_update_hidden(dm); } @@ -4534,7 +2279,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } else if (ob->type == OB_MESH) { - Mesh *me = ob->data; + Mesh *me = BKE_object_get_original_mesh(ob); const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri; @@ -4558,7 +2303,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) totvert = deformdm->getNumVerts(deformdm); vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos"); deformdm->getVertCos(deformdm, vertCos); - BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert); MEM_freeN(vertCos); } } @@ -4671,23 +2416,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm) ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop; ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter; - ccgdm->dm.drawVerts = ccgDM_drawVerts; - ccgdm->dm.drawEdges = ccgDM_drawEdges; - ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges; - ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid; - ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex; - ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL; - ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces; - ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex; - ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL; - ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat; - ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges; - - ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp; - ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges; - ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew; - ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data; - ccgdm->dm.release = ccgDM_release; } @@ -4790,14 +2518,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0); -#if 0 - /* this is not in trunk, can gives problems because colors initialize - * as black, just don't do it!, it works fine - campbell */ - if (!CustomData_has_layer(&ccgdm->dm.faceData, CD_MCOL)) - DM_add_tessface_layer(&ccgdm->dm, CD_MCOL, CD_CALLOC, NULL); - mcol = DM_get_tessface_data_layer(&ccgdm->dm, CD_MCOL); -#endif - loopindex = loopindex2 = 0; /* current loop index */ for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; @@ -5139,8 +2859,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags) */ return (flags & SUBSURF_USE_GPU_BACKEND) != 0 && - (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) && - (openSubdiv_supportGPUDisplay()); + (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE); #else (void)flags; return false; @@ -5150,12 +2869,13 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags) struct DerivedMesh *subsurf_make_derived_from_derived( struct DerivedMesh *dm, struct SubsurfModifierData *smd, + struct Scene *scene, float (*vertCos)[3], SubsurfFlags flags) { int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0; CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0; - int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv; + int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE); int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); CCGDerivedMesh *result; bool use_gpu_backend = subsurf_use_gpu_backend(flags); @@ -5163,7 +2883,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( /* note: editmode calculation can only run once per * modifier stack evaluation (uses freed cache) [#36299] */ if (flags & SUBSURF_FOR_EDIT_MODE) { - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; + int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels; /* TODO(sergey): Same as emCache below. */ if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) { @@ -5184,7 +2904,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( else if (flags & SUBSURF_USE_RENDER_PARAMS) { /* Do not use cache in render mode. */ CCGSubSurf *ss; - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels; + int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->renderLevels, true) : smd->renderLevels; if (levels == 0) return dm; @@ -5200,7 +2920,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( } else { int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental); - int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels; + int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels; CCGSubSurf *ss; /* It is quite possible there is a much better place to do this. It diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 63b9f838632..3b9edaa4c18 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -47,8 +47,6 @@ #include "BLI_fileops.h" #include "DNA_constraint_types.h" -#include "DNA_controller_types.h" -#include "DNA_actuator_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -58,7 +56,6 @@ #include "DNA_node_types.h" #include "DNA_material_types.h" -#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 1637c0c8054..356a36f5244 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -44,9 +44,7 @@ #include "DNA_key_types.h" #include "DNA_object_types.h" -#include "DNA_lamp_types.h" #include "DNA_material_types.h" -#include "DNA_world_types.h" #include "DNA_brush_types.h" #include "DNA_node_types.h" #include "DNA_color_types.h" @@ -213,22 +211,6 @@ void BKE_texture_free(Tex *tex) } MEM_SAFE_FREE(tex->coba); - if (tex->env) { - BKE_texture_envmap_free(tex->env); - tex->env = NULL; - } - if (tex->pd) { - BKE_texture_pointdensity_free(tex->pd); - tex->pd = NULL; - } - if (tex->vd) { - BKE_texture_voxeldata_free(tex->vd); - tex->vd = NULL; - } - if (tex->ot) { - BKE_texture_ocean_free(tex->ot); - tex->ot = NULL; - } BKE_icon_id_delete((ID *)tex); BKE_previewimg_free(&tex->preview); @@ -251,7 +233,6 @@ void BKE_texture_default(Tex *tex) tex->texfilter = TXF_EWA; tex->afmax = 8; tex->xrepeat = tex->yrepeat = 1; - tex->fie_ima = 2; tex->sfra = 1; tex->frames = 0; tex->offset = 0; @@ -285,31 +266,6 @@ void BKE_texture_default(Tex *tex) tex->vn_distm = 0; tex->vn_coltype = 0; - if (tex->env) { - tex->env->stype = ENV_ANIM; - tex->env->clipsta = 0.1; - tex->env->clipend = 100; - tex->env->cuberes = 512; - tex->env->depth = 0; - } - - if (tex->pd) { - tex->pd->radius = 0.3f; - tex->pd->falloff_type = TEX_PD_FALLOFF_STD; - } - - if (tex->vd) { - tex->vd->resol[0] = tex->vd->resol[1] = tex->vd->resol[2] = 0; - tex->vd->interp_type = TEX_VD_LINEAR; - tex->vd->file_format = TEX_VD_SMOKE; - } - - if (tex->ot) { - tex->ot->output = TEX_OCN_DISPLACEMENT; - tex->ot->object = NULL; - } - - tex->iuser.fie_ima = 2; tex->iuser.ok = 1; tex->iuser.frames = 100; tex->iuser.sfra = 1; @@ -319,26 +275,6 @@ void BKE_texture_default(Tex *tex) void BKE_texture_type_set(Tex *tex, int type) { - switch (type) { - - case TEX_VOXELDATA: - if (tex->vd == NULL) - tex->vd = BKE_texture_voxeldata_add(); - break; - case TEX_POINTDENSITY: - if (tex->pd == NULL) - tex->pd = BKE_texture_pointdensity_add(); - break; - case TEX_ENVMAP: - if (tex->env == NULL) - tex->env = BKE_texture_envmap_add(); - break; - case TEX_OCEAN: - if (tex->ot == NULL) - tex->ot = BKE_texture_ocean_add(); - break; - } - tex->type = type; } @@ -476,10 +412,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot) MEM_freeN(mtex_ar[slot]); mtex_ar[slot] = NULL; } - else if (GS(id->name) == ID_MA) { - /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */ - ((Material *)id)->septex &= ~(1 << slot); - } mtex_ar[slot] = BKE_texture_mtex_add(); @@ -498,9 +430,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot) */ void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag) { - /* We never handle usercount here for own data. */ - const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - if (!BKE_texture_is_image_user(tex_src)) { tex_dst->ima = NULL; } @@ -508,19 +437,6 @@ void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const if (tex_dst->coba) { tex_dst->coba = MEM_dupallocN(tex_dst->coba); } - if (tex_dst->env) { - tex_dst->env = BKE_texture_envmap_copy(tex_dst->env, flag_subdata); - } - if (tex_dst->pd) { - tex_dst->pd = BKE_texture_pointdensity_copy(tex_dst->pd, flag_subdata); - } - if (tex_dst->vd) { - tex_dst->vd = MEM_dupallocN(tex_dst->vd); - } - if (tex_dst->ot) { - tex_dst->ot = BKE_texture_ocean_copy(tex_dst->ot, flag_subdata); - } - if (tex_src->nodetree) { if (tex_src->nodetree->execdata) { ntreeTexEndExecTree(tex_src->nodetree->execdata); @@ -562,19 +478,6 @@ Tex *BKE_texture_localize(Tex *tex) /* image texture: BKE_texture_free also doesn't decrease */ if (texn->coba) texn->coba = MEM_dupallocN(texn->coba); - if (texn->env) { - texn->env = BKE_texture_envmap_copy(texn->env, LIB_ID_CREATE_NO_USER_REFCOUNT); - id_us_min(&texn->env->ima->id); - } - if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd, LIB_ID_CREATE_NO_USER_REFCOUNT); - if (texn->vd) { - texn->vd = MEM_dupallocN(texn->vd); - if (texn->vd->dataset) - texn->vd->dataset = MEM_dupallocN(texn->vd->dataset); - } - if (texn->ot) { - texn->ot = BKE_texture_ocean_copy(tex->ot, LIB_ID_CREATE_NO_USER_REFCOUNT); - } texn->preview = NULL; @@ -593,64 +496,6 @@ void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local) BKE_id_make_local_generic(bmain, &tex->id, true, lib_local); } -Tex *give_current_object_texture(Object *ob) -{ - Material *ma, *node_ma; - Tex *tex = NULL; - - if (ob == NULL) return NULL; - if (ob->totcol == 0 && !(ob->type == OB_LAMP)) return NULL; - - if (ob->type == OB_LAMP) { - tex = give_current_lamp_texture(ob->data); - } - else { - ma = give_current_material(ob, ob->actcol); - - if ((node_ma = give_node_material(ma))) - ma = node_ma; - - tex = give_current_material_texture(ma); - } - - return tex; -} - -Tex *give_current_lamp_texture(Lamp *la) -{ - MTex *mtex = NULL; - Tex *tex = NULL; - - if (la) { - mtex = la->mtex[(int)(la->texact)]; - if (mtex) tex = mtex->tex; - } - - return tex; -} - -void set_current_lamp_texture(Lamp *la, Tex *newtex) -{ - int act = la->texact; - - if (la->mtex[act] && la->mtex[act]->tex) - id_us_min(&la->mtex[act]->tex->id); - - if (newtex) { - if (!la->mtex[act]) { - la->mtex[act] = BKE_texture_mtex_add(); - la->mtex[act]->texco = TEXCO_GLOB; - } - - la->mtex[act]->tex = newtex; - id_us_plus(&newtex->id); - } - else if (la->mtex[act]) { - MEM_freeN(la->mtex[act]); - la->mtex[act] = NULL; - } -} - Tex *give_current_linestyle_texture(FreestyleLineStyle *linestyle) { MTex *mtex = NULL; @@ -686,55 +531,9 @@ void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex) } } -bNode *give_current_material_texture_node(Material *ma) -{ - if (ma && ma->use_nodes && ma->nodetree) - return nodeGetActiveID(ma->nodetree, ID_TE); - - return NULL; -} - -Tex *give_current_material_texture(Material *ma) -{ - MTex *mtex = NULL; - Tex *tex = NULL; - bNode *node; - - if (ma && ma->use_nodes && ma->nodetree) { - /* first check texture, then material, this works together - * with a hack that clears the active ID flag for textures on - * making a material node active */ - node = nodeGetActiveID(ma->nodetree, ID_TE); - - if (node) { - tex = (Tex *)node->id; - ma = NULL; - } - } - - if (ma) { - mtex = ma->mtex[(int)(ma->texact)]; - if (mtex) tex = mtex->tex; - } - - return tex; -} - bool give_active_mtex(ID *id, MTex ***mtex_ar, short *act) { switch (GS(id->name)) { - case ID_MA: - *mtex_ar = ((Material *)id)->mtex; - if (act) *act = (((Material *)id)->texact); - break; - case ID_WO: - *mtex_ar = ((World *)id)->mtex; - if (act) *act = (((World *)id)->texact); - break; - case ID_LA: - *mtex_ar = ((Lamp *)id)->mtex; - if (act) *act = (((Lamp *)id)->texact); - break; case ID_LS: *mtex_ar = ((FreestyleLineStyle *)id)->mtex; if (act) *act = (((FreestyleLineStyle *)id)->texact); @@ -758,15 +557,6 @@ void set_active_mtex(ID *id, short act) else if (act >= MAX_MTEX) act = MAX_MTEX - 1; switch (GS(id->name)) { - case ID_MA: - ((Material *)id)->texact = act; - break; - case ID_WO: - ((World *)id)->texact = act; - break; - case ID_LA: - ((Lamp *)id)->texact = act; - break; case ID_LS: ((FreestyleLineStyle *)id)->texact = act; break; @@ -778,100 +568,6 @@ void set_active_mtex(ID *id, short act) } } -void set_current_material_texture(Material *ma, Tex *newtex) -{ - Tex *tex = NULL; - bNode *node; - - if ((ma->use_nodes && ma->nodetree) && - (node = nodeGetActiveID(ma->nodetree, ID_TE))) - { - tex = (Tex *)node->id; - id_us_min(&tex->id); - if (newtex) { - node->id = &newtex->id; - id_us_plus(&newtex->id); - } - else { - node->id = NULL; - } - } - else { - int act = (int)ma->texact; - - tex = (ma->mtex[act]) ? ma->mtex[act]->tex : NULL; - id_us_min(&tex->id); - - if (newtex) { - if (!ma->mtex[act]) { - ma->mtex[act] = BKE_texture_mtex_add(); - /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */ - ma->septex &= ~(1 << act); - /* For volumes the default UV texture coordinates are not available. */ - if (ma->material_type == MA_TYPE_VOLUME) { - ma->mtex[act]->texco = TEXCO_ORCO; - } - } - - ma->mtex[act]->tex = newtex; - id_us_plus(&newtex->id); - } - else if (ma->mtex[act]) { - MEM_freeN(ma->mtex[act]); - ma->mtex[act] = NULL; - } - } -} - -bool has_current_material_texture(Material *ma) -{ - bNode *node; - - if (ma && ma->use_nodes && ma->nodetree) { - node = nodeGetActiveID(ma->nodetree, ID_TE); - - if (node) - return true; - } - - return (ma != NULL); -} - -Tex *give_current_world_texture(World *world) -{ - MTex *mtex = NULL; - Tex *tex = NULL; - - if (!world) return NULL; - - mtex = world->mtex[(int)(world->texact)]; - if (mtex) tex = mtex->tex; - - return tex; -} - -void set_current_world_texture(World *wo, Tex *newtex) -{ - int act = wo->texact; - - if (wo->mtex[act] && wo->mtex[act]->tex) - id_us_min(&wo->mtex[act]->tex->id); - - if (newtex) { - if (!wo->mtex[act]) { - wo->mtex[act] = BKE_texture_mtex_add(); - wo->mtex[act]->texco = TEXCO_VIEW; - } - - wo->mtex[act]->tex = newtex; - id_us_plus(&newtex->id); - } - else if (wo->mtex[act]) { - MEM_freeN(wo->mtex[act]); - wo->mtex[act] = NULL; - } -} - Tex *give_current_brush_texture(Brush *br) { return br->mtex.tex; @@ -926,65 +622,6 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex) /* ------------------------------------------------------------------------- */ -EnvMap *BKE_texture_envmap_add(void) -{ - EnvMap *env; - - env = MEM_callocN(sizeof(EnvMap), "envmap"); - env->type = ENV_CUBE; - env->stype = ENV_ANIM; - env->clipsta = 0.1; - env->clipend = 100.0; - env->cuberes = 512; - env->viewscale = 0.5; - - return env; -} - -/* ------------------------------------------------------------------------- */ - -EnvMap *BKE_texture_envmap_copy(const EnvMap *env, const int flag) -{ - EnvMap *envn; - int a; - - envn = MEM_dupallocN(env); - envn->ok = 0; - for (a = 0; a < 6; a++) { - envn->cube[a] = NULL; - } - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - id_us_plus((ID *)envn->ima); - } - - return envn; -} - -/* ------------------------------------------------------------------------- */ - -void BKE_texture_envmap_free_data(EnvMap *env) -{ - unsigned int part; - - for (part = 0; part < 6; part++) { - if (env->cube[part]) - IMB_freeImBuf(env->cube[part]); - env->cube[part] = NULL; - } - env->ok = 0; -} - -/* ------------------------------------------------------------------------- */ - -void BKE_texture_envmap_free(EnvMap *env) -{ - - BKE_texture_envmap_free_data(env); - MEM_freeN(env); - -} - -/* ------------------------------------------------------------------------- */ void BKE_texture_pointdensity_init_data(PointDensity *pd) { @@ -1057,77 +694,8 @@ void BKE_texture_pointdensity_free(PointDensity *pd) BKE_texture_pointdensity_free_data(pd); MEM_freeN(pd); } - -/* ------------------------------------------------------------------------- */ - -void BKE_texture_voxeldata_free_data(VoxelData *vd) -{ - if (vd->dataset) { - MEM_freeN(vd->dataset); - vd->dataset = NULL; - } - -} - -void BKE_texture_voxeldata_free(VoxelData *vd) -{ - BKE_texture_voxeldata_free_data(vd); - MEM_freeN(vd); -} - -VoxelData *BKE_texture_voxeldata_add(void) -{ - VoxelData *vd; - - vd = MEM_callocN(sizeof(VoxelData), "voxeldata"); - vd->dataset = NULL; - vd->resol[0] = vd->resol[1] = vd->resol[2] = 1; - vd->interp_type = TEX_VD_LINEAR; - vd->file_format = TEX_VD_SMOKE; - vd->int_multiplier = 1.0; - vd->extend = TEX_CLIP; - vd->object = NULL; - vd->cachedframe = -1; - vd->ok = 0; - - return vd; -} - -VoxelData *BKE_texture_voxeldata_copy(VoxelData *vd) -{ - VoxelData *vdn; - - vdn = MEM_dupallocN(vd); - vdn->dataset = NULL; - - return vdn; -} - /* ------------------------------------------------------------------------- */ -OceanTex *BKE_texture_ocean_add(void) -{ - OceanTex *ot; - - ot = MEM_callocN(sizeof(struct OceanTex), "ocean texture"); - ot->output = TEX_OCN_DISPLACEMENT; - ot->object = NULL; - - return ot; -} - -OceanTex *BKE_texture_ocean_copy(const OceanTex *ot, const int UNUSED(flag)) -{ - OceanTex *otn = MEM_dupallocN(ot); - - return otn; -} - -void BKE_texture_ocean_free(struct OceanTex *ot) -{ - MEM_freeN(ot); -} - /** * \returns true if this texture can use its #Texture.ima (even if its NULL) */ @@ -1138,15 +706,6 @@ bool BKE_texture_is_image_user(const struct Tex *tex) { return true; } - case TEX_ENVMAP: - { - if (tex->env) { - if (tex->env->stype == ENV_LOAD) { - return true; - } - } - break; - } } return false; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index a3536cd0d68..f19f27c85a7 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -61,6 +61,7 @@ #include "BKE_movieclip.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_layer.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -398,17 +399,17 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin /* Get transformation matrix for a given object which is used * for parenting motion tracker reconstruction to 3D world. */ -void BKE_tracking_get_camera_object_matrix(Scene *scene, Object *ob, float mat[4][4]) +void BKE_tracking_get_camera_object_matrix(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float mat[4][4]) { if (!ob) { if (scene->camera) ob = scene->camera; else - ob = BKE_scene_camera_find(scene); + ob = BKE_view_layer_camera_find(BKE_view_layer_context_active_PLACEHOLDER(scene)); } if (ob) - BKE_object_where_is_calc_mat4(scene, ob, mat); + BKE_object_where_is_calc_mat4(depsgraph, scene, ob, mat); else unit_m4(mat); } diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 331db5b6ff0..aae9985bc24 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -982,7 +982,7 @@ static void initialize_track_for_stabilization(StabContext *ctx, static void initialize_all_tracks(StabContext *ctx, float aspect) { - size_t i, track_cnt = 0; + size_t i, track_len = 0; MovieClip *clip = ctx->clip; MovieTracking *tracking = ctx->tracking; MovieTrackingTrack *track; @@ -1011,20 +1011,20 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) track); local_data->is_init_for_stabilization = false; - ++track_cnt; + ++track_len; } - if (!track_cnt) { + if (!track_len) { return; } - order = MEM_mallocN(track_cnt * sizeof(TrackInitOrder), + order = MEM_mallocN(track_len * sizeof(TrackInitOrder), "stabilization track order"); if (!order) { return; } - track_cnt = establish_track_initialization_order(ctx, order); - if (track_cnt == 0) { + track_len = establish_track_initialization_order(ctx, order); + if (track_len == 0) { goto cleanup; } @@ -1032,7 +1032,7 @@ static void initialize_all_tracks(StabContext *ctx, float aspect) average_marker_positions(ctx, reference_frame, average_pos); setup_pivot(average_pos, pivot); - for (i = 0; i < track_cnt; ++i) { + for (i = 0; i < track_len; ++i) { track = order[i].data; if (reference_frame != order[i].reference_frame) { reference_frame = order[i].reference_frame; diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index 0ebfb4065e4..abc53bf031a 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -39,6 +39,8 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_main.h" #include "BKE_undo_system.h" @@ -413,12 +415,21 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char return BKE_undosys_step_push_init_with_type(ustack, C, name, ut); } +/** + * \param C: Can be NULL from some callers if their encoding function doesn't need it + */ bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut) { UNDO_NESTED_ASSERT(false); undosys_stack_validate(ustack, false); bool is_not_empty = ustack->step_active != NULL; + /* Might not be final place for this to be called - probably only want to call it from some + * undo handlers, not all of them? */ + if (BKE_override_static_is_enabled()) { + BKE_main_override_static_operations_create(G.main, false); + } + /* Remove all undos after (also when 'ustack->step_active == NULL'). */ while (ustack->steps.last != ustack->step_active) { UndoStep *us_iter = ustack->steps.last; diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 3a903eb31c1..e2a0837b938 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -35,6 +35,8 @@ #include "BLI_string.h" #include "BLI_string_utf8.h" +#include "DNA_scene_types.h" + #include "BKE_unit.h" /* own include */ #ifdef WIN32 @@ -108,6 +110,8 @@ typedef struct bUnitCollection { int length; /* to quickly find the last item */ } bUnitCollection; +#define UNIT_COLLECTION_LENGTH(def) (sizeof(def) / sizeof(bUnitDef) - 1) + /* Dummy */ static struct bUnitDef buDummyDef[] = { {"", NULL, "", NULL, NULL, 1.0, 0.0}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}}; static struct bUnitCollection buDummyCollection = {buDummyDef, 0, 0, sizeof(buDummyDef)}; @@ -121,7 +125,7 @@ static const struct bUnitDef buMetricLenDef[] = { {"decimeter", "decimeters", "dm", NULL, "10 Centimeters", UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS}, {"centimeter", "centimeters", "cm", NULL, "Centimeters", UN_SC_CM, 0.0, B_UNIT_DEF_NONE}, {"millimeter", "millimeters", "mm", NULL, "Millimeters", UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH}, - {"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_UM, 0.0, B_UNIT_DEF_NONE}, + {"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_UM, 0.0, B_UNIT_DEF_NONE}, /* These get displayed because of float precision problems in the transform header, * could work around, but for now probably people wont use these */ @@ -131,7 +135,7 @@ static const struct bUnitDef buMetricLenDef[] = { #endif {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef) / sizeof(bUnitDef)}; +static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricLenDef)}; static struct bUnitDef buImperialLenDef[] = { {"mile", "miles", "mi", "m", "Miles", UN_SC_MI, 0.0, B_UNIT_DEF_NONE}, @@ -143,7 +147,7 @@ static struct bUnitDef buImperialLenDef[] = { {"thou", "thou", "thou", "mil", "Thou", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* plural for thou has no 's' */ {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buImperialLenCollection = {buImperialLenDef, 4, 0, sizeof(buImperialLenDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buImperialLenCollection = {buImperialLenDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialLenDef)}; /* Areas */ static struct bUnitDef buMetricAreaDef[] = { @@ -157,7 +161,7 @@ static struct bUnitDef buMetricAreaDef[] = { {"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, sizeof(buMetricAreaDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricAreaDef)}; static struct bUnitDef buImperialAreaDef[] = { {"square mile", "square miles", "sq mi", "sq m", "Square Miles", UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE}, @@ -169,7 +173,7 @@ static struct bUnitDef buImperialAreaDef[] = { {"square thou", "square thous", "sq mil", NULL, "Square Thous", UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buImperialAreaCollection = {buImperialAreaDef, 4, 0, sizeof(buImperialAreaDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buImperialAreaCollection = {buImperialAreaDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialAreaDef)}; /* Volumes */ static struct bUnitDef buMetricVolDef[] = { @@ -183,7 +187,7 @@ static struct bUnitDef buMetricVolDef[] = { {"cubic micrometer", "cubic micrometers", "µm³", "um3", "Cubic Micrometers", UN_SC_UM * UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buMetricVolCollection = {buMetricVolDef, 3, 0, sizeof(buMetricVolDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buMetricVolCollection = {buMetricVolDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricVolDef)}; static struct bUnitDef buImperialVolDef[] = { {"cubic mile", "cubic miles", "cu mi", "cu m", "Cubic Miles", UN_SC_MI * UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE}, @@ -195,11 +199,11 @@ static struct bUnitDef buImperialVolDef[] = { {"cubic thou", "cubic thous", "cu mil", NULL, "Cubic Thous", UN_SC_MIL * UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buImperialVolCollection = {buImperialVolDef, 4, 0, sizeof(buImperialVolDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buImperialVolCollection = {buImperialVolDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialVolDef)}; /* Mass */ static struct bUnitDef buMetricMassDef[] = { - {"ton", "tonnes", "ton", "t", "1000 Kilograms", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE}, + {"ton", "tonnes", "ton", "t", "Tonnes", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE}, {"quintal", "quintals", "ql", "q", "100 Kilograms", UN_SC_QL, 0.0, B_UNIT_DEF_SUPPRESS}, {"kilogram", "kilograms", "kg", NULL, "Kilograms", UN_SC_KG, 0.0, B_UNIT_DEF_NONE}, /* base unit */ {"hectogram", "hectograms", "hg", NULL, "Hectograms", UN_SC_HG, 0.0, B_UNIT_DEF_SUPPRESS}, @@ -208,7 +212,7 @@ static struct bUnitDef buMetricMassDef[] = { {"milligram", "milligrams", "mg", NULL, "Milligrams", UN_SC_MG, 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buMetricMassCollection = {buMetricMassDef, 2, 0, sizeof(buMetricMassDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buMetricMassCollection = {buMetricMassDef, 2, 0, UNIT_COLLECTION_LENGTH(buMetricMassDef)}; static struct bUnitDef buImperialMassDef[] = { {"ton", "tonnes", "ton", "t", "Tonnes", UN_SC_ITON, 0.0, B_UNIT_DEF_NONE}, @@ -218,7 +222,7 @@ static struct bUnitDef buImperialMassDef[] = { {"ounce", "ounces", "oz", NULL, "Ounces", UN_SC_OZ, 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3, 0, sizeof(buImperialMassDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3, 0, UNIT_COLLECTION_LENGTH(buImperialMassDef)}; /* Even if user scales the system to a point where km^3 is used, velocity and * acceleration aren't scaled: that's why we have so few units for them */ @@ -229,27 +233,27 @@ static struct bUnitDef buMetricVelDef[] = { {"kilometer per hour", "kilometers per hour", "km/h", NULL, "Kilometers per hour", UN_SC_KM / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buMetricVelCollection = {buMetricVelDef, 0, 0, sizeof(buMetricVelDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buMetricVelCollection = {buMetricVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricVelDef)}; static struct bUnitDef buImperialVelDef[] = { {"foot per second", "feet per second", "ft/s", "fps", "Feet per second", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */ {"mile per hour", "miles per hour", "mph", NULL, "Miles per hour", UN_SC_MI / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buImperialVelCollection = {buImperialVelDef, 0, 0, sizeof(buImperialVelDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buImperialVelCollection = {buImperialVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialVelDef)}; /* Acceleration */ static struct bUnitDef buMetricAclDef[] = { {"meter per second squared", "meters per second squared", "m/s²", "m/s2", "Meters per second squared", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */ {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buMetricAclCollection = {buMetricAclDef, 0, 0, sizeof(buMetricAclDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buMetricAclCollection = {buMetricAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricAclDef)}; static struct bUnitDef buImperialAclDef[] = { {"foot per second squared", "feet per second squared", "ft/s²", "ft/s2", "Feet per second squared", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */ {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0, sizeof(buImperialAclDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialAclDef)}; /* Time */ static struct bUnitDef buNaturalTimeDef[] = { @@ -262,7 +266,7 @@ static struct bUnitDef buNaturalTimeDef[] = { {"microsecond", "microseconds", "µs", "us", "Microseconds", 0.000001, 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buNaturalTimeCollection = {buNaturalTimeDef, 3, 0, sizeof(buNaturalTimeDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buNaturalTimeCollection = {buNaturalTimeDef, 3, 0, UNIT_COLLECTION_LENGTH(buNaturalTimeDef)}; static struct bUnitDef buNaturalRotDef[] = { @@ -274,7 +278,7 @@ static struct bUnitDef buNaturalRotDef[] = { // {"turn", "turns", "t", NULL, "Turns", 1.0 / (M_PI * 2.0), 0.0, B_UNIT_DEF_NONE}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buNaturalRotCollection = {buNaturalRotDef, 0, 0, sizeof(buNaturalRotDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buNaturalRotCollection = {buNaturalRotDef, 0, 0, UNIT_COLLECTION_LENGTH(buNaturalRotDef)}; /* Camera Lengths */ static struct bUnitDef buCameraLenDef[] = { @@ -285,7 +289,7 @@ static struct bUnitDef buCameraLenDef[] = { {"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0} }; -static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, sizeof(buCameraLenDef) / sizeof(bUnitDef)}; +static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buCameraLenDef)}; #define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1) @@ -341,9 +345,12 @@ static const bUnitDef *unit_best_fit( static void unit_dual_convert( double value, const bUnitCollection *usys, bUnitDef const **r_unit_a, bUnitDef const **r_unit_b, - double *r_value_a, double *r_value_b) + double *r_value_a, double *r_value_b, + const bUnitDef *main_unit) { - const bUnitDef *unit = unit_best_fit(value, usys, NULL, 1); + const bUnitDef *unit; + if (main_unit) unit = main_unit; + else unit = unit_best_fit(value, usys, NULL, 1); *r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar; *r_value_b = value - (*r_value_a); @@ -405,17 +412,6 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con while (unit->name_short[j] && (i < len_max)) { str[i++] = unit->name_short[j++]; } -#if 0 - if (pad) { - /* this loop only runs if so many zeros were removed that - * the unit name only used padded chars, - * In that case add padding for the name. */ - - while (i <= len + j && (i < len_max)) { - str[i++] = pad; - } - } -#endif } /* terminate no matter what's done with padding above */ @@ -426,43 +422,135 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con return i; } -/* Used for drawing number buttons, try keep fast. - * Return the length of the generated string. - */ -size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad) +static bool unit_should_be_split(int type) { - const bUnitCollection *usys = unit_get_system(system, type); + return ELEM(type, B_UNIT_LENGTH, B_UNIT_MASS, B_UNIT_TIME, B_UNIT_CAMERA); +} - if (usys == NULL || usys->units[0].name == NULL) - usys = &buDummyCollection; +typedef struct { + int system; + int rotation; + /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection */ + int length; + int mass; + int time; +} PreferredUnits; - /* split output makes sense only for length, mass and time */ - if (split && (type == B_UNIT_LENGTH || type == B_UNIT_MASS || type == B_UNIT_TIME || type == B_UNIT_CAMERA)) { - const bUnitDef *unit_a, *unit_b; - double value_a, value_b; +static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings) +{ + PreferredUnits units = { 0 }; + units.system = settings->system; + units.rotation = settings->system_rotation; + units.length = settings->length_unit; + units.mass = settings->mass_unit; + units.time = settings->time_unit; + return units; +} - unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b); +static size_t unit_as_string_splitted( + char *str, int len_max, double value, int prec, + const bUnitCollection *usys, const bUnitDef *main_unit) +{ + const bUnitDef *unit_a, *unit_b; + double value_a, value_b; - /* check the 2 is a smaller unit */ - if (unit_b > unit_a) { - size_t i; - i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0'); + unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b, main_unit); - prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar); - prec = max_ii(prec, 0); + /* check the 2 is a smaller unit */ + if (unit_b > unit_a) { + size_t i; + i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0'); - /* is there enough space for at least 1 char of the next unit? */ - if (i + 2 < len_max) { - str[i++] = ' '; + prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar); + prec = max_ii(prec, 0); - /* use low precision since this is a smaller unit */ - i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0'); - } - return i; + /* is there enough space for at least 1 char of the next unit? */ + if (i + 2 < len_max) { + str[i++] = ' '; + + /* use low precision since this is a smaller unit */ + i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0'); } + return i; + } + + return -1; +} + +static bool is_valid_unit_collection(const bUnitCollection *usys) +{ + return usys != NULL && usys->units[0].name != NULL; +} + +static const bUnitDef *get_preferred_unit_if_used(int type, PreferredUnits units) +{ + const bUnitCollection *usys = unit_get_system(units.system, type); + if (!is_valid_unit_collection(usys)) return NULL; + + int max_offset = usys->length - 1; + + switch (type) { + case B_UNIT_LENGTH: + case B_UNIT_AREA: + case B_UNIT_VOLUME: + if (units.length == USER_UNIT_ADAPTIVE) return NULL; + return usys->units + MIN2(units.length, max_offset); + case B_UNIT_MASS: + if (units.mass == USER_UNIT_ADAPTIVE) return NULL; + return usys->units + MIN2(units.mass, max_offset); + case B_UNIT_TIME: + if (units.time == USER_UNIT_ADAPTIVE) return NULL; + return usys->units + MIN2(units.time, max_offset); + case B_UNIT_ROTATION: + if (units.rotation == 0) return usys->units + 0; + else if (units.rotation == USER_UNIT_ROT_RADIANS) return usys->units + 3; + break; + default: + break; + } + return NULL; +} + +/* Return the length of the generated string. */ +static size_t unit_as_string_main( + char *str, int len_max, double value, int prec, + int type, bool split, bool pad, PreferredUnits units) +{ + const bUnitCollection *usys = unit_get_system(units.system, type); + const bUnitDef *main_unit = NULL; + + if (!is_valid_unit_collection(usys)) { + usys = &buDummyCollection; + } + else { + main_unit = get_preferred_unit_if_used(type, units); } - return unit_as_string(str, len_max, value, prec, usys, NULL, pad ? ' ' : '\0'); + if (split && unit_should_be_split(type)) { + int length = unit_as_string_splitted(str, len_max, value, prec, usys, main_unit); + /* failed when length is negative, fallback to no split */ + if (length >= 0) return length; + } + + return unit_as_string(str, len_max, value, prec, usys, main_unit, pad ? ' ' : '\0'); +} + +size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad) +{ + PreferredUnits units; + units.system = system; + units.rotation = 0; + units.length = USER_UNIT_ADAPTIVE; + units.mass = USER_UNIT_ADAPTIVE; + units.time = USER_UNIT_ADAPTIVE; + return unit_as_string_main(str, len_max, value, prec, type, split, pad, units); +} + +size_t bUnit_AsString2(char *str, int len_max, double value, int prec, int type, const UnitSettings *settings, bool pad) +{ + bool do_split = (settings->flag & USER_UNIT_OPT_SPLIT) != 0; + PreferredUnits units = preferred_units_from_UnitSettings(settings); + return unit_as_string_main(str, len_max, value, prec, type, do_split, pad, units); } BLI_INLINE bool isalpha_or_utf8(const int ch) @@ -631,6 +719,27 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const c return unit; } +bool bUnit_ContainsUnit(const char *str, int system, int type) +{ + const bUnitCollection *usys = unit_get_system(system, type); + if (!is_valid_unit_collection(usys)) return false; + + for (int i = 0; i < usys->length; i++) { + if (unit_find(str, usys->units + i)) { + return true; + } + } + return false; +} + +double bUnit_PreferredUnitScalar(const struct UnitSettings *settings, int type) +{ + PreferredUnits units = preferred_units_from_UnitSettings(settings); + const bUnitDef *unit = get_preferred_unit_if_used(type, units); + if (unit == NULL) return 1.0; + else return unit->scalar; +} + /* make a copy of the string that replaces the units with numbers * this is used before parsing * This is only used when evaluating user input and can afford to be a bit slower @@ -649,16 +758,13 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const c bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type) { const bUnitCollection *usys = unit_get_system(system, type); + if (!is_valid_unit_collection(usys)) return false; const bUnitDef *unit = NULL, *default_unit; double scale_pref_base = scale_pref; char str_tmp[TEMP_STR_SIZE]; bool changed = false; - if (usys == NULL || usys->units[0].name == NULL) { - return changed; - } - /* make lowercase */ BLI_str_tolower_ascii(str, len_max); @@ -824,6 +930,11 @@ int bUnit_GetBaseUnit(const void *usys_pt) return ((bUnitCollection *)usys_pt)->base_unit; } +int bUnit_GetBaseUnitOfType(int system, int type) +{ + return unit_get_system(system, type)->base_unit; +} + const char *bUnit_GetName(const void *usys_pt, int index) { return ((bUnitCollection *)usys_pt)->units[index].name; @@ -837,3 +948,8 @@ double bUnit_GetScaler(const void *usys_pt, int index) { return ((bUnitCollection *)usys_pt)->units[index].scalar; } + +bool bUnit_IsSuppressed(const void *usys_pt, int index) +{ + return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0; +} diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c new file mode 100644 index 00000000000..0b1f9d8bd24 --- /dev/null +++ b/source/blender/blenkernel/intern/workspace.c @@ -0,0 +1,446 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/workspace.c + * \ingroup bke + */ + +/* allow accessing private members of DNA_workspace_types.h */ +#define DNA_PRIVATE_WORKSPACE_ALLOW + +#include <stdlib.h> +#include <string.h> + +#include "BLI_utildefines.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_string_utils.h" +#include "BLI_listbase.h" + +#include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_object.h" +#include "BKE_workspace.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_workspace_types.h" + +#include "DEG_depsgraph.h" + +#include "MEM_guardedalloc.h" + + +/* -------------------------------------------------------------------- */ +/* Internal utils */ + +static void workspace_layout_name_set( + WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name) +{ + BLI_strncpy(layout->name, new_name, sizeof(layout->name)); + BLI_uniquename(&workspace->layouts, layout, "Layout", '.', offsetof(WorkSpaceLayout, name), sizeof(layout->name)); +} + +/** + * This should only be used directly when it is to be expected that there isn't + * a layout within \a workspace that wraps \a screen. Usually - especially outside + * of BKE_workspace - #BKE_workspace_layout_find should be used! + */ +static WorkSpaceLayout *workspace_layout_find_exec( + const WorkSpace *workspace, const bScreen *screen) +{ + return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen)); +} + +static void workspace_relation_add( + ListBase *relation_list, void *parent, void *data) +{ + WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__); + relation->parent = parent; + relation->value = data; + /* add to head, if we switch back to it soon we find it faster. */ + BLI_addhead(relation_list, relation); +} +static void workspace_relation_remove( + ListBase *relation_list, WorkSpaceDataRelation *relation) +{ + BLI_remlink(relation_list, relation); + MEM_freeN(relation); +} + +static void workspace_relation_ensure_updated( + ListBase *relation_list, void *parent, void *data) +{ + WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent)); + if (relation != NULL) { + relation->value = data; + /* reinsert at the head of the list, so that more commonly used relations are found faster. */ + BLI_remlink(relation_list, relation); + BLI_addhead(relation_list, relation); + } + else { + /* no matching relation found, add new one */ + workspace_relation_add(relation_list, parent, data); + } +} + +static void *workspace_relation_get_data_matching_parent( + const ListBase *relation_list, const void *parent) +{ + WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent)); + if (relation != NULL) { + return relation->value; + } + else { + return NULL; + } +} + +/** + * Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple + * WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks. + * Hence, this should only be used as assert check before assigining a screen to a workspace. + */ +#ifndef NDEBUG +static bool workspaces_is_screen_used +#else +static bool UNUSED_FUNCTION(workspaces_is_screen_used) +#endif + (const Main *bmain, bScreen *screen) +{ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + if (workspace_layout_find_exec(workspace, screen)) { + return true; + } + } + + return false; +} + +/* -------------------------------------------------------------------- */ +/* Create, delete, init */ + +WorkSpace *BKE_workspace_add(Main *bmain, const char *name) +{ + WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name, 0); + return new_workspace; +} + +/** + * The function that actually frees the workspace data (not workspace itself). It shouldn't be called + * directly, instead #BKE_workspace_remove should be, which calls this through #BKE_libblock_free then. + * + * Should something like a bke_internal.h be added, this should go there! + */ +void BKE_workspace_free(WorkSpace *workspace) +{ + BKE_workspace_relations_free(&workspace->hook_layout_relations); + + BLI_freelistN(&workspace->owner_ids); + BLI_freelistN(&workspace->layouts); + + while (!BLI_listbase_is_empty(&workspace->tools)) { + BKE_workspace_tool_remove(workspace, workspace->tools.first); + } + + if (workspace->status_text) { + MEM_freeN(workspace->status_text); + workspace->status_text = NULL; + } +} + +/** + * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that + * calls #BKE_workspace_free (through #BKE_libblock_free) to free the workspace data, and frees + * other data-blocks owned by \a workspace and its layouts (currently that is screens only). + * + * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here. + */ +void BKE_workspace_remove(Main *bmain, WorkSpace *workspace) +{ + for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout; layout = layout_next) { + layout_next = layout->next; + BKE_workspace_layout_remove(bmain, workspace, layout); + } + BKE_libblock_free(bmain, workspace); +} + +WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain) +{ + WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__); + + /* set an active screen-layout for each possible window/workspace combination */ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first); + } + + return hook; +} +void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook) +{ + /* workspaces should never be freed before wm (during which we call this function) */ + BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces)); + + /* Free relations for this hook */ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next; + relation; + relation = relation_next) + { + relation_next = relation->next; + if (relation->parent == hook) { + workspace_relation_remove(&workspace->hook_layout_relations, relation); + } + } + } + + MEM_freeN(hook); +} + +/** + * Add a new layout to \a workspace for \a screen. + */ +WorkSpaceLayout *BKE_workspace_layout_add( + Main *bmain, + WorkSpace *workspace, + bScreen *screen, + const char *name) +{ + WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__); + + BLI_assert(!workspaces_is_screen_used(bmain, screen)); +#ifndef DEBUG + UNUSED_VARS(bmain); +#endif + layout->screen = screen; + id_us_plus(&layout->screen->id); + workspace_layout_name_set(workspace, layout, name); + BLI_addtail(&workspace->layouts, layout); + + return layout; +} + +void BKE_workspace_layout_remove( + Main *bmain, + WorkSpace *workspace, WorkSpaceLayout *layout) +{ + id_us_min(&layout->screen->id); + BKE_libblock_free(bmain, layout->screen); + BLI_freelinkN(&workspace->layouts, layout); +} + +void BKE_workspace_relations_free( + ListBase *relation_list) +{ + for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) { + relation_next = relation->next; + workspace_relation_remove(relation_list, relation); + } +} + +/* -------------------------------------------------------------------- */ +/* General Utils */ + +WorkSpaceLayout *BKE_workspace_layout_find( + const WorkSpace *workspace, const bScreen *screen) +{ + WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen); + if (layout) { + return layout; + } + + printf("%s: Couldn't find layout in this workspace: '%s' screen: '%s'. " + "This should not happen!\n", + __func__, workspace->id.name + 2, screen->id.name + 2); + + return NULL; +} + +/** + * Find the layout for \a screen without knowing which workspace to look in. + * Can also be used to find the workspace that contains \a screen. + * + * \param r_workspace: Optionally return the workspace that contains the looked up layout (if found). + */ +WorkSpaceLayout *BKE_workspace_layout_find_global( + const Main *bmain, const bScreen *screen, + WorkSpace **r_workspace) +{ + WorkSpaceLayout *layout; + + if (r_workspace) { + *r_workspace = NULL; + } + + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + if ((layout = workspace_layout_find_exec(workspace, screen))) { + if (r_workspace) { + *r_workspace = workspace; + } + + return layout; + } + } + + return NULL; +} + +/** + * Circular workspace layout iterator. + * + * \param callback: Custom function which gets executed for each layout. Can return false to stop iterating. + * \param arg: Custom data passed to each \a callback call. + * + * \return the layout at which \a callback returned false. + */ +WorkSpaceLayout *BKE_workspace_layout_iter_circular( + const WorkSpace *workspace, WorkSpaceLayout *start, + bool (*callback)(const WorkSpaceLayout *layout, void *arg), + void *arg, const bool iter_backward) +{ + WorkSpaceLayout *iter_layout; + + if (iter_backward) { + LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start) + { + if (!callback(iter_layout, arg)) { + return iter_layout; + } + } + LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start); + } + else { + LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start) + { + if (!callback(iter_layout, arg)) { + return iter_layout; + } + } + LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start) + } + + return NULL; +} + +void BKE_workspace_tool_remove( + struct WorkSpace *workspace, struct bToolRef *tref) +{ + if (tref->runtime) { + MEM_freeN(tref->runtime); + } + if (tref->properties) { + IDP_FreeProperty(tref->properties); + MEM_freeN(tref->properties); + } + BLI_remlink(&workspace->tools, tref); + MEM_freeN(tref); +} + +/* -------------------------------------------------------------------- */ +/* Getters/Setters */ + +WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook) +{ + return hook->active; +} +void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) +{ + hook->active = workspace; + if (workspace) { + WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook); + if (layout) { + hook->act_layout = layout; + } + } +} + +WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) +{ + return hook->act_layout; +} +void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout) +{ + hook->act_layout = layout; +} + +bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) +{ + return hook->act_layout->screen; +} +void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace, bScreen *screen) +{ + /* we need to find the WorkspaceLayout that wraps this screen */ + WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen); + BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout); +} + +ListBase *BKE_workspace_layouts_get(WorkSpace *workspace) +{ + return &workspace->layouts; +} + +const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout) +{ + return layout->name; +} +void BKE_workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name) +{ + workspace_layout_name_set(workspace, layout, new_name); +} + +bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout) +{ + return layout->screen; +} +void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen) +{ + layout->screen = screen; +} + +WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get( + const WorkSpaceInstanceHook *hook, const WorkSpace *workspace) +{ + return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook); +} +void BKE_workspace_hook_layout_for_workspace_set( + WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout) +{ + hook->act_layout = layout; + workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout); +} + +bool BKE_workspace_owner_id_check( + const WorkSpace *workspace, const char *owner_id) +{ + if ((*owner_id == '\0') || + ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0)) + { + return true; + } + else { + /* we could use hash lookup, for now this list is highly under < ~16 items. */ + return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL; + } +} diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index cb3ef82ed62..14a9133f8fb 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -33,6 +33,7 @@ #include <string.h> #include <stdlib.h> #include <math.h> + #include "MEM_guardedalloc.h" #include "DNA_world_types.h" @@ -43,6 +44,7 @@ #include "BLI_listbase.h" #include "BKE_animsys.h" +#include "BKE_global.h" #include "BKE_icons.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -51,18 +53,18 @@ #include "BKE_node.h" #include "BKE_world.h" +#include "DRW_engine.h" + +#include "DEG_depsgraph.h" + #include "GPU_material.h" /** Free (or release) any data used by this world (does not free the world itself). */ void BKE_world_free(World *wrld) { - int a; - BKE_animdata_free((ID *)wrld, false); - for (a = 0; a < MAX_MTEX; a++) { - MEM_SAFE_FREE(wrld->mtex[a]); - } + DRW_drawdata_free((ID *)wrld); /* is no lib link block, but world extension */ if (wrld->nodetree) { @@ -84,23 +86,9 @@ void BKE_world_init(World *wrld) wrld->horr = 0.05f; wrld->horg = 0.05f; wrld->horb = 0.05f; - wrld->zenr = 0.01f; - wrld->zeng = 0.01f; - wrld->zenb = 0.01f; - wrld->skytype = 0; - - wrld->exp = 0.0f; - wrld->exposure = wrld->range = 1.0f; wrld->aodist = 10.0f; - wrld->aosamp = 5; wrld->aoenergy = 1.0f; - wrld->ao_env_energy = 1.0f; - wrld->ao_indirect_energy = 1.0f; - wrld->ao_indirect_bounces = 1; - wrld->aobias = 0.05f; - wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY; - wrld->ao_approx_error = 0.25f; wrld->preview = NULL; wrld->miststa = 5.0f; @@ -128,12 +116,6 @@ World *BKE_world_add(Main *bmain, const char *name) */ void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag) { - for (int a = 0; a < MAX_MTEX; a++) { - if (wrld_src->mtex[a]) { - wrld_dst->mtex[a] = MEM_dupallocN(wrld_src->mtex[a]); - } - } - if (wrld_src->nodetree) { /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level * (see BKE_libblock_copy_ex()). */ @@ -141,6 +123,7 @@ void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, co } BLI_listbase_clear(&wrld_dst->gpumaterial); + BLI_listbase_clear((ListBase *)&wrld_dst->drawdata); if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id); @@ -167,23 +150,16 @@ World *BKE_world_localize(World *wrld) * ... Once f*** nodes are fully converted to that too :( */ World *wrldn; - int a; wrldn = BKE_libblock_copy_nolib(&wrld->id, false); - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a]) { - wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), __func__); - memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex)); - } - } - if (wrld->nodetree) wrldn->nodetree = ntreeLocalize(wrld->nodetree); wrldn->preview = NULL; BLI_listbase_clear(&wrldn->gpumaterial); + BLI_listbase_clear((ListBase *)&wrldn->drawdata); return wrldn; } @@ -192,3 +168,9 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local) { BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local); } + +void BKE_world_eval(struct Depsgraph *depsgraph, World *world) +{ + DEG_debug_print_eval(depsgraph, __func__, world->id.name, world); + GPU_material_free(&world->gpumaterial); +} diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index 7e989b6588f..a1732b79ea3 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -43,6 +43,7 @@ #include "BLI_utildefines.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" @@ -84,10 +85,6 @@ static void context_free_avi(void *context_v); # include "BKE_writeffmpeg.h" #endif -#ifdef WITH_FRAMESERVER -# include "BKE_writeframeserver.h" -#endif - bMovieHandle *BKE_movie_handle_get(const char imtype) { static bMovieHandle mh = {NULL}; @@ -121,16 +118,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) mh.context_free = BKE_ffmpeg_context_free; } #endif -#ifdef WITH_FRAMESERVER - if (imtype == R_IMF_IMTYPE_FRAMESERVER) { - mh.start_movie = BKE_frameserver_start; - mh.append_movie = BKE_frameserver_append; - mh.end_movie = BKE_frameserver_end; - mh.get_next_frame = BKE_frameserver_loop; - mh.context_create = BKE_frameserver_context_create; - mh.context_free = BKE_frameserver_context_free; - } -#endif /* in case all above are disabled */ (void)imtype; @@ -211,8 +198,6 @@ static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int avi->interlace = 0; avi->odd_fields = 0; -/* avi->interlace = rd->mode & R_FIELDS; */ -/* avi->odd_fields = (rd->mode & R_ODDFIELD) ? 1 : 0; */ printf("Created avi: %s\n", name); return 1; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 68083b499f3..06f11301acb 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -45,8 +45,8 @@ #include "BLI_blenlib.h" #ifdef WITH_AUDASPACE -# include AUD_DEVICE_H -# include AUD_SPECIAL_H +# include <AUD_Device.h> +# include <AUD_Special.h> #endif #include "BLI_utildefines.h" @@ -54,6 +54,7 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_image.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_sound.h" @@ -326,10 +327,6 @@ static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, A frame->pts = cfra; - if (rd->mode & R_FIELDS) { - frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0); - } - ret = avcodec_encode_video2(c, &packet, frame, &got_output); if (ret >= 0 && got_output) { @@ -611,14 +608,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int } } -#if 0 - /* this options are not set in ffmpeg.c and leads to artifacts with MPEG-4 - * see #33586: Encoding to mpeg4 makes first frame(s) blocky - */ - c->rc_initial_buffer_occupancy = rd->ffcodecdata.rc_buffer_size * 3 / 4; - c->rc_buffer_aggressivity = 1.0; -#endif - /* Deprecated and not doing anything since July 2015, deleted in recent ffmpeg */ //c->me_method = ME_EPZS; @@ -674,25 +663,11 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int } } - if ((of->oformat->flags & AVFMT_GLOBALHEADER) -#if 0 - || STREQ(of->oformat->name, "mp4") - || STREQ(of->oformat->name, "mov") - || STREQ(of->oformat->name, "3gp") -#endif - ) - { + if ((of->oformat->flags & AVFMT_GLOBALHEADER)) { PRINT("Using global header\n"); c->flags |= CODEC_FLAG_GLOBAL_HEADER; } - /* Determine whether we are encoding interlaced material or not */ - if (rd->mode & R_FIELDS) { - PRINT("Encoding interlaced video\n"); - c->flags |= CODEC_FLAG_INTERLACED_DCT; - c->flags |= CODEC_FLAG_INTERLACED_ME; - } - /* xasp & yasp got float lately... */ st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255); @@ -1306,12 +1281,6 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) { PRINT("Closing ffmpeg...\n"); -#if 0 - if (context->audio_stream) { /* SEE UPPER */ - write_audio_frames(context); - } -#endif - #ifdef WITH_AUDASPACE if (is_autosplit == false) { if (context->audio_mixdown_device) { diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c deleted file mode 100644 index ebd6de6009e..00000000000 --- a/source/blender/blenkernel/intern/writeframeserver.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * ***** 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. - * - * Copyright (c) 2006 Peter Schlaile - * - * Contributor(s): - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/blenkernel/intern/writeframeserver.c - * \ingroup bke - * - * Frameserver - * Makes Blender accessible from TMPGenc directly using VFAPI (you can - * use firefox too ;-) - */ - -#ifdef WITH_FRAMESERVER - -#include <string.h> -#include <stdio.h> - -#if defined(_WIN32) -#include <winsock2.h> -#include <windows.h> -#include <winbase.h> -#include <direct.h> -#else -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <net/if.h> -#include <netdb.h> -#include <sys/ioctl.h> -#include <errno.h> -#include <unistd.h> -#include <sys/un.h> -#include <fcntl.h> -#endif - -#include <stdlib.h> - -#include "DNA_userdef_types.h" - -#include "BLI_utildefines.h" - -#include "BKE_writeframeserver.h" -#include "BKE_global.h" -#include "BKE_report.h" - -#include "DNA_scene_types.h" -#include "MEM_guardedalloc.h" - -typedef struct FrameserverContext { - int sock; - int connsock; - int write_ppm; - int render_width; - int render_height; -} FrameserverContext; - - -#if defined(_WIN32) -static int startup_socket_system(void) -{ - WSADATA wsa; - return (WSAStartup(MAKEWORD(2, 0), &wsa) == 0); -} - -static void shutdown_socket_system(void) -{ - WSACleanup(); -} -static int select_was_interrupted_by_signal(void) -{ - return (WSAGetLastError() == WSAEINTR); -} -#else -static int startup_socket_system(void) -{ - return 1; -} - -static void shutdown_socket_system(void) -{ -} - -static int select_was_interrupted_by_signal(void) -{ - return (errno == EINTR); -} - -static int closesocket(int fd) -{ - return close(fd); -} -#endif - -int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix)) -{ - struct sockaddr_in addr; - int arg = 1; - FrameserverContext *context = context_v; - - (void)scene; /* unused */ - - if (!startup_socket_system()) { - BKE_report(reports, RPT_ERROR, "Cannot startup socket system"); - return 0; - } - - if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - shutdown_socket_system(); - BKE_report(reports, RPT_ERROR, "Cannot open socket"); - return 0; - } - - setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(U.frameserverport); - addr.sin_addr.s_addr = INADDR_ANY; - - if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - shutdown_socket_system(); - BKE_report(reports, RPT_ERROR, "Cannot bind to socket"); - return 0; - } - - if (listen(context->sock, SOMAXCONN) < 0) { - shutdown_socket_system(); - BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog"); - return 0; - } - context->connsock = -1; - - context->render_width = rectx; - context->render_height = recty; - - return 1; -} - -static char index_page[] = -"HTTP/1.1 200 OK\r\n" -"Content-Type: text/html\r\n" -"\r\n" -"<html><head><title>Blender Frameserver</title></head>\n" -"<body><pre>\n" -"<H2>Blender Frameserver</H2>\n" -"<A HREF=info.txt>Render Info</A><br>\n" -"<A HREF=close.txt>Stop Rendering</A><br>\n" -"\n" -"Images can be found here\n" -"\n" -"images/ppm/%d.ppm\n" -"\n" -"</pre></body></html>\n"; - -static char good_bye[] = -"HTTP/1.1 200 OK\r\n" -"Content-Type: text/html\r\n" -"\r\n" -"<html><head><title>Blender Frameserver</title></head>\n" -"<body><pre>\n" -"Render stopped. Goodbye</pre></body></html>"; - -static int safe_write(const int connsock, char *s, int tosend) -{ - int total = tosend; - do { - int got = send(connsock, s, tosend, 0); - if (got < 0) { - return got; - } - tosend -= got; - s += got; - } while (tosend > 0); - - return total; -} - -static int safe_puts(const int connsock, char *s) -{ - return safe_write(connsock, s, strlen(s)); -} - -static int handle_request(FrameserverContext *context, RenderData *rd, char *req) -{ - char *p; - char *path; - int pathlen; - - if (memcmp(req, "GET ", 4) != 0) { - return -1; - } - - p = req + 4; - path = p; - - while (*p != ' ' && *p) p++; - - *p = 0; - - if (STREQ(path, "/index.html") || STREQ(path, "/")) { - safe_puts(context->connsock, index_page); - return -1; - } - - context->write_ppm = 0; - pathlen = strlen(path); - - if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) { - context->write_ppm = 1; - return atoi(path + 12); - } - if (STREQ(path, "/info.txt")) { - char buf[4096]; - - sprintf(buf, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "\r\n" - "start %d\n" - "end %d\n" - "width %d\n" - "height %d\n" - "rate %d\n" - "ratescale %d\n", - rd->sfra, - rd->efra, - context->render_width, - context->render_height, - rd->frs_sec, - 1 - ); - - safe_puts(context->connsock, buf); - return -1; - } - if (STREQ(path, "/close.txt")) { - safe_puts(context->connsock, good_bye); - G.is_break = true; /* Abort render */ - return -1; - } - return -1; -} - -int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports)) -{ - fd_set readfds; - struct timeval tv; - struct sockaddr_in addr; - int len, rval; - unsigned int socklen; - char buf[4096]; - - FrameserverContext *context = context_v; - - if (context->connsock != -1) { - closesocket(context->connsock); - context->connsock = -1; - } - - tv.tv_sec = 1; - tv.tv_usec = 0; - - FD_ZERO(&readfds); - FD_SET(context->sock, &readfds); - - rval = select(context->sock + 1, &readfds, NULL, NULL, &tv); - if (rval < 0) { - return -1; - } - - if (rval == 0) { /* nothing to be done */ - return -1; - } - - socklen = sizeof(addr); - - if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) { - return -1; - } - - FD_ZERO(&readfds); - FD_SET(context->connsock, &readfds); - - for (;;) { - /* give 10 seconds for telnet testing... */ - tv.tv_sec = 10; - tv.tv_usec = 0; - - rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv); - if (rval > 0) { - break; - } - else if (rval == 0) { - return -1; - } - else if (rval < 0) { - if (!select_was_interrupted_by_signal()) { - return -1; - } - } - } - - len = recv(context->connsock, buf, sizeof(buf) - 1, 0); - - if (len < 0) { - return -1; - } - - buf[len] = 0; - - return handle_request(context, rd, buf); -} - -static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty) -{ - unsigned char *rendered_frame; - unsigned char *row = (unsigned char *) malloc(context->render_width * 3); - int y; - char header[1024]; - - sprintf(header, - "HTTP/1.1 200 OK\r\n" - "Content-Type: image/ppm\r\n" - "Connection: close\r\n" - "\r\n" - "P6\n" - "# Creator: blender frameserver v0.0.1\n" - "%d %d\n" - "255\n", - rectx, recty); - - safe_puts(context->connsock, header); - - rendered_frame = (unsigned char *)pixels; - - for (y = recty - 1; y >= 0; y--) { - unsigned char *target = row; - unsigned char *src = rendered_frame + rectx * 4 * y; - unsigned char *end = src + rectx * 4; - while (src != end) { - target[2] = src[2]; - target[1] = src[1]; - target[0] = src[0]; - - target += 3; - src += 4; - } - safe_write(context->connsock, (char *)row, 3 * rectx); - } - free(row); - closesocket(context->connsock); - context->connsock = -1; -} - -int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels, - int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports)) -{ - FrameserverContext *context = context_v; - - fprintf(stderr, "Serving frame: %d\n", frame); - if (context->write_ppm) { - serve_ppm(context, pixels, rectx, recty); - } - if (context->connsock != -1) { - closesocket(context->connsock); - context->connsock = -1; - } - - return 1; -} - -void BKE_frameserver_end(void *context_v) -{ - FrameserverContext *context = context_v; - - if (context->connsock != -1) { - closesocket(context->connsock); - context->connsock = -1; - } - closesocket(context->sock); - shutdown_socket_system(); -} - -void *BKE_frameserver_context_create(void) -{ - FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context"); - return context; -} - -void BKE_frameserver_context_free(void *context_v) -{ - FrameserverContext *context = context_v; - if (context) { - MEM_freeN(context); - } -} - -#endif /* WITH_FRAMESERVER */ diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h index 71937531dac..67728445f3a 100644 --- a/source/blender/blenkernel/nla_private.h +++ b/source/blender/blenkernel/nla_private.h @@ -33,6 +33,10 @@ #ifndef __NLA_PRIVATE_H__ #define __NLA_PRIVATE_H__ +struct Depsgraph; + +#include "RNA_types.h" + /* --------------- NLA Evaluation DataTypes ----------------------- */ /* used for list of strips to accumulate at current time */ @@ -66,9 +70,11 @@ enum eNlaEvalStrip_StripMode { typedef struct NlaEvalChannel { struct NlaEvalChannel *next, *prev; - PointerRNA ptr; /* pointer to struct containing property to use */ - PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */ - int index; /* array index (where applicable) */ + /* RNA reference to use with pointer and index */ + PathResolvedRNA rna; + + /* Original parameters used to look up the reference for write_orig_anim_rna */ + const char *rna_path; float value; /* value of this channel */ } NlaEvalChannel; @@ -81,8 +87,8 @@ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode); /* --------------- NLA Evaluation (very-private stuff) ----------------------- */ /* these functions are only defined here to avoid problems with the order in which they get defined... */ -NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime); -void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes); -void nladata_flush_channels(ListBase *channels); +NlaEvalStrip *nlastrips_ctime_get_strip(struct Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime); +void nlastrip_evaluate(struct Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes); +void nladata_flush_channels(struct Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels); #endif /* __NLA_PRIVATE_H__ */ |