Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2012-06-11 00:50:43 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2012-06-11 00:50:43 +0400
commit8135cc9f954e0d63ab3e97d4a7c52ff5e573eef0 (patch)
treea12ec0daccfc45b7e3c68e4a2d7099655daf619d /source/blender/blenkernel
parent0f33d5719fd0adc666e7e92e0f062281f4285f13 (diff)
parent298feff39006c14aa28b5e0232aa7ed70a83a496 (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')
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_cloth.h29
-rw-r--r--source/blender/blenkernel/BKE_collision.h3
-rw-r--r--source/blender/blenkernel/BKE_context.h1
-rw-r--r--source/blender/blenkernel/BKE_customdata.h1
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h1
-rw-r--r--source/blender/blenkernel/BKE_image.h6
-rw-r--r--source/blender/blenkernel/BKE_library.h2
-rw-r--r--source/blender/blenkernel/BKE_main.h1
-rw-r--r--source/blender/blenkernel/BKE_mask.h186
-rw-r--r--source/blender/blenkernel/BKE_mesh.h9
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h5
-rw-r--r--source/blender/blenkernel/BKE_paint.h2
-rw-r--r--source/blender/blenkernel/BKE_sketch.h6
-rw-r--r--source/blender/blenkernel/BKE_tracking.h16
-rw-r--r--source/blender/blenkernel/CMakeLists.txt3
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/anim.c69
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c12
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c93
-rw-r--r--source/blender/blenkernel/intern/cloth.c14
-rw-r--r--source/blender/blenkernel/intern/collision.c4
-rw-r--r--source/blender/blenkernel/intern/colortools.c62
-rw-r--r--source/blender/blenkernel/intern/constraint.c25
-rw-r--r--source/blender/blenkernel/intern/context.c5
-rw-r--r--source/blender/blenkernel/intern/customdata.c42
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c22
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c4
-rw-r--r--source/blender/blenkernel/intern/gpencil.c13
-rw-r--r--source/blender/blenkernel/intern/idcode.c1
-rw-r--r--source/blender/blenkernel/intern/image.c136
-rw-r--r--source/blender/blenkernel/intern/implicit.c3
-rw-r--r--source/blender/blenkernel/intern/ipo.c12
-rw-r--r--source/blender/blenkernel/intern/library.c15
-rw-r--r--source/blender/blenkernel/intern/mask.c2225
-rw-r--r--source/blender/blenkernel/intern/mesh.c169
-rw-r--r--source/blender/blenkernel/intern/movieclip.c83
-rw-r--r--source/blender/blenkernel/intern/multires.c3
-rw-r--r--source/blender/blenkernel/intern/navmesh_conversion.c12
-rw-r--r--source/blender/blenkernel/intern/node.c3
-rw-r--r--source/blender/blenkernel/intern/object.c192
-rw-r--r--source/blender/blenkernel/intern/paint.c49
-rw-r--r--source/blender/blenkernel/intern/particle_system.c12
-rw-r--r--source/blender/blenkernel/intern/scene.c8
-rw-r--r--source/blender/blenkernel/intern/seqcache.c41
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c38
-rw-r--r--source/blender/blenkernel/intern/sequencer.c295
-rw-r--r--source/blender/blenkernel/intern/smoke.c1
-rw-r--r--source/blender/blenkernel/intern/tracking.c792
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c8
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) {