Sequencer: per-sequence modifier stack for color grading
authorSergey Sharybin <sergey.vfx@gmail.com>
Sun, 19 Aug 2012 15:41:56 +0000 (15:41 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Sun, 19 Aug 2012 15:41:56 +0000 (15:41 +0000)
This implements basic color grading modifiers in sequencer, supporting
color balance, RGB curves and HUE corrections.

Implementation is close to object modifiers, some details are there:

http://wiki.blender.org/index.php/User:Nazg-gul/SequencerModifiers

Modifiers supports multi-threaded calculation, masks and instant
parameter changes.

Also added cache for pre-processed image buffers for current frame,
so changing sequence properties does not require rendering of original
sequence (like rendering scene, loading file from disk and so)

18 files changed:
release/scripts/startup/bl_ui/space_image.py
release/scripts/startup/bl_ui/space_sequencer.py
source/blender/blenkernel/BKE_colortools.h
source/blender/blenkernel/BKE_sequencer.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/colortools.c
source/blender/blenkernel/intern/seqcache.c
source/blender/blenkernel/intern/seqmodifier.c [new file with mode: 0644]
source/blender/blenkernel/intern/sequencer.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_sequencer/CMakeLists.txt
source/blender/editors/space_sequencer/sequencer_intern.h
source/blender/editors/space_sequencer/sequencer_modifier.c [new file with mode: 0644]
source/blender/editors/space_sequencer/sequencer_ops.c
source/blender/makesdna/DNA_sequence_types.h
source/blender/makesrna/intern/rna_sequencer.c
source/blender/makesrna/intern/rna_ui_api.c

index 5302ad9b4711ca1636127f8e9c171ff1a16789db..0b4d4cd19e409f2d25687a001c8c377af074da69 100644 (file)
@@ -774,7 +774,7 @@ class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
         toolsettings = context.tool_settings.image_paint
         brush = toolsettings.brush
 
-        layout.template_curve_mapping(brush, "curve")
+        layout.template_curve_mapping(brush, "curve", type='COLOR')
 
         row = layout.row(align=True)
         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
index 50c8603a7c2bbd172961ca3714e3f9842b891082..cd10bce8ef6e86701bfc59036425f8add5247693 100644 (file)
@@ -28,6 +28,29 @@ def act_strip(context):
         return None
 
 
+def draw_color_balance(layout, color_balance):
+    col = layout.column()
+    col.label(text="Lift:")
+    col.template_color_wheel(color_balance, "lift", value_slider=True, cubic=True)
+    row = col.row()
+    row.prop(color_balance, "lift", text="")
+    row.prop(color_balance, "invert_lift", text="Inverse")
+
+    col = layout.column()
+    col.label(text="Gamma:")
+    col.template_color_wheel(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True)
+    row = col.row()
+    row.prop(color_balance, "gamma", text="")
+    row.prop(color_balance, "invert_gamma", text="Inverse")
+
+    col = layout.column()
+    col.label(text="Gain:")
+    col.template_color_wheel(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True)
+    row = col.row()
+    row.prop(color_balance, "gain", text="")
+    row.prop(color_balance, "invert_gain", text="Inverse")
+
+
 class SEQUENCER_HT_header(Header):
     bl_space_type = 'SEQUENCE_EDITOR'
 
@@ -442,7 +465,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
 
         if strip.is_supports_mask:
             col = layout.column()
-            col.prop_search(strip, "input_mask", sequencer, "sequences")
+            col.prop_search(strip, "input_mask_strip", sequencer, "sequences", text="Mask")
 
         if strip.type == 'COLOR':
             layout.prop(strip, "color")
@@ -772,26 +795,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
 
         layout.prop(strip, "use_color_balance")
         if strip.use_color_balance and strip.color_balance:  # TODO - need to add this somehow
-            col = layout.column()
-            col.label(text="Lift:")
-            col.template_color_wheel(strip.color_balance, "lift", value_slider=True, cubic=True)
-            row = col.row()
-            row.prop(strip.color_balance, "lift", text="")
-            row.prop(strip.color_balance, "invert_lift", text="Inverse")
-
-            col = layout.column()
-            col.label(text="Gamma:")
-            col.template_color_wheel(strip.color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True)
-            row = col.row()
-            row.prop(strip.color_balance, "gamma", text="")
-            row.prop(strip.color_balance, "invert_gamma", text="Inverse")
-
-            col = layout.column()
-            col.label(text="Gain:")
-            col.template_color_wheel(strip.color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True)
-            row = col.row()
-            row.prop(strip.color_balance, "gain", text="")
-            row.prop(strip.color_balance, "invert_gain", text="Inverse")
+            draw_color_balance(layout, strip.color_balance)
 
 
 class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
@@ -878,5 +882,46 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output, Panel):
             col.prop(st, "show_separate_color")
         col.prop(st, "proxy_render_size")
 
+
+class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
+    bl_label = "Modifiers"
+
+    def draw(self, context):
+        layout = self.layout
+
+        strip = act_strip(context)
+        sequencer = context.scene.sequence_editor
+
+        layout.operator_menu_enum("sequencer.strip_modifier_add", "type")
+
+        for mod in strip.modifiers:
+            box = layout.box()
+
+            row = box.row()
+            row.prop(mod, "show_expanded", text="", emboss=False)
+            row.prop(mod, "name")
+
+            row.prop(mod, "mute", text="")
+            props = row.operator("sequencer.strip_modifier_remove", text="", icon='X')
+            props.name = mod.name
+
+            if mod.show_expanded:
+                row = box.row()
+                row.prop(mod, "input_mask_type", expand=True)
+
+                if mod.input_mask_type == 'STRIP':
+                    box.prop_search(mod, "input_mask_strip", sequencer, "sequences", text="Mask")
+                else:
+                    box.prop(mod, "input_mask_id")
+
+                if mod.type == 'COLOR_BALANCE':
+                    box.prop(mod, "color_multiply")
+                    draw_color_balance(box, mod.color_balance)
+                elif mod.type == 'CURVES':
+                    box.template_curve_mapping(mod, "curve_mapping", type='COLOR')
+                elif mod.type == 'HUE_CORRECT':
+                    box.template_curve_mapping(mod, "curve_mapping", type='HUE')
+
+
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)
index f58af8f39a0c221ea718c43632b9ee7116ce26eb..dcb40c960b19e9228109e5695230cbdf1404e7fd 100644 (file)
@@ -47,8 +47,11 @@ struct rctf;
 #   define DO_INLINE static inline
 #endif
 
+void                curvemapping_set_defaults(struct CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy);
 struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
+void                curvemapping_free_data(struct CurveMapping *cumap);
 void                curvemapping_free(struct CurveMapping *cumap);
+void                curvemapping_copy_data(struct CurveMapping *target, struct CurveMapping *cumap);
 struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap);
 void                curvemapping_set_black_white(struct CurveMapping *cumap, const float black[3], const float white[3]);
 
@@ -69,6 +72,7 @@ float               curvemap_evaluateF(struct CurveMap *cuma, float value);
 float               curvemapping_evaluateF(struct CurveMapping *cumap, int cur, float value);
 void                curvemapping_evaluate3F(struct CurveMapping *cumap, float vecout[3], const float vecin[3]);
 void                curvemapping_evaluateRGBF(struct CurveMapping *cumap, float vecout[3], const float vecin[3]);
+void                curvemapping_evaluate_premulRGB(struct CurveMapping *cumap, unsigned char vecout_byte[3], const unsigned char vecin_byte[3]);
 void                curvemapping_evaluate_premulRGBF(struct CurveMapping *cumap, float vecout[3], const float vecin[3]);
 void                curvemapping_do_ibuf(struct CurveMapping *cumap, struct ImBuf *ibuf);
 void                curvemapping_premultiply(struct CurveMapping *cumap, int restore);
index 823b1dd14da96ca150d41651d173c7aab9b4cfcc..d05e065ac15c35e880b6f9eec9d44498d75bad9d 100644 (file)
  */
 
 struct bContext;
+struct StripColorBalance;
 struct Editing;
 struct ImBuf;
 struct Main;
+struct Mask;
 struct Scene;
 struct Sequence;
+struct SequenceModifierData;
 struct Strip;
 struct StripElem;
 struct bSound;
@@ -241,6 +244,10 @@ void BKE_sequencer_cache_put(SeqRenderData context, struct Sequence *seq, float
 
 void BKE_sequencer_cache_cleanup_sequence(struct Sequence *seq);
 
+struct ImBuf *BKE_sequencer_preprocessed_cache_get(SeqRenderData context, struct Sequence *seq, float cfra, seq_stripelem_ibuf_t type);
+void BKE_sequencer_preprocessed_cache_put(SeqRenderData context, struct Sequence *seq, float cfra, seq_stripelem_ibuf_t type, struct ImBuf *ibuf);
+void BKE_sequencer_preprocessed_cache_cleanup_sequence(struct Sequence *seq);
+
 /* **********************************************************************
  * seqeffects.c
  *
@@ -289,6 +296,7 @@ int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char
 
 int BKE_sequence_check_depend(struct Sequence *seq, struct Sequence *cur);
 void BKE_sequence_invalidate_cache(struct Scene *scene, struct Sequence *seq);
+void BKE_sequence_invalidate_cache_for_modifier(struct Scene *scene, struct Sequence *seq);
 
 void BKE_sequencer_update_sound_bounds_all(struct Scene *scene);
 void BKE_sequencer_update_sound_bounds(struct Scene *scene, struct Sequence *seq);
@@ -347,4 +355,46 @@ extern SequencerDrawView sequencer_view3d_cb;
 extern ListBase seqbase_clipboard;
 extern int seqbase_clipboard_frame;
 
+/* modifiers */
+typedef struct SequenceModifierTypeInfo {
+       /* default name for the modifier */
+       char name[64];  /* MAX_NAME */
+
+       /* DNA structure name used on load/save filed */
+       char struct_name[64];  /* MAX_NAME */
+
+       /* size of modifier data structure, used by allocation */
+       int struct_size;
+
+       /* data initialization */
+       void (*init_data) (struct SequenceModifierData *smd);
+
+       /* free data used by modifier,
+        * only modifier-specific data should be freed, modifier descriptor would
+        * be freed outside of this callback
+        */
+       void (*free_data) (struct SequenceModifierData *smd);
+
+       /* copy data from one modifier to another */
+       void (*copy_data) (struct SequenceModifierData *smd, struct SequenceModifierData *target);
+
+       /* apply modifier on a given image buffer */
+       struct ImBuf* (*apply) (struct SequenceModifierData *smd, struct ImBuf *ibuf, struct ImBuf *mask);
+} SequenceModifierTypeInfo;
+
+struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type);
+
+void BKE_sequence_modifier_new(struct Sequence *seq, int type);
+void BKE_sequence_modifier_free(struct SequenceModifierData *smd);
+void BKE_sequence_modifier_unique_name(struct Sequence *seq, struct SequenceModifierData *smd);
+struct SequenceModifierData *BKE_sequence_modifier_find_by_name(struct Sequence *seq, char *name);
+struct ImBuf *BKE_sequence_modifier_apply_stack(SeqRenderData context, struct Sequence *seq, struct ImBuf *ibuf, int cfra);
+void BKE_sequence_modifier_list_copy(struct Sequence *seqn, struct Sequence *seq);
+
+int BKE_sequence_supports_modifiers(struct Sequence *seq);
+
+/* internal filters */
+struct ImBuf *BKE_sequencer_render_mask_input(SeqRenderData context, int mask_input_type, struct Sequence *mask_sequence, struct Mask *mask_id, int cfra, int make_float);
+void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb, struct ImBuf *ibuf, float mul, short make_float, struct ImBuf *mask_input);
+
 #endif /* __BKE_SEQUENCER_H__ */
