diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2012-06-11 00:50:43 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2012-06-11 00:50:43 +0400 |
commit | 8135cc9f954e0d63ab3e97d4a7c52ff5e573eef0 (patch) | |
tree | a12ec0daccfc45b7e3c68e4a2d7099655daf619d /source/blender/blenkernel | |
parent | 0f33d5719fd0adc666e7e92e0f062281f4285f13 (diff) | |
parent | 298feff39006c14aa28b5e0232aa7ed70a83a496 (diff) |
Merged changes in the trunk up to revision 47700.
Conflicts resolved:
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/library.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/interface/resources.c
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_action_types.h
source/blender/makesdna/intern/makesdna.c
source/blender/makesrna/SConscript
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_main.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/windowmanager/WM_types.h
Diffstat (limited to 'source/blender/blenkernel')
51 files changed, 3909 insertions, 831 deletions
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 24386730ddb..b833bc44201 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 263 -#define BLENDER_SUBVERSION 8 +#define BLENDER_SUBVERSION 11 #define BLENDER_MINVERSION 250 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 378cc72beb1..bcda970e60c 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -56,7 +56,7 @@ struct CollisionTree; /* Bits to or into the ClothVertex.flags. */ #define CLOTH_VERT_FLAG_PINNED 1 -#define CLOTH_VERT_FLAG_COLLISION 2 +#define CLOTH_VERT_FLAG_NOSELFCOLL 2 /* vertex NOT used for self collisions */ #define CLOTH_VERT_FLAG_PINNED_EM 3 /** @@ -69,8 +69,7 @@ struct CollisionTree; * own connectivity of the mesh based on the actual edges in the mesh. * */ -typedef struct Cloth -{ +typedef struct Cloth { struct ClothVertex *verts; /* The vertices that represent this cloth. */ struct LinkNode *springs; /* The springs connecting the mesh. */ unsigned int numverts; /* The number of verts == m * n. */ @@ -91,8 +90,7 @@ typedef struct Cloth /** * The definition of a cloth vertex. */ -typedef struct ClothVertex -{ +typedef struct ClothVertex { int flags; /* General flags per vertex. */ float v[3]; /* The velocity of the point. */ float xconst[3]; /* constrained position */ @@ -117,8 +115,7 @@ ClothVertex; /** * The definition of a spring. */ -typedef struct ClothSpring -{ +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. */ float restlen; /* The original length of the spring. */ @@ -149,8 +146,7 @@ ClothSpring; /* SIMULATION FLAGS: goal flags,.. */ /* These are the bits used in SimSettings.flags. */ -typedef enum -{ +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_TEARING = ( 1 << 4 ),// true if tearing is enabled @@ -160,15 +156,13 @@ typedef enum } CLOTH_SIMSETTINGS_FLAGS; /* COLLISION FLAGS */ -typedef enum -{ +typedef enum { CLOTH_COLLSETTINGS_FLAG_ENABLED = ( 1 << 1 ), /* enables cloth - object collisions */ CLOTH_COLLSETTINGS_FLAG_SELF = ( 1 << 2 ), /* enables selfcollisions */ } CLOTH_COLLISIONSETTINGS_FLAGS; /* Spring types as defined in the paper.*/ -typedef enum -{ +typedef enum { CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1), CLOTH_SPRING_TYPE_SHEAR = (1 << 2), CLOTH_SPRING_TYPE_BENDING = (1 << 3), @@ -176,8 +170,7 @@ typedef enum } CLOTH_SPRING_TYPES; /* SPRING FLAGS */ -typedef enum -{ +typedef enum { CLOTH_SPRING_FLAG_DEACTIVATE = ( 1 << 1 ), CLOTH_SPRING_FLAG_NEEDED = ( 1 << 2 ), // springs has values to be applied } CLOTH_SPRINGS_FLAGS; @@ -230,16 +223,14 @@ int cloth_add_spring (struct ClothModifierData *clmd, unsigned int indexA, unsig /* This enum provides the IDs for our solvers. */ // only one available in the moment -typedef enum -{ +typedef enum { CM_IMPLICIT = 0, } CM_SOLVER_ID; /* This structure defines how to call the solver. */ -typedef struct -{ +typedef struct { const char *name; CM_SOLVER_ID id; int ( *init ) (struct Object *ob, struct ClothModifierData *clmd ); diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 191056571c0..ec257a2f394 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -59,8 +59,7 @@ struct LinkNode; //////////////////////////////////////// /* COLLISION FLAGS */ -typedef enum -{ +typedef enum { COLLISION_IN_FUTURE = (1 << 1), #ifdef WITH_ELTOPO COLLISION_USE_COLLFACE = (1 << 2), diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 23df246b430..7a1172335d8 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -260,6 +260,7 @@ struct Image *CTX_data_edit_image(const bContext *C); struct Text *CTX_data_edit_text(const bContext *C); struct MovieClip *CTX_data_edit_movieclip(const bContext *C); +struct Mask *CTX_data_edit_mask(const bContext *C); int CTX_data_selected_nodes(const bContext *C, ListBase *list); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index bbe68db8bfe..3dc68edf12b 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -321,6 +321,7 @@ 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_bmesh_init_pool(struct CustomData *data, int totelem, const char htype); /* External file storage */ diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 134ec1acd8e..f3223fb4af1 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -57,6 +57,7 @@ struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd); void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); +struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe); struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, short addnew); void gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf); struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 91e3e9edbf0..baa530c0599 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -44,6 +44,7 @@ struct anim; struct Scene; struct Object; struct ImageFormatData; +struct Main; /* call from library */ void BKE_image_free(struct Image *me); @@ -143,6 +144,9 @@ struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf); /* for reload, refresh, pack */ void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal); +void BKE_image_walk_all_users(const struct Main *mainp, void *customdata, + void callback(struct Image *ima, struct ImageUser *iuser, void *customdata)); + /* ensures an Image exists for viewing nodes or render */ struct Image *BKE_image_verify_viewer(int type, const char *name); @@ -151,7 +155,9 @@ void BKE_image_assign_ibuf(struct Image *ima, struct ImBuf *ibuf); /* 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); +void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path); /* sets index offset for multilayer files */ struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 3a19d6c9007..3248944dae8 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -66,7 +66,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id); struct ListBase *which_libbase(struct Main *mainlib, short type); -#define MAX_LIBARRAY 40 +#define MAX_LIBARRAY 41 int set_listbasepointers(struct Main *main, struct ListBase **lb); void BKE_libblock_free(struct ListBase *lb, void *idv); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 043d0a9886d..ad5541a5a2f 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -86,6 +86,7 @@ typedef struct Main { ListBase wm; ListBase gpencil; ListBase movieclip; + ListBase mask; ListBase linestyle; char id_tag_update[256]; diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h new file mode 100644 index 00000000000..ec2eb82a9eb --- /dev/null +++ b/source/blender/blenkernel/BKE_mask.h @@ -0,0 +1,186 @@ +/* + * ***** 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) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_MASK_H__ +#define __BKE_MASK_H__ + +struct Main; +struct Mask; +struct MaskParent; +struct MaskLayer; +struct MaskLayerShape; +struct MaskSpline; +struct MaskSplinePoint; +struct MaskSplinePointUW; +struct MovieClip; +struct MovieClipUser; +struct Scene; + +struct MaskSplinePoint *BKE_mask_spline_point_array(struct MaskSpline *spline); +struct MaskSplinePoint *BKE_mask_spline_point_array_from_point(struct MaskSpline *spline, struct MaskSplinePoint *point_ref); + +/* mask layers */ +struct MaskLayer *BKE_mask_layer_new(struct Mask *mask, const char *name); +struct MaskLayer *BKE_mask_layer_active(struct Mask *mask); +void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay); +void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay); + +void BKE_mask_layer_free(struct MaskLayer *masklay); +void BKE_mask_spline_free(struct MaskSpline *spline); +struct MaskSpline *BKE_mask_spline_copy(struct MaskSpline *spline); +void BKE_mask_point_free(struct MaskSplinePoint *point); + +void BKE_mask_layer_unique_name(struct Mask *mask, struct MaskLayer *masklay); + +/* splines */ +struct MaskSpline *BKE_mask_spline_add(struct MaskLayer *masklay); + +float (*BKE_mask_spline_differentiate(struct MaskSpline *spline, int *tot_diff_point))[2]; +float (*BKE_mask_spline_feather_differentiated_points(struct MaskSpline *spline, int *tot_feather_point))[2]; + +float (*BKE_mask_spline_differentiate_with_resolution(struct MaskSpline *spline, int width, int height, int *tot_diff_point))[2]; +float (*BKE_mask_spline_feather_differentiated_points_with_resolution(struct MaskSpline *spline, + int width, int height, int *tot_feather_point))[2]; + +float (*BKE_mask_spline_feather_points(struct MaskSpline *spline, int *tot_feather_point))[2]; + +void BKE_mask_point_direction_switch(struct MaskSplinePoint *point); +void BKE_mask_spline_direction_switch(struct MaskLayer *masklay, struct MaskSpline *spline); + +typedef enum { + MASK_PROJ_NEG = -1, + MASK_PROJ_ANY = 0, + MASK_PROJ_POS = 1 +} eMaskSign; +float BKE_mask_spline_project_co(struct MaskSpline *spline, struct MaskSplinePoint *point, + float start_u, const float co[2], const eMaskSign sign); + +/* point */ +int BKE_mask_point_has_handle(struct MaskSplinePoint *point); +void BKE_mask_point_handle(struct MaskSplinePoint *point, float handle[2]); +void BKE_mask_point_set_handle(struct MaskSplinePoint *point, float loc[2], int keep_direction, + float orig_handle[2], float orig_vec[3][3]); + +float *BKE_mask_point_segment_diff(struct MaskSpline *spline, struct MaskSplinePoint *point, int *tot_diff_point); +float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline, struct MaskSplinePoint *point, + int *tot_feather_point); + +float *BKE_mask_point_segment_diff_with_resolution(struct MaskSpline *spline, struct MaskSplinePoint *point, + int width, int height, int *tot_diff_point); + +float *BKE_mask_point_segment_feather_diff_with_resolution(struct MaskSpline *spline, struct MaskSplinePoint *point, + int width, int height, + int *tot_feather_point); + +void BKE_mask_point_segment_co(struct MaskSpline *spline, struct MaskSplinePoint *point, float u, float co[2]); +void BKE_mask_point_normal(struct MaskSpline *spline, struct MaskSplinePoint *point, + float u, float n[2]); +float BKE_mask_point_weight_scalar(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u); +float BKE_mask_point_weight(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u); +struct MaskSplinePointUW *BKE_mask_point_sort_uw(struct MaskSplinePoint *point, struct MaskSplinePointUW *uw); +void BKE_mask_point_add_uw(struct MaskSplinePoint *point, float u, float w); + +void BKE_mask_point_select_set(struct MaskSplinePoint *point, const short do_select); +void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const short do_select); + +/* general */ +struct Mask *BKE_mask_new(const char *name); + +void BKE_mask_free(struct Mask *mask); +void BKE_mask_unlink(struct Main *bmain, struct Mask *mask); + +void BKE_mask_coord_from_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2]); +void BKE_mask_coord_to_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2]); + +/* parenting */ + +void BKE_mask_update_display(struct Mask *mask, float ctime); + +void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const int do_newframe); +void BKE_mask_evaluate(struct Mask *mask, const float ctime, const int do_newframe); +void BKE_mask_update_scene(struct Main *bmain, struct Scene *scene, const int do_newframe); +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]); +void BKE_mask_calc_handle_point(struct MaskSpline *spline, struct MaskSplinePoint *point); +void BKE_mask_calc_handle_point_auto(struct MaskSpline *spline, struct MaskSplinePoint *point, + const short do_recalc_length); +void BKE_mask_get_handle_point_adjacent(struct MaskSpline *spline, struct MaskSplinePoint *point, + struct MaskSplinePoint **r_point_prev, struct MaskSplinePoint **r_point_next); +void BKE_mask_layer_calc_handles(struct MaskLayer *masklay); +void BKE_mask_layer_calc_handles_deform(struct MaskLayer *masklay); +void BKE_mask_calc_handles(struct Mask *mask); +void BKE_mask_calc_handles_deform(struct Mask *mask); +void BKE_mask_spline_ensure_deform(struct MaskSpline *spline); + +/* animation */ +int BKE_mask_layer_shape_totvert(struct MaskLayer *masklay); +void BKE_mask_layer_shape_from_mask(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape); +void BKE_mask_layer_shape_to_mask(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape); +void BKE_mask_layer_shape_to_mask_interp(struct MaskLayer *masklay, + struct MaskLayerShape *masklay_shape_a, + struct MaskLayerShape *masklay_shape_b, + const float fac); +struct MaskLayerShape *BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, const int frame); +int BKE_mask_layer_shape_find_frame_range(struct MaskLayer *masklay, const float frame, + struct MaskLayerShape **r_masklay_shape_a, + struct MaskLayerShape **r_masklay_shape_b); +struct MaskLayerShape *BKE_mask_layer_shape_alloc(struct MaskLayer *masklay, const int frame); +void BKE_mask_layer_shape_free(struct MaskLayerShape *masklay_shape); +struct MaskLayerShape *BKE_mask_layer_shape_varify_frame(struct MaskLayer *masklay, const int frame); +struct MaskLayerShape *BKE_mask_layer_shape_duplicate(struct MaskLayerShape *masklay_shape); +void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape); +void BKE_mask_layer_shape_sort(struct MaskLayer *masklay); + +int BKE_mask_layer_shape_spline_from_index(struct MaskLayer *masklay, int index, + struct MaskSpline **r_masklay_shape, int *r_index); +int BKE_mask_layer_shape_spline_to_index(struct MaskLayer *masklay, struct MaskSpline *spline); + +int BKE_mask_layer_shape_spline_index(struct MaskLayer *masklay, int index, + struct MaskSpline **r_masklay_shape, int *r_index); +void BKE_mask_layer_shape_changed_add(struct MaskLayer *masklay, int index, + int do_init, int do_init_interpolate); + +void BKE_mask_layer_shape_changed_remove(struct MaskLayer *masklay, int index, int count); + +/* rasterization */ +int BKE_mask_get_duration(struct Mask *mask); +void BKE_mask_rasterize(struct Mask *mask, int width, int height, float *buffer, + const short do_aspect_correct, const short do_linear); + +#define MASKPOINT_ISSEL_ANY(p) ( ((p)->bezt.f1 | (p)->bezt.f2 | (p)->bezt.f2) & SELECT) +#define MASKPOINT_ISSEL_KNOT(p) ( (p)->bezt.f2 & SELECT) +#define MASKPOINT_ISSEL_HANDLE_ONLY(p) ( (((p)->bezt.f1 | (p)->bezt.f2) & SELECT) && (((p)->bezt.f2 & SELECT) == 0) ) +#define MASKPOINT_ISSEL_HANDLE(p) ( (((p)->bezt.f1 | (p)->bezt.f2) & SELECT) ) + +#define MASKPOINT_SEL_ALL(p) { (p)->bezt.f1 |= SELECT; (p)->bezt.f2 |= SELECT; (p)->bezt.f3 |= SELECT; } (void)0 +#define MASKPOINT_DESEL_ALL(p) { (p)->bezt.f1 &= ~SELECT; (p)->bezt.f2 &= ~SELECT; (p)->bezt.f3 &= ~SELECT; } (void)0 +#define MASKPOINT_INVSEL_ALL(p) { (p)->bezt.f1 ^= SELECT; (p)->bezt.f2 ^= SELECT; (p)->bezt.f3 ^= SELECT; } (void)0 + +#define MASKPOINT_SEL_HANDLE(p) { (p)->bezt.f1 |= SELECT; (p)->bezt.f3 |= SELECT; } (void)0 +#define MASKPOINT_DESEL_HANDLE(p) { (p)->bezt.f1 &= ~SELECT; (p)->bezt.f3 &= ~SELECT; } (void)0 + +#endif diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 7abec074647..887340622ad 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -33,6 +33,7 @@ /***/ +struct ID; struct BoundBox; struct DispList; struct ListBase; @@ -150,6 +151,14 @@ void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); void BKE_mesh_delete_material_index(struct Mesh *me, short index); void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth); void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); +void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh); +void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id, + struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, + int totedge_i, int totface_i, int totloop_i, int totpoly_i, + struct MEdge *medge, struct MFace *mface, + int *totloop_r, int *totpoly_r, + struct MLoop **mloop_r, struct MPoly **mpoly_r); + void BKE_mesh_calc_normals_tessface(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]); /* used for unit testing; compares two meshes, checking only diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index 15b3cb91b90..221ae99a0ec 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -63,6 +63,9 @@ void BKE_movieclip_get_cache_segments(struct MovieClip *clip, struct MovieClipUs void BKE_movieclip_build_proxy_frame(struct MovieClip *clip, int clip_flag, struct MovieDistortion *distortion, int cfra, int *build_sizes, int build_count, int undistorted); +int BKE_movieclip_remap_scene_to_clip_frame(struct MovieClip *clip, int framenr); +int BKE_movieclip_remap_clip_to_scene_frame(struct MovieClip *clip, int framenr); + /* cacheing flags */ #define MOVIECLIP_CACHE_SKIP (1 << 0) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index d093c9108b6..b1e5fabc456 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -266,8 +266,7 @@ struct bNodeTreeExec; typedef void (*bNodeTreeCallback)(void *calldata, struct ID *owner_id, struct bNodeTree *ntree); typedef void (*bNodeClassCallback)(void *calldata, int nclass, const char *name); -typedef struct bNodeTreeType -{ +typedef struct bNodeTreeType { int type; /* type identifier */ char idname[64]; /* id name for RNA identification */ @@ -528,6 +527,7 @@ struct ShadeResult; #define SH_NODE_BRIGHTCONTRAST 165 #define SH_NODE_LIGHT_FALLOFF 166 #define SH_NODE_OBJECT_INFO 167 +#define SH_NODE_PARTICLE_INFO 168 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 @@ -658,6 +658,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat); #define CMP_NODE_MOVIEDISTORTION 265 #define CMP_NODE_DOUBLEEDGEMASK 266 #define CMP_NODE_OUTPUT_MULTI_FILE__DEPRECATED 267 /* DEPRECATED multi file node has been merged into regular CMP_NODE_OUTPUT_FILE */ +#define CMP_NODE_MASK 268 #define CMP_NODE_GLARE 301 #define CMP_NODE_TONEMAP 302 diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index b32b7145ff4..419fb4cedae 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -32,6 +32,7 @@ * \ingroup bke */ +struct bContext; struct Brush; struct MDisps; struct MeshElemMap; @@ -55,6 +56,7 @@ void free_paint(struct Paint *p); void copy_paint(struct Paint *src, struct Paint *tar); struct Paint *paint_get_active(struct Scene *sce); +struct Paint *paint_get_active_from_context(const struct bContext *C); struct Brush *paint_brush(struct Paint *paint); void paint_brush_set(struct Paint *paint, struct Brush *br); diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h index 50ee1184b3e..ed7ce05506d 100644 --- a/source/blender/blenkernel/BKE_sketch.h +++ b/source/blender/blenkernel/BKE_sketch.h @@ -26,14 +26,12 @@ * \ingroup bke */ -typedef enum SK_PType -{ +typedef enum SK_PType { PT_CONTINUOUS, PT_EXACT, } SK_PType; -typedef enum SK_PMode -{ +typedef enum SK_PMode { PT_SNAP, PT_PROJECT, } SK_PMode; diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index 817cb477aba..8c28dd93a5e 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -48,7 +48,7 @@ struct Object; struct Scene; void BKE_tracking_init_settings(struct MovieTracking *tracking); -void BKE_tracking_clamp_track(struct MovieTrackingTrack *track, int event); +void BKE_tracking_clamp_marker(struct MovieTrackingMarker *marker, int event); void BKE_tracking_track_flag(struct MovieTrackingTrack *track, int area, int flag, int clear); struct MovieTrackingTrack *BKE_tracking_add_track(struct MovieTracking *tracking, struct ListBase *tracksbase, @@ -57,6 +57,7 @@ struct MovieTrackingMarker *BKE_tracking_insert_marker(struct MovieTrackingTrack struct MovieTrackingMarker *marker); void BKE_tracking_delete_marker(struct MovieTrackingTrack *track, int framenr); +void BKE_tracking_marker_pattern_minmax(struct MovieTrackingMarker *marker, float min[2], float max[2]); struct MovieTrackingMarker *BKE_tracking_get_marker(struct MovieTrackingTrack *track, int framenr); struct MovieTrackingMarker *BKE_tracking_ensure_marker(struct MovieTrackingTrack *track, int framenr); struct MovieTrackingMarker *BKE_tracking_exact_marker(struct MovieTrackingTrack *track, int framenr); @@ -70,12 +71,15 @@ void BKE_tracking_clear_path(struct MovieTrackingTrack *track, int ref_frame, in void BKE_tracking_join_tracks(struct MovieTrackingTrack *dst_track, struct MovieTrackingTrack *src_track); void BKE_tracking_free(struct MovieTracking *tracking); +struct ImBuf *BKE_tracking_sample_pattern_imbuf(int frame_width, int frame_height, + struct ImBuf *struct_ibuf, struct MovieTrackingMarker *marker, + int num_samples_x, int num_samples_y, float pos[2]); struct ImBuf *BKE_tracking_get_pattern_imbuf(struct ImBuf *ibuf, struct MovieTrackingTrack *track, - struct MovieTrackingMarker *marker, int margin, int anchored, - float pos[2], int origin[2]); + struct MovieTrackingMarker *marker, int anchored, int disable_channels); struct ImBuf *BKE_tracking_get_search_imbuf(struct ImBuf *ibuf, struct MovieTrackingTrack *track, - struct MovieTrackingMarker *marker, int margin, int anchored, - float pos[2], int origin[2]); + struct MovieTrackingMarker *marker, int anchored, int disable_channels); +struct ImBuf *BKE_tracking_track_mask_get(struct MovieTracking *tracking, struct MovieTrackingTrack *track, + struct MovieTrackingMarker *marker, int width, int height); void BKE_track_unique_name(struct ListBase *tracksbase, struct MovieTrackingTrack *track); @@ -189,7 +193,6 @@ void BKE_tracking_dopesheet_update(struct MovieTracking *tracking, int sort_meth #define CLAMP_PAT_POS 2 #define CLAMP_SEARCH_DIM 3 #define CLAMP_SEARCH_POS 4 -#define CLAMP_PYRAMID_LEVELS 5 #define TRACK_AREA_NONE -1 #define TRACK_AREA_POINT 1 @@ -202,5 +205,6 @@ void BKE_tracking_dopesheet_update(struct MovieTracking *tracking, int sort_meth #define TRACK_SORT_NAME 0 #define TRACK_SORT_LONGEST 1 #define TRACK_SORT_TOTAL 2 +#define TRACK_SORT_AVERAGE_ERROR 3 #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index baa714c9de4..558db1c8742 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -44,6 +44,7 @@ set(INC ../../../intern/memutil ../../../intern/mikktspace ../../../intern/opennl/extern + ../../../intern/raskter # XXX - BAD LEVEL CALL WM_api.h ../windowmanager @@ -102,6 +103,7 @@ set(SRC intern/lattice.c intern/library.c intern/linestyle.c + intern/mask.c intern/material.c intern/mball.c intern/mesh.c @@ -190,6 +192,7 @@ set(SRC BKE_lattice.h BKE_library.h BKE_linestyle.h + BKE_mask.h BKE_main.h BKE_material.h BKE_mball.h diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 61ef30d5149..819632414d9 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -17,6 +17,7 @@ incs += ' #/intern/smoke/extern' incs += ' #/intern/mikktspace' incs += ' #/intern/audaspace/intern' incs += ' #/intern/ffmpeg' +incs += ' #/intern/raskter' incs += ' ' + env['BF_OPENGL_INC'] incs += ' ' + env['BF_ZLIB_INC'] diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index f73221066b1..170638f0e8d 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -75,7 +75,7 @@ /* --------------------- */ /* forward declarations */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated); +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, int level, int animated); /* ******************************************************************** */ /* Animation Visualisation */ @@ -699,7 +699,7 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua /* ******************************************************************** */ /* Dupli-Geometry */ -static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int type, int animated) +static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int par_index, int type, int animated) { DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupliobject"); @@ -709,6 +709,7 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i copy_m4_m4(dob->omat, ob->obmat); dob->origlay = ob->lay; dob->index = index; + dob->particle_index = par_index; dob->type = type; dob->animated = (type == OB_DUPLIGROUP) && animated; ob->lay = lay; @@ -716,7 +717,7 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i return dob; } -static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) +static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, int animated) { DupliObject *dob; Group *group; @@ -748,7 +749,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, i mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } - dob = new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP, animated); + dob = new_dupli_object(lb, go->ob, mat, ob->lay, 0, par_index, OB_DUPLIGROUP, animated); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ((dob->origlay & group->layer) == 0 || @@ -763,14 +764,14 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, i if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); - object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, level + 1, animated); + object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, par_index, level + 1, animated); copy_m4_m4(dob->ob->obmat, dob->omat); } } } } -static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) +static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, int animated) { extern int enable_cu_speed; /* object.c */ Object copyob; @@ -818,7 +819,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, 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); - dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, OB_DUPLIFRAMES, animated); + dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, par_index, OB_DUPLIFRAMES, animated); copy_m4_m4(dob->omat, copyob.obmat); } } @@ -839,7 +840,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, *ob = copyob; } -typedef struct vertexDupliData { +typedef struct VertexDupliData { ID *id; /* scene or group, for recursive loops */ int level; int animated; @@ -849,7 +850,8 @@ typedef struct vertexDupliData { Scene *scene; Object *ob, *par; float (*orco)[3]; -} vertexDupliData; + int par_index; +} VertexDupliData; /* ------------- */ @@ -857,7 +859,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) { DupliObject *dob; - vertexDupliData *vdd = userData; + VertexDupliData *vdd = userData; float vec[3], q2[4], mat[3][3], tmat[4][4], obmat[4][4]; int origlay; @@ -885,7 +887,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], origlay = vdd->ob->lay; - dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, OB_DUPLIVERTS, vdd->animated); + dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, vdd->par_index, OB_DUPLIVERTS, vdd->animated); /* restore the original layer so that each dupli will have proper dob->origlay */ vdd->ob->lay = origlay; @@ -897,18 +899,18 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], float tmpmat[4][4]; copy_m4_m4(tmpmat, vdd->ob->obmat); copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->level + 1, vdd->animated); + object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->par_index, vdd->level + 1, vdd->animated); copy_m4_m4(vdd->ob->obmat, tmpmat); } } -static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) +static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, int level, int animated) { Object *ob, *ob_iter; Mesh *me = par->data; Base *base = NULL; DerivedMesh *dm; - vertexDupliData vdd; + VertexDupliData vdd; Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; @@ -986,6 +988,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl vdd.scene = scene; vdd.par = par; copy_m4_m4(vdd.pmat, pmat); + vdd.par_index = par_index; /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ @@ -1024,7 +1027,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl dm->release(dm); } -static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) +static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; @@ -1171,7 +1174,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); - dob = new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated); + dob = new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIFACES, animated); if (G.rendering) { w = 1.0f / (float)mp->totloop; @@ -1194,7 +1197,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level + 1, animated); + object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, par_index, level + 1, animated); copy_m4_m4(ob->obmat, tmpmat); } } @@ -1214,7 +1217,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa dm->release(dm); } -static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) +static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int UNUSED(par_index), ParticleSystem *psys, int level, int animated) { GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; @@ -1228,7 +1231,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4], (*oldobmat)[4]; - int a, b, counter, hair = 0; + int a, b, counter, index, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; @@ -1342,6 +1345,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else a = totpart; + index = 0; for (pa = psys->particles, counter = 0; a < totpart + totchild; a++, pa++, counter++) { if (a < totpart) { /* handle parent particle */ @@ -1437,7 +1441,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else copy_m4_m4(mat, tmat); - dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated); + dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, index, OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, obcopylist[b].obmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); @@ -1479,11 +1483,14 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); - dob = new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); + dob = new_dupli_object(lb, ob, mat, ob->lay, counter, index, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, oldobmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } + + /* only counts visible particles */ + ++index; } /* restore objects since they were changed in BKE_object_where_is_calc_time */ @@ -1530,7 +1537,7 @@ static Object *find_family_object(Object **obar, char *family, char ch) } -static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, int animated) +static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_index, int level, int animated) { Object *ob, *obar[256] = {NULL}; Curve *cu; @@ -1569,7 +1576,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, i copy_m4_m4(obmat, par->obmat); copy_v3_v3(obmat[3], vec); - new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIVERTS, animated); + new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIVERTS, animated); } } @@ -1578,7 +1585,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, i /* ------------- */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated) +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, int level, int animated) { if ((ob->transflag & OB_DUPLI) == 0) return; @@ -1598,31 +1605,31 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas if (ob->transflag & OB_DUPLIPARTS) { ParticleSystem *psys = ob->particlesystem.first; for (; psys; psys = psys->next) - new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, psys, level + 1, animated); + new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, psys, level + 1, animated); } else if (ob->transflag & OB_DUPLIVERTS) { if (ob->type == OB_MESH) { - vertex_duplilist(duplilist, id, scene, ob, par_space_mat, level + 1, animated); + vertex_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated); } else if (ob->type == OB_FONT) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - font_duplilist(duplilist, scene, ob, level + 1, animated); + font_duplilist(duplilist, scene, ob, par_index, level + 1, animated); } } } else if (ob->transflag & OB_DUPLIFACES) { if (ob->type == OB_MESH) - face_duplilist(duplilist, id, scene, ob, par_space_mat, level + 1, animated); + face_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated); } else if (ob->transflag & OB_DUPLIFRAMES) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - frames_duplilist(duplilist, scene, ob, level + 1, animated); + frames_duplilist(duplilist, scene, ob, par_index, level + 1, animated); } } else if (ob->transflag & OB_DUPLIGROUP) { DupliObject *dob; - group_duplilist(duplilist, scene, ob, level + 1, animated); /* now recursive */ + group_duplilist(duplilist, scene, ob, par_index, level + 1, animated); /* now recursive */ if (level == 0) { for (dob = duplilist->first; dob; dob = dob->next) @@ -1638,7 +1645,7 @@ ListBase *object_duplilist(Scene *sce, Object *ob) { ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist"); duplilist->first = duplilist->last = NULL; - object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0); + object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0, 0); return duplilist; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index b042c0091d7..ec2b8a04c9a 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -91,6 +91,7 @@ short id_type_can_have_animdata(ID *id) case ID_SPK: case ID_SCE: case ID_MC: + case ID_MSK: { return 1; } @@ -803,10 +804,13 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u /* objects */ ANIMDATA_IDS_CB(mainptr->object.first); + + /* masks */ + ANIMDATA_IDS_CB(mainptr->mask.first); /* worlds */ ANIMDATA_IDS_CB(mainptr->world.first); - + /* scenes */ ANIMDATA_NODETREE_IDS_CB(mainptr->scene.first, Scene); @@ -890,6 +894,9 @@ void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const cha /* objects */ RENAMEFIX_ANIM_IDS(mainptr->object.first); + + /* masks */ + RENAMEFIX_ANIM_IDS(mainptr->mask.first); /* worlds */ RENAMEFIX_ANIM_IDS(mainptr->world.first); @@ -2360,6 +2367,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) * linked from other (not-visible) scenes will not need their data calculated. */ EVAL_ANIM_IDS(main->object.first, 0); + + /* masks */ + EVAL_ANIM_IDS(main->mask.first, ADT_RECALC_ANIM); /* worlds */ EVAL_ANIM_NODETREE_IDS(main->world.first, World, ADT_RECALC_ANIM); diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 4e6a4b4a43c..e5e73061d52 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -2594,94 +2594,15 @@ MPoly *CDDM_get_polys(DerivedMesh *dm) void CDDM_tessfaces_to_faces(DerivedMesh *dm) { - /*converts mfaces to mpolys/mloops*/ + /* converts mfaces to mpolys/mloops */ CDDerivedMesh *cddm = (CDDerivedMesh *)dm; - MFace *mf; - MEdge *me; - EdgeHash *eh = BLI_edgehash_new(); - int i, totloop; - /* ... on second thaughts, better comment this and assume caller knows edge state. */ -#if 0 - /* ensure we have all the edges we need */ - CDDM_calc_edges_tessface(dm); -#else -# ifndef NDEBUG - { - /* ensure we have correct edges on non release builds */ - i = cddm->dm.numEdgeData; - CDDM_calc_edges_tessface(dm); - BLI_assert(cddm->dm.numEdgeData == i); - } -# endif -#endif - - /*build edge hash*/ - me = cddm->medge; - for (i = 0; i < cddm->dm.numEdgeData; i++, me++) { - BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i)); - } - - mf = cddm->mface; - totloop = 0; - for (i = 0; i < cddm->dm.numTessFaceData; i++, mf++) { - totloop += mf->v4 ? 4 : 3; - } - - CustomData_free(&cddm->dm.polyData, cddm->dm.numPolyData); - CustomData_free(&cddm->dm.loopData, cddm->dm.numLoopData); - - cddm->dm.numLoopData = totloop; - cddm->dm.numPolyData = cddm->dm.numTessFaceData; - - if (totloop) { - MLoop *ml; - MPoly *mp; - int l, *polyindex; - - cddm->mloop = MEM_callocN(sizeof(MLoop) * totloop, "cddm->mloop in CDDM_tessfaces_to_faces"); - cddm->mpoly = MEM_callocN(sizeof(MPoly) * cddm->dm.numTessFaceData, "cddm->mpoly in CDDM_tessfaces_to_faces"); - - CustomData_add_layer(&cddm->dm.loopData, CD_MLOOP, CD_ASSIGN, cddm->mloop, totloop); - CustomData_add_layer(&cddm->dm.polyData, CD_MPOLY, CD_ASSIGN, cddm->mpoly, cddm->dm.numPolyData); - CustomData_merge(&cddm->dm.faceData, &cddm->dm.polyData, - CD_MASK_ORIGINDEX, CD_DUPLICATE, cddm->dm.numTessFaceData); - - polyindex = CustomData_get_layer(&cddm->dm.faceData, CD_POLYINDEX); - - mf = cddm->mface; - mp = cddm->mpoly; - ml = cddm->mloop; - l = 0; - for (i = 0; i < cddm->dm.numTessFaceData; i++, mf++, mp++, polyindex++) { - mp->flag = mf->flag; - mp->loopstart = l; - mp->mat_nr = mf->mat_nr; - mp->totloop = mf->v4 ? 4 : 3; - - ml->v = mf->v1; - ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); - ml++, l++; - - ml->v = mf->v2; - ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v2, mf->v3)); - ml++, l++; - - ml->v = mf->v3; - ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v3, mf->v4 ? mf->v4 : mf->v1)); - ml++, l++; - - if (mf->v4) { - ml->v = mf->v4; - ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v4, mf->v1)); - ml++, l++; - } - - *polyindex = i; - } - } - - BLI_edgehash_free(eh, NULL); + 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) diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index e067b7195ce..b681426f8a7 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -143,6 +143,7 @@ void cloth_init(ClothModifierData *clmd ) clmd->coll_parms->collision_list = NULL; clmd->coll_parms->self_loop_count = 1.0; clmd->coll_parms->selfepsilon = 0.75; + clmd->coll_parms->vgroup_selfcol = 0; /* These defaults are copied from softbody.c's * softbody_calc_forces() function. @@ -756,10 +757,12 @@ 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_GOAL ) || + (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_bend>0) || + (clmd->coll_parms->vgroup_selfcol>0))); } /** @@ -815,6 +818,13 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) verts->bend_stiff = dvert->dw [j].weight; } } + + if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) { + if ( dvert->dw[j].def_nr == (clmd->coll_parms->vgroup_selfcol-1)) { + if( dvert->dw [j].weight > 0.0) + verts->flags |= CLOTH_VERT_FLAG_NOSELFCOLL; + } + } /* // for later if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_weight-1)) diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 32e9dd7508b..44f524304d2 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -840,6 +840,10 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData * clmd, float step, flo 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); diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index d15f678f1c5..12dee600532 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -910,7 +910,7 @@ DO_INLINE int get_bin_float(float f) return bin; } -DO_INLINE void save_sample_line(Scopes *scopes, const int idx, const float fx, const float rgb[3], const float ycc[3]) +static void save_sample_line(Scopes *scopes, const int idx, const float fx, const float rgb[3], const float ycc[3]) { float yuv[3]; @@ -953,9 +953,9 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) double div, divl; float *rf = NULL; unsigned char *rc = NULL; - unsigned int *bin_r, *bin_g, *bin_b, *bin_lum; + unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a; int savedlines, saveline; - float rgb[3], ycc[3], luma; + float rgba[4], ycc[3], luma; int ycc_mode = -1; const short is_float = (ibuf->rect_float != NULL); @@ -987,11 +987,12 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) break; } - /* temp table to count pix value for histo */ - bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); - bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); - bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); - bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); + /* temp table to count pix value for histogram */ + bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); + bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); + bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); + bin_a = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); + bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); /* convert to number of lines with logarithmic scale */ scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y; @@ -1038,27 +1039,28 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) if (is_float) { if (use_color_management) - linearrgb_to_srgb_v3_v3(rgb, rf); + linearrgb_to_srgb_v3_v3(rgba, rf); else - copy_v3_v3(rgb, rf); + copy_v3_v3(rgba, rf); + rgba[3] = rf[3]; } else { - for (c = 0; c < 3; c++) - rgb[c] = rc[c] * INV_255; + for (c = 0; c < 4; c++) + rgba[c] = rc[c] * INV_255; } /* we still need luma for histogram */ - luma = rgb_to_luma(rgb); + luma = rgb_to_luma(rgba); /* check for min max */ if (ycc_mode == -1) { for (c = 0; c < 3; c++) { - if (rgb[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgb[c]; - if (rgb[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgb[c]; + if (rgba[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgba[c]; + if (rgba[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgba[c]; } } else { - rgb_to_ycc(rgb[0], rgb[1], rgb[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode); + rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode); for (c = 0; c < 3; c++) { ycc[c] *= INV_255; if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c]; @@ -1066,16 +1068,17 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) } } /* increment count for histo*/ - bin_r[get_bin_float(rgb[0])] += 1; - bin_g[get_bin_float(rgb[1])] += 1; - bin_b[get_bin_float(rgb[2])] += 1; bin_lum[get_bin_float(luma)] += 1; + bin_r[get_bin_float(rgba[0])] += 1; + bin_g[get_bin_float(rgba[1])] += 1; + bin_b[get_bin_float(rgba[2])] += 1; + bin_a[get_bin_float(rgba[3])] += 1; /* save sample if needed */ if (saveline) { const float fx = (float)x / (float)ibuf->x; const int idx = 2 * (ibuf->x * savedlines + x); - save_sample_line(scopes, idx, fx, rgb, ycc); + save_sample_line(scopes, idx, fx, rgba, ycc); } rf += ibuf->channels; @@ -1089,27 +1092,26 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) n = 0; nl = 0; for (x = 0; x < 256; x++) { - if (bin_r[x] > n) - n = bin_r[x]; - if (bin_g[x] > n) - n = bin_g[x]; - if (bin_b[x] > n) - n = bin_b[x]; - if (bin_lum[x] > nl) - nl = bin_lum[x]; + if (bin_lum[x] > nl) nl = bin_lum[x]; + if (bin_r[x] > n) n = bin_r[x]; + if (bin_g[x] > n) n = bin_g[x]; + if (bin_b[x] > n) n = bin_b[x]; + if (bin_a[x] > n) n = bin_a[x]; } div = 1.0 / (double)n; divl = 1.0 / (double)nl; for (x = 0; x < 256; x++) { + scopes->hist.data_luma[x] = bin_lum[x] * divl; scopes->hist.data_r[x] = bin_r[x] * div; scopes->hist.data_g[x] = bin_g[x] * div; scopes->hist.data_b[x] = bin_b[x] * div; - scopes->hist.data_luma[x] = bin_lum[x] * divl; + scopes->hist.data_a[x] = bin_a[x] * div; } + MEM_freeN(bin_lum); MEM_freeN(bin_r); MEM_freeN(bin_g); MEM_freeN(bin_b); - MEM_freeN(bin_lum); + MEM_freeN(bin_a); scopes->ok = 1; } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c6a0ecc057a..0150646a96c 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1460,7 +1460,7 @@ static bConstraintTypeInfo CTI_ROTLIMIT = { rotlimit_evaluate /* evaluate */ }; -/* --------- Limit Scaling --------- */ +/* --------- Limit Scale --------- */ static void sizelimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets)) @@ -1507,7 +1507,7 @@ static void sizelimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *U static bConstraintTypeInfo CTI_SIZELIMIT = { CONSTRAINT_TYPE_SIZELIMIT, /* type */ sizeof(bSizeLimitConstraint), /* size */ - "Limit Scaling", /* name */ + "Limit Scale", /* name */ "bSizeLimitConstraint", /* struct name */ NULL, /* free data */ NULL, /* id looper */ @@ -1721,7 +1721,7 @@ static bConstraintTypeInfo CTI_ROTLIKE = { rotlike_evaluate /* evaluate */ }; -/* ---------- Copy Scaling ---------- */ +/* ---------- Copy Scale ---------- */ static void sizelike_new_data(void *cdata) { @@ -3352,7 +3352,7 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t static bConstraintTypeInfo CTI_TRANSFORM = { CONSTRAINT_TYPE_TRANSFORM, /* type */ sizeof(bTransformConstraint), /* size */ - "Transform", /* name */ + "Transformation", /* name */ "bTransformConstraint", /* struct name */ NULL, /* free data */ transform_id_looper, /* id looper */ @@ -3897,6 +3897,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase MovieTrackingTrack *track; MovieTrackingObject *tracking_object; Object *camob = data->camera ? data->camera : scene->camera; + int framenr; if (data->flag & FOLLOWTRACK_ACTIVECLIP) clip = scene->clip; @@ -3919,6 +3920,8 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase if (!track) return; + framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); + if (data->flag & FOLLOWTRACK_USE_3D_POSITION) { if (track->flag & TRACK_HAS_BUNDLE) { float obmat[4][4], mat[4][4]; @@ -3930,7 +3933,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase copy_m4_m4(mat, camob->obmat); - BKE_tracking_get_interpolated_camera(tracking, tracking_object, scene->r.cfra, imat); + BKE_tracking_get_interpolated_camera(tracking, tracking_object, framenr, imat); invert_m4(imat); mul_serie_m4(cob->matrix, obmat, mat, imat, NULL, NULL, NULL, NULL, NULL); @@ -3969,7 +3972,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase CameraParams params; float pos[2], rmat[4][4]; - marker = BKE_tracking_get_marker(track, scene->r.cfra); + marker = BKE_tracking_get_marker(track, framenr); add_v2_v2v2(pos, marker->pos, track->offset); @@ -4092,8 +4095,9 @@ static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase float mat[4][4], obmat[4][4]; MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object = BKE_tracking_get_camera_object(tracking); + int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); - BKE_tracking_get_interpolated_camera(tracking, object, scene->r.cfra, mat); + BKE_tracking_get_interpolated_camera(tracking, object, framenr, mat); copy_m4_m4(obmat, cob->matrix); @@ -4156,10 +4160,11 @@ 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]; + int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); BKE_object_where_is_calc_mat4(scene, camob, cammat); - BKE_tracking_get_interpolated_camera(tracking, object, scene->r.cfra, mat); + BKE_tracking_get_interpolated_camera(tracking, object, framenr, mat); invert_m4_m4(camimat, cammat); mult_m4_m4m4(parmat, cammat, data->invmat); @@ -4208,10 +4213,10 @@ static void constraints_init_typeinfo(void) constraintsTypeInfo[4] = &CTI_FOLLOWPATH; /* Follow-Path Constraint */ constraintsTypeInfo[5] = &CTI_ROTLIMIT; /* Limit Rotation Constraint */ constraintsTypeInfo[6] = &CTI_LOCLIMIT; /* Limit Location Constraint */ - constraintsTypeInfo[7] = &CTI_SIZELIMIT; /* Limit Scaling Constraint */ + constraintsTypeInfo[7] = &CTI_SIZELIMIT; /* Limit Scale Constraint */ constraintsTypeInfo[8] = &CTI_ROTLIKE; /* Copy Rotation Constraint */ constraintsTypeInfo[9] = &CTI_LOCLIKE; /* Copy Location Constraint */ - constraintsTypeInfo[10] = &CTI_SIZELIKE; /* Copy Scaling Constraint */ + constraintsTypeInfo[10] = &CTI_SIZELIKE; /* Copy Scale Constraint */ constraintsTypeInfo[11] = &CTI_PYTHON; /* Python/Script Constraint */ constraintsTypeInfo[12] = &CTI_ACTION; /* Action Constraint */ constraintsTypeInfo[13] = &CTI_LOCKTRACK; /* Locked-Track Constraint */ diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 3c8f29d8440..ff2dd27e0c9 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -973,6 +973,11 @@ struct MovieClip *CTX_data_edit_movieclip(const bContext *C) return ctx_data_pointer_get(C, "edit_movieclip"); } +struct Mask *CTX_data_edit_mask(const bContext *C) +{ + return ctx_data_pointer_get(C, "edit_mask"); +} + struct EditBone *CTX_data_active_bone(const bContext *C) { return ctx_data_pointer_get(C, "active_bone"); diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 5dc50dca45a..f551b2d18a4 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -2219,6 +2219,48 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, } } +/* update active indices for active/render/clone/stencil custom data layers + * based on indices from fdata layers + * 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) +{ + 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); + } + + if (CustomData_has_layer(fdata, CD_MCOL)) { + act = CustomData_get_active_layer(fdata, CD_MCOL); + CustomData_set_layer_active(ldata, CD_MLOOPCOL, act); + + act = CustomData_get_render_layer(fdata, CD_MCOL); + CustomData_set_layer_render(ldata, CD_MLOOPCOL, act); + + act = CustomData_get_clone_layer(fdata, CD_MCOL); + CustomData_set_layer_clone(ldata, CD_MLOOPCOL, act); + + act = CustomData_get_stencil_layer(fdata, CD_MCOL); + CustomData_set_layer_stencil(ldata, CD_MLOOPCOL, act); + } +} + void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) { int chunksize; diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index a6ce5daf247..a1e67ebd414 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -54,6 +54,7 @@ #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" #include "DNA_movieclip_types.h" +#include "DNA_mask_types.h" #include "BKE_animsys.h" #include "BKE_action.h" @@ -2469,6 +2470,15 @@ void DAG_on_visible_update(Main *bmain, const short do_time) /* 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) @@ -2611,6 +2621,18 @@ static void dag_id_flush_update(Scene *sce, ID *id) } } + 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) */ diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 335758fec11..32c6caffff7 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -1697,8 +1697,8 @@ DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, BM_ITER_MESH_INDEX (eve, &iter, bmdm->tc->bm, BM_VERTS_OF_MESH, i) { DM_set_vert_data(&bmdm->dm, i, CD_MVERT_SKIN, - CustomData_bmesh_get(&bm->vdata, eve->head.data, - CD_MVERT_SKIN)); + CustomData_bmesh_get(&bm->vdata, eve->head.data, + CD_MVERT_SKIN)); } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 6ec19018ab5..c317dc63ef7 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -321,6 +321,19 @@ void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) /* -------- GP-Layer API ---------- */ +bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe) +{ + bGPDframe *gpf; + + for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) { + if (gpf->framenum == cframe) { + return gpf; + } + } + + return NULL; +} + /* get the appropriate gp-frame from a given layer * - this sets the layer's actframe var (if allowed to) * - extension beyond range (if first gp-frame is after all frame in interest and cannot add) diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index c5d25276085..828f752eaa5 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -80,6 +80,7 @@ static IDType idtypes[] = { { ID_WO, "World", "worlds", IDTYPE_FLAGS_ISLINKABLE}, { ID_WM, "WindowManager", "window_managers", 0}, { ID_MC, "MovieClip", "movieclips", IDTYPE_FLAGS_ISLINKABLE}, + { ID_MSK, "Mask", "masks", IDTYPE_FLAGS_ISLINKABLE}, }; static int nidtypes = sizeof(idtypes) / sizeof(idtypes[0]); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index a2b1fb10500..eaf4c898b86 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -91,6 +91,14 @@ #include "BLO_sys_types.h" // for intptr_t support +/* for image user iteration */ +#include "DNA_node_types.h" +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" + +#include "WM_api.h" + /* max int, to indicate we don't store sequences in ibuf */ #define IMA_NO_INDEX 0x7FEFEFEF @@ -111,8 +119,8 @@ static void de_interlace_ng(struct ImBuf *ibuf) /* neogeo fields */ if (ibuf->rect) { /* make copies */ - tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect); - tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect); + 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; @@ -139,8 +147,8 @@ static void de_interlace_st(struct ImBuf *ibuf) /* standard fields */ if (ibuf->rect) { /* make copies */ - tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect); - tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect); + 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; @@ -1814,6 +1822,65 @@ void BKE_image_assign_ibuf(Image *ima, ImBuf *ibuf) image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); } +void BKE_image_walk_all_users(const Main *mainp, void *customdata, + void callback(Image *ima, ImageUser *iuser, void *customdata)) +{ + wmWindowManager *wm; + wmWindow *win; + Tex *tex; + + /* texture users */ + for (tex = mainp->tex.first; tex; tex = tex->id.next) { + if (tex->type == TEX_IMAGE && tex->ima) { + if (ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { + callback(tex->ima, &tex->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) { + SpaceImage *sima = sa->spacedata.first; + callback(sima->image, &sima->iuser, customdata); + } + else if (sa->spacetype == SPACE_NODE) { + SpaceNode *snode = sa->spacedata.first; + if ((snode->treetype == NTREE_COMPOSIT) && (snode->nodetree)) { + bNode *node; + for (node = snode->nodetree->nodes.first; node; node = node->next) { + if (node->id && node->type == CMP_NODE_IMAGE) { + Image *ima = (Image *)node->id; + ImageUser *iuser = node->storage; + callback(ima, iuser, customdata); + } + } + } + } + } + } + } +} + +static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdata) +{ + Image *changed_image = customdata; + + if (ima == changed_image) { + iuser->flag |= IMA_NEED_FRAME_RECALC; + } +} + void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) { if (ima == NULL) @@ -1847,6 +1914,9 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) ima->ok = 1; if (iuser) iuser->ok = 1; + + BKE_image_walk_all_users(G.main, ima, image_tag_frame_recalc); + break; case IMA_SIGNAL_RELOAD: @@ -2014,8 +2084,7 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf) static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) { struct ImBuf *ibuf; - unsigned short numlen; - char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX]; + char name[FILE_MAX]; int flag; /* XXX temp stuff? */ @@ -2023,11 +2092,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) ima->tpageflag |= IMA_TPAGE_REFRESH; ima->lastframe = frame; - BLI_strncpy(name, ima->name, sizeof(name)); - BLI_stringdec(name, head, tail, &numlen); - BLI_stringenc(name, head, tail, numlen, frame); - - BLI_path_abs(name, ID_BLEND_PATH(G.main, &ima->id)); + BKE_image_user_file_path(iuser, ima, name); flag = IB_rect | IB_multilayer; if (ima->flag & IMA_DO_PREMUL) @@ -2139,8 +2204,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) if (ima->anim == NULL) { char str[FILE_MAX]; - BLI_strncpy(str, ima->name, FILE_MAX); - BLI_path_abs(str, ID_BLEND_PATH(G.main, &ima->id)); + BKE_image_user_file_path(iuser, ima, str); /* FIXME: make several stream accessible in image editor, too*/ ima->anim = openanim(str, IB_rect, 0); @@ -2203,8 +2267,8 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) flag |= IB_premul; /* get the right string */ - BLI_strncpy(str, ima->name, sizeof(str)); - BLI_path_abs(str, ID_BLEND_PATH(G.main, &ima->id)); + BKE_image_user_frame_calc(iuser, cfra, 0); + BKE_image_user_file_path(iuser, ima, str); /* read ibuf */ ibuf = IMB_loadiffname(str, flag); @@ -2658,15 +2722,42 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr) void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr) { - const int framenr = BKE_image_user_frame_get(iuser, cfra, fieldnr); + if (iuser) { + const int framenr = BKE_image_user_frame_get(iuser, cfra, fieldnr); + + /* allows image users to handle redraws */ + if (iuser->flag & IMA_ANIM_ALWAYS) + if (framenr != iuser->framenr) + iuser->flag |= IMA_ANIM_REFRESHED; + + iuser->framenr = framenr; + if (iuser->ok == 0) iuser->ok = 1; + } +} + +void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra, int fieldnr) +{ + if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC)) { + BKE_image_user_frame_calc(iuser, cfra, fieldnr); - /* allows image users to handle redraws */ - if (iuser->flag & IMA_ANIM_ALWAYS) - if (framenr != iuser->framenr) - iuser->flag |= IMA_ANIM_REFRESHED; + iuser->flag &= ~IMA_NEED_FRAME_RECALC; + } +} - iuser->framenr = framenr; - if (iuser->ok == 0) iuser->ok = 1; +void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) +{ + BLI_strncpy(filepath, ima->name, FILE_MAX); + + if (ima->source == IMA_SRC_SEQUENCE) { + char head[FILE_MAX], tail[FILE_MAX]; + unsigned short numlen; + int frame = iuser->framenr; + + BLI_stringdec(filepath, head, tail, &numlen); + BLI_stringenc(filepath, head, tail, numlen, frame); + } + + BLI_path_abs(filepath, ID_BLEND_PATH(G.main, &ima->id)); } int BKE_image_has_alpha(struct Image *image) @@ -2684,4 +2775,3 @@ int BKE_image_has_alpha(struct Image *image) else return 0; } - diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index d4861a27057..4aef47159df 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -695,8 +695,7 @@ DO_INLINE void subadd_bfmatrixS_bfmatrixS( fmatrix3x3 *to, fmatrix3x3 *from, flo /////////////////////////////////////////////////////////////////// // simulator start /////////////////////////////////////////////////////////////////// -typedef struct Implicit_Data -{ +typedef struct Implicit_Data { lfVector *X, *V, *Xnew, *Vnew, *olddV, *F, *B, *dV, *z; fmatrix3x3 *A, *dFdV, *dFdX, *S, *P, *Pinv, *bigI, *M; } Implicit_Data; diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 9737888e0b2..bbc1874c2ae 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1924,14 +1924,14 @@ void do_versions_ipos_to_animato(Main *main) * (semi-hack (tm) ) */ switch (seq->type) { - case SEQ_IMAGE: - case SEQ_META: - case SEQ_SCENE: - case SEQ_MOVIE: - case SEQ_COLOR: + case SEQ_TYPE_IMAGE: + case SEQ_TYPE_META: + case SEQ_TYPE_SCENE: + case SEQ_TYPE_MOVIE: + case SEQ_TYPE_COLOR: adrcode = SEQ_FAC_OPACITY; break; - case SEQ_SPEED: + case SEQ_TYPE_SPEED: adrcode = SEQ_FAC_SPEED; break; } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 5cc328212a9..2fe6999c6e8 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -66,6 +66,7 @@ #include "DNA_world_types.h" #include "DNA_gpencil_types.h" #include "DNA_movieclip_types.h" +#include "DNA_mask_types.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" @@ -108,6 +109,7 @@ #include "BKE_speaker.h" #include "BKE_utildefines.h" #include "BKE_movieclip.h" +#include "BKE_mask.h" #include "BKE_linestyle.h" #include "RNA_access.h" @@ -492,6 +494,8 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->gpencil); case ID_MC: return &(mainlib->movieclip); + case ID_MSK: + return &(mainlib->mask); case ID_LS: return &(mainlib->linestyle); } @@ -577,7 +581,8 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[a++] = &(main->library); lb[a++] = &(main->wm); lb[a++] = &(main->movieclip); - lb[a++]= &(main->linestyle); + lb[a++] = &(main->mask); + lb[a++] = &(main->linestyle); lb[a] = NULL; @@ -689,6 +694,9 @@ static ID *alloc_libblock_notest(short type) case ID_MC: id = MEM_callocN(sizeof(MovieClip), "Movie Clip"); break; + case ID_MSK: + id = MEM_callocN(sizeof(Mask), "Mask"); + break; case ID_LS: id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style"); break; @@ -900,6 +908,9 @@ void BKE_libblock_free(ListBase *lb, void *idv) case ID_MC: BKE_movieclip_free((MovieClip *)id); break; + case ID_MSK: + BKE_mask_free((Mask *)id); + break; case ID_LS: FRS_free_linestyle((FreestyleLineStyle *)id); break; @@ -1146,7 +1157,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name) * Normally the ID that's being check is already in the ListBase, so ID *id * points at the new entry. The Python Library module needs to know what * the name of a datablock will be before it is appended; in this case ID *id - * id is NULL; + * id is NULL */ static int check_for_dupid(ListBase *lb, ID *id, char *name) diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c new file mode 100644 index 00000000000..bb2940091e4 --- /dev/null +++ b/source/blender/blenkernel/intern/mask.c @@ -0,0 +1,2225 @@ +/* + * ***** 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) 2012 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mask.c + * \ingroup bke + */ + +#include <stddef.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_mask_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_mask.h" +#include "BKE_tracking.h" +#include "BKE_movieclip.h" +#include "BKE_utildefines.h" + +#include "raskter.h" + +static MaskSplinePoint *mask_spline_point_next(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point) +{ + if (point == &points_array[spline->tot_point - 1]) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + return &points_array[0]; + } + else { + return NULL; + } + } + else { + return point + 1; + } +} + +static MaskSplinePoint *mask_spline_point_prev(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point) +{ + if (point == points_array) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + return &points_array[spline->tot_point - 1]; + } + else { + return NULL; + } + } + else { + return point - 1; + } +} + +static BezTriple *mask_spline_point_next_bezt(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point) +{ + if (point == &points_array[spline->tot_point - 1]) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + return &(points_array[0].bezt); + } + else { + return NULL; + } + } + else { + return &((point + 1))->bezt; + } +} + +#if 0 +static BezTriple *mask_spline_point_prev_bezt(MaskSpline *spline, MaskSplinePoint *points_array, MaskSplinePoint *point) +{ + if (point == points_array) { + if (spline->flag & MASK_SPLINE_CYCLIC) { + return &(points_array[0].bezt); + } + else { + return NULL; + } + } + else { + return &((point - 1))->bezt; + } +} +#endif + +MaskSplinePoint *BKE_mask_spline_point_array(MaskSpline *spline) +{ + return spline->points_deform ? spline->points_deform : spline->points; +} + +MaskSplinePoint *BKE_mask_spline_point_array_from_point(MaskSpline *spline, MaskSplinePoint *point_ref) +{ + if ((point_ref >= spline->points) && (point_ref < &spline->points[spline->tot_point])) { + return spline->points; + } + + if ((point_ref >= spline->points_deform) && (point_ref < &spline->points_deform[spline->tot_point])) { + return spline->points_deform; + } + + BLI_assert(!"wrong array"); + return NULL; +} + +/* mask layers */ + +MaskLayer *BKE_mask_layer_new(Mask *mask, const char *name) +{ + MaskLayer *masklay = MEM_callocN(sizeof(MaskLayer), __func__); + + if (name && name[0]) + BLI_strncpy(masklay->name, name, sizeof(masklay->name)); + else + strcpy(masklay->name, "MaskLayer"); + + BLI_addtail(&mask->masklayers, masklay); + + BKE_mask_layer_unique_name(mask, masklay); + + mask->masklay_tot++; + + masklay->alpha = 1.0f; + + return masklay; +} + +/* note: may still be hidden, caller needs to check */ +MaskLayer *BKE_mask_layer_active(Mask *mask) +{ + return BLI_findlink(&mask->masklayers, mask->masklay_act); +} + +void BKE_mask_layer_active_set(Mask *mask, MaskLayer *masklay) +{ + mask->masklay_act = BLI_findindex(&mask->masklayers, masklay); +} + +void BKE_mask_layer_remove(Mask *mask, MaskLayer *masklay) +{ + BLI_remlink(&mask->masklayers, masklay); + BKE_mask_layer_free(masklay); + + mask->masklay_tot--; + + if (mask->masklay_act >= mask->masklay_tot) + mask->masklay_act = mask->masklay_tot - 1; +} + +void BKE_mask_layer_unique_name(Mask *mask, MaskLayer *masklay) +{ + BLI_uniquename(&mask->masklayers, masklay, "MaskLayer", '.', offsetof(MaskLayer, name), sizeof(masklay->name)); +} + +/* splines */ + +MaskSpline *BKE_mask_spline_add(MaskLayer *masklay) +{ + MaskSpline *spline; + + spline = MEM_callocN(sizeof(MaskSpline), "new mask spline"); + BLI_addtail(&masklay->splines, spline); + + /* spline shall have one point at least */ + spline->points = MEM_callocN(sizeof(MaskSplinePoint), "new mask spline point"); + spline->tot_point = 1; + + /* cyclic shapes are more usually used */ + // spline->flag |= MASK_SPLINE_CYCLIC; // disable because its not so nice for drawing. could be done differently + + spline->weight_interp = MASK_SPLINE_INTERP_LINEAR; + + BKE_mask_parent_init(&spline->parent); + + return spline; +} + +static int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height) +{ + float max_segment = 0.01f; + int i, resol = 1; + + if (width != 0 && height != 0) { + if (width >= height) + max_segment = 1.0f / (float) width; + else + max_segment = 1.0f / (float) height; + } + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + BezTriple *bezt, *bezt_next; + float a, b, c, len; + int cur_resol; + + bezt = &point->bezt; + bezt_next = mask_spline_point_next_bezt(spline, spline->points, point); + + if (bezt_next == NULL) { + break; + } + + a = len_v3v3(bezt->vec[1], bezt->vec[2]); + b = len_v3v3(bezt->vec[2], bezt_next->vec[0]); + c = len_v3v3(bezt_next->vec[0], bezt_next->vec[1]); + + len = a + b + c; + cur_resol = len / max_segment; + + resol = MAX2(resol, cur_resol); + } + + return resol; +} + +static int BKE_mask_spline_feather_resolution(MaskSpline *spline, int width, int height) +{ + const float max_segment = 0.005; + int resol = BKE_mask_spline_resolution(spline, width, height); + float max_jump = 0.0f; + int i; + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + float prev_u, prev_w; + int j; + + prev_u = 0.0f; + prev_w = point->bezt.weight; + + for (j = 0; j < point->tot_uw; j++) { + float jump = fabsf((point->uw[j].w - prev_w) / (point->uw[j].u - prev_u)); + + max_jump = MAX2(max_jump, jump); + + prev_u = point->uw[j].u; + prev_w = point->uw[j].w; + } + } + + resol += max_jump / max_segment; + + return resol; +} + +float (*BKE_mask_spline_differentiate_with_resolution(MaskSpline *spline, int width, int height, + int *tot_diff_point))[2] +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); + + MaskSplinePoint *point, *prev; + float (*diff_points)[2], (*fp)[2]; + int a, len, resol = BKE_mask_spline_resolution(spline, width, height); + + if (spline->tot_point <= 1) { + /* nothing to differentiate */ + *tot_diff_point = 0; + return NULL; + } + + /* count */ + len = (spline->tot_point - 1) * resol; + + if (spline->flag & MASK_SPLINE_CYCLIC) + len += resol; + else + len++; + + /* len+1 because of 'forward_diff_bezier' function */ + *tot_diff_point = len; + diff_points = fp = MEM_mallocN((len + 1) * sizeof(*diff_points), "mask spline vets"); + + a = spline->tot_point - 1; + if (spline->flag & MASK_SPLINE_CYCLIC) + a++; + + prev = points_array; + point = prev + 1; + + while (a--) { + BezTriple *prevbezt; + BezTriple *bezt; + int j; + + if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC)) + point = points_array; + + prevbezt = &prev->bezt; + bezt = &point->bezt; + + for (j = 0; j < 2; j++) { + BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], prevbezt->vec[2][j], + bezt->vec[0][j], bezt->vec[1][j], + &(*fp)[j], resol, 2 * sizeof(float)); + } + + fp += resol; + + if (a == 0 && (spline->flag & MASK_SPLINE_CYCLIC) == 0) { + copy_v2_v2(*fp, bezt->vec[1]); + } + + prev = point; + point++; + } + + return diff_points; +} + +float (*BKE_mask_spline_differentiate(MaskSpline *spline, int *tot_diff_point))[2] +{ + return BKE_mask_spline_differentiate_with_resolution(spline, 0, 0, tot_diff_point); +} + +float (*BKE_mask_spline_feather_differentiated_points_with_resolution(MaskSpline *spline, int width, int height, + int *tot_feather_point))[2] +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); + + float (*feather)[2], (*fp)[2]; + int i, j, tot, resol = BKE_mask_spline_feather_resolution(spline, width, height); + + tot = resol * spline->tot_point; + feather = fp = MEM_mallocN(tot * sizeof(*feather), "mask spline feather diff points"); + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &points_array[i]; + + for (j = 0; j < resol; j++, fp++) { + float u = (float) j / resol, weight; + float co[2], n[2]; + + /* TODO - these calls all calculate similar things + * could be unified for some speed */ + BKE_mask_point_segment_co(spline, point, u, co); + BKE_mask_point_normal(spline, point, u, n); + weight = BKE_mask_point_weight(spline, point, u); + + madd_v2_v2v2fl(*fp, co, n, weight); + } + } + + *tot_feather_point = tot; + + return feather; +} + +float (*BKE_mask_spline_feather_differentiated_points(MaskSpline *spline, int *tot_feather_point))[2] +{ + return BKE_mask_spline_feather_differentiated_points_with_resolution(spline, 0, 0, tot_feather_point); +} + +float (*BKE_mask_spline_feather_points(MaskSpline *spline, int *tot_feather_point))[2] +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); + + int i, tot = 0; + float (*feather)[2], (*fp)[2]; + + /* count */ + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &points_array[i]; + + tot += point->tot_uw + 1; + } + + /* create data */ + feather = fp = MEM_mallocN(tot * sizeof(*feather), "mask spline feather points"); + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &points_array[i]; + BezTriple *bezt = &point->bezt; + float weight, n[2]; + int j; + + BKE_mask_point_normal(spline, point, 0.0f, n); + weight = BKE_mask_point_weight(spline, point, 0.0f); + + madd_v2_v2v2fl(*fp, bezt->vec[1], n, weight); + fp++; + + for (j = 0; j < point->tot_uw; j++) { + float u = point->uw[j].u; + float co[2]; + + BKE_mask_point_segment_co(spline, point, u, co); + BKE_mask_point_normal(spline, point, u, n); + weight = BKE_mask_point_weight(spline, point, u); + + madd_v2_v2v2fl(*fp, co, n, weight); + fp++; + } + } + + *tot_feather_point = tot; + + return feather; +} + +void BKE_mask_point_direction_switch(MaskSplinePoint *point) +{ + const int tot_uw = point->tot_uw; + const int tot_uw_half = tot_uw / 2; + int i; + + float co_tmp[2]; + + /* swap handles */ + copy_v2_v2(co_tmp, point->bezt.vec[0]); + copy_v2_v2(point->bezt.vec[0], point->bezt.vec[2]); + copy_v2_v2(point->bezt.vec[2], co_tmp); + /* in this case the flags are unlikely to be different but swap anyway */ + SWAP(char, point->bezt.f1, point->bezt.f3); + SWAP(char, point->bezt.h1, point->bezt.h2); + + + /* swap UW's */ + if (tot_uw > 1) { + /* count */ + for (i = 0; i < tot_uw_half; i++) { + MaskSplinePointUW *uw_a = &point->uw[i]; + MaskSplinePointUW *uw_b = &point->uw[tot_uw - (i + 1)]; + SWAP(MaskSplinePointUW, *uw_a, *uw_b); + } + } + + for (i = 0; i < tot_uw; i++) { + MaskSplinePointUW *uw = &point->uw[i]; + uw->u = 1.0f - uw->u; + } +} + +void BKE_mask_spline_direction_switch(MaskLayer *masklay, MaskSpline *spline) +{ + const int tot_point = spline->tot_point; + const int tot_point_half = tot_point / 2; + int i, i_prev; + + if (tot_point < 2) { + return; + } + + /* count */ + for (i = 0; i < tot_point_half; i++) { + MaskSplinePoint *point_a = &spline->points[i]; + MaskSplinePoint *point_b = &spline->points[tot_point - (i + 1)]; + SWAP(MaskSplinePoint, *point_a, *point_b); + } + + /* correct UW's */ + i_prev = tot_point - 1; + for (i = 0; i < tot_point; i++) { + + BKE_mask_point_direction_switch(&spline->points[i]); + + SWAP(MaskSplinePointUW *, spline->points[i].uw, spline->points[i_prev].uw); + SWAP(int, spline->points[i].tot_uw, spline->points[i_prev].tot_uw); + + i_prev = i; + } + + /* correct animation */ + if (masklay->splines_shapes.first) { + MaskLayerShape *masklay_shape; + + const int spline_index = BKE_mask_layer_shape_spline_to_index(masklay, spline); + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + MaskLayerShapeElem *fp_arr = (MaskLayerShapeElem *)masklay_shape->data; + + for (i = 0; i < tot_point_half; i++) { + MaskLayerShapeElem *fp_a = &fp_arr[spline_index + (i) ]; + MaskLayerShapeElem *fp_b = &fp_arr[spline_index + (tot_point - (i + 1))]; + SWAP(MaskLayerShapeElem, *fp_a, *fp_b); + } + } + } +} + + +float BKE_mask_spline_project_co(MaskSpline *spline, MaskSplinePoint *point, + float start_u, const float co[2], const eMaskSign sign) +{ + const float proj_eps = 1e-3; + const float proj_eps_squared = proj_eps * proj_eps; + const int N = 1000; + float u = -1.0f, du = 1.0f / N, u1 = start_u, u2 = start_u; + float ang = -1.0f; + + BLI_assert(ABS(sign) <= 1); /* (-1, 0, 1) */ + + while (u1 > 0.0f || u2 < 1.0f) { + float n1[2], n2[2], co1[2], co2[2]; + float v1[2], v2[2]; + float ang1, ang2; + + if (u1 >= 0.0f) { + BKE_mask_point_segment_co(spline, point, u1, co1); + BKE_mask_point_normal(spline, point, u1, n1); + sub_v2_v2v2(v1, co, co1); + + if ((sign == MASK_PROJ_ANY) || + ((sign == MASK_PROJ_NEG) && (dot_v2v2(v1, n1) <= 0.0f)) || + ((sign == MASK_PROJ_POS) && (dot_v2v2(v1, n1) >= 0.0f))) + { + + if (len_squared_v2(v1) > proj_eps_squared) { + ang1 = angle_v2v2(v1, n1); + if (ang1 > M_PI / 2.0f) + ang1 = M_PI - ang1; + + if (ang < 0.0f || ang1 < ang) { + ang = ang1; + u = u1; + } + } + else { + u = u1; + break; + } + } + } + + if (u2 <= 1.0f) { + BKE_mask_point_segment_co(spline, point, u2, co2); + BKE_mask_point_normal(spline, point, u2, n2); + sub_v2_v2v2(v2, co, co2); + + if ((sign == MASK_PROJ_ANY) || + ((sign == MASK_PROJ_NEG) && (dot_v2v2(v2, n2) <= 0.0f)) || + ((sign == MASK_PROJ_POS) && (dot_v2v2(v2, n2) >= 0.0f))) + { + + if (len_squared_v2(v2) > proj_eps_squared) { + ang2 = angle_v2v2(v2, n2); + if (ang2 > M_PI / 2.0f) + ang2 = M_PI - ang2; + + if (ang2 < ang) { + ang = ang2; + u = u2; + } + } + else { + u = u2; + break; + } + } + } + + u1 -= du; + u2 += du; + } + + return u; +} + +/* point */ + +int BKE_mask_point_has_handle(MaskSplinePoint *point) +{ + BezTriple *bezt = &point->bezt; + + return bezt->h1 == HD_ALIGN; +} + +void BKE_mask_point_handle(MaskSplinePoint *point, float handle[2]) +{ + float vec[2]; + + sub_v2_v2v2(vec, point->bezt.vec[0], point->bezt.vec[1]); + + handle[0] = (point->bezt.vec[1][0] + vec[1]); + handle[1] = (point->bezt.vec[1][1] - vec[0]); +} + +void BKE_mask_point_set_handle(MaskSplinePoint *point, float loc[2], int keep_direction, + float orig_handle[2], float orig_vec[3][3]) +{ + BezTriple *bezt = &point->bezt; + float v1[2], v2[2], vec[2]; + + if (keep_direction) { + sub_v2_v2v2(v1, loc, orig_vec[1]); + sub_v2_v2v2(v2, orig_handle, orig_vec[1]); + + project_v2_v2v2(vec, v1, v2); + + if (dot_v2v2(v2, vec) > 0) { + float len = len_v2(vec); + + sub_v2_v2v2(v1, orig_vec[0], orig_vec[1]); + + mul_v2_fl(v1, len / len_v2(v1)); + + add_v2_v2v2(bezt->vec[0], bezt->vec[1], v1); + sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v1); + } + else { + copy_v3_v3(bezt->vec[0], bezt->vec[1]); + copy_v3_v3(bezt->vec[2], bezt->vec[1]); + } + } + else { + sub_v2_v2v2(v1, loc, bezt->vec[1]); + + v2[0] = -v1[1]; + v2[1] = v1[0]; + + add_v2_v2v2(bezt->vec[0], bezt->vec[1], v2); + sub_v2_v2v2(bezt->vec[2], bezt->vec[1], v2); + } +} + +float *BKE_mask_point_segment_feather_diff_with_resolution(MaskSpline *spline, MaskSplinePoint *point, + int width, int height, + int *tot_feather_point) +{ + float *feather, *fp; + int i, resol = BKE_mask_spline_feather_resolution(spline, width, height); + + feather = fp = MEM_callocN(2 * resol * sizeof(float), "mask point spline feather diff points"); + + for (i = 0; i < resol; i++, fp += 2) { + float u = (float)(i % resol) / resol, weight; + float co[2], n[2]; + + BKE_mask_point_segment_co(spline, point, u, co); + BKE_mask_point_normal(spline, point, u, n); + weight = BKE_mask_point_weight(spline, point, u); + + fp[0] = co[0] + n[0] * weight; + fp[1] = co[1] + n[1] * weight; + } + + *tot_feather_point = resol; + + return feather; +} + +float *BKE_mask_point_segment_feather_diff(MaskSpline *spline, MaskSplinePoint *point, int *tot_feather_point) +{ + return BKE_mask_point_segment_feather_diff_with_resolution(spline, point, 0, 0, tot_feather_point); +} + +float *BKE_mask_point_segment_diff_with_resolution(MaskSpline *spline, MaskSplinePoint *point, + int width, int height, int *tot_diff_point) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + BezTriple *bezt, *bezt_next; + float *diff_points, *fp; + int j, resol = BKE_mask_spline_resolution(spline, width, height); + + bezt = &point->bezt; + bezt_next = mask_spline_point_next_bezt(spline, points_array, point); + + if (!bezt_next) + return NULL; + + /* resol+1 because of 'forward_diff_bezier' function */ + *tot_diff_point = resol + 1; + diff_points = fp = MEM_callocN((resol + 1) * 2 * sizeof(float), "mask segment vets"); + + for (j = 0; j < 2; j++) { + BKE_curve_forward_diff_bezier(bezt->vec[1][j], bezt->vec[2][j], + bezt_next->vec[0][j], bezt_next->vec[1][j], + fp + j, resol, 2 * sizeof(float)); + } + + copy_v2_v2(fp + 2 * resol, bezt_next->vec[1]); + + return diff_points; +} + +float *BKE_mask_point_segment_diff(MaskSpline *spline, MaskSplinePoint *point, int *tot_diff_point) +{ + return BKE_mask_point_segment_diff_with_resolution(spline, point, 0, 0, tot_diff_point); +} + +void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float u, float co[2]) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + BezTriple *bezt = &point->bezt, *bezt_next; + float q0[2], q1[2], q2[2], r0[2], r1[2]; + + bezt_next = mask_spline_point_next_bezt(spline, points_array, point); + + if (!bezt_next) { + copy_v2_v2(co, bezt->vec[1]); + return; + } + + interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u); + interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u); + interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u); + + interp_v2_v2v2(r0, q0, q1, u); + interp_v2_v2v2(r1, q1, q2, u); + + interp_v2_v2v2(co, r0, r1, u); +} + +void BKE_mask_point_normal(MaskSpline *spline, MaskSplinePoint *point, float u, float n[2]) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + BezTriple *bezt = &point->bezt, *bezt_next; + float q0[2], q1[2], q2[2], r0[2], r1[2], vec[2]; + + bezt_next = mask_spline_point_next_bezt(spline, points_array, point); + + if (!bezt_next) { + BKE_mask_point_handle(point, vec); + + sub_v2_v2v2(n, vec, bezt->vec[1]); + normalize_v2(n); + return; + } + + interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u); + interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u); + interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u); + + interp_v2_v2v2(r0, q0, q1, u); + interp_v2_v2v2(r1, q1, q2, u); + + sub_v2_v2v2(vec, r1, r0); + + n[0] = -vec[1]; + n[1] = vec[0]; + + normalize_v2(n); +} + +static float mask_point_interp_weight(BezTriple *bezt, BezTriple *bezt_next, const float u) +{ + return (bezt->weight * (1.0f - u)) + (bezt_next->weight * u); +} + +float BKE_mask_point_weight_scalar(MaskSpline *spline, MaskSplinePoint *point, const float u) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + BezTriple *bezt = &point->bezt, *bezt_next; + + bezt_next = mask_spline_point_next_bezt(spline, points_array, point); + + if (!bezt_next) { + return bezt->weight; + } + else if (u <= 0.0) { + return bezt->weight; + } + else if (u >= 1.0f) { + return bezt_next->weight; + } + else { + return mask_point_interp_weight(bezt, bezt_next, u); + } +} + +float BKE_mask_point_weight(MaskSpline *spline, MaskSplinePoint *point, const float u) +{ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + BezTriple *bezt = &point->bezt, *bezt_next; + + bezt_next = mask_spline_point_next_bezt(spline, points_array, point); + + if (!bezt_next) { + return bezt->weight; + } + else if (u <= 0.0) { + return bezt->weight; + } + else if (u >= 1.0f) { + return bezt_next->weight; + } + else { + float cur_u = 0.0f, cur_w = 0.0f, next_u = 0.0f, next_w = 0.0f, fac; /* Quite warnings */ + int i; + + for (i = 0; i < point->tot_uw + 1; i++) { + + if (i == 0) { + cur_u = 0.0f; + cur_w = 1.0f; /* mask_point_interp_weight will scale it */ + } + else { + cur_u = point->uw[i - 1].u; + cur_w = point->uw[i - 1].w; + } + + if (i == point->tot_uw) { + next_u = 1.0f; + next_w = 1.0f; /* mask_point_interp_weight will scale it */ + } + else { + next_u = point->uw[i].u; + next_w = point->uw[i].w; + } + + if (u >= cur_u && u <= next_u) { + break; + } + } + + fac = (u - cur_u) / (next_u - cur_u); + + cur_w *= mask_point_interp_weight(bezt, bezt_next, cur_u); + next_w *= mask_point_interp_weight(bezt, bezt_next, next_u); + + if (spline->weight_interp == MASK_SPLINE_INTERP_EASE) { + return cur_w + (next_w - cur_w) * (3.0f * fac * fac - 2.0f * fac * fac * fac); + } + else { + return (1.0f - fac) * cur_w + fac * next_w; + } + } +} + +MaskSplinePointUW *BKE_mask_point_sort_uw(MaskSplinePoint *point, MaskSplinePointUW *uw) +{ + if (point->tot_uw > 1) { + int idx = uw - point->uw; + + if (idx > 0 && point->uw[idx - 1].u > uw->u) { + while (idx > 0 && point->uw[idx - 1].u > point->uw[idx].u) { + SWAP(MaskSplinePointUW, point->uw[idx - 1], point->uw[idx]); + idx--; + } + } + + if (idx < point->tot_uw - 1 && point->uw[idx + 1].u < uw->u) { + while (idx < point->tot_uw - 1 && point->uw[idx + 1].u < point->uw[idx].u) { + SWAP(MaskSplinePointUW, point->uw[idx + 1], point->uw[idx]); + idx++; + } + } + + return &point->uw[idx]; + } + + return uw; +} + +void BKE_mask_point_add_uw(MaskSplinePoint *point, float u, float w) +{ + if (!point->uw) + point->uw = MEM_callocN(sizeof(*point->uw), "mask point uw"); + else + point->uw = MEM_reallocN(point->uw, (point->tot_uw + 1) * sizeof(*point->uw)); + + point->uw[point->tot_uw].u = u; + point->uw[point->tot_uw].w = w; + + point->tot_uw++; + + BKE_mask_point_sort_uw(point, &point->uw[point->tot_uw - 1]); +} + +void BKE_mask_point_select_set(MaskSplinePoint *point, const short do_select) +{ + int i; + + if (do_select) { + MASKPOINT_SEL_ALL(point); + } + else { + MASKPOINT_DESEL_ALL(point); + } + + for (i = 0; i < point->tot_uw; i++) { + if (do_select) { + point->uw[i].flag |= SELECT; + } + else { + point->uw[i].flag &= ~SELECT; + } + } +} + +void BKE_mask_point_select_set_handle(MaskSplinePoint *point, const short do_select) +{ + if (do_select) { + MASKPOINT_SEL_HANDLE(point); + } + else { + MASKPOINT_DESEL_HANDLE(point); + } +} + +/* only mask block itself */ +static Mask *mask_alloc(const char *name) +{ + Mask *mask; + + mask = BKE_libblock_alloc(&G.main->mask, ID_MSK, name); + + return mask; +} + +Mask *BKE_mask_new(const char *name) +{ + Mask *mask; + char mask_name[MAX_ID_NAME - 2]; + + if (name && name[0]) + BLI_strncpy(mask_name, name, sizeof(mask_name)); + else + strcpy(mask_name, "Mask"); + + mask = mask_alloc(mask_name); + + /* arbitrary defaults */ + mask->sfra = 1; + mask->efra = 100; + + return mask; +} + +void BKE_mask_point_free(MaskSplinePoint *point) +{ + if (point->uw) + MEM_freeN(point->uw); +} + +void BKE_mask_spline_free(MaskSpline *spline) +{ + int i = 0; + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point; + point = &spline->points[i]; + BKE_mask_point_free(point); + + if (spline->points_deform) { + point = &spline->points_deform[i]; + BKE_mask_point_free(point); + } + } + + MEM_freeN(spline->points); + + if (spline->points_deform) { + MEM_freeN(spline->points_deform); + } + + MEM_freeN(spline); +} + +MaskSpline *BKE_mask_spline_copy(MaskSpline *spline) +{ + MaskSpline *nspline = MEM_callocN(sizeof(MaskSpline), "new spline"); + int i; + + *nspline = *spline; + + nspline->points_deform = NULL; + nspline->points = MEM_dupallocN(nspline->points); + + for (i = 0; i < nspline->tot_point; i++) { + MaskSplinePoint *point = &nspline->points[i]; + + if (point->uw) + point->uw = MEM_dupallocN(point->uw); + } + + return nspline; +} + +/* note: does NOT add to the list */ +MaskLayerShape *BKE_mask_layer_shape_alloc(MaskLayer *masklay, const int frame) +{ + MaskLayerShape *masklay_shape; + int tot_vert = BKE_mask_layer_shape_totvert(masklay); + + masklay_shape = MEM_mallocN(sizeof(MaskLayerShape), __func__); + masklay_shape->frame = frame; + masklay_shape->tot_vert = tot_vert; + masklay_shape->data = MEM_mallocN(tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__); + + return masklay_shape; +} + +void BKE_mask_layer_shape_free(MaskLayerShape *masklay_shape) +{ + MEM_freeN(masklay_shape->data); + + MEM_freeN(masklay_shape); +} + +void BKE_mask_layer_free(MaskLayer *masklay) +{ + MaskSpline *spline; + MaskLayerShape *masklay_shape; + + /* free splines */ + spline = masklay->splines.first; + while (spline) { + MaskSpline *next_spline = spline->next; + + BLI_remlink(&masklay->splines, spline); + BKE_mask_spline_free(spline); + + spline = next_spline; + } + + /* free animation data */ + masklay_shape = masklay->splines_shapes.first; + while (masklay_shape) { + MaskLayerShape *next_masklay_shape = masklay_shape->next; + + BLI_remlink(&masklay->splines_shapes, masklay_shape); + BKE_mask_layer_shape_free(masklay_shape); + + masklay_shape = next_masklay_shape; + } + + MEM_freeN(masklay); +} + +void BKE_mask_free(Mask *mask) +{ + MaskLayer *masklay = mask->masklayers.first; + + while (masklay) { + MaskLayer *next_masklay = masklay->next; + + BLI_remlink(&mask->masklayers, masklay); + BKE_mask_layer_free(masklay); + + masklay = next_masklay; + } +} + +void BKE_mask_unlink(Main *bmain, Mask *mask) +{ + bScreen *scr; + ScrArea *area; + SpaceLink *sl; + + for (scr = bmain->screen.first; scr; scr = scr->id.next) { + for (area = scr->areabase.first; area; area = area->next) { + for (sl = area->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_CLIP) { + SpaceClip *sc = (SpaceClip *) sl; + + if (sc->mask == mask) + sc->mask = NULL; + } + } + } + } + + mask->id.us = 0; +} + +void BKE_mask_coord_from_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2]) +{ + int width, height; + + /* scaling for the clip */ + BKE_movieclip_get_size(clip, user, &width, &height); + + if (width == height) { + r_co[0] = co[0]; + r_co[1] = co[1]; + } + else if (width < height) { + r_co[0] = ((co[0] - 0.5f) * ((float)width / (float)height)) + 0.5f; + r_co[1] = co[1]; + } + else { /* (width > height) */ + r_co[0] = co[0]; + r_co[1] = ((co[1] - 0.5f) * ((float)height / (float)width)) + 0.5f; + } +} + +/* as above but divide */ +void BKE_mask_coord_to_movieclip(MovieClip *clip, MovieClipUser *user, float r_co[2], const float co[2]) +{ + int width, height; + + /* scaling for the clip */ + BKE_movieclip_get_size(clip, user, &width, &height); + + if (width == height) { + r_co[0] = co[0]; + r_co[1] = co[1]; + } + else if (width < height) { + r_co[0] = ((co[0] - 0.5f) / ((float)width / (float)height)) + 0.5f; + r_co[1] = co[1]; + } + else { /* (width > height) */ + r_co[0] = co[0]; + r_co[1] = ((co[1] - 0.5f) / ((float)height / (float)width)) + 0.5f; + } +} + +static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[2]) +{ + if (!parent) + return FALSE; + + if (parent->id_type == ID_MC) { + if (parent->id) { + MovieClip *clip = (MovieClip *) parent->id; + MovieTracking *tracking = (MovieTracking *) &clip->tracking; + MovieTrackingObject *ob = BKE_tracking_named_object(tracking, parent->parent); + + if (ob) { + MovieTrackingTrack *track = BKE_tracking_named_track(tracking, ob, parent->sub_parent); + + MovieClipUser user = {0}; + user.framenr = ctime; + + if (track) { + MovieTrackingMarker *marker = BKE_tracking_get_marker(track, ctime); + float marker_pos_ofs[2]; + add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); + BKE_mask_coord_from_movieclip(clip, &user, r_co, marker_pos_ofs); + + return TRUE; + } + } + } + } + + return FALSE; +} + +int BKE_mask_evaluate_parent_delta(MaskParent *parent, float ctime, float r_delta[2]) +{ + float parent_co[2]; + + if (BKE_mask_evaluate_parent(parent, ctime, parent_co)) { + sub_v2_v2v2(r_delta, parent_co, parent->parent_orig); + return TRUE; + } + else { + return FALSE; + } +} + +static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *point_prev, MaskSplinePoint *point_next) +{ + BezTriple *bezt = &point->bezt; + BezTriple *bezt_prev = NULL, *bezt_next = NULL; + //int handle_type = bezt->h1; + + if (point_prev) + bezt_prev = &point_prev->bezt; + + if (point_next) + bezt_next = &point_next->bezt; + +#if 1 + if (bezt_prev || bezt_next) { + BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0); + } +#else + if (handle_type == HD_VECT) { + BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0); + } + else if (handle_type == HD_AUTO) { + BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, 0); + } + else if (handle_type == HD_ALIGN) { + float v1[3], v2[3]; + float vec[3], h[3]; + + sub_v3_v3v3(v1, bezt->vec[0], bezt->vec[1]); + sub_v3_v3v3(v2, bezt->vec[2], bezt->vec[1]); + add_v3_v3v3(vec, v1, v2); + + if (len_v3(vec) > 1e-3) { + h[0] = vec[1]; + h[1] = -vec[0]; + h[2] = 0.0f; + } + else { + copy_v3_v3(h, v1); + } + + add_v3_v3v3(bezt->vec[0], bezt->vec[1], h); + sub_v3_v3v3(bezt->vec[2], bezt->vec[1], h); + } +#endif +} + +void BKE_mask_get_handle_point_adjacent(MaskSpline *spline, MaskSplinePoint *point, + MaskSplinePoint **r_point_prev, MaskSplinePoint **r_point_next) +{ + /* TODO, could avoid calling this at such low level */ + MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); + + *r_point_prev = mask_spline_point_prev(spline, points_array, point); + *r_point_next = mask_spline_point_next(spline, points_array, point); +} + +/* calculates the tanget of a point by its previous and next + * (ignoring handles - as if its a poly line) */ +void BKE_mask_calc_tangent_polyline(MaskSpline *spline, MaskSplinePoint *point, float t[2]) +{ + float tvec_a[2], tvec_b[2]; + + MaskSplinePoint *point_prev, *point_next; + + BKE_mask_get_handle_point_adjacent(spline, point, + &point_prev, &point_next); + + if (point_prev) { + sub_v2_v2v2(tvec_a, point->bezt.vec[1], point_prev->bezt.vec[1]); + normalize_v2(tvec_a); + } + else { + zero_v2(tvec_a); + } + + if (point_next) { + sub_v2_v2v2(tvec_b, point_next->bezt.vec[1], point->bezt.vec[1]); + normalize_v2(tvec_b); + } + else { + zero_v2(tvec_b); + } + + add_v2_v2v2(t, tvec_a, tvec_b); + normalize_v2(t); +} + +void BKE_mask_calc_handle_point(MaskSpline *spline, MaskSplinePoint *point) +{ + MaskSplinePoint *point_prev, *point_next; + + BKE_mask_get_handle_point_adjacent(spline, point, + &point_prev, &point_next); + + mask_calc_point_handle(point, point_prev, point_next); +} + +static void enforce_dist_v2_v2fl(float v1[2], const float v2[2], const float dist) +{ + if (!equals_v2v2(v2, v1)) { + float nor[2]; + + sub_v2_v2v2(nor, v1, v2); + normalize_v2(nor); + madd_v2_v2v2fl(v1, v2, nor, dist); + } +} + +void BKE_mask_calc_handle_adjacent_interp(MaskSpline *spline, MaskSplinePoint *point, const float u) +{ + /* TODO! - make this interpolate between siblings - not always midpoint! */ + int length_tot = 0; + float length_average = 0.0f; + float weight_average = 0.0f; + + + MaskSplinePoint *point_prev, *point_next; + + BLI_assert(u >= 0.0f && u <= 1.0f); + + BKE_mask_get_handle_point_adjacent(spline, point, + &point_prev, &point_next); + + if (point_prev && point_next) { + length_average = ((len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]) * (1.0f - u)) + + (len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]) * u)); + + weight_average = (point_prev->bezt.weight * (1.0f - u) + + point_next->bezt.weight * u); + length_tot = 1; + } + else { + if (point_prev) { + length_average += len_v2v2(point_prev->bezt.vec[0], point_prev->bezt.vec[1]); + weight_average += point_prev->bezt.weight; + length_tot++; + } + + if (point_next) { + length_average += len_v2v2(point_next->bezt.vec[2], point_next->bezt.vec[1]); + weight_average += point_next->bezt.weight; + length_tot++; + } + } + + if (length_tot) { + length_average /= (float)length_tot; + weight_average /= (float)length_tot; + + enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); + enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); + point->bezt.weight = weight_average; + } +} + + +/** + * \brief Resets auto handles even for non-auto bezier points + * + * Useful for giving sane defaults. + */ +void BKE_mask_calc_handle_point_auto(MaskSpline *spline, MaskSplinePoint *point, + const short do_recalc_length) +{ + MaskSplinePoint *point_prev, *point_next; + const char h_back[2] = {point->bezt.h1, point->bezt.h2}; + const float length_average = (do_recalc_length) ? 0.0f /* dummy value */ : + (len_v3v3(point->bezt.vec[0], point->bezt.vec[1]) + + len_v3v3(point->bezt.vec[1], point->bezt.vec[2])) / 2.0f; + + BKE_mask_get_handle_point_adjacent(spline, point, + &point_prev, &point_next); + + point->bezt.h1 = HD_AUTO; + point->bezt.h2 = HD_AUTO; + mask_calc_point_handle(point, point_prev, point_next); + + point->bezt.h1 = h_back[0]; + point->bezt.h2 = h_back[1]; + + /* preserve length by applying it back */ + if (do_recalc_length == FALSE) { + enforce_dist_v2_v2fl(point->bezt.vec[0], point->bezt.vec[1], length_average); + enforce_dist_v2_v2fl(point->bezt.vec[2], point->bezt.vec[1], length_average); + } +} + +void BKE_mask_layer_calc_handles(MaskLayer *masklay) +{ + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + BKE_mask_calc_handle_point(spline, &spline->points[i]); + } + } +} + +void BKE_mask_layer_calc_handles_deform(MaskLayer *masklay) +{ + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + BKE_mask_calc_handle_point(spline, &spline->points_deform[i]); + } + } +} + +void BKE_mask_calc_handles(Mask *mask) +{ + MaskLayer *masklay; + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + BKE_mask_layer_calc_handles(masklay); + } +} + +void BKE_mask_update_deform(Mask *mask) +{ + MaskLayer *masklay; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + + for (i = 0; i < spline->tot_point; i++) { + const int i_prev = (i - 1) % spline->tot_point; + const int i_next = (i + 1) % spline->tot_point; + + BezTriple *bezt_prev = &spline->points[i_prev].bezt; + BezTriple *bezt = &spline->points[i].bezt; + BezTriple *bezt_next = &spline->points[i_next].bezt; + + BezTriple *bezt_def_prev = &spline->points_deform[i_prev].bezt; + BezTriple *bezt_def = &spline->points_deform[i].bezt; + BezTriple *bezt_def_next = &spline->points_deform[i_next].bezt; + + float w_src[4]; + int j; + + for (j = 0; j <= 2; j += 2) { /* (0, 2) */ + printf("--- %d %d, %d, %d\n", i, j, i_prev, i_next); + barycentric_weights_v2(bezt_prev->vec[1], bezt->vec[1], bezt_next->vec[1], + bezt->vec[j], w_src); + interp_v3_v3v3v3(bezt_def->vec[j], + bezt_def_prev->vec[1], bezt_def->vec[1], bezt_def_next->vec[1], w_src); + } + } + } + } +} + +void BKE_mask_spline_ensure_deform(MaskSpline *spline) +{ + int allocated_points = (MEM_allocN_len(spline->points_deform) / sizeof(*spline->points_deform)); + // printf("SPLINE ALLOC %p %d\n", spline->points_deform, allocated_points); + + if (spline->points_deform == NULL || allocated_points != spline->tot_point) { + printf("alloc new deform spline\n"); + + if (spline->points_deform) { + int i; + + for (i = 0; i < allocated_points; i++) { + MaskSplinePoint *point = &spline->points_deform[i]; + BKE_mask_point_free(point); + } + + MEM_freeN(spline->points_deform); + } + + spline->points_deform = MEM_callocN(sizeof(*spline->points_deform) * spline->tot_point, __func__); + } + else { + // printf("alloc spline done\n"); + } +} + +void BKE_mask_evaluate(Mask *mask, const float ctime, const int do_newframe) +{ + MaskLayer *masklay; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + + /* animation if available */ + if (do_newframe) { + MaskLayerShape *masklay_shape_a; + MaskLayerShape *masklay_shape_b; + int found; + + if ((found = BKE_mask_layer_shape_find_frame_range(masklay, ctime, + &masklay_shape_a, &masklay_shape_b))) + { + if (found == 1) { +#if 0 + printf("%s: exact %d %d (%d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), + masklay_shape_a->frame); +#endif + + BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); + } + else if (found == 2) { + float w = masklay_shape_b->frame - masklay_shape_a->frame; +#if 0 + printf("%s: tween %d %d (%d %d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), + masklay_shape_a->frame, masklay_shape_b->frame); +#endif + BKE_mask_layer_shape_to_mask_interp(masklay, masklay_shape_a, masklay_shape_b, + (ctime - masklay_shape_a->frame) / w); + } + else { + /* always fail, should never happen */ + BLI_assert(found == 2); + } + } + } + /* animation done... */ + } + + BKE_mask_calc_handles(mask); + + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + int has_auto = FALSE; + + BKE_mask_spline_ensure_deform(spline); + + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + MaskSplinePoint *point_deform = &spline->points_deform[i]; + float delta[2]; + + BKE_mask_point_free(point_deform); + + *point_deform = *point; + point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; + + if (BKE_mask_evaluate_parent_delta(&point->parent, ctime, delta)) { + add_v2_v2(point_deform->bezt.vec[0], delta); + add_v2_v2(point_deform->bezt.vec[1], delta); + add_v2_v2(point_deform->bezt.vec[2], delta); + } + + if (point->bezt.h1 == HD_AUTO) { + has_auto = TRUE; + } + } + + /* if the spline has auto handles, these need to be recalculated after deformation */ + if (has_auto) { + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point_deform = &spline->points_deform[i]; + if (point_deform->bezt.h1 == HD_AUTO) { + BKE_mask_calc_handle_point(spline, point_deform); + } + } + } + /* end extra calc handles loop */ + } + } +} + +/* the purpose of this function is to ensure spline->points_deform is never out of date. + * 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); +} + +void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const int do_newframe) +{ + Mask *mask; + + for (mask = bmain->mask.first; mask; mask = mask->id.next) { + BKE_mask_evaluate(mask, ctime, do_newframe); + } +} + +void BKE_mask_update_scene(Main *bmain, Scene *scene, const int do_newframe) +{ + Mask *mask; + + for (mask = bmain->mask.first; mask; mask = mask->id.next) { + if (mask->id.flag & LIB_ID_RECALC) { + BKE_mask_evaluate_all_masks(bmain, CFRA, do_newframe); + } + } +} + +void BKE_mask_parent_init(MaskParent *parent) +{ + parent->id_type = ID_MC; +} + + +/* *** own animation/shapekey implimentation *** + * BKE_mask_layer_shape_XXX */ + +int BKE_mask_layer_shape_totvert(MaskLayer *masklay) +{ + int tot = 0; + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + tot += spline->tot_point; + } + + return tot; +} + +static void mask_layer_shape_from_mask_point(BezTriple *bezt, float fp[MASK_OBJECT_SHAPE_ELEM_SIZE]) +{ + copy_v2_v2(&fp[0], bezt->vec[0]); + copy_v2_v2(&fp[2], bezt->vec[1]); + copy_v2_v2(&fp[4], bezt->vec[2]); + fp[6] = bezt->weight; + fp[7] = bezt->radius; +} + +static void mask_layer_shape_to_mask_point(BezTriple *bezt, float fp[MASK_OBJECT_SHAPE_ELEM_SIZE]) +{ + copy_v2_v2(bezt->vec[0], &fp[0]); + copy_v2_v2(bezt->vec[1], &fp[2]); + copy_v2_v2(bezt->vec[2], &fp[4]); + bezt->weight = fp[6]; + bezt->radius = fp[7]; +} + +/* these functions match. copy is swapped */ +void BKE_mask_layer_shape_from_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape) +{ + int tot = BKE_mask_layer_shape_totvert(masklay); + + if (masklay_shape->tot_vert == tot) { + float *fp = masklay_shape->data; + + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + mask_layer_shape_from_mask_point(&spline->points[i].bezt, fp); + fp += MASK_OBJECT_SHAPE_ELEM_SIZE; + } + } + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert, tot, masklay_shape->frame); + } +} + +void BKE_mask_layer_shape_to_mask(MaskLayer *masklay, MaskLayerShape *masklay_shape) +{ + int tot = BKE_mask_layer_shape_totvert(masklay); + + if (masklay_shape->tot_vert == tot) { + float *fp = masklay_shape->data; + + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + mask_layer_shape_to_mask_point(&spline->points[i].bezt, fp); + fp += MASK_OBJECT_SHAPE_ELEM_SIZE; + } + } + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert, tot, masklay_shape->frame); + } +} + +BLI_INLINE void interp_v2_v2v2_flfl(float target[2], const float a[2], const float b[2], + const float t, const float s) +{ + target[0] = s * a[0] + t * b[0]; + target[1] = s * a[1] + t * b[1]; +} + +/* linear interpolation only */ +void BKE_mask_layer_shape_to_mask_interp(MaskLayer *masklay, + MaskLayerShape *masklay_shape_a, + MaskLayerShape *masklay_shape_b, + const float fac) +{ + int tot = BKE_mask_layer_shape_totvert(masklay); + if (masklay_shape_a->tot_vert == tot && masklay_shape_b->tot_vert == tot) { + float *fp_a = masklay_shape_a->data; + float *fp_b = masklay_shape_b->data; + const float ifac = 1.0f - fac; + + MaskSpline *spline; + for (spline = masklay->splines.first; spline; spline = spline->next) { + int i; + for (i = 0; i < spline->tot_point; i++) { + BezTriple *bezt = &spline->points[i].bezt; + /* *** BKE_mask_layer_shape_from_mask - swapped *** */ + interp_v2_v2v2_flfl(bezt->vec[0], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2; + interp_v2_v2v2_flfl(bezt->vec[1], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2; + interp_v2_v2v2_flfl(bezt->vec[2], fp_a, fp_b, fac, ifac); fp_a += 2; fp_b += 2; + bezt->weight = (fp_a[0] * ifac) + (fp_b[0] * fac); + bezt->radius = (fp_a[1] * ifac) + (fp_b[1] * fac); fp_a += 2; fp_b += 2; + } + } + } + else { + printf("%s: vert mismatch %d != %d != %d (frame %d - %d)\n", + __func__, masklay_shape_a->tot_vert, masklay_shape_b->tot_vert, tot, + masklay_shape_a->frame, masklay_shape_b->frame); + } +} + +MaskLayerShape *BKE_mask_layer_shape_find_frame(MaskLayer *masklay, const int frame) +{ + MaskLayerShape *masklay_shape; + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (frame == masklay_shape->frame) { + return masklay_shape; + } + else if (frame < masklay_shape->frame) { + break; + } + } + + return NULL; +} + +/* when returning 2 - the frame isnt found but before/after frames are */ +int BKE_mask_layer_shape_find_frame_range(MaskLayer *masklay, const float frame, + MaskLayerShape **r_masklay_shape_a, + MaskLayerShape **r_masklay_shape_b) +{ + MaskLayerShape *masklay_shape; + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (frame == masklay_shape->frame) { + *r_masklay_shape_a = masklay_shape; + *r_masklay_shape_b = NULL; + return 1; + } + else if (frame < masklay_shape->frame) { + if (masklay_shape->prev) { + *r_masklay_shape_a = masklay_shape->prev; + *r_masklay_shape_b = masklay_shape; + return 2; + } + else { + *r_masklay_shape_a = masklay_shape; + *r_masklay_shape_b = NULL; + return 1; + } + } + } + + if ((masklay_shape = masklay->splines_shapes.last)) { + *r_masklay_shape_a = masklay_shape; + *r_masklay_shape_b = NULL; + return 1; + } + else { + *r_masklay_shape_a = NULL; + *r_masklay_shape_b = NULL; + + return 0; + } +} + +MaskLayerShape *BKE_mask_layer_shape_varify_frame(MaskLayer *masklay, const int frame) +{ + MaskLayerShape *masklay_shape; + + masklay_shape = BKE_mask_layer_shape_find_frame(masklay, frame); + + if (masklay_shape == NULL) { + masklay_shape = BKE_mask_layer_shape_alloc(masklay, frame); + BLI_addtail(&masklay->splines_shapes, masklay_shape); + 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; +} + +MaskLayerShape *BKE_mask_layer_shape_duplicate(MaskLayerShape *masklay_shape) +{ + MaskLayerShape *masklay_shape_copy; + + masklay_shape_copy = MEM_dupallocN(masklay_shape); + + if (LIKELY(masklay_shape_copy->data)) { + masklay_shape_copy->data = MEM_dupallocN(masklay_shape_copy->data); + } + + return masklay_shape_copy; +} + +void BKE_mask_layer_shape_unlink(MaskLayer *masklay, MaskLayerShape *masklay_shape) +{ + BLI_remlink(&masklay->splines_shapes, masklay_shape); + + BKE_mask_layer_shape_free(masklay_shape); +} + +static int mask_layer_shape_sort_cb(void *masklay_shape_a_ptr, void *masklay_shape_b_ptr) +{ + MaskLayerShape *masklay_shape_a = (MaskLayerShape *)masklay_shape_a_ptr; + MaskLayerShape *masklay_shape_b = (MaskLayerShape *)masklay_shape_b_ptr; + + if (masklay_shape_a->frame < masklay_shape_b->frame) return -1; + else if (masklay_shape_a->frame > masklay_shape_b->frame) return 1; + else return 0; +} + +void BKE_mask_layer_shape_sort(MaskLayer *masklay) +{ + BLI_sortlist(&masklay->splines_shapes, mask_layer_shape_sort_cb); +} + +int BKE_mask_layer_shape_spline_from_index(MaskLayer *masklay, int index, + MaskSpline **r_masklay_shape, int *r_index) +{ + MaskSpline *spline; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + if (index < spline->tot_point) { + *r_masklay_shape = spline; + *r_index = index; + return TRUE; + } + index -= spline->tot_point; + } + + return FALSE; +} + +int BKE_mask_layer_shape_spline_to_index(MaskLayer *masklay, MaskSpline *spline) +{ + MaskSpline *spline_iter; + int i_abs = 0; + for (spline_iter = masklay->splines.first; + spline_iter && spline_iter != spline; + i_abs += spline_iter->tot_point, spline_iter = spline_iter->next) + { + /* pass */ + } + + return i_abs; +} + +/* basic 2D interpolation functions, could make more comprehensive later */ +static void interp_weights_uv_v2_calc(float r_uv[2], const float pt[2], const float pt_a[2], const float pt_b[2]) +{ + float pt_on_line[2]; + r_uv[0] = closest_to_line_v2(pt_on_line, pt, pt_a, pt_b); + r_uv[1] = (len_v2v2(pt_on_line, pt) / len_v2v2(pt_a, pt_b)) * + ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ? -1.0 : 1.0); /* this line only sets the sign */ +} + + +static void interp_weights_uv_v2_apply(const float uv[2], float r_pt[2], const float pt_a[2], const float pt_b[2]) +{ + const float dvec[2] = {pt_b[0] - pt_a[0], + pt_b[1] - pt_a[1]}; + + /* u */ + madd_v2_v2v2fl(r_pt, pt_a, dvec, uv[0]); + + /* v */ + r_pt[0] += -dvec[1] * uv[1]; + r_pt[1] += dvec[0] * uv[1]; +} + +/* when a now points added - resize all shapekey array */ +void BKE_mask_layer_shape_changed_add(MaskLayer *masklay, int index, + int do_init, int do_init_interpolate) +{ + MaskLayerShape *masklay_shape; + + /* spline index from masklay */ + MaskSpline *spline; + int spline_point_index; + + if (BKE_mask_layer_shape_spline_from_index(masklay, index, + &spline, &spline_point_index)) + { + /* sanity check */ + /* the point has already been removed in this array so subtract one when comparing with the shapes */ + int tot = BKE_mask_layer_shape_totvert(masklay) - 1; + + /* for interpolation */ + /* TODO - assumes closed curve for now */ + float uv[3][2]; /* 3x 2D handles */ + const int pi_curr = spline_point_index; + const int pi_prev = ((spline_point_index - 1) + spline->tot_point) % spline->tot_point; + const int pi_next = (spline_point_index + 1) % spline->tot_point; + + const int index_offset = index - spline_point_index; + /* const int pi_curr_abs = index; */ + const int pi_prev_abs = pi_prev + index_offset; + const int pi_next_abs = pi_next + index_offset; + + int i; + if (do_init_interpolate) { + for (i = 0; i < 3; i++) { + interp_weights_uv_v2_calc(uv[i], + spline->points[pi_curr].bezt.vec[i], + spline->points[pi_prev].bezt.vec[i], + spline->points[pi_next].bezt.vec[i]); + } + } + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (tot == masklay_shape->tot_vert) { + float *data_resized; + + masklay_shape->tot_vert++; + data_resized = MEM_mallocN(masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__); + if (index > 0) { + memcpy(data_resized, + masklay_shape->data, + index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + if (index != masklay_shape->tot_vert - 1) { + memcpy(&data_resized[(index + 1) * MASK_OBJECT_SHAPE_ELEM_SIZE], + masklay_shape->data + (index * MASK_OBJECT_SHAPE_ELEM_SIZE), + (masklay_shape->tot_vert - (index + 1)) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + if (do_init) { + float *fp = &data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE]; + + mask_layer_shape_from_mask_point(&spline->points[spline_point_index].bezt, fp); + + if (do_init_interpolate && spline->tot_point > 2) { + for (i = 0; i < 3; i++) { + interp_weights_uv_v2_apply(uv[i], + &fp[i * 2], + &data_resized[(pi_prev_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)], + &data_resized[(pi_next_abs * MASK_OBJECT_SHAPE_ELEM_SIZE) + (i * 2)]); + } + } + } + else { + memset(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE], + 0, + sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + MEM_freeN(masklay_shape->data); + masklay_shape->data = data_resized; + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert, tot, masklay_shape->frame); + } + } + } +} + + +/* move array to account for removed point */ +void BKE_mask_layer_shape_changed_remove(MaskLayer *masklay, int index, int count) +{ + MaskLayerShape *masklay_shape; + + /* the point has already been removed in this array so add one when comparing with the shapes */ + int tot = BKE_mask_layer_shape_totvert(masklay); + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + if (tot == masklay_shape->tot_vert - count) { + float *data_resized; + + masklay_shape->tot_vert -= count; + data_resized = MEM_mallocN(masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, __func__); + if (index > 0) { + memcpy(data_resized, + masklay_shape->data, + index * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + if (index != masklay_shape->tot_vert) { + memcpy(&data_resized[index * MASK_OBJECT_SHAPE_ELEM_SIZE], + masklay_shape->data + ((index + count) * MASK_OBJECT_SHAPE_ELEM_SIZE), + (masklay_shape->tot_vert - index) * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE); + } + + MEM_freeN(masklay_shape->data); + masklay_shape->data = data_resized; + } + else { + printf("%s: vert mismatch %d != %d (frame %d)\n", + __func__, masklay_shape->tot_vert - count, tot, masklay_shape->frame); + } + } +} + +/* local functions */ +static void invert_vn_vn(float *array, const int size) +{ + float *arr = array + (size - 1); + int i = size; + while (i--) { + *(arr) = 1.0f - *(arr); + arr--; + } +} + +static void m_invert_vn_vn(float *array, const float f, const int size) +{ + float *arr = array + (size - 1); + int i = size; + while (i--) { + *(arr) = 1.0f - (*(arr) * f); + arr--; + } +} + +static void clamp_vn_vn_linear(float *array, const int size) +{ + float *arr = array + (size - 1); + + int i = size; + while (i--) { + if (*arr <= 0.0f) *arr = 0.0f; + else if (*arr >= 1.0f) *arr = 1.0f; + else *arr = srgb_to_linearrgb(*arr); + arr--; + } +} + +static void clamp_vn_vn(float *array, const int size) +{ + float *arr = array + (size - 1); + + int i = size; + while (i--) { + if (*arr < 0.0f) *arr = 0.0f; + else if (*arr > 1.0f) *arr = 1.0f; + arr--; + } +} + +int BKE_mask_get_duration(Mask *mask) +{ + return MAX2(1, mask->efra - mask->sfra); +} + +/* rasterization */ +void BKE_mask_rasterize(Mask *mask, int width, int height, float *buffer, + const short do_aspect_correct, const short do_linear) +{ + MaskLayer *masklay; + + /* temp blending buffer */ + const int buffer_size = width * height; + float *buffer_tmp = MEM_mallocN(sizeof(float) * buffer_size, __func__); + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + MaskSpline *spline; + float alpha; + + if (masklay->restrictflag & MASK_RESTRICT_RENDER) { + continue; + } + + memset(buffer_tmp, 0, sizeof(float) * buffer_size); + + for (spline = masklay->splines.first; spline; spline = spline->next) { + float (*diff_points)[2]; + int tot_diff_point; + + float (*diff_feather_points)[2]; + int tot_diff_feather_points; + + diff_points = BKE_mask_spline_differentiate_with_resolution(spline, width, height, + &tot_diff_point); + + if (tot_diff_point) { + diff_feather_points = + BKE_mask_spline_feather_differentiated_points_with_resolution(spline, width, height, + &tot_diff_feather_points); + + if (do_aspect_correct) { + if (width != height) { + float *fp; + float *ffp; + int i; + float asp; + + if (width < height) { + fp = &diff_points[0][0]; + ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL; + asp = (float)width / (float)height; + } + else { + fp = &diff_points[0][1]; + ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL; + asp = (float)height / (float)width; + } + + for (i = 0; i < tot_diff_point; i++, fp += 2) { + (*fp) = (((*fp) - 0.5f) / asp) + 0.5f; + } + + if (tot_diff_feather_points) { + for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) { + (*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f; + } + } + } + } + + if (tot_diff_point) { + PLX_raskterize(diff_points, tot_diff_point, + buffer_tmp, width, height); + + if (tot_diff_feather_points) { + PLX_raskterize_feather(diff_points, tot_diff_point, + diff_feather_points, tot_diff_feather_points, + buffer_tmp, width, height); + MEM_freeN(diff_feather_points); + } + + MEM_freeN(diff_points); + } + } + } + + /* blend with original */ + if (masklay->blend_flag & MASK_BLENDFLAG_INVERT) { + /* apply alpha multiply before inverting */ + if (masklay->alpha != 1.0f) { + m_invert_vn_vn(buffer_tmp, masklay->alpha, buffer_size); + } + else { + invert_vn_vn(buffer_tmp, buffer_size); + } + + alpha = 1.0f; + } + else { + alpha = masklay->alpha; + } + + switch (masklay->blend) { + case MASK_BLEND_SUBTRACT: + { + if (alpha == 1.0f) { + sub_vn_vn(buffer, buffer_tmp, buffer_size); + } + else { + msub_vn_vn(buffer, buffer_tmp, alpha, buffer_size); + } + break; + } + case MASK_BLEND_ADD: + default: + { + if (alpha == 1.0f) { + add_vn_vn(buffer, buffer_tmp, buffer_size); + } + else { + madd_vn_vn(buffer, buffer_tmp, alpha, buffer_size); + } + break; + } + } + + /* clamp at the end */ + if (do_linear) { + clamp_vn_vn_linear(buffer, buffer_size); + } + else { + clamp_vn_vn(buffer, buffer_size); + } + } + + MEM_freeN(buffer_tmp); +} diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index fd952b7b518..d0b9e73e295 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1946,8 +1946,8 @@ void BKE_mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces, MEM_freeN(fnors); } - -static void bm_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol) +static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, + MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol) { MTFace *texface; MTexPoly *texpoly; @@ -1957,15 +1957,15 @@ static void bm_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, MFace *mf; int i; - mf = me->mface + findex; + mf = mface + findex; for (i = 0; i < numTex; i++) { - texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i); - texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, 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(&me->ldata, CD_MLOOPUV, loopstart, i); + + mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i); copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++; copy_v2_v2(mloopuv->uv, texface->uv[1]); mloopuv++; copy_v2_v2(mloopuv->uv, texface->uv[2]); mloopuv++; @@ -1976,8 +1976,8 @@ static void bm_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, } for (i = 0; i < numCol; i++) { - mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i); - mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i); + mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i); + mcol = CustomData_get_n(fdata, CD_MCOL, findex, i); MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]); mloopcol++; MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]); mloopcol++; @@ -1986,21 +1986,23 @@ static void bm_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]); mloopcol++; } } - - if (CustomData_has_layer(&me->fdata, CD_MDISPS)) { - MDisps *ld = CustomData_get(&me->ldata, loopstart, CD_MDISPS); - MDisps *fd = CustomData_get(&me->fdata, findex, CD_MDISPS); + + if (CustomData_has_layer(fdata, CD_MDISPS)) { + MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS); + MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS); float (*disps)[3] = fd->disps; int i, tot = mf->v4 ? 4 : 3; int side, corners; - if (CustomData_external_test(&me->fdata, CD_MDISPS)) { - CustomData_external_add(&me->ldata, &me->id, CD_MDISPS, - me->totloop, me->fdata.external->filename); + if (CustomData_external_test(fdata, CD_MDISPS)) { + if (id) { + CustomData_external_add(ldata, id, CD_MDISPS, + totloop, fdata->external->filename); + } } - + corners = multires_mdisp_corners(fd); - + if (corners == 0) { /* Empty MDisp layers appear in at least one of the sintel.blend files. * Not sure why this happens, but it seems fine to just ignore them here. @@ -2009,14 +2011,14 @@ static void bm_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, } else { side = sqrt(fd->totdisp / corners); - + for (i = 0; i < tot; i++, disps += side * side, ld++) { ld->totdisp = side * side; ld->level = (int)(logf(side - 1.0f) / (float)M_LN2) + 1; - + if (ld->disps) MEM_freeN(ld->disps); - + ld->disps = MEM_callocN(sizeof(float) * 3 * side * side, "converted loop mdisps"); if (fd->disps) { memcpy(ld->disps, disps, sizeof(float) * 3 * side * side); @@ -2028,70 +2030,109 @@ static void bm_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh) { + BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata, + mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly, + mesh->medge, mesh->mface, + &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly); + + mesh_update_customdata_pointers(mesh, TRUE); +} + +/* the same as BKE_mesh_convert_mfaces_to_mpolys but oriented to be used in do_versions from readfile.c + * the difference is how active/render/clone/stencil indices are handled here + * + * normally thay're being set from pdata which totally makes sense for meshes which are already + * converted to bmesh structures, but when loading older files indices shall be updated in other + * way around, so newly added pdata and ldata would have this indices set based on fdata layer + * + * this is normally only needed when reading older files, in all other cases BKE_mesh_convert_mfaces_to_mpolys + * shall be always used + */ +void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) +{ + BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata, + mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly, + 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); + + mesh_update_customdata_pointers(mesh, TRUE); +} + +void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, + int totedge_i, int totface_i, int totloop_i, int totpoly_i, + MEdge *medge, MFace *mface, + int *totloop_r, int *totpoly_r, + MLoop **mloop_r, MPoly **mpoly_r) +{ MFace *mf; - MLoop *ml; - MPoly *mp; + MLoop *ml, *mloop; + MPoly *mp, *mpoly; MEdge *me; EdgeHash *eh; int numTex, numCol; - int i, j, totloop; + int i, j, totloop, totpoly, *polyindex; /* just in case some of these layers are filled in (can happen with python created meshes) */ - CustomData_free(&mesh->ldata, mesh->totloop); - CustomData_free(&mesh->pdata, mesh->totpoly); - memset(&mesh->ldata, 0, sizeof(mesh->ldata)); - memset(&mesh->pdata, 0, sizeof(mesh->pdata)); + CustomData_free(ldata, totloop_i); + CustomData_free(pdata, totpoly_i); + memset(ldata, 0, sizeof(*ldata)); + memset(pdata, 0, sizeof(*pdata)); - mesh->totpoly = mesh->totface; - mesh->mpoly = MEM_callocN(sizeof(MPoly) * mesh->totpoly, "mpoly converted"); - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly); + totpoly = totface_i; + mpoly = MEM_callocN(sizeof(MPoly) * totpoly, "mpoly converted"); + CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly); + + numTex = CustomData_number_of_layers(fdata, CD_MTFACE); + numCol = CustomData_number_of_layers(fdata, CD_MCOL); - numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE); - numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL); - totloop = 0; - mf = mesh->mface; - for (i = 0; i < mesh->totface; i++, mf++) { + mf = mface; + for (i = 0; i < totface_i; i++, mf++) { totloop += mf->v4 ? 4 : 3; } - - mesh->totloop = totloop; - mesh->mloop = MEM_callocN(sizeof(MLoop) * mesh->totloop, "mloop converted"); - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop); - CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata, - mesh->totloop, mesh->totpoly); + mloop = MEM_callocN(sizeof(MLoop) * totloop, "mloop converted"); + + CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); - /* ensure external data is transferred */ - CustomData_external_read(&mesh->fdata, &mesh->id, CD_MASK_MDISPS, mesh->totface); + CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly); + + if (id) { + /* ensure external data is transferred */ + CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i); + } eh = BLI_edgehash_new(); - /*build edge hash*/ - me = mesh->medge; - for (i = 0; i < mesh->totedge; i++, me++) { + /* build edge hash */ + me = medge; + for (i = 0; i < totedge_i; i++, me++) { BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i)); /* unrelated but avoid having the FGON flag enabled, so we can reuse it later for something else */ me->flag &= ~ME_FGON; } - j = 0; /*current loop index*/ - ml = mesh->mloop; - mf = mesh->mface; - mp = mesh->mpoly; - for (i = 0; i < mesh->totface; i++, mf++, mp++) { + polyindex = CustomData_get_layer(fdata, CD_POLYINDEX); + + j = 0; /* current loop index */ + ml = mloop; + mf = mface; + mp = mpoly; + for (i = 0; i < totface_i; i++, mf++, mp++) { mp->loopstart = j; - + mp->totloop = mf->v4 ? 4 : 3; mp->mat_nr = mf->mat_nr; mp->flag = mf->flag; - + # define ML(v1, v2) { \ ml->v = mf->v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); ml++; j++; \ } (void)0 - + ML(v1, v2); ML(v2, v3); if (mf->v4) { @@ -2101,18 +2142,26 @@ void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh) else { ML(v3, v1); } - + # undef ML - bm_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol); + bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol); + + if (polyindex) { + *polyindex = i; + polyindex++; + } } /* note, we don't convert FGons at all, these are not even real ngons, * they have their own UV's, colors etc - its more an editing feature. */ - mesh_update_customdata_pointers(mesh, TRUE); - BLI_edgehash_free(eh, NULL); + + *totpoly_r = totpoly; + *totloop_r = totloop; + *mpoly_r = mpoly; + *mloop_r = mloop; } float (*mesh_getVertexCos(Mesh * me, int *numVerts_r))[3] diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index ccf64639967..8b91ee29c59 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -154,11 +154,12 @@ static void get_sequence_fname(MovieClip *clip, int framenr, char *name) BLI_stringdec(name, head, tail, &numlen); /* movieclips always points to first image from sequence, - * autoguess offset for now. could be something smarter in the future */ + * autoguess offset for now. could be something smarter in the future + */ offset = sequence_guess_offset(clip->name, strlen(head), numlen); if (numlen) - BLI_stringenc(name, head, tail, numlen, offset + framenr - 1); + BLI_stringenc(name, head, tail, numlen, offset + framenr - clip->start_frame); else BLI_strncpy(name, clip->name, sizeof(clip->name)); @@ -170,6 +171,7 @@ static void get_proxy_fname(MovieClip *clip, int proxy_render_size, int undistor { int size = rendersize_to_number(proxy_render_size); char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX]; + int proxynr = framenr - clip->start_frame + 1; BLI_split_dirfile(clip->name, clipdir, clipfile, FILE_MAX, FILE_MAX); @@ -181,9 +183,9 @@ static void get_proxy_fname(MovieClip *clip, int proxy_render_size, int undistor } if (undistorted) - BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d_undistorted/%08d", dir, clipfile, size, framenr); + BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d_undistorted/%08d", dir, clipfile, size, proxynr); else - BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, framenr); + BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, proxynr); BLI_path_abs(name, G.main->name); BLI_path_frame(name, 1, 0); @@ -248,7 +250,7 @@ static ImBuf *movieclip_load_movie_file(MovieClip *clip, MovieClipUser *user, in int fra; dur = IMB_anim_get_duration(clip->anim, tc); - fra = framenr - 1; + fra = framenr - clip->start_frame; if (fra < 0) fra = 0; @@ -312,7 +314,7 @@ typedef struct MovieClipCache { /* cache for undistorted shot */ float principal[2]; float k1, k2, k3; - short undistoriton_used; + short undistortion_used; int proxy; short render_flag; @@ -443,6 +445,8 @@ static MovieClip *movieclip_alloc(const char *name) IMB_TC_RECORD_RUN_NO_GAPS; clip->proxy.quality = 90; + clip->start_frame = 1; + return clip; } @@ -623,7 +627,7 @@ static ImBuf *get_postprocessed_cached_frame(MovieClip *clip, MovieClipUser *use if (!check_undistortion_cache_flags(clip)) return NULL; } - else if (cache->postprocessed.undistoriton_used) + else if (cache->postprocessed.undistortion_used) return NULL; IMB_refImBuf(cache->postprocessed.ibuf); @@ -656,11 +660,11 @@ static ImBuf *put_postprocessed_frame_to_cache(MovieClip *clip, MovieClipUser *u if (need_undistortion_postprocess(user, flag)) { copy_v2_v2(cache->postprocessed.principal, camera->principal); copy_v3_v3(&cache->postprocessed.k1, &camera->k1); - cache->postprocessed.undistoriton_used = TRUE; + cache->postprocessed.undistortion_used = TRUE; postproc_ibuf = get_undistorted_ibuf(clip, NULL, ibuf); } else { - cache->postprocessed.undistoriton_used = FALSE; + cache->postprocessed.undistortion_used = FALSE; } if (postprocess_flag) { @@ -912,7 +916,17 @@ int BKE_movieclip_has_frame(MovieClip *clip, MovieClipUser *user) void BKE_movieclip_get_size(MovieClip *clip, MovieClipUser *user, int *width, int *height) { +#if 0 + /* originally was needed to support image sequences with different image dimensions, + * which might be useful for such things as reconstruction of unordered image sequence, + * or painting/rotoscoping of non-equal-sized images, but this ended up in unneeded + * 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) + */ if (user->framenr == clip->lastframe) { +#endif + if (clip->lastsize[0] != 0 && clip->lastsize[1] != 0) { *width = clip->lastsize[0]; *height = clip->lastsize[1]; } @@ -1018,6 +1032,11 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip scopes->track_preview = NULL; } + if (scopes->track_search) { + IMB_freeImBuf(scopes->track_search); + scopes->track_search = NULL; + } + scopes->marker = NULL; scopes->track = NULL; @@ -1026,7 +1045,8 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip if (act_track) { MovieTrackingTrack *track = act_track; - MovieTrackingMarker *marker = BKE_tracking_get_marker(track, user->framenr); + int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); + MovieTrackingMarker *marker = BKE_tracking_get_marker(track, framenr); if (marker->flag & MARKER_DISABLED) { scopes->track_disabled = TRUE; @@ -1037,7 +1057,7 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip scopes->track_disabled = FALSE; if (ibuf && (ibuf->rect || ibuf->rect_float)) { - ImBuf *tmpibuf; + ImBuf *search_ibuf; MovieTrackingMarker undist_marker = *marker; if (user->render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { @@ -1055,27 +1075,36 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip undist_marker.pos[1] /= height * aspy; } - /* NOTE: margin should be kept in sync with value from ui_draw_but_TRACKPREVIEW */ - tmpibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, &undist_marker, 3 /* margin */, - 1 /* anchor */, scopes->track_pos, NULL); + search_ibuf = BKE_tracking_get_search_imbuf(ibuf, track, &undist_marker, TRUE, TRUE); - if (tmpibuf->rect_float) - IMB_rect_from_float(tmpibuf); + if (!search_ibuf->rect_float) { + /* sampling happens in float buffer */ + IMB_float_from_rect(search_ibuf); + } + + scopes->undist_marker = undist_marker; + scopes->track_search = search_ibuf; - if (tmpibuf->rect) - scopes->track_preview = tmpibuf; - else - IMB_freeImBuf(tmpibuf); + scopes->frame_width = ibuf->x; + scopes->frame_height = ibuf->y; } IMB_freeImBuf(ibuf); } if ((track->flag & TRACK_LOCKED) == 0) { + float pat_min[2], pat_max[2]; + scopes->marker = marker; scopes->track = track; - scopes->slide_scale[0] = track->pat_max[0] - track->pat_min[0]; - scopes->slide_scale[1] = track->pat_max[1] - track->pat_min[1]; + + /* XXX: would work fine with non-transformed patterns, but would likely fail + * with transformed patterns, but that would be easier to debug when + * we'll have real pattern sampling (at least to test) */ + BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); + + scopes->slide_scale[0] = pat_max[0] - pat_min[0]; + scopes->slide_scale[1] = pat_max[1] - pat_min[1]; } } } @@ -1218,3 +1247,13 @@ void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) clip->id.us = 0; } + +int BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, int framenr) +{ + return framenr - clip->start_frame + 1; +} + +int BKE_movieclip_remap_clip_to_scene_frame(MovieClip *clip, int framenr) +{ + return framenr + clip->start_frame - 1; +} diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index d818ca09f20..4cbfb4f0f3e 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -1058,7 +1058,8 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm /* if needed, reallocate multires paint mask */ if (gpm && gpm->level < key.level) { gpm->level = key.level; - MEM_freeN(gpm->data); + if (gpm->data) + MEM_freeN(gpm->data); gpm->data = MEM_callocN(sizeof(float) * key.grid_area, "gpm.data"); } diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c index 24382b3bf91..a21878d1d7d 100644 --- a/source/blender/blenkernel/intern/navmesh_conversion.c +++ b/source/blender/blenkernel/intern/navmesh_conversion.c @@ -307,15 +307,15 @@ struct SortContext static int compareByData(void *ctx, const void * a, const void * b) { return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)a]] - - ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)b]] ); + ((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) + 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; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 22286e57c0a..d62e91dbde5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1910,6 +1910,8 @@ static void registerCompositNodes(bNodeTreeType *ttype) register_node_type_cmp_bokehimage(ttype); register_node_type_cmp_bokehblur(ttype); register_node_type_cmp_switch(ttype); + + register_node_type_cmp_mask(ttype); } static void registerShaderNodes(bNodeTreeType *ttype) @@ -1954,6 +1956,7 @@ static void registerShaderNodes(bNodeTreeType *ttype) register_node_type_sh_fresnel(ttype); register_node_type_sh_layer_weight(ttype); register_node_type_sh_tex_coord(ttype); + register_node_type_sh_particle_info(ttype); register_node_type_sh_background(ttype); register_node_type_sh_bsdf_diffuse(ttype); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 3304ccc73cf..b656cb6d8de 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -117,8 +117,6 @@ #include "FRS_freestyle.h" /* Local function protos */ -static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul); - float originmat[3][3]; /* after BKE_object_where_is_calc(), can be used in other functions (bad!) */ void BKE_object_workob_clear(Object *workob) @@ -1914,109 +1912,6 @@ static void ob_parvert3(Object *ob, Object *par, float mat[][4]) } } -static int where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat[4][4]) -{ - float *fp1, *fp2; - float fac1, fac2; - int a; - - // include framerate - fac1 = (1.0f / (1.0f + fabsf(ob->sf)) ); - if (fac1 >= 1.0f) return 0; - fac2 = 1.0f - fac1; - - fp1 = obmat[0]; - fp2 = slowmat[0]; - for (a = 0; a < 16; a++, fp1++, fp2++) { - fp1[0] = fac1 * fp1[0] + fac2 * fp2[0]; - } - - return 1; -} - -void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime) -{ - float slowmat[4][4] = MAT4_UNITY; - float stime = ctime; - - /* new version: correct parent+vertexparent and track+parent */ - /* this one only calculates direct attached parent and track */ - /* is faster, but should keep track of timeoffs */ - - 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); - - if (ob->parent) { - Object *par = ob->parent; - - /* hurms, code below conflicts with depgraph... (ton) */ - /* and even worse, it gives bad effects for NLA stride too (try ctime != par->ctime, with MBlur) */ - if (stime != par->ctime) { - // only for ipo systems? - Object tmp = *par; - - if (par->proxy_from) ; // was a copied matrix, no where_is! bad... - else BKE_object_where_is_calc_time(scene, par, ctime); - - solve_parenting(scene, ob, par, ob->obmat, slowmat, 0); - - *par = tmp; - } - else - solve_parenting(scene, ob, par, ob->obmat, slowmat, 0); - - /* "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 - */ - if (ob->partype & PARSLOW) { - if (!where_is_object_parslow(ob, ob->obmat, slowmat)) - return; - } - } - else { - BKE_object_to_mat4(ob, ob->obmat); - } - - /* solve constraints */ - if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) { - bConstraintOb *cob; - - cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - - /* constraints need ctime, not stime. Some call BKE_object_where_is_calc_time and bsystem_time */ - solve_constraints(&ob->constraints, cob, ctime); - - constraints_clear_evalob(cob); - } - - /* set negative scale flag in object */ - if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE; - else ob->transflag &= ~OB_NEG_SCALE; -} - -/* 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]) -{ - float slowmat[4][4] = MAT4_UNITY; - - if (ob->parent) { - Object *par = ob->parent; - - solve_parenting(scene, ob, par, obmat, slowmat, 1); - - if (ob->partype & PARSLOW) - where_is_object_parslow(ob, obmat, slowmat); - } - else { - BKE_object_to_mat4(ob, obmat); - } -} - static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul) { float totmat[4][4]; @@ -2038,11 +1933,11 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[] ok = 1; } } - + if (ok) mul_serie_m4(totmat, par->obmat, tmat, NULL, NULL, NULL, NULL, NULL, NULL); else copy_m4_m4(totmat, par->obmat); - + break; case PARBONE: ob_parbone(ob, par, tmat); @@ -2062,7 +1957,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[] break; case PARVERT3: ob_parvert3(ob, par, tmat); - + mul_serie_m4(totmat, par->obmat, tmat, NULL, NULL, NULL, NULL, NULL, NULL); break; @@ -2093,7 +1988,87 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[] copy_v3_v3(ob->orig, totmat[3]); } } +} + +static int where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat[4][4]) +{ + float *fp1, *fp2; + float fac1, fac2; + int a; + + // include framerate + fac1 = (1.0f / (1.0f + fabsf(ob->sf)) ); + if (fac1 >= 1.0f) return 0; + fac2 = 1.0f - fac1; + + fp1 = obmat[0]; + fp2 = slowmat[0]; + for (a = 0; a < 16; a++, fp1++, fp2++) { + fp1[0] = fac1 * fp1[0] + fac2 * fp2[0]; + } + + return 1; +} + +void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime) +{ + 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); + + if (ob->parent) { + Object *par = ob->parent; + float slowmat[4][4] = MAT4_UNITY; + + /* calculate parent matrix */ + solve_parenting(scene, ob, par, ob->obmat, slowmat, 0); + + /* "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 + */ + if (ob->partype & PARSLOW) { + if (!where_is_object_parslow(ob, ob->obmat, slowmat)) + return; + } + } + else { + BKE_object_to_mat4(ob, ob->obmat); + } + + /* solve constraints */ + if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) { + bConstraintOb *cob; + + cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + solve_constraints(&ob->constraints, cob, ctime); + constraints_clear_evalob(cob); + } + + /* set negative scale flag in object */ + if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE; + else ob->transflag &= ~OB_NEG_SCALE; +} +/* 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]) +{ + float slowmat[4][4] = MAT4_UNITY; + + if (ob->parent) { + Object *par = ob->parent; + + solve_parenting(scene, ob, par, obmat, slowmat, 1); + + if (ob->partype & PARSLOW) + where_is_object_parslow(ob, obmat, slowmat); + } + else { + BKE_object_to_mat4(ob, obmat); + } } void BKE_object_where_is_calc(struct Scene *scene, Object *ob) @@ -2101,7 +2076,6 @@ void BKE_object_where_is_calc(struct Scene *scene, Object *ob) BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); } - void BKE_object_where_is_calc_simul(Scene *scene, Object *ob) /* was written for the old game engine (until 2.04) */ /* It seems that this function is only called diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index c7f904755d9..f7e3e103e99 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -41,6 +41,7 @@ #include "BLI_utildefines.h" #include "BKE_brush.h" +#include "BKE_context.h" #include "BKE_library.h" #include "BKE_paint.h" #include "BKE_subsurf.h" @@ -83,6 +84,54 @@ Paint *paint_get_active(Scene *sce) return NULL; } +Paint *paint_get_active_from_context(const bContext *C) +{ + Scene *sce = CTX_data_scene(C); + + if (sce) { + ToolSettings *ts = sce->toolsettings; + Object *obact = NULL; + + if (sce->basact && sce->basact->object) + obact = sce->basact->object; + + if (CTX_wm_space_image(C) != NULL) { + if (obact->mode == OB_MODE_EDIT) { + if (ts->use_uv_sculpt) + return &ts->uvsculpt->paint; + else + return &ts->imapaint.paint; + } + else { + return &ts->imapaint.paint; + } + } + else if (obact) { + switch (obact->mode) { + case OB_MODE_SCULPT: + return &ts->sculpt->paint; + case OB_MODE_VERTEX_PAINT: + return &ts->vpaint->paint; + case OB_MODE_WEIGHT_PAINT: + return &ts->wpaint->paint; + case OB_MODE_TEXTURE_PAINT: + return &ts->imapaint.paint; + case OB_MODE_EDIT: + if (ts->use_uv_sculpt) + return &ts->uvsculpt->paint; + else + return &ts->imapaint.paint; + } + } + else { + /* default to image paint */ + return &ts->imapaint.paint; + } + } + + return NULL; +} + Brush *paint_brush(Paint *p) { return p ? p->brush : NULL; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index cdedd818b43..6c7336958b5 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2363,13 +2363,12 @@ static EdgeHash *sph_springhash_build(ParticleSystem *psys) } #define SPH_NEIGHBORS 512 -typedef struct SPHNeighbor -{ +typedef struct SPHNeighbor { ParticleSystem *psys; int index; } SPHNeighbor; -typedef struct SPHRangeData -{ + +typedef struct SPHRangeData { SPHNeighbor neighbors[SPH_NEIGHBORS]; int tot_neighbors; @@ -2641,8 +2640,7 @@ static void sph_integrate(ParticleSimulationData *sim, ParticleData *pa, float d /************************************************/ /* Basic physics */ /************************************************/ -typedef struct EfData -{ +typedef struct EfData { ParticleTexture ptex; ParticleSimulationData *sim; ParticleData *pa; @@ -2674,7 +2672,7 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo force[2] += (BLI_frand()-0.5f) * part->brownfac; } - if(part->flag & PART_ROT_DYN && epoint.ave) + if (part->flag & PART_ROT_DYN && epoint.ave) copy_v3_v3(pa->state.ave, epoint.ave); } /* gathers all forces that effect particles and calculates a new state for the particle */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 7c9d6bd05be..e0aed029451 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -63,6 +63,7 @@ #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_mask.h" #include "BKE_node.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -616,8 +617,6 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) /* not too nice... for recovering objects with lost data */ //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE; ob->flag = base->flag; - - ob->ctime = -1234567.0; /* force ipo to be calculated later */ } /* no full animation update, this to enable render code to work (render code calls own animation updates) */ } @@ -1011,6 +1010,9 @@ static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scen /* update sound system animation */ sound_update_scene(scene); + + /* update masking curves */ + BKE_mask_update_scene(bmain, scene, FALSE); } /* this is called in main loop, doing tagged updates before redraw */ @@ -1081,6 +1083,8 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) * so don't call within 'scene_update_tagged_recursive' */ DAG_scene_update_flags(bmain, sce, lay, TRUE); // only stuff that moves or needs display still + BKE_mask_evaluate_all_masks(bmain, ctime, TRUE); + /* 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 diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index f1f3dd47d8b..582034ae623 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -29,7 +29,7 @@ #include <stddef.h> -#include "BLO_sys_types.h" /* for intptr_t */ +#include "BLO_sys_types.h" /* for intptr_t */ #include "MEM_guardedalloc.h" @@ -38,22 +38,21 @@ #include "IMB_moviecache.h" -typedef struct seqCacheKey -{ - struct Sequence * seq; +typedef struct SeqCacheKey { + struct Sequence *seq; SeqRenderData context; float cfra; seq_stripelem_ibuf_t type; -} seqCacheKey; +} SeqCacheKey; static struct MovieCache *moviecache = NULL; static unsigned int seqcache_hashhash(const void *key_) { - const seqCacheKey *key = (seqCacheKey*) key_; + const SeqCacheKey *key = (SeqCacheKey *) key_; unsigned int rval = seq_hash_render_data(&key->context); - rval ^= *(unsigned int*) &key->cfra; + rval ^= *(unsigned int *) &key->cfra; rval += key->type; rval ^= ((intptr_t) key->seq) << 6; @@ -62,11 +61,11 @@ static unsigned int seqcache_hashhash(const void *key_) static int seqcache_hashcmp(const void *a_, const void *b_) { - const seqCacheKey * a = (seqCacheKey*) a_; - const seqCacheKey * b = (seqCacheKey*) b_; + const SeqCacheKey *a = (SeqCacheKey *) a_; + const SeqCacheKey *b = (SeqCacheKey *) b_; if (a->seq < b->seq) { - return -1; + return -1; } if (a->seq > b->seq) { return 1; @@ -99,18 +98,18 @@ void seq_stripelem_cache_cleanup(void) { if (moviecache) { IMB_moviecache_free(moviecache); - moviecache = IMB_moviecache_create(sizeof(seqCacheKey), seqcache_hashhash, - seqcache_hashcmp, NULL); + moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), seqcache_hashhash, + seqcache_hashcmp, NULL); } } -struct ImBuf * seq_stripelem_cache_get( - SeqRenderData context, struct Sequence * seq, - float cfra, seq_stripelem_ibuf_t type) +struct ImBuf *seq_stripelem_cache_get( + SeqRenderData context, struct Sequence *seq, + float cfra, seq_stripelem_ibuf_t type) { if (moviecache && seq) { - seqCacheKey key; + SeqCacheKey key; key.seq = seq; key.context = context; @@ -124,18 +123,18 @@ struct ImBuf * seq_stripelem_cache_get( } void seq_stripelem_cache_put( - SeqRenderData context, struct Sequence * seq, - float cfra, seq_stripelem_ibuf_t type, struct ImBuf * i) + SeqRenderData context, struct Sequence *seq, + float cfra, seq_stripelem_ibuf_t type, struct ImBuf *i) { - seqCacheKey key; + SeqCacheKey key; if (!i) { return; } if (!moviecache) { - moviecache = IMB_moviecache_create(sizeof(seqCacheKey), seqcache_hashhash, - seqcache_hashcmp, NULL); + moviecache = IMB_moviecache_create(sizeof(SeqCacheKey), seqcache_hashhash, + seqcache_hashcmp, NULL); } key.seq = seq; diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 4b6c362cd85..6e5149d7924 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -77,7 +77,7 @@ static ImBuf *prepare_effect_imbufs( if (!ibuf1 && !ibuf2 && !ibuf3) { /* hmmm, global float option ? */ - out = IMB_allocImBuf((short)x, (short)y, 32, IB_rect); + out = IMB_allocImBuf(x, y, 32, IB_rect); } else if ((ibuf1 && ibuf1->rect_float) || (ibuf2 && ibuf2->rect_float) || @@ -85,10 +85,10 @@ static ImBuf *prepare_effect_imbufs( { /* if any inputs are rectfloat, output is float too */ - out = IMB_allocImBuf((short)x, (short)y, 32, IB_rectfloat); + out = IMB_allocImBuf(x, y, 32, IB_rectfloat); } else { - out = IMB_allocImBuf((short)x, (short)y, 32, IB_rect); + out = IMB_allocImBuf(x, y, 32, IB_rect); } if (ibuf1 && !ibuf1->rect_float && out->rect_float) { @@ -2987,12 +2987,12 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.copy = NULL; switch (sequence_type) { - case SEQ_CROSS: + case SEQ_TYPE_CROSS: rval.execute = do_cross_effect; rval.early_out = early_out_fade; rval.get_default_fac = get_default_fac_fade; break; - case SEQ_GAMCROSS: + case SEQ_TYPE_GAMCROSS: rval.init = init_gammacross; rval.load = load_gammacross; rval.free = free_gammacross; @@ -3000,30 +3000,30 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.get_default_fac = get_default_fac_fade; rval.execute = do_gammacross_effect; break; - case SEQ_ADD: + case SEQ_TYPE_ADD: rval.execute = do_add_effect; rval.early_out = early_out_mul_input2; break; - case SEQ_SUB: + case SEQ_TYPE_SUB: rval.execute = do_sub_effect; rval.early_out = early_out_mul_input2; break; - case SEQ_MUL: + case SEQ_TYPE_MUL: rval.execute = do_mul_effect; rval.early_out = early_out_mul_input2; break; - case SEQ_ALPHAOVER: + case SEQ_TYPE_ALPHAOVER: rval.init = init_alpha_over_or_under; rval.execute = do_alphaover_effect; break; - case SEQ_OVERDROP: + case SEQ_TYPE_OVERDROP: rval.execute = do_overdrop_effect; break; - case SEQ_ALPHAUNDER: + case SEQ_TYPE_ALPHAUNDER: rval.init = init_alpha_over_or_under; rval.execute = do_alphaunder_effect; break; - case SEQ_WIPE: + case SEQ_TYPE_WIPE: rval.init = init_wipe_effect; rval.num_inputs = num_inputs_wipe; rval.free = free_wipe_effect; @@ -3032,21 +3032,21 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.get_default_fac = get_default_fac_fade; rval.execute = do_wipe_effect; break; - case SEQ_GLOW: + case SEQ_TYPE_GLOW: rval.init = init_glow_effect; rval.num_inputs = num_inputs_glow; rval.free = free_glow_effect; rval.copy = copy_glow_effect; rval.execute = do_glow_effect; break; - case SEQ_TRANSFORM: + case SEQ_TYPE_TRANSFORM: rval.init = init_transform_effect; rval.num_inputs = num_inputs_transform; rval.free = free_transform_effect; rval.copy = copy_transform_effect; rval.execute = do_transform_effect; break; - case SEQ_SPEED: + case SEQ_TYPE_SPEED: rval.init = init_speed_effect; rval.num_inputs = num_inputs_speed; rval.load = load_speed_effect; @@ -3056,7 +3056,7 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.early_out = early_out_speed; rval.store_icu_yrange = store_icu_yrange_speed; break; - case SEQ_COLOR: + case SEQ_TYPE_COLOR: rval.init = init_solid_color; rval.num_inputs = num_inputs_color; rval.early_out = early_out_color; @@ -3064,12 +3064,12 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.copy = copy_solid_color; rval.execute = do_solid_color; break; - case SEQ_MULTICAM: + case SEQ_TYPE_MULTICAM: rval.num_inputs = num_inputs_multicam; rval.early_out = early_out_multicam; rval.execute = do_multicam; break; - case SEQ_ADJUSTMENT: + case SEQ_TYPE_ADJUSTMENT: rval.num_inputs = num_inputs_adjustment; rval.early_out = early_out_adjustment; rval.execute = do_adjustment; @@ -3084,7 +3084,7 @@ struct SeqEffectHandle get_sequence_effect(Sequence *seq) { struct SeqEffectHandle rval = {NULL}; - if (seq->type & SEQ_EFFECT) { + if (seq->type & SEQ_TYPE_EFFECT) { rval = get_sequence_effect_impl(seq->type); if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) { rval.load(seq); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 5318c5514ca..af5b7716bbc 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -29,7 +29,6 @@ * \ingroup bke */ - #include <stddef.h> #include <stdlib.h> #include <string.h> @@ -40,6 +39,7 @@ #include "DNA_sequence_types.h" #include "DNA_movieclip_types.h" +#include "DNA_mask_types.h" #include "DNA_scene_types.h" #include "DNA_anim_types.h" #include "DNA_object_types.h" @@ -61,6 +61,7 @@ #include "BKE_movieclip.h" #include "BKE_fcurve.h" #include "BKE_scene.h" +#include "BKE_mask.h" #include "BKE_utildefines.h" #include "RNA_access.h" @@ -178,7 +179,7 @@ void seq_free_sequence(Scene *scene, Sequence *seq) if (seq->anim) IMB_free_anim(seq->anim); - if (seq->type & SEQ_EFFECT) { + if (seq->type & SEQ_TYPE_EFFECT) { struct SeqEffectHandle sh = get_sequence_effect(seq); sh.free(seq); @@ -195,7 +196,7 @@ void seq_free_sequence(Scene *scene, Sequence *seq) if (ed->act_seq == seq) ed->act_seq = NULL; - if (seq->scene_sound && ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) + if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) sound_remove_scene_sound(scene, seq->scene_sound); seq_free_animdata(scene, seq); @@ -543,10 +544,10 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene, Sequence *metase /* for sound we go over full meta tree to update bounds of the sound strips, * since sound is played outside of evaluating the imbufs, */ for (seq = metaseq->seqbase.first; seq; seq = seq->next) { - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { seq_update_sound_bounds_recursive_rec(scene, seq, MAX2(start, metaseq_start(seq)), MIN2(end, metaseq_end(seq))); } - else if (ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) { + else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { if (seq->scene_sound) { int startofs = seq->startofs; int endofs = seq->endofs; @@ -582,10 +583,10 @@ void calc_sequence_disp(Scene *scene, Sequence *seq) seq->handsize = (float)((seq->enddisp - seq->startdisp) / 25); } - if (ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) { + if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { seq_update_sound_bounds(scene, seq); } - else if (seq->type == SEQ_META) + else if (seq->type == SEQ_TYPE_META) seq_update_sound_bounds_recursive(scene, seq); } @@ -603,7 +604,7 @@ void calc_sequence(Scene *scene, Sequence *seq) /* effects and meta: automatic start and end */ - if (seq->type & SEQ_EFFECT) { + if (seq->type & SEQ_TYPE_EFFECT) { /* pointers */ if (seq->seq2 == NULL) seq->seq2 = seq->seq1; if (seq->seq3 == NULL) seq->seq3 = seq->seq1; @@ -641,7 +642,7 @@ void calc_sequence(Scene *scene, Sequence *seq) } } else { - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { seqm = seq->seqbase.first; if (seqm) { min = MAXFRAME * 2; @@ -669,7 +670,10 @@ void reload_sequence_new_file(Scene *scene, Sequence *seq, int lock_range) int prev_startdisp = 0, prev_enddisp = 0; /* note: don't rename the strip, will break animation curves */ - if (ELEM6(seq->type, SEQ_MOVIE, SEQ_IMAGE, SEQ_SOUND, SEQ_SCENE, SEQ_META, SEQ_MOVIECLIP) == 0) { + if (ELEM7(seq->type, + SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, + SEQ_TYPE_SCENE, SEQ_TYPE_META, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) == 0) + { return; } @@ -681,7 +685,7 @@ void reload_sequence_new_file(Scene *scene, Sequence *seq, int lock_range) } switch (seq->type) { - case SEQ_IMAGE: + case SEQ_TYPE_IMAGE: { /* Hack? */ size_t olen = MEM_allocN_len(seq->strip->stripdata) / sizeof(struct StripElem); @@ -694,7 +698,7 @@ void reload_sequence_new_file(Scene *scene, Sequence *seq, int lock_range) } break; } - case SEQ_MOVIE: + case SEQ_TYPE_MOVIE: BLI_join_dirfile(str, sizeof(str), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(str, G.main->name); @@ -719,7 +723,7 @@ void reload_sequence_new_file(Scene *scene, Sequence *seq, int lock_range) seq->len = 0; } break; - case SEQ_MOVIECLIP: + case SEQ_TYPE_MOVIECLIP: seq->len = BKE_movieclip_get_duration(seq->clip); seq->len -= seq->anim_startofs; @@ -728,7 +732,16 @@ void reload_sequence_new_file(Scene *scene, Sequence *seq, int lock_range) seq->len = 0; } break; - case SEQ_SOUND: + case SEQ_TYPE_MASK: + seq->len = BKE_mask_get_duration(seq->mask); + + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + break; + case SEQ_TYPE_SOUND_RAM: #ifdef WITH_AUDASPACE if (!seq->sound) return; @@ -742,7 +755,7 @@ void reload_sequence_new_file(Scene *scene, Sequence *seq, int lock_range) return; #endif break; - case SEQ_SCENE: + case SEQ_TYPE_SCENE: { seq->len = (seq->scene) ? seq->scene->r.efra - seq->scene->r.sfra + 1 : 0; seq->len -= seq->anim_startofs; @@ -781,7 +794,7 @@ void BKE_sequencer_sort(Scene *scene) while ( (seq = ed->seqbasep->first) ) { BLI_remlink(ed->seqbasep, seq); - if (seq->type & SEQ_EFFECT) { + if (seq->type & SEQ_TYPE_EFFECT) { seqt = effbase.first; while (seqt) { if (seqt->machine >= seq->machine) { @@ -895,27 +908,28 @@ void seqbase_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq) static const char *give_seqname_by_type(int type) { switch (type) { - case SEQ_META: return "Meta"; - case SEQ_IMAGE: return "Image"; - case SEQ_SCENE: return "Scene"; - case SEQ_MOVIE: return "Movie"; - case SEQ_MOVIECLIP: return "Clip"; - case SEQ_SOUND: return "Audio"; - case SEQ_CROSS: return "Cross"; - case SEQ_GAMCROSS: return "Gamma Cross"; - case SEQ_ADD: return "Add"; - case SEQ_SUB: return "Sub"; - case SEQ_MUL: return "Mul"; - case SEQ_ALPHAOVER: return "Alpha Over"; - case SEQ_ALPHAUNDER: return "Alpha Under"; - case SEQ_OVERDROP: return "Over Drop"; - case SEQ_WIPE: return "Wipe"; - case SEQ_GLOW: return "Glow"; - case SEQ_TRANSFORM: return "Transform"; - case SEQ_COLOR: return "Color"; - case SEQ_MULTICAM: return "Multicam"; - case SEQ_ADJUSTMENT: return "Adjustment"; - case SEQ_SPEED: return "Speed"; + case SEQ_TYPE_META: return "Meta"; + case SEQ_TYPE_IMAGE: return "Image"; + case SEQ_TYPE_SCENE: return "Scene"; + case SEQ_TYPE_MOVIE: return "Movie"; + case SEQ_TYPE_MOVIECLIP: return "Clip"; + case SEQ_TYPE_MASK: return "Mask"; + case SEQ_TYPE_SOUND_RAM: return "Audio"; + case SEQ_TYPE_CROSS: return "Cross"; + case SEQ_TYPE_GAMCROSS: return "Gamma Cross"; + case SEQ_TYPE_ADD: return "Add"; + case SEQ_TYPE_SUB: return "Sub"; + case SEQ_TYPE_MUL: return "Mul"; + case SEQ_TYPE_ALPHAOVER: return "Alpha Over"; + case SEQ_TYPE_ALPHAUNDER: return "Alpha Under"; + case SEQ_TYPE_OVERDROP: return "Over Drop"; + case SEQ_TYPE_WIPE: return "Wipe"; + case SEQ_TYPE_GLOW: return "Glow"; + case SEQ_TYPE_TRANSFORM: return "Transform"; + case SEQ_TYPE_COLOR: return "Color"; + case SEQ_TYPE_MULTICAM: return "Multicam"; + case SEQ_TYPE_ADJUSTMENT: return "Adjustment"; + case SEQ_TYPE_SPEED: return "Speed"; default: return NULL; } @@ -926,7 +940,7 @@ const char *give_seqname(Sequence *seq) const char *name = give_seqname_by_type(seq->type); if (!name) { - if (seq->type < SEQ_EFFECT) { + if (seq->type < SEQ_TYPE_EFFECT) { return seq->strip->dir; } else { @@ -1008,7 +1022,7 @@ static float give_stripelem_index(Sequence *seq, float cfra) int sta = seq->start; int end = seq->start + seq->len - 1; - if (seq->type & SEQ_EFFECT) { + if (seq->type & SEQ_TYPE_EFFECT) { end = seq->enddisp; } @@ -1041,7 +1055,7 @@ StripElem *give_stripelem(Sequence *seq, int cfra) { StripElem *se = seq->strip->stripdata; - if (seq->type == SEQ_IMAGE) { /* only + if (seq->type == SEQ_TYPE_IMAGE) { /* only * IMAGE strips use the whole array, * MOVIE strips use only * the first element, all other strips @@ -1085,7 +1099,7 @@ int evaluate_seq_frame(Scene *scene, int cfra) static int video_seq_is_rendered(Sequence *seq) { - return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_SOUND); + return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM); } static int get_shown_sequences(ListBase *seqbasep, int cfra, int chanshown, Sequence **seq_arr_out) @@ -1231,7 +1245,7 @@ static int seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *n if (seq->flag & (SEQ_USE_PROXY_CUSTOM_DIR | SEQ_USE_PROXY_CUSTOM_FILE)) { BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir)); } - else if (seq->type == SEQ_IMAGE) { + else if (seq->type == SEQ_TYPE_IMAGE) { BLI_snprintf(dir, PROXY_MAXFILE, "%s/BL_proxy", seq->strip->dir); } else { @@ -1248,7 +1262,7 @@ static int seq_proxy_get_fname(Sequence *seq, int cfra, int render_size, char *n /* generate a separate proxy directory for each preview size */ - if (seq->type == SEQ_IMAGE) { + if (seq->type == SEQ_TYPE_IMAGE) { BLI_snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", dir, render_size, give_stripelem(seq, cfra)->name); @@ -1393,7 +1407,7 @@ struct SeqIndexBuildContext *seq_proxy_rebuild_context(Main *bmain, Scene *scene context->orig_seq = seq; context->seq = nseq; - if (nseq->type == SEQ_MOVIE) { + if (nseq->type == SEQ_TYPE_MOVIE) { seq_open_anim_file(nseq); if (nseq->anim) { @@ -1412,7 +1426,7 @@ void seq_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_upd Scene *scene = context->scene; int cfra; - if (seq->type == SEQ_MOVIE) { + if (seq->type == SEQ_TYPE_MOVIE) { if (context->index_context) { IMB_anim_index_rebuild(context->index_context, stop, do_update, progress); } @@ -1642,7 +1656,7 @@ static void color_balance(Sequence *seq, ImBuf *ibuf, float mul) } /* - * input preprocessing for SEQ_IMAGE, SEQ_MOVIE, SEQ_MOVIECLIP and SEQ_SCENE + * input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE * * Do all the things you can't really do afterwards using sequence effects * (read: before rescaling to render resolution has been done) @@ -1696,7 +1710,7 @@ static ImBuf *input_preprocess( ibuf = IMB_makeSingleUser(ibuf); if ((seq->flag & SEQ_FILTERY) && - !ELEM(seq->type, SEQ_MOVIE, SEQ_MOVIECLIP)) + !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) { IMB_filtery(ibuf); } @@ -1905,8 +1919,7 @@ static ImBuf *seq_render_effect_strip_impl( input[0] = seq->seq1; input[1] = seq->seq2; input[2] = seq->seq3; if (!sh.execute) { /* effect not supported in this version... */ - out = IMB_allocImBuf((short)context.rectx, - (short)context.recty, 32, IB_rect); + out = IMB_allocImBuf(context.rectx, context.recty, 32, IB_rect); return out; } @@ -1983,7 +1996,7 @@ static ImBuf *seq_render_effect_strip_impl( } if (out == NULL) { - out = IMB_allocImBuf((short)context.rectx, (short)context.recty, 32, IB_rect); + out = IMB_allocImBuf(context.rectx, context.recty, 32, IB_rect); } return out; @@ -2041,6 +2054,75 @@ static ImBuf *seq_render_movieclip_strip( return ibuf; } + +static ImBuf *seq_render_mask_strip( + SeqRenderData context, Sequence *seq, float nr) +{ + /* TODO - add option to rasterize to alpha imbuf? */ + ImBuf *ibuf = NULL; + float *maskbuf; + int i; + + if (!seq->mask) { + return NULL; + } + + BKE_mask_evaluate(seq->mask, seq->mask->sfra + nr, TRUE); + + maskbuf = MEM_callocN(sizeof(float) * context.rectx * context.recty, __func__); + + if (seq->flag & SEQ_MAKE_FLOAT) { + /* pixels */ + float *fp_src; + float *fp_dst; + + ibuf = IMB_allocImBuf(context.rectx, context.recty, 32, IB_rectfloat); + + BKE_mask_rasterize(seq->mask, + context.rectx, context.recty, + maskbuf, + TRUE, FALSE); + + fp_src = maskbuf; + fp_dst = ibuf->rect_float; + i = context.rectx * context.recty; + while(--i) { + fp_dst[0] = fp_dst[1] = fp_dst[2] = *fp_src; + fp_dst[3] = 1.0f; + + fp_src += 1; + fp_dst += 4; + } + } + else { + /* pixels */ + float *fp_src; + unsigned char *ub_dst; + + ibuf = IMB_allocImBuf(context.rectx, context.recty, 32, IB_rect); + + BKE_mask_rasterize(seq->mask, + context.rectx, context.recty, + maskbuf, + TRUE, FALSE); + + fp_src = maskbuf; + ub_dst = (unsigned char *)ibuf->rect; + i = context.rectx * context.recty; + while(--i) { + ub_dst[0] = ub_dst[1] = ub_dst[2] = (unsigned char)(*fp_src * 255.0f); /* already clamped */ + ub_dst[3] = 255; + + fp_src += 1; + ub_dst += 4; + } + } + + MEM_freeN(maskbuf); + + return ibuf; +} + static ImBuf *seq_render_scene_strip( SeqRenderData context, Sequence *seq, float nr) { @@ -2126,7 +2208,8 @@ static ImBuf *seq_render_scene_strip( if (sequencer_view3d_cb && BLI_thread_is_main() && doseq_gl && (scene == context.scene || have_seq == 0) && camera) { char err_out[256] = "unknown"; - /* for old scened this can be uninitialized, should probably be added to do_versions at some point if the functionality stays */ + /* for old scened this can be uninitialized, + * should probably be added to do_versions at some point if the functionality stays */ if (context.scene->r.seq_prev_type == 0) context.scene->r.seq_prev_type = 3 /* ==OB_SOLID */; @@ -2204,8 +2287,8 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) int is_proxy_image = FALSE; float nr = give_stripelem_index(seq, cfra); /* all effects are handled similarly with the exception of speed effect */ - int type = (seq->type & SEQ_EFFECT && seq->type != SEQ_SPEED) ? SEQ_EFFECT : seq->type; - int is_preprocessed = !ELEM3(type, SEQ_IMAGE, SEQ_MOVIE, SEQ_SCENE); + int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type; + int is_preprocessed = !ELEM3(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE); ibuf = seq_stripelem_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); @@ -2218,13 +2301,13 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) ibuf = copy_from_ibuf_still(context, seq, nr); /* MOVIECLIPs have their own proxy management */ - if (ibuf == NULL && seq->type != SEQ_MOVIECLIP) { + if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) { ibuf = seq_proxy_fetch(context, seq, cfra); is_proxy_image = (ibuf != NULL); } if (ibuf == NULL) switch (type) { - case SEQ_META: + case SEQ_TYPE_META: { ImBuf *meta_ibuf = NULL; @@ -2246,7 +2329,7 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) break; } - case SEQ_SPEED: + case SEQ_TYPE_SPEED: { ImBuf *child_ibuf = NULL; @@ -2272,13 +2355,13 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) } break; } - case SEQ_EFFECT: + case SEQ_TYPE_EFFECT: { ibuf = seq_render_effect_strip_impl( context, seq, seq->start + nr); break; } - case SEQ_IMAGE: + case SEQ_TYPE_IMAGE: { StripElem *s_elem = give_stripelem(seq, cfra); @@ -2303,7 +2386,7 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) } break; } - case SEQ_MOVIE: + case SEQ_TYPE_MOVIE: { seq_open_anim_file(seq); @@ -2330,7 +2413,7 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) copy_to_ibuf_still(context, seq, nr, ibuf); break; } - case SEQ_SCENE: + case SEQ_TYPE_SCENE: { // scene can be NULL after deletions ibuf = seq_render_scene_strip(context, seq, nr); @@ -2340,7 +2423,7 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) copy_to_ibuf_still(context, seq, nr, ibuf); break; } - case SEQ_MOVIECLIP: + case SEQ_TYPE_MOVIECLIP: { ibuf = seq_render_movieclip_strip(context, seq, nr); @@ -2355,10 +2438,18 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) copy_to_ibuf_still(context, seq, nr, ibuf); break; } + case SEQ_TYPE_MASK: + { + /* ibuf is alwats new */ + ibuf = seq_render_mask_strip(context, seq, nr); + + copy_to_ibuf_still(context, seq, nr, ibuf); + break; + } } if (ibuf == NULL) - ibuf = IMB_allocImBuf((short)context.rectx, (short)context.recty, 32, IB_rect); + ibuf = IMB_allocImBuf(context.rectx, context.recty, 32, IB_rect); if (ibuf->x != context.rectx || ibuf->y != context.recty) use_preprocess = TRUE; @@ -2383,7 +2474,7 @@ static int seq_must_swap_input_in_blend_mode(Sequence *seq) /* bad hack, to fix crazy input ordering of * those two effects */ - if (ELEM3(seq->blend_mode, SEQ_ALPHAOVER, SEQ_ALPHAUNDER, SEQ_OVERDROP)) { + if (ELEM3(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) { swap_input = TRUE; } @@ -2473,7 +2564,7 @@ static ImBuf *seq_render_strip_stack( break; case EARLY_USE_INPUT_1: if (i == 0) { - out = IMB_allocImBuf((short)context.rectx, (short)context.recty, 32, IB_rect); + out = IMB_allocImBuf(context.rectx, context.recty, 32, IB_rect); } break; case EARLY_DO_EFFECT: @@ -2567,7 +2658,7 @@ ImBuf *give_ibuf_seq_direct(SeqRenderData context, float cfra, Sequence *seq) /* check used when we need to change seq->blend_mode but not to effect or audio strips */ static int seq_can_blend(Sequence *seq) { - if (ELEM4(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE)) { + if (ELEM4(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE)) { return 1; } else { @@ -2949,16 +3040,16 @@ void free_imbuf_seq(Scene *scene, ListBase *seqbase, int check_mem_usage, for (seq = seqbase->first; seq; seq = seq->next) { if (seq->strip) { - if (seq->type == SEQ_MOVIE && !keep_file_handles) + if (seq->type == SEQ_TYPE_MOVIE && !keep_file_handles) free_anim_seq(seq); - if (seq->type == SEQ_SPEED) { + if (seq->type == SEQ_TYPE_SPEED) { sequence_effect_speed_rebuild_map(scene, seq, 1); } } - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { free_imbuf_seq(scene, &seq->seqbase, FALSE, keep_file_handles); } - if (seq->type == SEQ_SCENE) { + if (seq->type == SEQ_TYPE_SCENE) { /* FIXME: recurs downwards, * but do recurs protection somehow! */ } @@ -2995,9 +3086,9 @@ static int update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *chan if (free_imbuf) { if (ibuf_change) { - if (seq->type == SEQ_MOVIE) + if (seq->type == SEQ_TYPE_MOVIE) free_anim_seq(seq); - if (seq->type == SEQ_SPEED) { + if (seq->type == SEQ_TYPE_SPEED) { sequence_effect_speed_rebuild_map(scene, seq, 1); } } @@ -3086,8 +3177,8 @@ void seq_tx_set_final_right(Sequence *seq, int val) int seq_single_check(Sequence *seq) { return ((seq->len == 1) && - (seq->type == SEQ_IMAGE || - ((seq->type & SEQ_EFFECT) && + (seq->type == SEQ_TYPE_IMAGE || + ((seq->type & SEQ_TYPE_EFFECT) && get_sequence_effect_num_inputs(seq->type) == 0))); } @@ -3110,7 +3201,7 @@ int seqbase_isolated_sel_check(ListBase *seqbase) /* test relationships */ for (seq = seqbase->first; seq; seq = seq->next) { - if ((seq->type & SEQ_EFFECT) == 0) + if ((seq->type & SEQ_TYPE_EFFECT) == 0) continue; if (seq->flag & SELECT) { @@ -3173,7 +3264,7 @@ void seq_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag) } /* sounds cannot be extended past their endpoints */ - if (seq->type == SEQ_SOUND) { + if (seq->type == SEQ_TYPE_SOUND_RAM) { seq->startstill = 0; seq->endstill = 0; } @@ -3199,7 +3290,7 @@ void seq_single_fix(Sequence *seq) int seq_tx_test(Sequence *seq) { - return (seq->type < SEQ_EFFECT) || (get_sequence_effect_num_inputs(seq->type) == 0); + return (seq->type < SEQ_TYPE_EFFECT) || (get_sequence_effect_num_inputs(seq->type) == 0); } static int seq_overlap(Sequence *seq1, Sequence *seq2) @@ -3228,7 +3319,7 @@ void seq_translate(Scene *evil_scene, Sequence *seq, int delta) seq_offset_animdata(evil_scene, seq, delta); seq->start += delta; - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { Sequence *seq_child; for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) { seq_translate(evil_scene, seq_child, delta); @@ -3240,7 +3331,7 @@ void seq_translate(Scene *evil_scene, Sequence *seq, int delta) void seq_sound_init(Scene *scene, Sequence *seq) { - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { Sequence *seq_child; for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) { seq_sound_init(scene, seq_child); @@ -3268,7 +3359,7 @@ Sequence *seq_foreground_frame_get(Scene *scene, int frame) if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) continue; /* only use elements you can see - not */ - if (ELEM5(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_COLOR)) { + if (ELEM5(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) { if (seq->machine > best_machine) { best_seq = seq; best_machine = seq->machine; @@ -3394,10 +3485,10 @@ void seq_update_sound_bounds_all(Scene *scene) Sequence *seq; for (seq = ed->seqbase.first; seq; seq = seq->next) { - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { seq_update_sound_bounds_recursive(scene, seq); } - else if (ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) { + else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { seq_update_sound_bounds(scene, seq); } } @@ -3420,7 +3511,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i for (seq = seqbasep->first; seq; seq = seq->next) { seqmute = (mute || (seq->flag & SEQ_MUTE)); - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { /* if this is the current meta sequence, unmute because * all sequences above this were set to mute */ if (seq == metaseq) @@ -3428,7 +3519,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute); } - else if (ELEM(seq->type, SEQ_SOUND, SEQ_SCENE)) { + else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { if (seq->scene_sound) { sound_mute_scene_sound(seq->scene_sound, seqmute); } @@ -3454,10 +3545,10 @@ static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound Sequence *seq; for (seq = seqbasep->first; seq; seq = seq->next) { - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { seq_update_sound_recursive(scene, &seq->seqbase, sound); } - else if (seq->type == SEQ_SOUND) { + else if (seq->type == SEQ_TYPE_SOUND_RAM) { if (seq->scene_sound && sound == seq->sound) { sound_update_scene_sound(seq->scene_sound, sound); } @@ -3521,18 +3612,18 @@ int seq_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) /* type checking, could be more advanced but disalow sound vs non-sound copy */ if (seq_a->type != seq_b->type) { - if (seq_a->type == SEQ_SOUND || seq_b->type == SEQ_SOUND) { + if (seq_a->type == SEQ_TYPE_SOUND_RAM || seq_b->type == SEQ_TYPE_SOUND_RAM) { *error_str = "Strips were not compatible"; return 0; } /* disallow effects to swap with non-effects strips */ - if ((seq_a->type & SEQ_EFFECT) != (seq_b->type & SEQ_EFFECT)) { + if ((seq_a->type & SEQ_TYPE_EFFECT) != (seq_b->type & SEQ_TYPE_EFFECT)) { *error_str = "Strips were not compatible"; return 0; } - if ((seq_a->type & SEQ_EFFECT) && (seq_b->type & SEQ_EFFECT)) { + if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) { if (get_sequence_effect_num_inputs(seq_a->type) != get_sequence_effect_num_inputs(seq_b->type)) { *error_str = "Strips must have the same number of inputs"; return 0; @@ -3769,8 +3860,8 @@ Sequence *sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo Strip *strip; seq = alloc_sequence(seqbasep, seq_load->start_frame, seq_load->channel); - seq->type = SEQ_IMAGE; - seq->blend_mode = SEQ_CROSS; /* so alpha adjustment fade to the strip below */ + seq->type = SEQ_TYPE_IMAGE; + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ /* basic defaults */ seq->strip = strip = MEM_callocN(sizeof(Strip), "strip"); @@ -3818,7 +3909,7 @@ Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo seq = alloc_sequence(seqbasep, seq_load->start_frame, seq_load->channel); - seq->type = SEQ_SOUND; + seq->type = SEQ_TYPE_SOUND_RAM; seq->sound = sound; BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2); seqbase_unique_name_recursive(&scene->ed->seqbase, seq); @@ -3874,8 +3965,8 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo return NULL; seq = alloc_sequence(seqbasep, seq_load->start_frame, seq_load->channel); - seq->type = SEQ_MOVIE; - seq->blend_mode = SEQ_CROSS; /* so alpha adjustment fade to the strip below */ + seq->type = SEQ_TYPE_MOVIE; + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ seq->anim = an; seq->anim_preseek = IMB_anim_get_preseek(an); @@ -3942,24 +4033,24 @@ static Sequence *seq_dupli(struct Scene *scene, struct Scene *scene_to, Sequence seqn->strip->color_balance = MEM_dupallocN(seq->strip->color_balance); } - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { seqn->strip->stripdata = NULL; seqn->seqbase.first = seqn->seqbase.last = NULL; /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */ /* - seq_dupli_recursive(&seq->seqbase,&seqn->seqbase);*/ } - else if (seq->type == SEQ_SCENE) { + else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; if (seq->scene_sound) seqn->scene_sound = sound_scene_add_scene_sound_defaults(sce_audio, seqn); } - else if (seq->type == SEQ_MOVIE) { + else if (seq->type == SEQ_TYPE_MOVIE) { seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); seqn->anim = NULL; } - else if (seq->type == SEQ_SOUND) { + else if (seq->type == SEQ_TYPE_SOUND_RAM) { seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); if (seq->scene_sound) @@ -3967,16 +4058,16 @@ static Sequence *seq_dupli(struct Scene *scene, struct Scene *scene_to, Sequence seqn->sound->id.us++; } - else if (seq->type == SEQ_IMAGE) { + else if (seq->type == SEQ_TYPE_IMAGE) { seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata); } - else if (seq->type >= SEQ_EFFECT) { + else if (seq->type >= SEQ_TYPE_EFFECT) { if (seq->seq1 && seq->seq1->tmp) seqn->seq1 = seq->seq1->tmp; if (seq->seq2 && seq->seq2->tmp) seqn->seq2 = seq->seq2->tmp; if (seq->seq3 && seq->seq3->tmp) seqn->seq3 = seq->seq3->tmp; - if (seq->type & SEQ_EFFECT) { + if (seq->type & SEQ_TYPE_EFFECT) { struct SeqEffectHandle sh; sh = get_sequence_effect(seq); if (sh.copy) @@ -4004,7 +4095,7 @@ static Sequence *seq_dupli(struct Scene *scene, struct Scene *scene_to, Sequence Sequence *seq_dupli_recursive(struct Scene *scene, struct Scene *scene_to, Sequence *seq, int dupe_flag) { Sequence *seqn = seq_dupli(scene, scene_to, seq, dupe_flag); - if (seq->type == SEQ_META) { + if (seq->type == SEQ_TYPE_META) { Sequence *s; for (s = seq->seqbase.first; s; s = s->next) { Sequence *n = seq_dupli_recursive(scene, scene_to, s, dupe_flag); @@ -4033,7 +4124,7 @@ void seqbase_dupli_recursive(Scene *scene, Scene *scene_to, ListBase *nseqbase, } BLI_addtail(nseqbase, seqn); - if (seq->type == SEQ_META) + if (seq->type == SEQ_TYPE_META) seqbase_dupli_recursive(scene, scene_to, &seqn->seqbase, &seq->seqbase, dupe_flag); if (dupe_flag & SEQ_DUPE_CONTEXT) { diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 7a5465edf02..ebc31517524 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -150,6 +150,7 @@ static void fill_scs_points(Object *ob, DerivedMesh *dm, SmokeCollSettings *scs) struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), int UNUSED(amplify), int UNUSED(noisetype)) { return NULL; } struct FLUID_3D *smoke_init(int *UNUSED(res), float *UNUSED(p0)) { return NULL; } void smoke_free(struct FLUID_3D *UNUSED(fluid)) {} +float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) { return NULL; } void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) {} void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) {} 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)) {} diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index b0745ebf1c8..bbb70bb77ff 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -20,6 +20,7 @@ * * Contributor(s): Blender Foundation, * Sergey Sharybin + * Keir Mierle * * ***** END GPL LICENSE BLOCK ***** */ @@ -59,6 +60,8 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "raskter.h" + #ifdef WITH_LIBMV # include "libmv-capi.h" #else @@ -73,6 +76,141 @@ static struct { ListBase tracks; } tracking_clipboard; +/*********************** space transformation functions *************************/ + +/* Three coordinate frames: Frame, Search, and Marker + * Two units: Pixels, Unified + * Notation: {coordinate frame}_{unit}; for example, "search_pixel" are search + * window relative coordinates in pixels, and "frame_unified" are unified 0..1 + * coordinates relative to the entire frame. + */ +static void unified_to_pixel(int frame_width, int frame_height, + const float unified_coords[2], float pixel_coords[2]) +{ + pixel_coords[0] = unified_coords[0] * frame_width; + pixel_coords[1] = unified_coords[1] * frame_height; +} + +static void marker_to_frame_unified(const MovieTrackingMarker *marker, const float marker_unified_coords[2], + float frame_unified_coords[2]) +{ + frame_unified_coords[0] = marker_unified_coords[0] + marker->pos[0]; + frame_unified_coords[1] = marker_unified_coords[1] + marker->pos[1]; +} + +static void marker_unified_to_frame_pixel_coordinates(int frame_width, int frame_height, + const MovieTrackingMarker *marker, + const float marker_unified_coords[2], float frame_pixel_coords[2]) +{ + marker_to_frame_unified(marker, marker_unified_coords, frame_pixel_coords); + unified_to_pixel(frame_width, frame_height, frame_pixel_coords, frame_pixel_coords); +} + +static void get_search_origin_frame_pixel(int frame_width, int frame_height, + const MovieTrackingMarker *marker, float frame_pixel[2]) +{ + /* Get the lower left coordinate of the search window and snap to pixel coordinates */ + marker_unified_to_frame_pixel_coordinates(frame_width, frame_height, marker, marker->search_min, frame_pixel); + frame_pixel[0] = (int)frame_pixel[0]; + frame_pixel[1] = (int)frame_pixel[1]; +} + +#ifdef WITH_LIBMV +static void pixel_to_unified(int frame_width, int frame_height, const float pixel_coords[2], float unified_coords[2]) +{ + unified_coords[0] = pixel_coords[0] / frame_width; + unified_coords[1] = pixel_coords[1] / frame_height; +} + +static void marker_unified_to_search_pixel(int frame_width, int frame_height, + const MovieTrackingMarker *marker, + const float marker_unified[2], float search_pixel[2]) +{ + float frame_pixel[2]; + float search_origin_frame_pixel[2]; + + marker_unified_to_frame_pixel_coordinates(frame_width, frame_height, marker, marker_unified, frame_pixel); + get_search_origin_frame_pixel(frame_width, frame_height, marker, search_origin_frame_pixel); + sub_v2_v2v2(search_pixel, frame_pixel, search_origin_frame_pixel); +} + +static void search_pixel_to_marker_unified(int frame_width, int frame_height, + const MovieTrackingMarker *marker, + const float search_pixel[2], float marker_unified[2]) +{ + float frame_unified[2]; + float search_origin_frame_pixel[2]; + + get_search_origin_frame_pixel(frame_width, frame_height, marker, search_origin_frame_pixel); + add_v2_v2v2(frame_unified, search_pixel, search_origin_frame_pixel); + pixel_to_unified(frame_width, frame_height, frame_unified, frame_unified); + + /* marker pos is in frame unified */ + sub_v2_v2v2(marker_unified, frame_unified, marker->pos); +} + +/* Each marker has 5 coordinates associated with it that get warped with + * tracking: the four corners ("pattern_corners"), and the cernter ("pos"). + * This function puts those 5 points into the appropriate frame for tracking + * (the "search" coordinate frame). + */ +static void get_marker_coords_for_tracking(int frame_width, int frame_height, + const MovieTrackingMarker *marker, + double search_pixel_x[5], double search_pixel_y[5]) +{ + int i; + float unified_coords[2]; + float pixel_coords[2]; + + /* Convert the corners into search space coordinates. */ + for (i = 0; i < 4; i++) { + marker_unified_to_search_pixel(frame_width, frame_height, marker, marker->pattern_corners[i], pixel_coords); + search_pixel_x[i] = pixel_coords[0]; + search_pixel_y[i] = pixel_coords[1]; + } + /* Convert the center position (aka "pos"); this is the origin */ + unified_coords[0] = 0.0; + unified_coords[1] = 0.0; + marker_unified_to_search_pixel(frame_width, frame_height, marker, unified_coords, pixel_coords); + + search_pixel_x[4] = pixel_coords[0]; + search_pixel_y[4] = pixel_coords[1]; +} + +/* Inverse of above. */ +static void set_marker_coords_from_tracking(int frame_width, int frame_height, MovieTrackingMarker *marker, + const double search_pixel_x[5], const double search_pixel_y[5]) +{ + int i; + float marker_unified[2]; + float search_pixel[2]; + + /* Convert the corners into search space coordinates. */ + for (i = 0; i < 4; i++) { + search_pixel[0] = search_pixel_x[i]; + search_pixel[1] = search_pixel_y[i]; + search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker->pattern_corners[i]); + } + + /* Convert the center position (aka "pos"); this is the origin */ + search_pixel[0] = search_pixel_x[4]; + search_pixel[1] = search_pixel_y[4]; + search_pixel_to_marker_unified(frame_width, frame_height, marker, search_pixel, marker_unified); + + /* If the tracker tracked nothing, then "marker_unified" would be zero. + * Otherwise, the entire patch shifted, and that delta should be applied to + * all the coordinates. + */ + for (i = 0; i < 4; i++) { + marker->pattern_corners[i][0] -= marker_unified[0]; + marker->pattern_corners[i][1] -= marker_unified[1]; + } + + marker->pos[0] += marker_unified[0]; + marker->pos[1] += marker_unified[1]; +} +#endif + /*********************** common functions *************************/ void BKE_tracking_init_settings(MovieTracking *tracking) @@ -81,11 +219,10 @@ void BKE_tracking_init_settings(MovieTracking *tracking) tracking->camera.pixel_aspect = 1.0f; tracking->camera.units = CAMERA_UNITS_MM; - tracking->settings.default_tracker = TRACKER_HYBRID; + tracking->settings.default_motion_model = TRACK_MOTION_MODEL_TRANSLATION; tracking->settings.default_minimum_correlation = 0.75; tracking->settings.default_pattern_size = 11; tracking->settings.default_search_size = 61; - tracking->settings.default_pyramid_levels = 2; tracking->settings.keyframe1 = 1; tracking->settings.keyframe2 = 30; tracking->settings.dist = 1; @@ -99,105 +236,68 @@ void BKE_tracking_init_settings(MovieTracking *tracking) BKE_tracking_new_object(tracking, "Camera"); } -void BKE_tracking_clamp_track(MovieTrackingTrack *track, int event) +void BKE_tracking_clamp_marker(MovieTrackingMarker *marker, int event) { int a; - float pat_min[2]; - float pat_max[2]; - float max_pyramid_level_factor = 1.0; - - if (track->tracker == TRACKER_KLT) { - max_pyramid_level_factor = 1 << (track->pyramid_levels - 1); - } - - /* sort */ - for (a = 0; a < 2; a++) { - if (track->pat_min[a] > track->pat_max[a]) - SWAP(float, track->pat_min[a], track->pat_max[a]); + float pat_min[2], pat_max[2]; - if (track->search_min[a] > track->search_max[a]) - SWAP(float, track->search_min[a], track->search_max[a]); - } - - /* compute the effective pattern size, which differs from the fine resolution - * pattern size for the pyramid KLT tracker */ - for (a = 0; a < 2; a++) { - pat_min[a] = max_pyramid_level_factor * track->pat_min[a]; - pat_max[a] = max_pyramid_level_factor * track->pat_max[a]; - } + BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); if (event == CLAMP_PAT_DIM) { for (a = 0; a < 2; a++) { /* search shouldn't be resized smaller than pattern */ - track->search_min[a] = MIN2(pat_min[a], track->search_min[a]); - track->search_max[a] = MAX2(pat_max[a], track->search_max[a]); + marker->search_min[a] = MIN2(pat_min[a], marker->search_min[a]); + marker->search_max[a] = MAX2(pat_max[a], marker->search_max[a]); } } else if (event == CLAMP_PAT_POS) { float dim[2]; - sub_v2_v2v2(dim, track->pat_max, track->pat_min); + sub_v2_v2v2(dim, pat_max, pat_min); for (a = 0; a < 2; a++) { + int b; /* pattern shouldn't be moved outside of search */ - if (pat_min[a] < track->search_min[a]) { - track->pat_min[a] = track->search_min[a] - (pat_min[a] - track->pat_min[a]); - track->pat_max[a] = track->pat_min[a] + dim[a]; + if (pat_min[a] < marker->search_min[a]) { + for (b = 0; b < 4; b++) + marker->pattern_corners[b][a] += marker->search_min[a] - pat_min[a]; } - if (track->pat_max[a] > track->search_max[a]) { - track->pat_max[a] = track->search_max[a] - (pat_max[a] - track->pat_max[a]); - track->pat_min[a] = track->pat_max[a] - dim[a]; + if (pat_max[a] > marker->search_max[a]) { + for (b = 0; b < 4; b++) + marker->pattern_corners[b][a] -= pat_max[a] - marker->search_max[a]; } } } else if (event == CLAMP_SEARCH_DIM) { for (a = 0; a < 2; a++) { /* search shouldn't be resized smaller than pattern */ - track->search_min[a] = MIN2(pat_min[a], track->search_min[a]); - track->search_max[a] = MAX2(pat_max[a], track->search_max[a]); + marker->search_min[a] = MIN2(pat_min[a], marker->search_min[a]); + marker->search_max[a] = MAX2(pat_max[a], marker->search_max[a]); } } else if (event == CLAMP_SEARCH_POS) { float dim[2]; - sub_v2_v2v2(dim, track->search_max, track->search_min); + sub_v2_v2v2(dim, marker->search_max, marker->search_min); for (a = 0; a < 2; a++) { /* search shouldn't be moved inside pattern */ - if (track->search_min[a] > pat_min[a]) { - track->search_min[a] = pat_min[a]; - track->search_max[a] = track->search_min[a] + dim[a]; + if (marker->search_min[a] > pat_min[a]) { + marker->search_min[a] = pat_min[a]; + marker->search_max[a] = marker->search_min[a] + dim[a]; } - if (track->search_max[a] < pat_max[a]) { - track->search_max[a] = pat_max[a]; - track->search_min[a] = track->search_max[a] - dim[a]; + if (marker->search_max[a] < pat_max[a]) { + marker->search_max[a] = pat_max[a]; + marker->search_min[a] = marker->search_max[a] - dim[a]; } } } - else if (event == CLAMP_PYRAMID_LEVELS || (event == CLAMP_SEARCH_DIM && track->tracker == TRACKER_KLT)) { - float dim[2]; - sub_v2_v2v2(dim, track->pat_max, track->pat_min); - { - float search_ratio = 2.3f * max_pyramid_level_factor; - - /* resize the search area to something sensible based - * on the number of pyramid levels */ - for (a = 0; a < 2; a++) { - track->search_min[a] = search_ratio * track->pat_min[a]; - track->search_max[a] = search_ratio * track->pat_max[a]; - } - } - } - - /* marker's center should be in center of pattern */ - if (event == CLAMP_PAT_DIM || event == CLAMP_PAT_POS) { + else if (event == CLAMP_SEARCH_DIM) { float dim[2]; - - sub_v2_v2v2(dim, track->pat_max, track->pat_min); - + sub_v2_v2v2(dim, pat_max, pat_min); for (a = 0; a < 2; a++) { - track->pat_min[a] = -dim[a] / 2.0f; - track->pat_max[a] = dim[a] / 2.0f; + marker->search_min[a] = pat_min[a]; + marker->search_max[a] = pat_max[a]; } } } @@ -245,29 +345,32 @@ MovieTrackingTrack *BKE_tracking_add_track(MovieTracking *tracking, ListBase *tr track = MEM_callocN(sizeof(MovieTrackingTrack), "add_marker_exec track"); strcpy(track->name, "Track"); - track->tracker = settings->default_tracker; - track->pyramid_levels = settings->default_pyramid_levels; + track->motion_model = settings->default_motion_model; track->minimum_correlation = settings->default_minimum_correlation; track->margin = settings->default_margin; track->pattern_match = settings->default_pattern_match; track->frames_limit = settings->default_frames_limit; track->flag = settings->default_flag; + track->algorithm_flag = settings->default_algorithm_flag; memset(&marker, 0, sizeof(marker)); marker.pos[0] = x; marker.pos[1] = y; marker.framenr = framenr; - copy_v2_v2(track->pat_max, pat); - negate_v2_v2(track->pat_min, pat); + marker.pattern_corners[0][0] = -pat[0]; + marker.pattern_corners[0][1] = -pat[1]; - copy_v2_v2(track->search_max, search); - negate_v2_v2(track->search_min, search); + marker.pattern_corners[1][0] = pat[0]; + marker.pattern_corners[1][1] = -pat[1]; - BKE_tracking_insert_marker(track, &marker); + negate_v2_v2(marker.pattern_corners[2], marker.pattern_corners[0]); + negate_v2_v2(marker.pattern_corners[3], marker.pattern_corners[1]); - if (track->tracker == TRACKER_KLT) - BKE_tracking_clamp_track(track, CLAMP_PYRAMID_LEVELS); + copy_v2_v2(marker.search_max, search); + negate_v2_v2(marker.search_min, search); + + BKE_tracking_insert_marker(track, &marker); BLI_addtail(tracksbase, track); BKE_track_unique_name(tracksbase, track); @@ -337,6 +440,16 @@ void BKE_tracking_delete_marker(MovieTrackingTrack *track, int framenr) } } +void BKE_tracking_marker_pattern_minmax(MovieTrackingMarker *marker, float min[2], float max[2]) +{ + INIT_MINMAX2(min, max); + + DO_MINMAX2(marker->pattern_corners[0], min, max); + DO_MINMAX2(marker->pattern_corners[1], min, max); + DO_MINMAX2(marker->pattern_corners[2], min, max); + DO_MINMAX2(marker->pattern_corners[3], min, max); +} + MovieTrackingMarker *BKE_tracking_get_marker(MovieTrackingTrack *track, int framenr) { int a = track->markersnr - 1; @@ -527,7 +640,8 @@ void BKE_tracking_join_tracks(MovieTrackingTrack *dst_track, MovieTrackingTrack if ((dst_track->markers[b].flag & MARKER_DISABLED) == 0) { /* both tracks are enabled on this frame, so find the whole segment * on which tracks are intersecting and blend tracks using linear - * interpolation to prevent jumps */ + * interpolation to prevent jumps + */ MovieTrackingMarker *marker_a, *marker_b; int start_a = a, start_b = b, len = 0, frame = src_track->markers[a].framenr; @@ -827,7 +941,8 @@ static void tracks_map_merge(TracksMap *map, MovieTracking *tracking) /* duplicate currently operating tracks to temporary list. * this is needed to keep names in unique state and it's faster to change names - * of currently operating tracks (if needed) */ + * of currently operating tracks (if needed) + */ for (a = 0; a < map->num_tracks; a++) { int replace_sel = 0, replace_rot = 0; MovieTrackingTrack *new_track, *old; @@ -929,10 +1044,14 @@ static void tracks_map_free(TracksMap *map, void (*customdata_free) (void *custo typedef struct TrackContext { #ifdef WITH_LIBMV - float keyframed_pos[2]; + /* the reference marker and cutout search area */ + MovieTrackingMarker marker; - struct libmv_RegionTracker *region_tracker; - float *patch; /* keyframed patch */ + /* keyframed patch. This is the search area */ + float *search_area; + int search_area_height; + int search_area_width; + int framenr; #else int pad; #endif @@ -972,7 +1091,8 @@ MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *u track = tracksbase->first; while (track) { if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) { - MovieTrackingMarker *marker = BKE_tracking_get_marker(track, user->framenr); + int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); + MovieTrackingMarker *marker = BKE_tracking_get_marker(track, framenr); if ((marker->flag & MARKER_DISABLED) == 0) num_tracks++; @@ -993,53 +1113,12 @@ MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *u track = tracksbase->first; while (track) { if (TRACK_SELECTED(track) && (track->flag & (TRACK_HIDDEN | TRACK_LOCKED)) == 0) { - MovieTrackingMarker *marker = BKE_tracking_get_marker(track, user->framenr); + int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); + MovieTrackingMarker *marker = BKE_tracking_get_marker(track, framenr); if ((marker->flag & MARKER_DISABLED) == 0) { TrackContext track_context; - memset(&track_context, 0, sizeof(TrackContext)); - -#ifdef WITH_LIBMV - { - float patx = (int)((track->pat_max[0] - track->pat_min[0]) * width), - paty = (int)((track->pat_max[1] - track->pat_min[1]) * height); - - float search_size_x = (track->search_max[0] - track->search_min[0]) * width; - float search_size_y = (track->search_max[1] - track->search_min[1]) * height; - float pattern_size_x = (track->pat_max[0] - track->pat_min[0]) * width; - float pattern_size_y = (track->pat_max[1] - track->pat_min[1]) * height; - int wndx = (int)patx / 2, wndy = (int)paty / 2; - int half_wnd = MAX2(wndx, wndy); - - /* compute the maximum pyramid size */ - float search_to_pattern_ratio = MIN2(search_size_x, search_size_y) - / MAX2(pattern_size_x, pattern_size_y); - float log2_search_to_pattern_ratio = log(floor(search_to_pattern_ratio)) / M_LN2; - int max_pyramid_levels = floor(log2_search_to_pattern_ratio + 1); - - /* try to accommodate the user's choice of pyramid level in a way - * that doesn't cause the coarsest pyramid pattern to be larger - * than the search size */ - int level = MIN2(track->pyramid_levels, max_pyramid_levels); - - struct libmv_RegionTracker *region_tracker; - - if (track->tracker == TRACKER_KLT) { - region_tracker = libmv_pyramidRegionTrackerNew(100, level, half_wnd, - track->minimum_correlation); - } - else if (track->tracker == TRACKER_HYBRID) { - region_tracker = libmv_hybridRegionTrackerNew(100, half_wnd, track->minimum_correlation); - } - else if (track->tracker == TRACKER_SAD) { - region_tracker = libmv_bruteRegionTrackerNew(MAX2(wndx, wndy), track->minimum_correlation); - } - - track_context.region_tracker = region_tracker; - } -#endif - tracks_map_insert(context->tracks_map, track, &track_context); } } @@ -1057,7 +1136,8 @@ MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *u * would be used for images * - MCLIP_USE_PROXY_CUSTOM_DIR is needed because proxy/timecode files might * be stored in a different location - * ignore all the rest possible flags for now */ + * ignore all the rest possible flags for now + */ context->clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS; context->user = *user; @@ -1075,11 +1155,8 @@ static void track_context_free(void *customdata) TrackContext *track_context = (TrackContext *)customdata; #if WITH_LIBMV - if (track_context->region_tracker) - libmv_regionTrackerDestroy(track_context->region_tracker); - - if (track_context->patch) - MEM_freeN(track_context->patch); + if (track_context->search_area) + MEM_freeN(track_context->search_area); #else (void) track_context; @@ -1098,7 +1175,8 @@ void BKE_tracking_context_free(MovieTrackingContext *context) /* zap channels from the imbuf that are disabled by the user. this can lead to * better tracks sometimes. however, instead of simply zeroing the channels - * out, do a partial grayscale conversion so the display is better. */ + * out, do a partial grayscale conversion so the display is better. + */ void BKE_tracking_disable_imbuf_channels(ImBuf *ibuf, int disable_red, int disable_green, int disable_blue, int grayscale) { @@ -1109,7 +1187,8 @@ void BKE_tracking_disable_imbuf_channels(ImBuf *ibuf, int disable_red, int disab return; /* If only some components are selected, it's important to rescale the result - * appropriately so that e.g. if only blue is selected, it's not zeroed out. */ + * appropriately so that e.g. if only blue is selected, it's not zeroed out. + */ scale = (disable_red ? 0.0f : 0.2126f) + (disable_green ? 0.0f : 0.7152f) + (disable_blue ? 0.0f : 0.0722f); @@ -1165,116 +1244,271 @@ static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, int g track->flag & TRACK_DISABLE_GREEN, track->flag & TRACK_DISABLE_BLUE, grayscale); } -static ImBuf *get_area_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, - float min[2], float max[2], int margin, int anchored, float pos[2], int origin[2]) +ImBuf *BKE_tracking_sample_pattern_imbuf(int frame_width, int frame_height, + ImBuf *search_ibuf, MovieTrackingMarker *marker, + int num_samples_x, int num_samples_y, float pos[2]) { - ImBuf *tmpibuf; - int x, y; - int x1, y1, w, h; - float mpos[2]; +#ifdef WITH_LIBMV + ImBuf *pattern_ibuf; + double src_pixel_x[5], src_pixel_y[5]; + double warped_position_x, warped_position_y; - copy_v2_v2(mpos, marker->pos); - if (anchored) - add_v2_v2(mpos, track->offset); + pattern_ibuf = IMB_allocImBuf(num_samples_x, num_samples_y, 32, IB_rectfloat); + pattern_ibuf->profile = IB_PROFILE_LINEAR_RGB; - if (pos) - zero_v2(pos); + if (!search_ibuf->rect_float) { + IMB_float_from_rect(search_ibuf); + } - x = mpos[0]*ibuf->x; - y = mpos[1]*ibuf->y; + get_marker_coords_for_tracking(frame_width, frame_height, marker, src_pixel_x, src_pixel_y); - w = (max[0] - min[0]) * ibuf->x; - h = (max[1] - min[1]) * ibuf->y; + libmv_samplePlanarPatch(search_ibuf->rect_float, search_ibuf->x, search_ibuf->y, 4, + src_pixel_x, src_pixel_y, num_samples_x, + num_samples_y, pattern_ibuf->rect_float, + &warped_position_x, &warped_position_y); - /* dimensions should be odd */ - w = w | 1; - h = h | 1; + if (pos) { + pos[0] = warped_position_x; + pos[1] = warped_position_y; + } - x1 = x - (int)(w * (-min[0] / (max[0] - min[0]))); - y1 = y - (int)(h * (-min[1] / (max[1] - min[1]))); + return pattern_ibuf; +#else + ImBuf *pattern_ibuf; - if (ibuf->rect_float) - tmpibuf = IMB_allocImBuf(w + margin * 2, h + margin * 2, 32, IB_rectfloat); - else - tmpibuf = IMB_allocImBuf(w + margin * 2, h + margin * 2, 32, IB_rect); + /* real sampling requires libmv, but areas are supposing pattern would be + * sampled if search area does exists, so we'll need to create empty + * pattern area here to prevent adding NULL-checks all over just to deal + * with situation when lubmv is disabled + */ + + (void) frame_width; + (void) frame_height; + (void) search_ibuf; + (void) marker; + + pattern_ibuf = IMB_allocImBuf(num_samples_x, num_samples_y, 32, IB_rectfloat); + + pos[0] = num_samples_x / 2.0f; + pos[1] = num_samples_y / 2.0f; + + return pattern_ibuf; +#endif +} + +ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, + int anchored, int disable_channels) +{ + ImBuf *pattern_ibuf, *search_ibuf; + float pat_min[2], pat_max[2]; + int num_samples_x, num_samples_y; - tmpibuf->profile = ibuf->profile; + BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); - IMB_rectcpy(tmpibuf, ibuf, 0, 0, x1 - margin, y1 - margin, w + margin * 2, h + margin * 2); + num_samples_x = (pat_max[0] - pat_min[0]) * ibuf->x; + num_samples_y = (pat_max[1] - pat_min[1]) * ibuf->y; - if (pos != NULL) { - pos[0] = mpos[0] * ibuf->x - x1 + margin; - pos[1] = mpos[1] * ibuf->y - y1 + margin; + search_ibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, anchored, disable_channels); + + pattern_ibuf = BKE_tracking_sample_pattern_imbuf(ibuf->x, ibuf->y, search_ibuf, marker, + num_samples_x, num_samples_y, NULL); + + IMB_freeImBuf(search_ibuf); + + return pattern_ibuf; +} + +ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, + int anchored, int disable_channels) +{ + ImBuf *searchibuf; + int x, y, w, h; + float search_origin[2]; + + get_search_origin_frame_pixel(ibuf->x, ibuf->y, marker, search_origin); + + x = search_origin[0]; + y = search_origin[1]; + + if (anchored) { + x += track->offset[0] * ibuf->x; + y += track->offset[1] * ibuf->y; } - if (origin != NULL) { - origin[0] = x1 - margin; - origin[1] = y1 - margin; + w = (marker->search_max[0] - marker->search_min[0]) * ibuf->x; + h = (marker->search_max[1] - marker->search_min[1]) * ibuf->y; + + searchibuf = IMB_allocImBuf(w, h, 32, ibuf->rect_float ? IB_rectfloat : IB_rect); + searchibuf->profile = ibuf->profile; + + IMB_rectcpy(searchibuf, ibuf, 0, 0, x, y, w, h); + + if (disable_channels) { + if ((track->flag & TRACK_PREVIEW_GRAYSCALE) || + (track->flag & TRACK_DISABLE_RED) || + (track->flag & TRACK_DISABLE_GREEN) || + (track->flag & TRACK_DISABLE_BLUE)) + { + disable_imbuf_channels(searchibuf, track, TRUE); + } } - if ((track->flag & TRACK_PREVIEW_GRAYSCALE) || - (track->flag & TRACK_DISABLE_RED) || - (track->flag & TRACK_DISABLE_GREEN) || - (track->flag & TRACK_DISABLE_BLUE)) - { - disable_imbuf_channels(tmpibuf, track, TRUE /* grayscale */); + return searchibuf; +} + +static bGPDlayer *track_mask_gpencil_layer_get(MovieTrackingTrack *track) +{ + bGPDlayer *layer; + + if (!track->gpd) + return NULL; + + layer = track->gpd->layers.first; + + while (layer) { + if (layer->flag & GP_LAYER_ACTIVE) + return layer; + + layer = layer->next; } - return tmpibuf; + return NULL; } -ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int margin, int anchored, float pos[2], int origin[2]) +static void track_mask_gpencil_layer_rasterize(MovieTracking *tracking, MovieTrackingMarker *marker, + bGPDlayer *layer, ImBuf *ibuf, int width, int height) { - return get_area_imbuf(ibuf, track, marker, track->pat_min, track->pat_max, margin, anchored, pos, origin); + bGPDframe *frame = layer->frames.first; + float *mask; + int x, y; + float aspy = 1.0f / tracking->camera.pixel_aspect; + + mask = MEM_callocN(ibuf->x * ibuf->y * sizeof(float), "track mask"); + + while (frame) { + bGPDstroke *stroke = frame->strokes.first; + + while (stroke) { + bGPDspoint *stroke_points = stroke->points; + float *mask_points, *fp; + int i; + + if (stroke->flag & GP_STROKE_2DSPACE) { + fp = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(float), + "track mask rasterization points"); + + for (i = 0; i < stroke->totpoints; i++, fp += 2) { + fp[0] = stroke_points[i].x * width / ibuf->x - marker->search_min[0]; + fp[1] = stroke_points[i].y * height * aspy / ibuf->x - marker->search_min[1]; + } + + PLX_raskterize((float (*)[2])mask_points, stroke->totpoints, mask, ibuf->x, ibuf->y); + + MEM_freeN(mask_points); + } + + stroke = stroke->next; + } + + frame = frame->next; + } + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + float *pixel = &ibuf->rect_float[4 * (y * ibuf->x + x)]; + float val = mask[y * ibuf->x + x]; + + pixel[0] = val; + pixel[1] = val; + pixel[2] = val; + pixel[3] = 1.0f; + } + } + + MEM_freeN(mask); + + IMB_rect_from_float(ibuf); } -ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int margin, int anchored, float pos[2], int origin[2]) +ImBuf *BKE_tracking_track_mask_get(MovieTracking *tracking, MovieTrackingTrack *track, MovieTrackingMarker *marker, + int width, int height) { - return get_area_imbuf(ibuf, track, marker, track->search_min, track->search_max, margin, anchored, pos, origin); + ImBuf *ibuf; + bGPDlayer *layer = track_mask_gpencil_layer_get(track); + int mask_width, mask_height; + + mask_width = (marker->search_max[0] - marker->search_min[0]) * width; + mask_height = (marker->search_max[1] - marker->search_min[1]) * height; + + ibuf = IMB_allocImBuf(mask_width, mask_height, 32, IB_rect | IB_rectfloat); + + if (layer) { + track_mask_gpencil_layer_rasterize(tracking, marker, layer, ibuf, width, height); + } + else { + float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + IMB_rectfill(ibuf, white); + } + + return ibuf; } #ifdef WITH_LIBMV -static float *get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int *width_r, int *height_r, float pos[2], int origin[2]) + +/* Convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */ +static void float_rgba_to_gray(const float *rgba, float *gray, int num_pixels, + float weight_red, float weight_green, float weight_blue) { - ImBuf *tmpibuf; - float *pixels, *fp; - int x, y, width, height; + int i; + + for (i = 0; i < num_pixels; i++) { + const float *pixel = rgba + 4 * i; + + gray[i] = weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]; + } +} - width = (track->search_max[0] - track->search_min[0]) * ibuf->x; - height = (track->search_max[1] - track->search_min[1]) * ibuf->y; +static void uint8_rgba_to_float_gray(const unsigned char *rgba, float *gray, int num_pixels, + float weight_red, float weight_green, float weight_blue) +{ + int i; - tmpibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, 0, 0, pos, origin); - disable_imbuf_channels(tmpibuf, track, FALSE /* don't grayscale */); + for (i = 0; i < num_pixels; i++) { + const unsigned char *pixel = rgba + i * 4; - *width_r = width; - *height_r = height; + *gray++ = (weight_red * pixel[0] + weight_green * pixel[1] + weight_blue * pixel[2]) / 255.0f; + } +} - fp = pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf"); - for (y = 0; y < (int)height; y++) { - for (x = 0; x < (int)width; x++) { - int pixel = tmpibuf->x * y + x; +static float *get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, + int *width_r, int *height_r) +{ + ImBuf *searchibuf; + float *gray_pixels; + int width, height; - if (tmpibuf->rect_float) { - float *rrgbf = tmpibuf->rect_float + pixel * 4; + searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, FALSE, TRUE); - *fp = 0.2126 * rrgbf[0] + 0.7152 * rrgbf[1] + 0.0722 * rrgbf[2]; - } - else { - unsigned char *rrgb = (unsigned char*)tmpibuf->rect + pixel * 4; + width = searchibuf->x; + height = searchibuf->y; - *fp = (0.2126 * rrgb[0] + 0.7152 * rrgb[1] + 0.0722 * rrgb[2]) / 255.0f; - } + *width_r = searchibuf->x; + *height_r = searchibuf->y; - fp++; - } + gray_pixels = MEM_callocN(width * height * sizeof(float), "tracking floatBuf"); + + if (searchibuf->rect_float) { + float_rgba_to_gray(searchibuf->rect_float, gray_pixels, width * height, + 0.2126f, 0.7152f, 0.0722f); + } + else { + uint8_rgba_to_float_gray((unsigned char *)searchibuf->rect, gray_pixels, width * height, + 0.2126f, 0.7152f, 0.0722f); } - IMB_freeImBuf(tmpibuf); + IMB_freeImBuf(searchibuf); - return pixels; + return gray_pixels; } static unsigned char *get_ucharbuf(ImBuf *ibuf) @@ -1311,7 +1545,7 @@ static ImBuf *get_frame_ibuf(MovieTrackingContext *context, int framenr) ImBuf *ibuf; MovieClipUser user = context->user; - user.framenr = framenr; + user.framenr = BKE_movieclip_remap_clip_to_scene_frame(context->clip, framenr); ibuf = BKE_movieclip_get_ibuf_flag(context->clip, &user, context->clip_flag, MOVIECLIP_CACHE_SKIP); @@ -1398,10 +1632,12 @@ void BKE_tracking_sync_user(MovieClipUser *user, MovieTrackingContext *context) int BKE_tracking_next(MovieTrackingContext *context) { - ImBuf *ibuf_new; - int curfra = context->user.framenr; + ImBuf *destination_ibuf; + int curfra = BKE_movieclip_remap_scene_to_clip_frame(context->clip, context->user.framenr); int a, ok = FALSE, map_size; + int frame_width, frame_height; + map_size = tracks_map_size(context->tracks_map); /* nothing to track, avoid unneeded frames reading to save time and memory */ @@ -1413,28 +1649,31 @@ int BKE_tracking_next(MovieTrackingContext *context) else context->user.framenr++; - ibuf_new = BKE_movieclip_get_ibuf_flag(context->clip, &context->user, context->clip_flag, MOVIECLIP_CACHE_SKIP); - if (!ibuf_new) + destination_ibuf = BKE_movieclip_get_ibuf_flag(context->clip, &context->user, + context->clip_flag, MOVIECLIP_CACHE_SKIP); + if (!destination_ibuf) return FALSE; - #pragma omp parallel for private(a) shared(ibuf_new, ok) if (map_size>1) + frame_width = destination_ibuf->x; + frame_height = destination_ibuf->y; + + #pragma omp parallel for private(a) shared(destination_ibuf, ok) if (map_size>1) for (a = 0; a < map_size; a++) { TrackContext *track_context = NULL; MovieTrackingTrack *track; MovieTrackingMarker *marker; - tracks_map_get(context->tracks_map, a, &track, (void**)&track_context); + tracks_map_get(context->tracks_map, a, &track, (void **)&track_context); marker = BKE_tracking_exact_marker(track, curfra); if (marker && (marker->flag & MARKER_DISABLED) == 0) { #ifdef WITH_LIBMV - int width, height, origin[2], tracked = 0, need_readjust = 0; - float pos[2], margin[2], dim[2]; - double x1, y1, x2, y2; - ImBuf *ibuf = NULL; + int width, height, tracked = 0, need_readjust = 0; + float margin[2], dim[2], pat_min[2], pat_max[2]; MovieTrackingMarker marker_new, *marker_keyed; int onbound = FALSE, nextfra; + double dst_pixel_x[5], dst_pixel_y[5]; if (track->pattern_match == TRACK_MATCH_KEYFRAME) need_readjust = context->first_time; @@ -1447,11 +1686,12 @@ int BKE_tracking_next(MovieTrackingContext *context) nextfra = curfra + 1; /* margin from frame boundaries */ - sub_v2_v2v2(dim, track->pat_max, track->pat_min); + BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); + sub_v2_v2v2(dim, pat_max, pat_min); margin[0] = margin[1] = MAX2(dim[0], dim[1]) / 2.0f; - margin[0] = MAX2(margin[0], (float)track->margin / ibuf_new->x); - margin[1] = MAX2(margin[1], (float)track->margin / ibuf_new->y); + margin[0] = MAX2(margin[0], (float)track->margin / destination_ibuf->x); + margin[1] = MAX2(margin[1], (float)track->margin / destination_ibuf->y); /* do not track markers which are too close to boundary */ if (marker->pos[0] < margin[0] || marker->pos[0] > 1.0f - margin[0] || @@ -1460,58 +1700,83 @@ int BKE_tracking_next(MovieTrackingContext *context) onbound = TRUE; } else { + /* to convert to the x/y split array format for libmv. */ + double src_pixel_x[5]; + double src_pixel_y[5]; + + /* settings for the tracker */ + struct libmv_trackRegionOptions options; + struct libmv_trackRegionResult result; + float *patch_new; if (need_readjust) { + ImBuf *reference_ibuf = NULL; /* calculate patch for keyframed position */ - ibuf = get_adjust_ibuf(context, track, marker, curfra, &marker_keyed); + reference_ibuf = get_adjust_ibuf(context, track, marker, curfra, &marker_keyed); + track_context->marker = *marker_keyed; - if (track_context->patch) - MEM_freeN(track_context->patch); + if (track_context->search_area) + MEM_freeN(track_context->search_area); - track_context->patch = get_search_floatbuf(ibuf, track, marker_keyed, &width, &height, - track_context->keyframed_pos, origin); + track_context->search_area = get_search_floatbuf(reference_ibuf, track, + marker_keyed, &width, &height); + track_context->search_area_height = height; + track_context->search_area_width = width; - IMB_freeImBuf(ibuf); + IMB_freeImBuf(reference_ibuf); } - patch_new = get_search_floatbuf(ibuf_new, track, marker, &width, &height, pos, origin); + /* for now track to the same search area dimension as marker has got for current frame + * will make all tracked markers in currently tracked segment have the same search area + * size, but it's quite close to what is actually needed + */ + patch_new = get_search_floatbuf(destination_ibuf, track, marker, &width, &height); + + /* Configure the tracker */ + options.motion_model = track->motion_model; + + options.use_brute = + ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_BRUTE) != 0); - x1 = track_context->keyframed_pos[0]; - y1 = track_context->keyframed_pos[1]; + options.use_normalization = + ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_NORMALIZATION) != 0); - x2 = pos[0]; - y2 = pos[1]; + options.num_iterations = 50; + options.minimum_correlation = track->minimum_correlation; + options.sigma = 0.9; - tracked = libmv_regionTrackerTrack(track_context->region_tracker, track_context->patch, patch_new, - width, height, x1, y1, &x2, &y2); + /* Convert the marker corners and center into pixel coordinates in the search/destination images. */ + get_marker_coords_for_tracking(frame_width, frame_height, &track_context->marker, src_pixel_x, src_pixel_y); + get_marker_coords_for_tracking(frame_width, frame_height, marker, dst_pixel_x, dst_pixel_y); + /* Run the tracker! */ + tracked = libmv_trackRegion(&options, + track_context->search_area, patch_new, + width, height, + src_pixel_x, src_pixel_y, + &result, + dst_pixel_x, dst_pixel_y); MEM_freeN(patch_new); } - if (tracked && !onbound && finite(x2) && finite(y2)) { + if (tracked && !onbound) { + memset(&marker_new, 0, sizeof(marker_new)); + marker_new = *marker; + set_marker_coords_from_tracking(frame_width, frame_height, &marker_new, dst_pixel_x, dst_pixel_y); + marker_new.flag |= MARKER_TRACKED; + marker_new.framenr = nextfra; + if (context->first_time) { #pragma omp critical { /* check if there's no keyframe/tracked markers before tracking marker. - * if so -- create disabled marker before currently tracking "segment" */ - put_disabled_marker(track, marker, !context->backwards, 0); + * if so -- create disabled marker before currently tracking "segment" + */ + put_disabled_marker(track, &marker_new, !context->backwards, 0); } } - memset(&marker_new, 0, sizeof(marker_new)); - - if (!onbound) { - marker_new.pos[0] = (origin[0] + x2) / ibuf_new->x; - marker_new.pos[1] = (origin[1] + y2) / ibuf_new->y; - } - else { - copy_v2_v2(marker_new.pos, marker->pos); - } - - marker_new.flag |= MARKER_TRACKED; - marker_new.framenr = nextfra; - #pragma omp critical { BKE_tracking_insert_marker(track, &marker_new); @@ -1529,7 +1794,7 @@ int BKE_tracking_next(MovieTrackingContext *context) marker_new.framenr = nextfra; marker_new.flag |= MARKER_DISABLED; - #pragma omp critical + //#pragma omp critical { BKE_tracking_insert_marker(track, &marker_new); } @@ -1540,7 +1805,7 @@ int BKE_tracking_next(MovieTrackingContext *context) } } - IMB_freeImBuf(ibuf_new); + IMB_freeImBuf(destination_ibuf); context->first_time = FALSE; context->frames++; @@ -2763,7 +3028,8 @@ ImBuf *BKE_tracking_stabilize(MovieTracking *tracking, int framenr, ImBuf *ibuf, if (tangle == 0.0f) { /* if angle is zero, then it's much faster to use rect copy - * but could be issues with subpixel precisions */ + * but could be issues with subpixel precisions + */ IMB_rectcpy(tmpibuf, ibuf, tloc[0] - (tscale - 1.0f) * width / 2.0f, tloc[1] - (tscale - 1.0f) * height / 2.0f, @@ -3113,6 +3379,17 @@ static int channels_longest_segment_sort(void *a, void *b) return 0; } +static int channels_average_error_sort(void *a, void *b) +{ + MovieTrackingDopesheetChannel *channel_a = a; + MovieTrackingDopesheetChannel *channel_b = b; + + if (channel_a->track->error > channel_b->track->error) + return 1; + else + return 0; +} + static int channels_alpha_inverse_sort(void *a, void *b) { if (channels_alpha_sort(a, b)) @@ -3137,6 +3414,17 @@ static int channels_longest_segment_inverse_sort(void *a, void *b) return 1; } +static int channels_average_error_inverse_sort(void *a, void *b) +{ + MovieTrackingDopesheetChannel *channel_a = a; + MovieTrackingDopesheetChannel *channel_b = b; + + if (channel_a->track->error < channel_b->track->error) + return 1; + else + return 0; +} + static void channels_segments_calc(MovieTrackingDopesheetChannel *channel) { MovieTrackingTrack *track = channel->track; @@ -3232,6 +3520,9 @@ static void tracking_dopesheet_sort(MovieTracking *tracking, int sort_method, i else if (sort_method == TRACK_SORT_TOTAL) { BLI_sortlist(&dopesheet->channels, channels_total_track_inverse_sort); } + else if (sort_method == TRACK_SORT_AVERAGE_ERROR) { + BLI_sortlist(&dopesheet->channels, channels_average_error_inverse_sort); + } } else { if (sort_method == TRACK_SORT_NAME) { @@ -3243,6 +3534,9 @@ static void tracking_dopesheet_sort(MovieTracking *tracking, int sort_method, i else if (sort_method == TRACK_SORT_TOTAL) { BLI_sortlist(&dopesheet->channels, channels_total_track_sort); } + else if (sort_method == TRACK_SORT_AVERAGE_ERROR) { + BLI_sortlist(&dopesheet->channels, channels_average_error_sort); + } } dopesheet->sort_method = sort_method; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 91e93bbd05d..40471514b48 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -1003,9 +1003,11 @@ void BKE_ffmpeg_end(void) fprintf(stderr, "Closing ffmpeg...\n"); -/* if (audio_stream) { SEE UPPER - write_audio_frames(); - }*/ +#if 0 + if (audio_stream) { /* SEE UPPER */ + write_audio_frames(); + } +#endif #ifdef WITH_AUDASPACE if (audio_mixdown_device) { |