index 38a39ad492d193add768512c544865aff97d6261..0a0635126f5744ef062227700524d265cd9787f7 100644 (file)
@@ -128,6 +128,7 @@ set(SRC
        intern/script.c
        intern/seqcache.c
        intern/seqeffects.c
+       intern/seqmodifier.c
        intern/sequencer.c
        intern/shrinkwrap.c
        intern/sketch.c
index 20fae9737568497f0fc58fd1f093ff47bf327ee9..118169e8f7d42b7959482a8d63f9c9bf2105df2a 100644 (file)
 
 /* ***************** operations on full struct ************* */
 
-CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
+void curvemapping_set_defaults(CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
 {
-       CurveMapping *cumap;
        int a;
        float clipminx, clipminy, clipmaxx, clipmaxy;
        
-       cumap = MEM_callocN(sizeof(CurveMapping), "new curvemap");
        cumap->flag = CUMA_DO_CLIP;
        if (tot == 4) cumap->cur = 3;   /* rhms, hack for 'col' curve? */
        
@@ -89,38 +87,59 @@ CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, floa
        }       
 
        cumap->changed_timestamp = 0;
+}
+
+CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
+{
+       CurveMapping *cumap;
+
+       cumap = MEM_callocN(sizeof(CurveMapping), "new curvemap");
+
+       curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy);
 
        return cumap;
 }
 
-void curvemapping_free(CurveMapping *cumap)
+void curvemapping_free_data(CurveMapping *cumap)
 {
        int a;
-       
+
+       for (a = 0; a < CM_TOT; a++) {
+               if (cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
+               if (cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
+               if (cumap->cm[a].premultable) MEM_freeN(cumap->cm[a].premultable);
+       }
+}
+
+void curvemapping_free(CurveMapping *cumap)
+{
        if (cumap) {
-               for (a = 0; a < CM_TOT; a++) {
-                       if (cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
-                       if (cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
-                       if (cumap->cm[a].premultable) MEM_freeN(cumap->cm[a].premultable);
-               }
+               curvemapping_free_data(cumap);
                MEM_freeN(cumap);
        }
 }
 
-CurveMapping *curvemapping_copy(CurveMapping *cumap)
+void curvemapping_copy_data(CurveMapping *target, CurveMapping *cumap)
 {
        int a;
-       
+
+       *target = *cumap;
+
+       for (a = 0; a < CM_TOT; a++) {
+               if (cumap->cm[a].curve)
+                       target->cm[a].curve = MEM_dupallocN(cumap->cm[a].curve);
+               if (cumap->cm[a].table)
+                       target->cm[a].table = MEM_dupallocN(cumap->cm[a].table);
+               if (cumap->cm[a].premultable)
+                       target->cm[a].premultable = MEM_dupallocN(cumap->cm[a].premultable);
+       }
+}
+
+CurveMapping *curvemapping_copy(CurveMapping *cumap)
+{
        if (cumap) {
                CurveMapping *cumapn = MEM_dupallocN(cumap);
-               for (a = 0; a < CM_TOT; a++) {
-                       if (cumap->cm[a].curve) 
-                               cumapn->cm[a].curve = MEM_dupallocN(cumap->cm[a].curve);
-                       if (cumap->cm[a].table) 
-                               cumapn->cm[a].table = MEM_dupallocN(cumap->cm[a].table);
-                       if (cumap->cm[a].premultable) 
-                               cumapn->cm[a].premultable = MEM_dupallocN(cumap->cm[a].premultable);
-               }
+               curvemapping_copy_data(cumapn, cumap);
                return cumapn;
        }
        return NULL;
@@ -782,6 +801,22 @@ void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float vecout[3], cons
        vecout[2] = curvemap_evaluateF(cumap->cm + 2, fac);
 }
 
+/* same as above, byte version */
+void curvemapping_evaluate_premulRGB(CurveMapping *cumap, unsigned char vecout_byte[3], const unsigned char vecin_byte[3])
+{
+       float vecin[3], vecout[3];
+
+       vecin[0] = (float) vecin_byte[0] / 255.0f;
+       vecin[1] = (float) vecin_byte[1] / 255.0f;
+       vecin[2] = (float) vecin_byte[2] / 255.0f;
+
+       curvemapping_evaluate_premulRGBF(cumap, vecout, vecin);
+
+       vecout_byte[0] = FTOCHAR(vecout[0]);
+       vecout_byte[1] = FTOCHAR(vecout[1]);
+       vecout_byte[2] = FTOCHAR(vecout[2]);
+}
+
 
 /* only used for image editor curves */
 void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
index 387ec67eb1cccd50465a945e7b9e37360c15867f..d79f23e8979a6457be67eaec340d5e64a8a163bd 100644 (file)
 #include "BKE_sequencer.h"
 
 #include "IMB_moviecache.h"
+#include "IMB_imbuf.h"
 #include "IMB_imbuf_types.h"
 
+#include "BLI_listbase.h"
+
 typedef struct SeqCacheKey {
        struct Sequence *seq;
        SeqRenderData context;
@@ -46,7 +49,25 @@ typedef struct SeqCacheKey {
        seq_stripelem_ibuf_t type;
 } SeqCacheKey;
 
+typedef struct SeqPreprocessCacheElem {
+       struct SeqPreprocessCacheElem *next, *prev;
+
+       struct Sequence *seq;
+       SeqRenderData context;
+       seq_stripelem_ibuf_t type;
+
+       ImBuf *ibuf;
+} SeqPreprocessCacheElem;
+
+typedef struct SeqPreprocessCache {
+       int cfra;
+       ListBase elems;
+} SeqPreprocessCache;
+
 static struct MovieCache *moviecache = NULL;
+static struct SeqPreprocessCache *preprocess_cache = NULL;
+
+static void preprocessed_cache_destruct(void);
 
 static int seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
 {
@@ -160,6 +181,8 @@ void BKE_sequencer_cache_destruct(void)
 {
        if (moviecache)
                IMB_moviecache_free(moviecache);
+
+       preprocessed_cache_destruct();
 }
 
 void BKE_sequencer_cache_cleanup(void)
@@ -219,3 +242,100 @@ void BKE_sequencer_cache_put(SeqRenderData context, Sequence *seq, float cfra, s
 
        IMB_moviecache_put(moviecache, &key, i);
 }
+
+static void preprocessed_cache_clean(void)
+{
+       SeqPreprocessCacheElem *elem;
+
+       if (!preprocess_cache)
+               return;
+
+       for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
+               IMB_freeImBuf(elem->ibuf);
+       }
+       BLI_freelistN(&preprocess_cache->elems);
+
+       preprocess_cache->elems.first = preprocess_cache->elems.last = NULL;
+}
+
+static void preprocessed_cache_destruct(void)
+{
+       if (!preprocess_cache)
+               return;
+
+       preprocessed_cache_clean();
+
+       MEM_freeN(preprocess_cache);
+       preprocess_cache = NULL;
+}
+
+ImBuf *BKE_sequencer_preprocessed_cache_get(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type)
+{
+       SeqPreprocessCacheElem *elem;
+
+       if (!preprocess_cache)
+               return NULL;
+
+       if (preprocess_cache->cfra != cfra)
+               return NULL;
+
+       for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
+               if (elem->seq != seq)
+                       continue;
+
+               if (elem->type != type)
+                       continue;
+
+               if (seq_cmp_render_data(&elem->context, &context) != 0)
+                       continue;
+
+               IMB_refImBuf(elem->ibuf);
+               return elem->ibuf;
+       }
+
+       return NULL;
+}
+
+void BKE_sequencer_preprocessed_cache_put(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type, ImBuf *ibuf)
+{
+       SeqPreprocessCacheElem *elem;
+
+       if (!preprocess_cache) {
+               preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
+       }
+       else {
+               if (preprocess_cache->cfra != cfra)
+                       preprocessed_cache_clean();
+       }
+
+       elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
+
+       elem->seq = seq;
+       elem->type = type;
+       elem->context = context;
+       elem->ibuf = ibuf;
+
+       preprocess_cache->cfra = cfra;
+
+       IMB_refImBuf(ibuf);
+
+       BLI_addtail(&preprocess_cache->elems, elem);
+}
+
+void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
+{
+       SeqPreprocessCacheElem *elem, *elem_next;
+
+       if (!preprocess_cache)
+               return;
+
+       for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
+               elem_next = elem->next;
+
+               if (elem->seq == seq) {
+                       IMB_freeImBuf(elem->ibuf);
+
+                       BLI_freelinkN(&preprocess_cache->elems, elem);
+               }
+       }
+}
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
new file mode 100644 (file)
index 0000000..4157a3a
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * ***** 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/seqmodifier.c
+ *  \ingroup bke
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "DNA_sequence_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_sequencer.h"
+#include "BKE_utildefines.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+static SequenceModifierTypeInfo *modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES];
+static int modifierTypesInit = FALSE;
+
+/*********************** Modifiers *************************/
+
+typedef void (*modifier_apply_threaded_cb) (int width, int height, unsigned char *rect, float *rect_float,
+                                            unsigned char *mask_rect, float *mask_rect_float, void *data_v);
+
+typedef struct ModifierInitData {
+       ImBuf *ibuf;
+       ImBuf *mask;
+       void *user_data;
+
+       modifier_apply_threaded_cb apply_callback;
+} ModifierInitData;
+
+typedef struct ModifierThread {
+       int width, height;
+
+       unsigned char *rect, *mask_rect;
+       float *rect_float, *mask_rect_float;
+
+       void *user_data;
+
+       modifier_apply_threaded_cb apply_callback;
+} ModifierThread;
+
+
+static ImBuf *modifier_mask_get(SequenceModifierData *smd, SeqRenderData context, int cfra, int make_float)
+{
+       return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, make_float);
+}
+
+static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
+{
+       ModifierThread *handle = (ModifierThread *) handle_v;
+       ModifierInitData *init_data = (ModifierInitData *) init_data_v;
+       ImBuf *ibuf = init_data->ibuf;
+       ImBuf *mask = init_data->mask;
+
+       int offset = 4 * start_line * ibuf->x;
+
+       memset(handle, 0, sizeof(ModifierThread));
+
+       handle->width = ibuf->x;
+       handle->height = tot_line;
+       handle->apply_callback = init_data->apply_callback;
+       handle->user_data = init_data->user_data;
+
+       if (ibuf->rect)
+               handle->rect = (unsigned char *) ibuf->rect + offset;
+
+       if (ibuf->rect_float)
+               handle->rect_float = ibuf->rect_float + offset;
+
+       if (mask) {
+               if (mask->rect)
+                       handle->mask_rect = (unsigned char *) mask->rect + offset;
+
+               if (mask->rect_float)
+                       handle->mask_rect_float = mask->rect_float + offset;
+       }
+       else {
+               handle->mask_rect = NULL;
+               handle->mask_rect_float = NULL;
+       }
+}
+
+static void *modifier_do_thread(void *thread_data_v)
+{
+       ModifierThread *td = (ModifierThread *) thread_data_v;
+
+       td->apply_callback(td->width, td->height, td->rect, td->rect_float, td->mask_rect, td->mask_rect_float, td->user_data);
+
+       return NULL;
+}
+
+static void modifier_apply_threaded(ImBuf *ibuf, ImBuf *mask, modifier_apply_threaded_cb apply_callback, void *user_data)
+{
+       ModifierInitData init_data;
+
+       init_data.ibuf = ibuf;
+       init_data.mask = mask;
+       init_data.user_data = user_data;
+
+       init_data.apply_callback = apply_callback;
+
+       IMB_processor_apply_threaded(ibuf->y, sizeof(ModifierThread), &init_data,
+                                 modifier_init_handle, modifier_do_thread);
+}
+
+/* **** Color Balance Modifier **** */
+
+void colorBalance_init_data(SequenceModifierData *smd)
+{
+       ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
+       int c;
+
+       cbmd->color_multiply = 1.0f;
+
+       for (c = 0; c < 3; c++) {
+               cbmd->color_balance.lift[c] = 1.0f;
+               cbmd->color_balance.gamma[c] = 1.0f;
+               cbmd->color_balance.gain[c] = 1.0f;
+       }
+}
+
+ImBuf *colorBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
+{
+       ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
+       ImBuf *ibuf_new = IMB_dupImBuf(ibuf);
+
+       BKE_sequencer_color_balance_apply(&cbmd->color_balance, ibuf_new, cbmd->color_multiply, FALSE, mask);
+
+       return ibuf_new;
+}
+
+static SequenceModifierTypeInfo seqModifier_ColorBalance = {
+       "Color Balance",                   /* name */
+       "ColorBalanceModifierData",        /* struct_name */
+       sizeof(ColorBalanceModifierData),  /* struct_size */
+       colorBalance_init_data,            /* init_data */
+       NULL,                              /* free_data */
+       NULL,                              /* copy_data */
+       colorBalance_apply                 /* apply */
+};
+
+/* **** Curves Modifier **** */
+
+void curves_init_data(SequenceModifierData *smd)
+{
+       CurvesModifierData *cmd = (CurvesModifierData *) smd;
+
+       curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+void curves_free_data(SequenceModifierData *smd)
+{
+       CurvesModifierData *cmd = (CurvesModifierData *) smd;
+
+       curvemapping_free_data(&cmd->curve_mapping);
+}
+
+void curves_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
+{
+       CurvesModifierData *cmd = (CurvesModifierData *) smd;
+       CurvesModifierData *cmd_target = (CurvesModifierData *) target;
+
+       curvemapping_copy_data(&cmd_target->curve_mapping, &cmd->curve_mapping);
+}
+
+void curves_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
+                           unsigned char *mask_rect, float *mask_rect_float, void *data_v)
+{
+       CurveMapping *curve_mapping = (CurveMapping *) data_v;
+       int x, y;
+
+       for (y = 0; y < height; y++) {
+               for (x = 0; x < width; x++) {
+                       int pixel_index = (y * width + x) * 4;
+
+                       if (rect_float) {
+                               float *pixel = rect_float + pixel_index;
+                               float result[3];
+
+                               curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
+
+                               if (mask_rect_float) {
+                                       float *m = mask_rect_float + pixel_index;
+
+                                       pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
+                                       pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
+                                       pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
+                               }
+                               else {
+                                       pixel[0] = result[0];
+                                       pixel[1] = result[1];
+                                       pixel[2] = result[2];
+                               }
+                       }
+                       if (rect) {
+                               unsigned char *pixel = rect + pixel_index;
+                               unsigned char result[3];
+
+                               curvemapping_evaluate_premulRGB(curve_mapping, result, pixel);
+
+                               if (mask_rect) {
+                                       float t[3];
+
+                                       rgb_uchar_to_float(t, mask_rect + pixel_index);
+
+                                       pixel[0] = pixel[0] * (1.0f - t[0]) + result[0] * t[0];
+                                       pixel[1] = pixel[1] * (1.0f - t[1]) + result[1] * t[1];
+                                       pixel[2] = pixel[2] * (1.0f - t[2]) + result[2] * t[2];
+                               }
+                               else {
+                                       pixel[0] = result[0];
+                                       pixel[1] = result[1];
+                                       pixel[2] = result[2];
+                               }
+                       }
+               }
+       }
+}
+
+ImBuf *curves_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
+{
+       CurvesModifierData *cmd = (CurvesModifierData *) smd;
+       ImBuf *ibuf_new = IMB_dupImBuf(ibuf);
+
+       float black[3] = {0.0f, 0.0f, 0.0f};
+       float white[3] = {1.0f, 1.0f, 1.0f};
+
+       curvemapping_initialize(&cmd->curve_mapping);
+
+       curvemapping_premultiply(&cmd->curve_mapping, 0);
+       curvemapping_set_black_white(&cmd->curve_mapping, black, white);
+
+       modifier_apply_threaded(ibuf_new, mask, curves_apply_threaded, &cmd->curve_mapping);
+
+       curvemapping_premultiply(&cmd->curve_mapping, 1);
+
+       return ibuf_new;
+}
+
+static SequenceModifierTypeInfo seqModifier_Curves = {
+       "Curves",                    /* name */
+       "CurvesModifierData",        /* struct_name */
+       sizeof(CurvesModifierData),  /* struct_size */
+       curves_init_data,            /* init_data */
+       curves_free_data,            /* free_data */
+       curves_copy_data,            /* copy_data */
+       curves_apply                 /* apply */
+};
+
+/* **** Hue Correct Modifier **** */
+
+void hue_correct_init_data(SequenceModifierData *smd)
+{
+       HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+       int c;
+
+       curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
+       hcmd->curve_mapping.preset = CURVE_PRESET_MID9;
+
+       for (c = 0; c < 3; c++) {
+               CurveMap *cuma = &hcmd->curve_mapping.cm[c];
+
+               curvemap_reset(cuma, &hcmd->curve_mapping.clipr, hcmd->curve_mapping.preset, CURVEMAP_SLOPE_POSITIVE);
+       }
+
+       /* default to showing Saturation */
+       hcmd->curve_mapping.cur = 1;
+}
+
+void hue_correct_free_data(SequenceModifierData *smd)
+{
+       HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+
+       curvemapping_free_data(&hcmd->curve_mapping);
+}
+
+void hue_correct_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
+{
+       HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+       HueCorrectModifierData *hcmd_target = (HueCorrectModifierData *) target;
+
+       curvemapping_copy_data(&hcmd_target->curve_mapping, &hcmd->curve_mapping);
+}
+
+void hue_correct_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
+                                unsigned char *mask_rect, float *mask_rect_float, void *data_v)
+{
+       CurveMapping *curve_mapping = (CurveMapping *) data_v;
+       int x, y;
+
+       for (y = 0; y < height; y++) {
+               for (x = 0; x < width; x++) {
+                       int pixel_index = (y * width + x) * 4;
+                       float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
+                       float hsv[3], f;
+
+                       if (rect_float)
+                               copy_v3_v3(pixel, rect_float + pixel_index);
+                       else
+                               rgb_uchar_to_float(pixel, rect + pixel_index);
+
+                       rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
+
+                       /* adjust hue, scaling returned default 0.5 up to 1 */
+                       f = curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
+                       hsv[0] += f - 0.5f;
+
+                       /* adjust saturation, scaling returned default 0.5 up to 1 */
+                       f = curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
+                       hsv[1] *= (f * 2.0f);
+
+                       /* adjust value, scaling returned default 0.5 up to 1 */
+                       f = curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
+                       hsv[2] *= (f * 2.f);
+
+                       hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
+                       CLAMP(hsv[1], 0.0f, 1.0f);
+
+                       /* convert back to rgb */
+                       hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
+
+                       if (mask_rect_float)
+                                       copy_v3_v3(mask, mask_rect_float + pixel_index);
+                       else if (mask_rect)
+                                       rgb_uchar_to_float(mask, mask_rect + pixel_index);
+
+                       result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
+                       result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
+                       result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
+
+                       if (rect_float)
+                               copy_v3_v3(rect_float + pixel_index, result);
+                       else
+                               rgb_float_to_uchar(rect + pixel_index, result);
+               }
+       }
+}
+
+ImBuf *hue_correct_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
+{
+       HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+       ImBuf *ibuf_new = IMB_dupImBuf(ibuf);
+
+       curvemapping_initialize(&hcmd->curve_mapping);
+
+       modifier_apply_threaded(ibuf_new, mask, hue_correct_apply_threaded, &hcmd->curve_mapping);
+
+       return ibuf_new;
+}
+
+static SequenceModifierTypeInfo seqModifier_HueCorrect = {
+       "Hue Correct",                    /* name */
+       "HueCorrectModifierData",         /* struct_name */
+       sizeof(HueCorrectModifierData),   /* struct_size */
+       hue_correct_init_data,            /* init_data */
+       hue_correct_free_data,            /* free_data */
+       hue_correct_copy_data,            /* copy_data */
+       hue_correct_apply                 /* apply */
+};
+
+/*********************** Modifier functions *************************/
+
+static void sequence_modifier_type_info_init(void)
+{
+#define INIT_TYPE(typeName) (modifiersTypes[seqModifierType_##typeName] = &seqModifier_##typeName)
+
+       INIT_TYPE(ColorBalance);
+       INIT_TYPE(Curves);
+       INIT_TYPE(HueCorrect);
+
+#undef INIT_TYPE
+}
+
+SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
+{
+       if (!modifierTypesInit) {
+               sequence_modifier_type_info_init();
+               modifierTypesInit = TRUE;
+       }
+
+       return modifiersTypes[type];
+}
+
+void BKE_sequence_modifier_new(Sequence *seq, int type)
+{
+       SequenceModifierData *smd;
+       SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
+
+       smd = MEM_callocN(smti->struct_size, "sequence modifier");
+
+       smd->type = type;
+       smd->flag |= SEQUENCE_MODIFIER_EXPANDED;
+
+       BLI_strncpy(smd->name, smti->name, sizeof(smd->name));
+
+       BLI_addtail(&seq->modifiers, smd);
+
+       BKE_sequence_modifier_unique_name(seq, smd);
+
+       if (smti->init_data)
+               smti->init_data(smd);
+}
+
+void BKE_sequence_modifier_free(SequenceModifierData *smd)
+{
+       SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+       if (smti && smti->free_data) {
+               smti->free_data(smd);
+       }
+
+       MEM_freeN(smd);
+}
+
+void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
+{
+       SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+       BLI_uniquename(&seq->modifiers, smd, smti->name, '.', offsetof(SequenceModifierData, name), sizeof(smd->name));
+}
+
+SequenceModifierData *BKE_sequence_modifier_find_by_name(Sequence *seq, char *name)
+{
+       return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name));
+}
+
+ImBuf *BKE_sequence_modifier_apply_stack(SeqRenderData context, Sequence *seq, ImBuf *ibuf, int cfra)
+{
+       SequenceModifierData *smd;
+       ImBuf *processed_ibuf = ibuf;
+
+       for (smd = seq->modifiers.first; smd; smd = smd->next) {
+               SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+               ImBuf *ibuf_new;
+
+               /* could happen if modifier is being removed or not exists in current version of blender */
+               if (!smti)
+                       continue;
+
+               /* modifier is muted, do nothing */
+               if (smd->flag & SEQUENCE_MODIFIER_MUTE)
+                       continue;
+
+               if (smti->apply) {
+                       ImBuf *mask = modifier_mask_get(smd, context, cfra, ibuf->rect_float != NULL);
+
+                       if (processed_ibuf == ibuf)
+                               processed_ibuf = IMB_dupImBuf(ibuf);
+
+                       ibuf_new = smti->apply(smd, processed_ibuf, mask);
+
+                       if (ibuf_new != processed_ibuf) {
+                               IMB_freeImBuf(processed_ibuf);
+                               processed_ibuf = ibuf_new;
+                       }
+
+                       if (mask)
+                               IMB_freeImBuf(mask);
+               }
+       }
+
+       return processed_ibuf;
+}
+
+void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq)
+{
+       SequenceModifierData *smd;
+
+       for (smd = seq->modifiers.first; smd; smd = smd->next) {
+               SequenceModifierData *smdn;
+               SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+               smdn = MEM_dupallocN(smd);
+
+               if (smti && smti->copy_data)
+                       smti->copy_data(smdn, smd);
+
+               smdn->next = smdn->prev = NULL;
+               BLI_addtail(&seqn->modifiers, smdn);
+       }
+}
+
+int BKE_sequence_supports_modifiers(Sequence *seq)
+{
+       return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD);
+}
index 9625fad69a6951dd5330472017b17a78d5c7fe96..b156d622202345ad6b2b15ca69eb52c2dcb53e8a 100644 (file)
@@ -83,6 +83,7 @@
 static ImBuf *seq_render_strip_stack(SeqRenderData context, ListBase *seqbasep, float cfra, int chanshown);
 static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra);
 static void seq_free_animdata(Scene *scene, Sequence *seq);
+static ImBuf *seq_render_mask(SeqRenderData context, Mask *mask, float nr, short make_float);
 
 /* **** XXX ******** */
 #define SELECT 1
@@ -203,7 +204,18 @@ void BKE_sequence_free(Scene *scene, Sequence *seq)
                seq_free_animdata(scene, seq);
        }
 
+       /* free modifiers */
+       if (seq->modifiers.first) {
+               SequenceModifierData *smd, *smd_next;
+
+               for (smd = seq->modifiers.first; smd; smd = smd_next) {
+                       smd_next = smd->next;
+                       BKE_sequence_modifier_free(smd);
+               }
+       }
+
        BKE_sequencer_cache_cleanup_sequence(seq);
+       BKE_sequencer_preprocessed_cache_cleanup_sequence(seq);
 
        MEM_freeN(seq);
 }
@@ -1432,7 +1444,7 @@ static void make_cb_table_float(float lift, float gain, float gamma,
        }
 }
 
-static void color_balance_byte_byte(Sequence *seq, unsigned char *rect, unsigned char *mask_rect, int width, int height, float mul)
+static void color_balance_byte_byte(StripColorBalance *cb_, unsigned char *rect, unsigned char *mask_rect, int width, int height, float mul)
 {
        unsigned char cb_tab[3][256];
        int c;
@@ -1440,7 +1452,7 @@ static void color_balance_byte_byte(Sequence *seq, unsigned char *rect, unsigned
        unsigned char *e = p + width * 4 * height;
        unsigned char *m = mask_rect;
 
-       StripColorBalance cb = calc_cb(seq->strip->color_balance);
+       StripColorBalance cb = calc_cb(cb_);
 
        for (c = 0; c < 3; c++) {
                make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
@@ -1466,7 +1478,7 @@ static void color_balance_byte_byte(Sequence *seq, unsigned char *rect, unsigned
        }
 }
 
-static void color_balance_byte_float(Sequence *seq, unsigned char *rect, float *rect_float, unsigned char *mask_rect, int width, int height, float mul)
+static void color_balance_byte_float(StripColorBalance *cb_, unsigned char *rect, float *rect_float, unsigned char *mask_rect, int width, int height, float mul)
 {
        float cb_tab[4][256];
        int c, i;
@@ -1478,7 +1490,7 @@ static void color_balance_byte_float(Sequence *seq, unsigned char *rect, float *
 
        o = rect_float;
 
-       cb = calc_cb(seq->strip->color_balance);
+       cb = calc_cb(cb_);
 
        for (c = 0; c < 3; c++) {
                make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
@@ -1510,12 +1522,12 @@ static void color_balance_byte_float(Sequence *seq, unsigned char *rect, float *
        }
 }
 
-static void color_balance_float_float(Sequence *seq, float *rect_float, float *mask_rect_float, int width, int height, float mul)
+static void color_balance_float_float(StripColorBalance *cb_, float *rect_float, float *mask_rect_float, int width, int height, float mul)
 {
        float *p = rect_float;
        float *e = rect_float + width * 4 * height;
        float *m = mask_rect_float;
-       StripColorBalance cb = calc_cb(seq->strip->color_balance);
+       StripColorBalance cb = calc_cb(cb_);
 
        while (p < e) {
                int c;
@@ -1535,20 +1547,23 @@ static void color_balance_float_float(Sequence *seq, float *rect_float, float *m
 }
 
 typedef struct ColorBalanceInitData {
-       Sequence *seq;
+       StripColorBalance *cb;
        ImBuf *ibuf;
        float mul;
        ImBuf *mask;
+       short make_float;
 } ColorBalanceInitData;
 
 typedef struct ColorBalanceThread {
-       Sequence *seq;
+       StripColorBalance *cb;
        float mul;
 
        int width, height;
 
        unsigned char *rect, *mask_rect;
        float *rect_float, *mask_rect_float;
+
+       short make_float;
 } ColorBalanceThread;
 
 static void color_balance_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
@@ -1562,10 +1577,11 @@ static void color_balance_init_handle(void *handle_v, int start_line, int tot_li
 
        memset(handle, 0, sizeof(ColorBalanceThread));
 
-       handle->seq = init_data->seq;
+       handle->cb = init_data->cb;
        handle->mul = init_data->mul;
        handle->width = ibuf->x;
        handle->height = tot_line;
+       handle->make_float = init_data->make_float;
 
        if (ibuf->rect)
                handle->rect = (unsigned char *) ibuf->rect + offset;
@@ -1589,7 +1605,7 @@ static void color_balance_init_handle(void *handle_v, int start_line, int tot_li
 static void *color_balance_do_thread(void *thread_data_v)
 {
        ColorBalanceThread *thread_data = (ColorBalanceThread *) thread_data_v;
-       Sequence *seq = thread_data->seq;
+       StripColorBalance *cb = thread_data->cb;
        int width = thread_data->width, height = thread_data->height;
        unsigned char *rect = thread_data->rect;
        unsigned char *mask_rect = thread_data->mask_rect;
@@ -1598,48 +1614,56 @@ static void *color_balance_do_thread(void *thread_data_v)
        float mul = thread_data->mul;
 
        if (rect_float) {
-               color_balance_float_float(seq, rect_float, mask_rect_float, width, height, mul);
+               color_balance_float_float(cb, rect_float, mask_rect_float, width, height, mul);
        }
-       else if (seq->flag & SEQ_MAKE_FLOAT) {
-               color_balance_byte_float(seq, rect, rect_float, mask_rect, width, height, mul);
+       else if (thread_data->make_float) {
+               color_balance_byte_float(cb, rect, rect_float, mask_rect, width, height, mul);
        }
        else {
-               color_balance_byte_byte(seq, rect, mask_rect, width, height, mul);
+               color_balance_byte_byte(cb, rect, mask_rect, width, height, mul);
        }
 
        return NULL;
 }
 
-static void color_balance(SeqRenderData context, Sequence *seq, ImBuf *ibuf, float mul, int cfra)
+ImBuf *BKE_sequencer_render_mask_input(SeqRenderData context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id, int cfra, int make_float)
+{
+       ImBuf *mask_input = NULL;
+
+       if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
+               if (mask_sequence) {
+                       mask_input = seq_render_strip(context, mask_sequence, cfra);
+
+                       if (make_float) {
+                               if (!mask_input->rect_float)
+                                       IMB_float_from_rect(mask_input);
+                       }
+                       else {
+                               if (!mask_input->rect)
+                                       IMB_rect_from_float(mask_input);
+                       }
+               }
+       }
+       else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
+               mask_input = seq_render_mask(context, mask_id, cfra, make_float);
+       }
+
+       return mask_input;
+}
+
+void BKE_sequencer_color_balance_apply(StripColorBalance *cb, ImBuf *ibuf, float mul, short make_float, ImBuf *mask_input)
 {
        ColorBalanceInitData init_data;
 
-       if (!ibuf->rect_float && seq->flag & SEQ_MAKE_FLOAT)
+       if (!ibuf->rect_float && make_float)
                imb_addrectfloatImBuf(ibuf);
 
-       init_data.seq = seq;
+       init_data.cb = cb;
        init_data.ibuf = ibuf;
        init_data.mul = mul;
        init_data.mask = NULL;
-
-       if (seq->mask_sequence) {
-               if (seq->mask_sequence != seq && !BKE_sequence_check_depend(seq, seq->mask_sequence)) {
-                       ImBuf *mask = seq_render_strip(context, seq->mask_sequence, cfra);
-
-                       if (mask) {
-                               if (ibuf->rect_float) {
-                                       if (!mask->rect_float)
-                                               IMB_float_from_rect(mask);
-                               }
-                               else {
-                                       if (!mask->rect)
-                                               IMB_rect_from_float(mask);
-                               }
-
-                               init_data.mask = mask;
-                       }
-               }
-       }
+       init_data.make_float = make_float;
+       init_data.mask = mask_input;
 
        IMB_processor_apply_threaded(ibuf->y, sizeof(ColorBalanceThread), &init_data,
                                  color_balance_init_handle, color_balance_do_thread);
@@ -1650,9 +1674,26 @@ static void color_balance(SeqRenderData context, Sequence *seq, ImBuf *ibuf, flo
         */
        if (ibuf->rect_float && ibuf->rect)
                imb_freerectImBuf(ibuf);
+}
 
-       if (init_data.mask)
-               IMB_freeImBuf(init_data.mask);
+static void sequence_color_balance(SeqRenderData context, Sequence *seq, ImBuf *ibuf, float mul, int cfra)
+{
+       StripColorBalance *cb = seq->strip->color_balance;
+       ImBuf *mask_input = NULL;
+       short make_float = seq->flag & SEQ_MAKE_FLOAT;
+
+       if (seq->mask_sequence) {
+               if (seq->mask_sequence != seq && !BKE_sequence_check_depend(seq, seq->mask_sequence)) {
+                       int make_float = ibuf->rect_float != NULL;
+
+                       mask_input = BKE_sequencer_render_mask_input(context, SEQUENCE_MASK_INPUT_STRIP, seq->mask_sequence, NULL, cfra, make_float);
+               }
+       }
+
+       BKE_sequencer_color_balance_apply(cb, ibuf, mul, make_float, mask_input);
+
+       if (mask_input)
+               IMB_freeImBuf(mask_input);
 }
 
 /*
@@ -1696,6 +1737,10 @@ int BKE_sequencer_input_have_to_preprocess(SeqRenderData UNUSED(context), Sequen
        if (seq->sat != 1.0f) {
                return TRUE;
        }
+
+       if (seq->modifiers.first) {
+               return TRUE;
+       }
                
        return FALSE;
 }
@@ -1795,7 +1840,7 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra,
        }
 
        if (seq->flag & SEQ_USE_COLOR_BALANCE && seq->strip->color_balance) {
-               color_balance(context, seq, ibuf, mul, cfra);
+               sequence_color_balance(context, seq, ibuf, mul, cfra);
                mul = 1.0;
        }
 
@@ -1818,7 +1863,6 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra,
                }
        }
 
-
        if (ibuf->x != context.rectx || ibuf->y != context.recty) {
                if (context.scene->r.mode & R_OSA) {
                        IMB_scaleImBuf(ibuf, (short)context.rectx, (short)context.recty);
@@ -1827,6 +1871,16 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra,
                        IMB_scalefastImBuf(ibuf, (short)context.rectx, (short)context.recty);
                }
        }
+
+       if (seq->modifiers.first) {
+               ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra);
+
+               if (ibuf_new != ibuf) {
+                       IMB_freeImBuf(ibuf);
+                       ibuf = ibuf_new;
+               }
+       }
+
        return ibuf;
 }
 
@@ -2098,23 +2152,23 @@ static ImBuf *seq_render_movieclip_strip(SeqRenderData context, Sequence *seq, f
 }
 
 
-static ImBuf *seq_render_mask_strip(SeqRenderData context, Sequence *seq, float nr)
+static ImBuf *seq_render_mask(SeqRenderData context, Mask *mask, float nr, short make_float)
 {
        /* TODO - add option to rasterize to alpha imbuf? */
        ImBuf *ibuf = NULL;
        float *maskbuf;
        int i;
 
-       if (!seq->mask) {
+       if (!mask) {
                return NULL;
        }
        else {
                Mask *mask_temp;
                MaskRasterHandle *mr_handle;
 
-               mask_temp = BKE_mask_copy_nolib(seq->mask);
+               mask_temp = BKE_mask_copy_nolib(mask);
 
-               BKE_mask_evaluate(mask_temp, seq->mask->sfra + nr, TRUE);
+               BKE_mask_evaluate(mask_temp, mask->sfra + nr, TRUE);
 
                maskbuf = MEM_mallocN(sizeof(float) * context.rectx * context.recty, __func__);
 
@@ -2131,7 +2185,7 @@ static ImBuf *seq_render_mask_strip(SeqRenderData context, Sequence *seq, float
        }
 
 
-       if (seq->flag & SEQ_MAKE_FLOAT) {
+       if (make_float) {
                /* pixels */
                float *fp_src;
                float *fp_dst;
@@ -2173,6 +2227,13 @@ static ImBuf *seq_render_mask_strip(SeqRenderData context, Sequence *seq, float
        return ibuf;
 }
 
+static ImBuf *seq_render_mask_strip(SeqRenderData context, Sequence *seq, float nr)
+{
+       short make_float = seq->flag & SEQ_MAKE_FLOAT;
+
+       return seq_render_mask(context, seq->mask, nr, make_float);
+}
+
 static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float nr)
 {
        ImBuf *ibuf = NULL;
@@ -2328,160 +2389,146 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float
        return ibuf;
 }
 
-static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra)
+static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, float cfra)
 {
        ImBuf *ibuf = NULL;
-       char name[FILE_MAX];
-       int use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, 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_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 = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
-
-       /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF,
-        * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL */
-       if (ibuf)
-               use_preprocess = FALSE;
-
-       if (ibuf == NULL)
-               ibuf = copy_from_ibuf_still(context, seq, nr);
-       
-       /* MOVIECLIPs have their own proxy management */
-       if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) {
-               ibuf = seq_proxy_fetch(context, seq, cfra);
-               is_proxy_image = (ibuf != NULL);
-       }
+       int use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra);
+       char name[FILE_MAX];
 
-       if (ibuf == NULL) switch (type) {
-                       case SEQ_TYPE_META:
-                       {
-                               ImBuf *meta_ibuf = NULL;
+       switch (type) {
+               case SEQ_TYPE_META:
+               {
+                       ImBuf *meta_ibuf = NULL;
 
-                               if (seq->seqbase.first)
-                                       meta_ibuf = seq_render_strip_stack(
-                                               context, &seq->seqbase,
-                                               seq->start + nr, 0);
+                       if (seq->seqbase.first)
+                               meta_ibuf = seq_render_strip_stack(context, &seq->seqbase, seq->start + nr, 0);
 
-                               if (meta_ibuf) {
-                                       ibuf = meta_ibuf;
-                                       if (ibuf && use_preprocess) {
-                                               ImBuf *i = IMB_dupImBuf(ibuf);
+                       if (meta_ibuf) {
+                               ibuf = meta_ibuf;
+                               if (ibuf && use_preprocess) {
+                                       ImBuf *i = IMB_dupImBuf(ibuf);
 
-                                               IMB_freeImBuf(ibuf);
+                                       IMB_freeImBuf(ibuf);
 
-                                               ibuf = i;
-                                       }
+                                       ibuf = i;
                                }
-
-                               break;
                        }
-                       case SEQ_TYPE_SPEED:
-                       {
-                               ImBuf *child_ibuf = NULL;
 
-                               float f_cfra;
-                               SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
+                       break;
+               }
 
-                               BKE_sequence_effect_speed_rebuild_map(context.scene, seq, 0);
+               case SEQ_TYPE_SPEED:
+               {
+                       ImBuf *child_ibuf = NULL;
 
-                               /* weeek! */
-                               f_cfra = seq->start + s->frameMap[(int)nr];
+                       float f_cfra;
+                       SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
 
-                               child_ibuf = seq_render_strip(context, seq->seq1, f_cfra);
+                       BKE_sequence_effect_speed_rebuild_map(context.scene, seq, 0);
 
-                               if (child_ibuf) {
-                                       ibuf = child_ibuf;
-                                       if (ibuf && use_preprocess) {
-                                               ImBuf *i = IMB_dupImBuf(ibuf);
+                       /* weeek! */
+                       f_cfra = seq->start + s->frameMap[(int)nr];
 
-                                               IMB_freeImBuf(ibuf);
+                       child_ibuf = seq_render_strip(context, seq->seq1, f_cfra);
 
-                                               ibuf = i;
-                                       }
+                       if (child_ibuf) {
+                               ibuf = child_ibuf;
+                               if (ibuf && use_preprocess) {
+                                       ImBuf *i = IMB_dupImBuf(ibuf);
+
+                                       IMB_freeImBuf(ibuf);
+
+                                       ibuf = i;
                                }
-                               break;
                        }
-                       case SEQ_TYPE_EFFECT:
-                       {
-                               ibuf = seq_render_effect_strip_impl(context, seq, seq->start + nr);
-                               break;
-                       }
-                       case SEQ_TYPE_IMAGE:
-                       {
-                               StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
+                       break;
+               }
 
-                               if (s_elem) {
-                                       BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
-                                       BLI_path_abs(name, G.main->name);
-                               }
+               case SEQ_TYPE_EFFECT:
+               {
+                       ibuf = seq_render_effect_strip_impl(context, seq, seq->start + nr);
+                       break;
+               }
 
-                               if (s_elem && (ibuf = IMB_loadiffname(name, IB_rect))) {
-                                       /* we don't need both (speed reasons)! */
-                                       if (ibuf->rect_float && ibuf->rect)
-                                               imb_freerectImBuf(ibuf);
+               case SEQ_TYPE_IMAGE:
+               {
+                       StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra);
 
-                                       /* all sequencer color is done in SRGB space, linear gives odd crossfades */
-                                       if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
-                                               IMB_convert_profile(ibuf, IB_PROFILE_NONE);
+                       if (s_elem) {
+                               BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
+                               BLI_path_abs(name, G.main->name);
+                       }
 
-                                       copy_to_ibuf_still(context, seq, nr, ibuf);
+                       if (s_elem && (ibuf = IMB_loadiffname(name, IB_rect))) {
+                               /* we don't need both (speed reasons)! */
+                               if (ibuf->rect_float && ibuf->rect)
+                                       imb_freerectImBuf(ibuf);
 
-                                       s_elem->orig_width  = ibuf->x;
-                                       s_elem->orig_height = ibuf->y;
-                               }
-                               break;
+                               /* all sequencer color is done in SRGB space, linear gives odd crossfades */
+                               if (ibuf->profile == IB_PROFILE_LINEAR_RGB)
+                                       IMB_convert_profile(ibuf, IB_PROFILE_NONE);
+
+                               copy_to_ibuf_still(context, seq, nr, ibuf);
+
+                               s_elem->orig_width  = ibuf->x;
+                               s_elem->orig_height = ibuf->y;
                        }
-                       case SEQ_TYPE_MOVIE:
-                       {
-                               seq_open_anim_file(seq);
+                       break;
+               }
+
+               case SEQ_TYPE_MOVIE:
+               {
+                       seq_open_anim_file(seq);
 
-                               if (seq->anim) {
-                                       IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
+                       if (seq->anim) {
+                               IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
 
-                                       ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
-                                                                seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
-                                                                seq_rendersize_to_proxysize(context.preview_render_size));
+                               ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
+                                                        seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+                                                        seq_rendersize_to_proxysize(context.preview_render_size));
 
-                                       /* we don't need both (speed reasons)! */
-                                       if (ibuf && ibuf->rect_float && ibuf->rect)
-                                               imb_freerectImBuf(ibuf);
-                                       if (ibuf) {
-                                               seq->strip->stripdata->orig_width = ibuf->x;
-                                               seq->strip->stripdata->orig_height = ibuf->y;
-                                       }
+                               /* we don't need both (speed reasons)! */
+                               if (ibuf && ibuf->rect_float && ibuf->rect)
+                                       imb_freerectImBuf(ibuf);
+                               if (ibuf) {
+                                       seq->strip->stripdata->orig_width = ibuf->x;
+                                       seq->strip->stripdata->orig_height = ibuf->y;
                                }
-                               copy_to_ibuf_still(context, seq, nr, ibuf);
-                               break;
                        }
-                       case SEQ_TYPE_SCENE:
-                       {
-                               /* scene can be NULL after deletions */
-                               ibuf = seq_render_scene_strip(context, seq, nr);
+                       copy_to_ibuf_still(context, seq, nr, ibuf);
+                       break;
+               }
 
-                               /* Scene strips update all animation, so we need to restore original state.*/
-                               BKE_animsys_evaluate_all_animation(context.bmain, context.scene, cfra);
+               case SEQ_TYPE_SCENE:
+               {
+                       /* scene can be NULL after deletions */
+                       ibuf = seq_render_scene_strip(context, seq, nr);
 
-                               copy_to_ibuf_still(context, seq, nr, ibuf);
-                               break;
-                       }
-                       case SEQ_TYPE_MOVIECLIP:
-                       {
-                               ibuf = seq_render_movieclip_strip(context, seq, nr);
+                       /* Scene strips update all animation, so we need to restore original state.*/
+                       BKE_animsys_evaluate_all_animation(context.bmain, context.scene, cfra);
 
-                               if (ibuf && use_preprocess) {
-                                       ImBuf *i = IMB_dupImBuf(ibuf);
+                       copy_to_ibuf_still(context, seq, nr, ibuf);
+                       break;
+               }
 
-                                       IMB_freeImBuf(ibuf);
+               case SEQ_TYPE_MOVIECLIP:
+               {
+                       ibuf = seq_render_movieclip_strip(context, seq, nr);
 
-                                       ibuf = i;
-                               }
+                       if (ibuf && use_preprocess) {
+                               ImBuf *i = IMB_dupImBuf(ibuf);
 
-                               copy_to_ibuf_still(context, seq, nr, ibuf);
-                               break;
+                               IMB_freeImBuf(ibuf);
+
+                               ibuf = i;
                        }
+
+                       copy_to_ibuf_still(context, seq, nr, ibuf);
+                       break;
+               }
+
                case SEQ_TYPE_MASK:
                {
                        /* ibuf is alwats new */
@@ -2492,6 +2539,45 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra)
                }
        }
 
+       return ibuf;
+}
+
+static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra)
+{
+       ImBuf *ibuf = NULL;
+       int use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, 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_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 = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
+
+       /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF,
+        * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL */
+       if (ibuf)
+               use_preprocess = FALSE;
+
+       if (ibuf == NULL)
+               ibuf = copy_from_ibuf_still(context, seq, nr);
+
+       if (ibuf == NULL) {
+               ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
+
+               if (ibuf == NULL) {
+                       /* MOVIECLIPs have their own proxy management */
+                       if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) {
+                               ibuf = seq_proxy_fetch(context, seq, cfra);
+                               is_proxy_image = (ibuf != NULL);
+                       }
+
+                       ibuf = do_render_strip_uncached(context, seq, cfra);
+
+                       BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf);
+               }
+       }
+
        if (ibuf == NULL)
                ibuf = IMB_allocImBuf(context.rectx, context.recty, 32, IB_rect);
 
@@ -2876,7 +2962,7 @@ int BKE_sequence_check_depend(Sequence *seq, Sequence *cur)
        return TRUE;
 }
 
-void BKE_sequence_invalidate_cache(Scene *scene, Sequence *seq)
+static void sequence_invalidate_cache(Scene *scene, Sequence *seq, int invalidate_preprocess)
 {
        Editing *ed = scene->ed;
        Sequence *cur;
@@ -2884,18 +2970,33 @@ void BKE_sequence_invalidate_cache(Scene *scene, Sequence *seq)
        /* invalidate cache for current sequence */
        BKE_sequencer_cache_cleanup_sequence(seq);
 
+       if (invalidate_preprocess)
+               BKE_sequencer_preprocessed_cache_cleanup_sequence(seq);
+
        /* invalidate cache for all dependent sequences */
        SEQ_BEGIN (ed, cur)
        {
                if (cur == seq)
                        continue;
 
-               if (BKE_sequence_check_depend(seq, cur))
+               if (BKE_sequence_check_depend(seq, cur)) {
                        BKE_sequencer_cache_cleanup_sequence(cur);
+                       BKE_sequencer_preprocessed_cache_cleanup_sequence(cur);
+               }
        }
        SEQ_END
 }
 
+void BKE_sequence_invalidate_cache(Scene *scene, Sequence *seq)
+{
+       sequence_invalidate_cache(scene, seq, TRUE);
+}
+
+void BKE_sequence_invalidate_cache_for_modifier(Scene *scene, Sequence *seq)
+{
+       sequence_invalidate_cache(scene, seq, FALSE);
+}
+
 void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, int check_mem_usage, int keep_file_handles)
 {
        Sequence *seq;
@@ -3941,6 +4042,12 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup
                seqn->strip->color_balance = MEM_dupallocN(seq->strip->color_balance);
        }
 
+       if (seqn->modifiers.first) {
+               seqn->modifiers.first = seqn->modifiers.last = NULL;
+
+               BKE_sequence_modifier_list_copy(seqn, seq);
+       }
+
        if (seq->type == SEQ_TYPE_META) {
                seqn->strip->stripdata = NULL;
 
@@ -4060,3 +4167,4 @@ int BKE_seqence_is_valid_check(Sequence *seq)
 
        return TRUE;
 }
+
index e7722e074425eb481662cb500895a31652f05cda..eb22b9a2e2e3d550129e04effeba583e7ae7aae8 100644 (file)
@@ -4785,6 +4785,16 @@ static void link_paint(FileData *fd, Scene *sce, Paint *p)
        }
 }
 
+static void lib_link_sequence_modifiers(FileData *fd, Scene *scene, ListBase *lb)
+{
+       SequenceModifierData *smd;
+
+       for (smd = lb->first; smd; smd = smd->next) {
+               if (smd->mask_id)
+                       smd->mask_id = newlibadr_us(fd, scene->id.lib, smd->mask_id);
+       }
+}
+
 static void lib_link_scene(FileData *fd, Main *main)
 {
        Scene *sce;
@@ -4869,6 +4879,8 @@ static void lib_link_scene(FileData *fd, Main *main)
                                        }
                                }
                                seq->anim = NULL;
+
+                               lib_link_sequence_modifiers(fd, sce, &seq->modifiers);
                        }
                        SEQ_END
 
@@ -4925,6 +4937,29 @@ static void direct_link_paint(FileData *fd, Paint **paint)
                (*paint)->num_input_samples = 1;
 }
 
+static void direct_link_sequence_modifiers(FileData *fd, ListBase *lb)
+{
+       SequenceModifierData *smd;
+
+       link_list(fd, lb);
+
+       for (smd = lb->first; smd; smd = smd->next) {
+               if (smd->mask_sequence)
+                       smd->mask_sequence = newdataadr(fd, smd->mask_sequence);
+
+               if (smd->type == seqModifierType_Curves) {
+                       CurvesModifierData *cmd = (CurvesModifierData *) smd;
+
+                       direct_link_curvemapping(fd, &cmd->curve_mapping);
+               }
+               else if (smd->type == seqModifierType_HueCorrect) {
+                       HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+
+                       direct_link_curvemapping(fd, &hcmd->curve_mapping);
+               }
+       }
+}
+
 static void direct_link_scene(FileData *fd, Scene *sce)
 {
        Editing *ed;
@@ -5037,6 +5072,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
                                        // seq->strip->color_balance->gui = 0; // XXX - peter, is this relevant in 2.5?
                                }
                        }
+
+                       direct_link_sequence_modifiers(fd, &seq->modifiers);
                }
                SEQ_END
                
index 2a68af688edc8cf633841aee0ba85183191310af..4ada0c54a93a4b3c02704dcca80cf3b95d5e7bf0 100644 (file)
@@ -646,15 +646,21 @@ static void write_animdata(WriteData *wd, AnimData *adt)
        write_nladata(wd, &adt->nla_tracks);
 }
 
-static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
+static void write_curvemapping_curves(WriteData *wd, CurveMapping *cumap)
 {
        int a;
-       
-       writestruct(wd, DATA, "CurveMapping", 1, cumap);
-       for (a=0; a<CM_TOT; a++)
+
+       for (a = 0; a < CM_TOT; a++)
                writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve);
 }
 
+static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
+{
+       writestruct(wd, DATA, "CurveMapping", 1, cumap);
+
+       write_curvemapping_curves(wd, cumap);
+}
+
 static void write_node_socket(WriteData *wd, bNodeSocket *sock)
 {
        bNodeSocketType *stype= ntreeGetSocketType(sock->type);
@@ -2086,6 +2092,32 @@ static void write_lamps(WriteData *wd, ListBase *idbase)
        }
 }
 
+static void write_sequence_modifiers(WriteData *wd, ListBase *modbase)
+{
+       SequenceModifierData *smd;
+
+       for (smd = modbase->first; smd; smd = smd->next) {
+               SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
+
+               if (smti) {
+                       writestruct(wd, DATA, smti->struct_name, 1, smd);
+
+                       if (smd->type == seqModifierType_Curves) {
+                               CurvesModifierData *cmd = (CurvesModifierData *) smd;
+
+                               write_curvemapping(wd, &cmd->curve_mapping);
+                       }
+                       else if (smd->type == seqModifierType_HueCorrect) {
+                               HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
+
+                               write_curvemapping(wd, &hcmd->curve_mapping);
+                       }
+               }
+               else {
+                       writestruct(wd, DATA, "SequenceModifierData", 1, smd);
+               }
+       }
+}
 
 static void write_scenes(WriteData *wd, ListBase *scebase)
 {
@@ -2192,6 +2224,8 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                                        
                                        strip->done = TRUE;
                                }
+
+                               write_sequence_modifiers(wd, &seq->modifiers);
                        }
                        SEQ_END
                                
index 7bee8c2bebfe322832e2c5a7aa72df676545300e..dd5fbb921712ea1455214b9b279e6fca60d77f53 100644 (file)
@@ -40,6 +40,7 @@ set(SRC
        sequencer_buttons.c
        sequencer_draw.c
        sequencer_edit.c
+       sequencer_modifier.c
        sequencer_ops.c
        sequencer_scopes.c
        sequencer_select.c
index 16cf929a832aef466e12a5f7351a0945d17464cd..bad4fcf9135eb6cae85be4f931bb2c021a06ce0d 100644 (file)
@@ -177,5 +177,9 @@ struct ImBuf *make_histogram_view_from_ibuf(struct ImBuf * ibuf);
 void sequencer_buttons_register(struct ARegionType *art);
 void SEQUENCER_OT_properties(struct wmOperatorType *ot);
 
+/* sequencer_modifiers.c */
+void SEQUENCER_OT_strip_modifier_add(struct wmOperatorType *ot);
+void SEQUENCER_OT_strip_modifier_remove(struct wmOperatorType *ot);
+
 #endif /* __SEQUENCER_INTERN_H__ */
 
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
new file mode 100644 (file)
index 0000000..4ae4b99
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * ***** 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/editors/space_sequencer/sequencer_modifier.c
+ *  \ingroup spseq
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_sequencer.h"
+#include "BKE_movieclip.h"
+#include "BKE_sequencer.h"
+#include "BKE_mask.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+/* own include */
+#include "sequencer_intern.h"
+
+/*********************** Add modifier operator *************************/
+
+static int strip_modifier_active_poll(bContext *C)
+{
+       Scene *scene = CTX_data_scene(C);
+       Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
+
+       if (ed) {
+               Sequence *seq = BKE_sequencer_active_get(scene);
+
+               if (seq)
+                       return BKE_sequence_supports_modifiers(seq);
+       }
+
+       return FALSE;
+}
+
+static int strip_modifier_add_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene = CTX_data_scene(C);
+       Sequence *seq = BKE_sequencer_active_get(scene);
+       int type = RNA_enum_get(op->ptr, "type");
+
+       BKE_sequence_modifier_new(seq, type);
+
+       BKE_sequence_invalidate_cache(scene, seq);
+       WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+       return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_strip_modifier_add(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* TODO: de-duplicate from RNA */
+       static EnumPropertyItem sequence_modifier_type_items[] = {
+               {seqModifierType_ColorBalance, "COLOR_BALANCE", ICON_NONE, "Color Balance", ""},
+               {seqModifierType_Curves, "CURVES", ICON_NONE, "Curves", ""},
+               {seqModifierType_HueCorrect,"HUE_CORRECT", ICON_NONE, "Hue Correct", ""},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       /* identifiers */
+       ot->name = "Add Strip Modifier";
+       ot->idname = "SEQUENCER_OT_strip_modifier_add";
+       ot->description = "Add a modifier to strip";
+
+       /* api callbacks */
+       ot->exec = strip_modifier_add_exec;
+       ot->poll = strip_modifier_active_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* properties */
+       prop = RNA_def_enum(ot->srna, "type", sequence_modifier_type_items, seqModifierType_ColorBalance, "Type", "");
+       ot->prop = prop;
+}
+
+/*********************** Remove modifier operator *************************/
+
+static int strip_modifier_remove_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene = CTX_data_scene(C);
+       Sequence *seq = BKE_sequencer_active_get(scene);
+       char name[MAX_NAME];
+       SequenceModifierData *smd;
+
+       RNA_string_get(op->ptr, "name", name);
+
+       smd = BKE_sequence_modifier_find_by_name(seq, name);
+       if (!smd)
+               return OPERATOR_CANCELLED;
+
+       BLI_remlink(&seq->modifiers, smd);
+       BKE_sequence_modifier_free(smd);
+
+       BKE_sequence_invalidate_cache(scene, seq);
+       WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+       return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Remove Strip Modifier";
+       ot->idname = "SEQUENCER_OT_strip_modifier_remove";
+       ot->description = "Add a modifier to strip";
+
+       /* api callbacks */
+       ot->exec = strip_modifier_remove_exec;
+       ot->poll = strip_modifier_active_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_string(ot->srna, "name", "Name", MAX_NAME, "Name", "Name of modifier to remove");
+}
index 4a1c8f0c006c12a9fb9fa6658e6f5b839b6e299c..45ffc997172037bf58e7e03b9ec5fb79bf13b286 100644 (file)
@@ -114,6 +114,10 @@ void sequencer_operatortypes(void)
 
        WM_operatortype_append(SEQUENCER_OT_copy);
        WM_operatortype_append(SEQUENCER_OT_paste);
+
+       /* sequencer_modifiers.c */
+       WM_operatortype_append(SEQUENCER_OT_strip_modifier_add);
+       WM_operatortype_append(SEQUENCER_OT_strip_modifier_remove);
 }
 
 
index 16e8b8904fab76c5c32dad8c49ce6ab8d8c8d057..d6c59456bd0fb439c971a485ac3a83bfba504c99 100644 (file)
@@ -34,6 +34,7 @@
 #define __DNA_SEQUENCE_TYPES_H__
 
 #include "DNA_defs.h"
+#include "DNA_color_types.h"
 #include "DNA_listBase.h"
 #include "DNA_vec_types.h"
 
@@ -167,6 +168,9 @@ typedef struct Sequence {
 
        /* is sfra needed anymore? - it looks like its only used in one place */
        int sfra, pad;  /* starting frame according to the timeline of the scene. */
+
+       /* modifiers */
+       ListBase modifiers;
 } Sequence;
 
 typedef struct MetaStack {
@@ -229,6 +233,40 @@ typedef struct SpeedControlVars {
        int lastValidFrame;
 } SpeedControlVars;
 
+/* ***************** Sequence modifiers ****************** */
+
+typedef struct SequenceModifierData {
+       struct SequenceModifierData *next, *prev;
+       int type, flag;
+       char name[64]; /* MAX_NAME */
+
+       /* mask input, either sequence or maks ID */
+       int mask_input_type, pad;
+
+       struct Sequence *mask_sequence;
+       struct Mask     *mask_id;
+} SequenceModifierData;
+
+typedef struct ColorBalanceModifierData {
+       SequenceModifierData modifier;
+
+       StripColorBalance color_balance;
+       float color_multiply;
+       int pad;
+} ColorBalanceModifierData;
+
+typedef struct CurvesModifierData {
+       SequenceModifierData modifier;
+
+       struct CurveMapping curve_mapping;
+} CurvesModifierData;
+
+typedef struct HueCorrectModifierData {
+       SequenceModifierData modifier;
+
+       struct CurveMapping curve_mapping;
+} HueCorrectModifierData;
+
 #define MAXSEQ          32
 
 #define SELECT 1
@@ -352,5 +390,26 @@ enum {
 
 #define SEQ_HAS_PATH(_seq) (ELEM4((_seq)->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD))
 
-#endif
+/* modifiers */
+
+/* SequenceModifierData->type */
+enum {
+       seqModifierType_ColorBalance   = 1,
+       seqModifierType_Curves         = 2,
+       seqModifierType_HueCorrect     = 3,
+
+       NUM_SEQUENCE_MODIFIER_TYPES
+};
+
+/* SequenceModifierData->flag */
+enum {
+       SEQUENCE_MODIFIER_MUTE      = (1 << 0),
+       SEQUENCE_MODIFIER_EXPANDED  = (1 << 1),
+};
+
+enum {
+       SEQUENCE_MASK_INPUT_STRIP   = 0,
+       SEQUENCE_MASK_INPUT_ID      = 1
+};
 
+#endif
index 6fc304e6bbbf3d65c96734001eb299ed4bb87bd3..fd8195005aaa06dd3deb5b3e4da0c169a15fd6e1 100644 (file)
@@ -332,8 +332,9 @@ static char *rna_SequenceTransform_path(PointerRNA *ptr)
                return BLI_strdup("");
 }
 
-static void rna_SequenceTransform_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_SequenceTransform_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
        Sequence *seq = sequence_get_by_transform(ed, ptr->data);
 
@@ -376,8 +377,9 @@ static char *rna_SequenceCrop_path(PointerRNA *ptr)
                return BLI_strdup("");
 }
 
-static void rna_SequenceCrop_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_SequenceCrop_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
        Sequence *seq = sequence_get_by_crop(ed, ptr->data);
 
@@ -613,8 +615,9 @@ static void rna_SequenceElement_filename_set(PointerRNA *ptr, const char *value)
 }
 #endif
 
-static void rna_Sequence_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_Sequence_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
 
        if (ed) {
@@ -638,8 +641,9 @@ static int rna_Sequence_otherSequence_poll(PointerRNA *ptr, PointerRNA value)
        return TRUE;
 }
 
-static void rna_Sequence_update_reopen_files(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_Sequence_update_reopen_files(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
 
        BKE_sequencer_free_imbuf(scene, &ed->seqbase, FALSE, FALSE);
@@ -648,16 +652,18 @@ static void rna_Sequence_update_reopen_files(Main *UNUSED(bmain), Scene *scene,
                BKE_sequencer_update_sound_bounds(scene, ptr->data);
 }
 
-static void rna_Sequence_mute_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Sequence_mute_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
 
        BKE_sequencer_update_muting(ed);
        rna_Sequence_update(bmain, scene, ptr);
 }
 
-static void rna_Sequence_filepath_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Sequence *seq = (Sequence *)(ptr->data);
        BKE_sequence_reload_new_file(scene, seq, TRUE);
        BKE_sequence_calc(scene, seq);
@@ -686,8 +692,9 @@ static Sequence *sequence_get_by_proxy(Editing *ed, StripProxy *proxy)
        return data.seq;
 }
 
-static void rna_Sequence_tcindex_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Sequence_tcindex_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
        Sequence *seq = sequence_get_by_proxy(ed, ptr->data);
 
@@ -695,8 +702,9 @@ static void rna_Sequence_tcindex_update(Main *bmain, Scene *scene, PointerRNA *p
        rna_Sequence_frame_change_update(scene, seq);
 }
 
-static void rna_SequenceProxy_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_SequenceProxy_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
        Sequence *seq = sequence_get_by_proxy(ed, ptr->data);
 
@@ -724,6 +732,22 @@ static int colbalance_seq_cmp_cb(Sequence *seq, void *arg_pt)
                data->seq = seq;
                return -1; /* done so bail out */
        }
+
+       if (seq->modifiers.first) {
+               SequenceModifierData *smd = seq->modifiers.first;
+
+               for (smd = seq->modifiers.first; smd; smd = smd->next) {
+                       if (smd->type == seqModifierType_ColorBalance) {
+                               ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
+
+                               if (&cbmd->color_balance == data->data) {
+                                       data->seq = seq;
+                                       return -1; /* done so bail out */
+                               }
+                       }
+               }
+       }
+
        return 1;
 }
 
@@ -752,12 +776,16 @@ static char *rna_SequenceColorBalance_path(PointerRNA *ptr)
                return BLI_strdup("");
 }
 
-static void rna_SequenceColorBalance_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_SequenceColorBalance_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
+       Scene *scene = (Scene *) ptr->id.data;
        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
        Sequence *seq = sequence_get_by_colorbalance(ed, ptr->data);
 
-       BKE_sequence_invalidate_cache(scene, seq);
+       if (seq->strip->color_balance == ptr->data)
+               BKE_sequence_invalidate_cache(scene, seq);
+       else
+               BKE_sequence_invalidate_cache_for_modifier(scene, seq);
 }
 
 static void rna_SequenceEditor_overlay_lock_set(PointerRNA *ptr, int value)
@@ -825,6 +853,113 @@ static float rna_WipeSequence_angle_get(PointerRNA *ptr)
        return DEG2RADF(((WipeVars *)seq->effectdata)->angle);
 }
 
+static int modifier_seq_cmp_cb(Sequence *seq, void *arg_pt)
+{
+       SequenceSearchData *data = arg_pt;
+
+       if (BLI_findindex(&seq->modifiers, data->data) != -1) {
+               data->seq = seq;
+               return -1; /* done so bail out */
+       }
+
+       return 1;
+}
+
+static Sequence *sequence_get_by_modifier(Editing *ed, SequenceModifierData *smd)
+{
+       SequenceSearchData data;
+
+       data.seq = NULL;
+       data.data = smd;
+
+       /* irritating we need to search for our sequence! */
+       BKE_sequencer_base_recursive_apply(&ed->seqbase, modifier_seq_cmp_cb, &data);
+
+       return data.seq;
+}
+
+static StructRNA *rna_SequenceModifier_refine(struct PointerRNA *ptr)
+{
+       SequenceModifierData *smd = (SequenceModifierData *) ptr->data;
+
+       switch (smd->type) {
+               case seqModifierType_ColorBalance:
+                       return &RNA_ColorBalanceModifier;
+               case seqModifierType_Curves:
+                       return &RNA_CurvesModifier;
+               case seqModifierType_HueCorrect:
+                       return &RNA_HueCorrectModifier;
+               default:
+                       return &RNA_SequenceModifier;
+       }
+}
+
+static char *rna_SequenceModifier_path(PointerRNA *ptr)
+{
+       Scene *scene = ptr->id.data;
+       Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
+       SequenceModifierData *smd = ptr->data;
+       Sequence *seq = sequence_get_by_modifier(ed, smd);
+
+       if (seq && seq->name + 2)
+               return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].modifiers[\"%s\"]", seq->name + 2, smd->name);
+       else
+               return BLI_strdup("");
+}
+
+static void rna_SequenceModifier_name_set(PointerRNA *ptr, const char *value)
+{
+       SequenceModifierData *smd = ptr->data;
+       Scene *scene = (Scene *) ptr->id.data;
+       Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
+       Sequence *seq = sequence_get_by_modifier(ed, smd);
+       AnimData *adt;
+       char oldname[sizeof(smd->name)];
+
+       /* make a copy of the old name first */
+       BLI_strncpy(oldname, smd->name, sizeof(smd->name));
+
+       /* copy the new name into the name slot */
+       BLI_strncpy_utf8(smd->name, value, sizeof(smd->name));
+
+       /* make sure the name is truly unique */
+       BKE_sequence_modifier_unique_name(seq, smd);
+
+       /* fix all the animation data which may link to this */
+       adt = BKE_animdata_from_id(&scene->id);
+       if (adt) {
+               char path[1024];
+
+               BLI_snprintf(path, sizeof(path), "sequence_editor.sequences_all[\"%s\"].modifiers", seq->name);
+               BKE_animdata_fix_paths_rename(&scene->id, adt, NULL, path, oldname, smd->name + 2, 0, 0, 1);
+       }
+}
+
+static void rna_SequenceModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+       /* strip from other scenes could be modified, so using active scene is not reliable */
+       Scene *scene = (Scene *) ptr->id.data;
+       Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
+       Sequence *seq = sequence_get_by_modifier(ed, ptr->data);
+
+       BKE_sequence_invalidate_cache_for_modifier(scene, seq);
+}
+
+static int rna_SequenceModifier_otherSequence_poll(PointerRNA *ptr, PointerRNA value)
+{
+       Scene *scene = (Scene *) ptr->id.data;
+       Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
+       Sequence *seq = sequence_get_by_modifier(ed, ptr->data);
+       Sequence *cur = (Sequence *) value.data;
+
+       if (seq == cur)
+               return FALSE;
+
+       if (BKE_sequence_check_depend(seq, cur))
+               return FALSE;
+
+       return TRUE;
+}
 
 #else
 
@@ -991,13 +1126,13 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
 
 }
 
-static void rna_def_strip_color_balance(BlenderRNA *brna)
+static void rna_def_color_balance(BlenderRNA *brna)
 {
        StructRNA *srna;
        PropertyRNA *prop;
 
-       srna = RNA_def_struct(brna, "SequenceColorBalance", NULL);
-       RNA_def_struct_ui_text(srna, "Sequence Color Balance", "Color balance parameters for a sequence strip");
+       srna = RNA_def_struct(brna, "SequenceColorBalanceData", NULL);
+       RNA_def_struct_ui_text(srna, "Sequence Color Balance Data", "Color balance parameters for a sequence strip and it's modifiers");
        RNA_def_struct_sdna(srna, "StripColorBalance");
 
        prop = RNA_def_property(srna, "lift", PROP_FLOAT, PROP_COLOR);
@@ -1005,19 +1140,19 @@ static void rna_def_strip_color_balance(BlenderRNA *brna)
        RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
        RNA_def_property_float_default(prop, 1.0f);
        RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
-       
+
        prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_COLOR);
        RNA_def_property_ui_text(prop, "Gamma", "Color balance gamma (midtones)");
        RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
        RNA_def_property_float_default(prop, 1.0f);
        RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
-       
+
        prop = RNA_def_property(srna, "gain", PROP_FLOAT, PROP_COLOR);
        RNA_def_property_ui_text(prop, "Gain", "Color balance gain (highlights)");
        RNA_def_property_ui_range(prop, 0, 2, 0.1, 3);
        RNA_def_property_float_default(prop, 1.0f);
        RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
-       
+
        prop = RNA_def_property(srna, "invert_gain", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_COLOR_BALANCE_INVERSE_GAIN);
        RNA_def_property_ui_text(prop, "Inverse Gain", "");
@@ -1033,15 +1168,13 @@ static void rna_def_strip_color_balance(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Inverse Lift", "");
        RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceColorBalance_update");
 
-       RNA_def_struct_path_func(srna, "rna_SequenceColorBalance_path");
-
        /* not yet used */
 #if 0
        prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE);
        RNA_def_property_range(prop, 0.0f, 1.0f);
        RNA_def_property_ui_text(prop, "Exposure", "");
        RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_ColorBabalnce_update");
-       
+
        prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE);
        RNA_def_property_range(prop, 0.0f, 1.0f);
        RNA_def_property_ui_text(prop, "Saturation", "");
@@ -1049,6 +1182,17 @@ static void rna_def_strip_color_balance(BlenderRNA *brna)
 #endif
 }
 
+static void rna_def_strip_color_balance(BlenderRNA *brna)
+{
+       StructRNA *srna;
+
+       srna = RNA_def_struct(brna, "SequenceColorBalance", "SequenceColorBalanceData");
+       RNA_def_struct_ui_text(srna, "Sequence Color Balance", "Color balance parameters for a sequence strip");
+       RNA_def_struct_sdna(srna, "StripColorBalance");
+
+       RNA_def_struct_path_func(srna, "rna_SequenceColorBalance_path");
+}
+
 EnumPropertyItem blend_mode_items[] = {
        {SEQ_BLEND_REPLACE, "REPLACE", 0, "Replace", ""},
        {SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""},
@@ -1062,6 +1206,18 @@ EnumPropertyItem blend_mode_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+       StructRNA *srna;
+
+       RNA_def_property_srna(cprop, "SequenceModifiers");
+       srna = RNA_def_struct(brna, "SequenceModifiers", NULL);
+       RNA_def_struct_sdna(srna, "Sequence");
+       RNA_def_struct_ui_text(srna, "Strip Modifiers", "Collection of strip modifiers");
+
+       /* TODO: implement new/remove/clear methods for modifier stack */
+}
+
 static void rna_def_sequence(BlenderRNA *brna)
 {
        StructRNA *srna;
@@ -1253,6 +1409,12 @@ static void rna_def_sequence(BlenderRNA *brna)
                                 "to this frame");
        RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
 
+       /* modifiers */
+       prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
+       RNA_def_property_struct_type(prop, "SequenceModifier");
+       RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting this strip");
+       rna_def_sequence_modifiers(brna, prop);
+
        RNA_api_sequence_strip(srna);
 }
 
@@ -1475,7 +1637,7 @@ static void rna_def_effect_inputs(StructRNA *srna, int count, int supports_mask)
        */
 
        if (supports_mask) {
-               prop = RNA_def_property(srna, "input_mask",  PROP_POINTER, PROP_NONE);
+               prop = RNA_def_property(srna, "input_mask_strip",  PROP_POINTER, PROP_NONE);
                RNA_def_property_pointer_sdna(prop, NULL, "mask_sequence");
                RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Sequence_otherSequence_poll");
                RNA_def_property_flag(prop, PROP_EDITABLE);
@@ -1963,8 +2125,138 @@ static void rna_def_effects(BlenderRNA *brna)
        }
 }
 
+static void rna_def_modifier(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       static EnumPropertyItem sequence_modifier_type_items[] = {
+               {seqModifierType_ColorBalance, "COLOR_BALANCE", ICON_NONE, "Color Balance", ""},
+               {seqModifierType_Curves, "CURVES", ICON_NONE, "Curves", ""},
+               {seqModifierType_HueCorrect,"HUE_CORRECT", ICON_NONE, "Hue Correct", ""},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       static const EnumPropertyItem mask_input_type_items[] = {
+               {SEQUENCE_MASK_INPUT_STRIP, "STRIP", 0, "Strip", "Use sequencer strip as mask input"},
+               {SEQUENCE_MASK_INPUT_ID, "ID", 0, "Mask", "Use mask ID as mask input"},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       srna = RNA_def_struct(brna, "SequenceModifier", NULL);
+       RNA_def_struct_sdna(srna, "SequenceModifierData");
+       RNA_def_struct_ui_text(srna, "SequenceModifier", "Modifier for sequence strip");
+       RNA_def_struct_refine_func(srna, "rna_SequenceModifier_refine");
+       RNA_def_struct_path_func(srna, "rna_SequenceModifier_path");
+
+       prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SequenceModifier_name_set");
+       RNA_def_property_ui_text(prop, "Name", "");
+       RNA_def_struct_name_property(srna, prop);
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+       prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_enum_items(prop, sequence_modifier_type_items);
+       RNA_def_property_ui_text(prop, "Type", "");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+       prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQUENCE_MODIFIER_MUTE);
+       RNA_def_property_ui_text(prop, "Mute", "Mute this modifier");
+       RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+       prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQUENCE_MODIFIER_EXPANDED);
+       RNA_def_property_ui_text(prop, "Expanded", "Mute expanded settings for the modifier");
+       RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+       prop = RNA_def_property(srna, "input_mask_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "mask_input_type");
+       RNA_def_property_enum_items(prop, mask_input_type_items);
+       RNA_def_property_ui_text(prop, "Mask Input Type", "Type of input data used for mask");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+       prop = RNA_def_property(srna, "input_mask_strip",  PROP_POINTER, PROP_NONE);
+       RNA_def_property_pointer_sdna(prop, NULL, "mask_sequence");
+       RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_SequenceModifier_otherSequence_poll");
+       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Mask Strip", "Strip used as mask input for the modifier");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+       prop = RNA_def_property(srna, "input_mask_id", PROP_POINTER, PROP_NONE);
+       RNA_def_property_pointer_sdna(prop, NULL, "mask_id");
+       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Mask", "Mask ID used as mask input for the modifier");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+}
+
+static void rna_def_colorbalance_modifier(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       srna = RNA_def_struct(brna, "ColorBalanceModifier", "SequenceModifier");
+       RNA_def_struct_sdna(srna, "ColorBalanceModifierData");
+       RNA_def_struct_ui_text(srna, "ColorBalanceModifier", "Color balance modifier for sequence strip");
+
+       prop = RNA_def_property(srna, "color_balance", PROP_POINTER, PROP_NONE);
+       RNA_def_property_struct_type(prop, "SequenceColorBalanceData");
+
+       prop = RNA_def_property(srna, "color_multiply", PROP_FLOAT, PROP_UNSIGNED);
+       RNA_def_property_float_sdna(prop, NULL, "color_multiply");
+       RNA_def_property_range(prop, 0.0f, 20.0f);
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_ui_text(prop, "Multiply Colors", "");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+}
+
+static void rna_def_curves_modifier(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       srna = RNA_def_struct(brna, "CurvesModifier", "SequenceModifier");
+       RNA_def_struct_sdna(srna, "CurvesModifierData");
+       RNA_def_struct_ui_text(srna, "CurvesModifier", "RGB curves modifier for sequence strip");
+
+       prop = RNA_def_property(srna, "curve_mapping", PROP_POINTER, PROP_NONE);
+       RNA_def_property_pointer_sdna(prop, NULL, "curve_mapping");
+       RNA_def_property_struct_type(prop, "CurveMapping");
+       RNA_def_property_ui_text(prop, "Curve Mapping", "");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+}
+
+static void rna_def_hue_modifier(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       srna = RNA_def_struct(brna, "HueCorrectModifier", "SequenceModifier");
+       RNA_def_struct_sdna(srna, "HueCorrectModifierData");
+       RNA_def_struct_ui_text(srna, "HueCorrectModifier", "Hue correction modifier for sequence strip");
+
+       prop = RNA_def_property(srna, "curve_mapping", PROP_POINTER, PROP_NONE);
+       RNA_def_property_pointer_sdna(prop, NULL, "curve_mapping");
+       RNA_def_property_struct_type(prop, "CurveMapping");
+       RNA_def_property_ui_text(prop, "Curve Mapping", "");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+}
+
+static void rna_def_modifiers(BlenderRNA *brna)
+{
+       rna_def_modifier(brna);
+       rna_def_colorbalance_modifier(brna);
+       rna_def_curves_modifier(brna);
+       rna_def_hue_modifier(brna);
+}
+
 void RNA_def_sequencer(BlenderRNA *brna)
 {
+       rna_def_color_balance(brna);
+
        rna_def_strip_element(brna);
        rna_def_strip_proxy(brna);
        rna_def_strip_color_balance(brna);
@@ -1983,6 +2275,7 @@ void RNA_def_sequencer(BlenderRNA *brna)
        rna_def_sound(brna);
        rna_def_effect(brna);
        rna_def_effects(brna);
+       rna_def_modifiers(brna);
 }
 
 #endif
index 96ddcce600471589863d9bc8a34866c97b9cf39d..cf43bd74d726cf5eadf474bce61c245d24cc2d16 100644 (file)
@@ -125,6 +125,7 @@ void RNA_api_ui_layout(StructRNA *srna)
                {0, "NONE", 0, "None", ""},
                {'v', "VECTOR", 0, "Vector", ""},
                {'c', "COLOR", 0, "Color", ""},
+               {'h', "HUE", 0, "Hue", ""},
                {0, NULL, 0, NULL, NULL}
        };