Text effect strip for sequencer.
authorAntony Riakiotakis <kalast@gmail.com>
Wed, 1 Jul 2015 18:29:18 +0000 (20:29 +0200)
committerAntony Riakiotakis <kalast@gmail.com>
Thu, 2 Jul 2015 16:46:46 +0000 (18:46 +0200)
Is pretty much what it says :)
Easy subtitles for everyone!

Supports size, positioning,
a cheap shadow effect (probably will need more work),
and autocentering on x axis.

Now you can go wild with long spanish names
in your soap opera videos.

Will probably be refined as days go by,
but at least it's now ready for testing.

12 files changed:
release/scripts/startup/bl_ui/space_sequencer.py
source/blender/blenkernel/intern/seqeffects.c
source/blender/blenkernel/intern/sequencer.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_sequencer/sequencer_add.c
source/blender/editors/space_sequencer/sequencer_draw.c
source/blender/editors/space_sequencer/sequencer_edit.c
source/blender/gpu/intern/gpu_debug.c
source/blender/makesdna/DNA_sequence_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_sequencer.c
source/blender/makesrna/intern/rna_sequencer_api.c

index 432244120094fc8c8ce5d52262c5ef50b53d21c1..5291ff4bb3d1cd1ae69439fe41e70cbe3785f08d 100644 (file)
@@ -333,6 +333,7 @@ class SEQUENCER_MT_add_effect(Menu):
         layout.operator("sequencer.effect_strip_add", text="Over Drop").type = 'OVER_DROP'
         layout.operator("sequencer.effect_strip_add", text="Wipe").type = 'WIPE'
         layout.operator("sequencer.effect_strip_add", text="Glow").type = 'GLOW'
+        layout.operator("sequencer.effect_strip_add", text="Text").type = 'TEXT'
         layout.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM'
         layout.operator("sequencer.effect_strip_add", text="Color").type = 'COLOR'
         layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED'
@@ -537,7 +538,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
         return strip.type in {'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED',
-                              'MULTICAM', 'GAUSSIAN_BLUR'}
+                              'MULTICAM', 'GAUSSIAN_BLUR', 'TEXT'}
 
     def draw(self, context):
         layout = self.layout
@@ -628,6 +629,17 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
             for i in range(1, strip.channel):
                 row.operator("sequencer.cut_multicam", text="%d" % i).camera = i
 
+        elif strip.type == 'TEXT':
+            col = layout.column()
+            col.prop(strip, "text")
+            col.prop(strip, "text_size")
+            col.prop(strip, "use_shadow")
+            col.prop(strip, "use_autocenter")
+            row = layout.row(align=True)
+            if not strip.use_autocenter:
+                row.prop(strip, "xpos")
+            row.prop(strip, "ypos")
+
         col = layout.column(align=True)
         if strip.type == 'SPEED':
             col.prop(strip, "multiply_speed")
@@ -638,7 +650,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
         elif strip.type == 'GAUSSIAN_BLUR':
             col.prop(strip, "size_x")
             col.prop(strip, "size_y")
-
 
 class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
     bl_label = "Strip Input"
index f8608ce9406e5d759072ebdd91ab065600b3b860..2d1ea536b279243514dfe58322e128bb2d2d4cf5 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "BLI_math.h" /* windows needs for M_PI */
 #include "BLI_utildefines.h"
+#include "BLI_string.h"
 
 #include "DNA_scene_types.h"
 #include "DNA_sequence_types.h"
@@ -54,6 +55,8 @@
 
 #include "RE_pipeline.h"
 
+#include "BLF_api.h"
+
 static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
                                    const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1,
                                    unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out)
@@ -2876,6 +2879,82 @@ static void do_gaussian_blur_effect(const SeqRenderData *context,
        }
 }
 
+/*********************** text *************************/
+static void init_text_effect(Sequence *seq)
+{
+       TextVars *data;
+
+       if (seq->effectdata)
+               MEM_freeN(seq->effectdata);
+
+       data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars");
+       data->text_size = U.pixelsize * 30;
+       BLI_strncpy(data->text, "Text", sizeof(data->text));
+}
+
+static int num_inputs_text(void)
+{
+       return 0;
+}
+
+static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+{
+       TextVars *data = seq->effectdata;
+       if (data->text[0] == 0 || data->text_size < 1) {
+               return EARLY_USE_INPUT_1;
+       }
+       return EARLY_NO_INPUT;
+}
+
+static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1),
+                          ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+{
+       ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+       TextVars *data = seq->effectdata;
+       int width = out->x;
+       int height = out->y;
+       struct ColorManagedDisplay *display;
+       const char *display_device;
+       const int mono = blf_mono_font_render; // XXX
+       int y_ofs, x, y, w;
+
+       display_device = context->scene->display_settings.display_device;
+       display = IMB_colormanagement_display_get_named(display_device);
+
+       /* set before return */
+       BLF_size(mono, (context->scene->r.size / 100.0f) * data->text_size, 72);
+
+       BLF_buffer(mono, out->rect_float, (unsigned char *)out->rect, width, height, out->channels, display);
+
+       y_ofs = -BLF_descender(mono);
+
+       w = BLF_width(mono, data->text, sizeof(data->text));
+
+       if (data->flags & TEXT_SEQ_AUTO_CENTER)
+               x = width / 2 - w / 2;
+       else
+               x = (context->scene->r.size / 100.0f) * data->xpos;
+
+       y = y_ofs + (context->scene->r.size / 100.0f) * data->ypos;
+
+       /* BLF_SHADOW won't work with buffers, instead use cheap shadow trick */
+       if (data->flags & TEXT_SEQ_SHADOW) {
+               int fontx, fonty;
+               fontx = BLF_width_max(mono);
+               fonty = BLF_height_max(mono);
+               BLF_position(mono, x + max_ii(fontx / 25, 1), y + max_ii(fonty / 25, 1), 0.0);
+               BLF_buffer_col(mono, 0.0f, 0.0f, 0.0f, 1.0);
+               BLF_draw_buffer(mono, data->text);
+       }
+       BLF_position(mono, x, y, 0.0);
+       BLF_buffer_col(mono, 1.0f, 1.0f, 1.0f, 1.0);
+       BLF_draw_buffer(mono, data->text);
+
+       BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL);
+
+       return out;
+}
+
 /*********************** sequence effect factory *************************/
 
 static void init_noop(Sequence *UNUSED(seq))
@@ -2898,6 +2977,19 @@ static int num_inputs_default(void)
        return 2;
 }
 
+static void copy_effect_default(Sequence *dst, Sequence *src)
+{
+       dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static void free_effect_default(Sequence *seq)
+{
+       if (seq->effectdata)
+               MEM_freeN(seq->effectdata);
+
+       seq->effectdata = NULL;
+}
+
 static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
 {
        return EARLY_DO_EFFECT;
@@ -3073,6 +3165,14 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
                        rval.early_out = early_out_gaussian_blur;
                        rval.execute_slice = do_gaussian_blur_effect;
                        break;
+               case SEQ_TYPE_TEXT:
+                       rval.num_inputs = num_inputs_text;
+                       rval.init = init_text_effect;
+                       rval.free = free_effect_default;
+                       rval.copy = copy_effect_default;
+                       rval.early_out = early_out_text;
+                       rval.execute = do_text_effect;
+                       break;
        }
 
        return rval;
index 6b6839d870a19b8e52c2f49f5b75423d89129ffd..37cc5b7746220a4c2d09751d10eccaf9d0c04c99 100644 (file)
@@ -1115,6 +1115,7 @@ static const char *give_seqname_by_type(int type)
                case SEQ_TYPE_ADJUSTMENT:    return "Adjustment";
                case SEQ_TYPE_SPEED:         return "Speed";
                case SEQ_TYPE_GAUSSIAN_BLUR: return "Gaussian Blur";
+               case SEQ_TYPE_TEXT:          return "Text";
                default:
                        return NULL;
        }
index f5954ab75a79c4382edb4da2c630f70a9b924edd..aa44b484f035d82504ea0856c996b72c1263116d 100644 (file)
@@ -2468,6 +2468,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                                                case SEQ_TYPE_GAUSSIAN_BLUR:
                                                        writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata);
                                                        break;
+                                               case SEQ_TYPE_TEXT:
+                                                       writestruct(wd, DATA, "TextVars", 1, seq->effectdata);
+                                                       break;
                                                }
                                        }
 
index 86d1fe71adef58122fb1fd27f84fcfafbcb96b66..edf8a41b5a80f1419aeaa104ccd9b176a9d28afd 100644 (file)
@@ -1010,6 +1010,9 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
        else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
                seq->blend_mode = SEQ_TYPE_CROSS;
        }
+       else if (seq->type == SEQ_TYPE_TEXT) {
+               seq->blend_mode = SEQ_TYPE_ALPHAOVER;
+       }
 
        /* an unset channel is a special case where we automatically go above
         * the other strips. */
index 38107fa69cb466ae62064c5b00db8a03dcfdd775..7aa6550a77bbc0e0063f1d95e48b95f5621fb28a 100644 (file)
@@ -499,6 +499,11 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
                str_len = BLI_snprintf(str, sizeof(str), "%s: %s%s | %d",
                                       name, seq->strip->dir, seq->strip->stripdata->name, seq->len);
        }
+       else if (seq->type == SEQ_TYPE_TEXT) {
+               TextVars *textdata = seq->effectdata;
+               str_len = BLI_snprintf(str, sizeof(str), "%s | %d",
+                                      textdata->text, seq->startdisp);
+       }
        else if (seq->type & SEQ_TYPE_EFFECT) {
                str_len = BLI_snprintf(str, sizeof(str), "%s | %d",
                                       name, seq->len);
index 8030efbf7565e6f90ab664b115c55a4ba343684b..070b41667053c2919cb5a2f0f5dc618d4db9300a 100644 (file)
@@ -91,6 +91,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
        {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
        {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
        {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
+       {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
index 21d7eb4370b5af31250c3499b4deb31d03026c1f..d06c154be5bd0a9399d4109f9e0d5364db9e4f0f 100644 (file)
@@ -191,7 +191,7 @@ void gpu_debug_init(void)
 
 #if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY)
        if (GLEW_VERSION_4_3) {
-               glEnable(GL_DEBUG_OUTPUT);
+               //glEnable(GL_DEBUG_OUTPUT);
                glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext());
                glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
                GPU_STRING_MARKER(sizeof(success), success);
index 7904d056e1a79949cabbcd322c498e651ae4001a..7cf4d9fdff7471cf0157748d65ab08a2040ba79a 100644 (file)
@@ -271,6 +271,17 @@ typedef struct GaussianBlurVars {
        float size_y;
 } GaussianBlurVars;
 
+typedef struct TextVars {
+       char text[512];
+       int text_size;
+       int xpos, ypos;
+       int flags;
+} TextVars;
+
+enum {
+       TEXT_SEQ_SHADOW =      (1 << 0),
+       TEXT_SEQ_AUTO_CENTER = (1 << 1),
+};
 /* ***************** Sequence modifiers ****************** */
 
 typedef struct SequenceModifierData {
@@ -463,7 +474,9 @@ enum {
        SEQ_TYPE_MULTICAM    = 30,
        SEQ_TYPE_ADJUSTMENT  = 31,
        SEQ_TYPE_GAUSSIAN_BLUR = 40,
-       SEQ_TYPE_MAX  = 40
+       SEQ_TYPE_TEXT = 41,
+
+       SEQ_TYPE_MAX  = 41
 };
 
 #define SEQ_MOVIECLIP_RENDER_UNDISTORTED (1 << 0)
index 965d1d916144953629b83035224d052ac10969af..6b05642240407ff50228b3573debee0119a6c853 100644 (file)
@@ -625,6 +625,7 @@ extern StructRNA RNA_ThemeNodeEditor;
 extern StructRNA RNA_ThemeOutliner;
 extern StructRNA RNA_ThemeProperties;
 extern StructRNA RNA_ThemeSequenceEditor;
+extern StructRNA RNA_TextSequence;
 extern StructRNA RNA_ThemeSpaceGeneric;
 extern StructRNA RNA_ThemeSpaceGradient;
 extern StructRNA RNA_ThemeSpaceListGeneric;
index d62509e5ab554f1b10a8dca5791daf5d1381f080..d7311b93b2f03f0c329ab8d3e2598eb2c1f2c34f 100644 (file)
@@ -546,6 +546,8 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr)
                        return &RNA_SpeedControlSequence;
                case SEQ_TYPE_GAUSSIAN_BLUR:
                        return &RNA_GaussianBlurSequence;
+               case SEQ_TYPE_TEXT:
+                       return &RNA_TextSequence;
                default:
                        return &RNA_Sequence;
        }
@@ -1407,6 +1409,7 @@ static void rna_def_sequence(BlenderRNA *brna)
                {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
                {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
                {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
+               {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
                {0, NULL, 0, NULL, NULL}
        };
        
@@ -2302,6 +2305,42 @@ static void rna_def_gaussian_blur(StructRNA *srna)
        RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
 }
 
+static void rna_def_text(StructRNA *srna)
+{
+       PropertyRNA *prop;
+
+       RNA_def_struct_sdna_from(srna, "TextVars", "effectdata");
+
+       prop = RNA_def_property(srna, "text_size", PROP_INT, PROP_UNSIGNED);
+       RNA_def_property_ui_text(prop, "Size", "Size of the text");
+       RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1);
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+       prop = RNA_def_property(srna, "xpos", PROP_INT, PROP_NONE);
+       RNA_def_property_ui_text(prop, "X Position", "X position of the text");
+       RNA_def_property_ui_range(prop, -1000, 1000, 1, -1);
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+       prop = RNA_def_property(srna, "ypos", PROP_INT, PROP_NONE);
+       RNA_def_property_ui_text(prop, "Y Position", "Y position of the text");
+       RNA_def_property_ui_range(prop, -1000, 1000, 1, -1);
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+       prop = RNA_def_property(srna, "text", PROP_STRING, PROP_NONE);
+       RNA_def_property_ui_text(prop, "Text", "Text that will be displayed");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+       prop = RNA_def_property(srna, "use_shadow", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flags", TEXT_SEQ_SHADOW);
+       RNA_def_property_ui_text(prop, "Shadow", "draw text with shadow");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+       prop = RNA_def_property(srna, "use_autocenter", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flags", TEXT_SEQ_AUTO_CENTER);
+       RNA_def_property_ui_text(prop, "Auto-Center", "draw text centered in x axis");
+       RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+}
+
 static EffectInfo def_effects[] = {
        {"AddSequence", "Add Sequence", "Add Sequence", NULL, 2},
        {"AdjustmentSequence", "Adjustment Layer Sequence",
@@ -2326,6 +2365,8 @@ static EffectInfo def_effects[] = {
         rna_def_wipe, 1},
        {"GaussianBlurSequence", "Gaussian Blur Sequence", "Sequence strip creating a gaussian blur",
         rna_def_gaussian_blur, 1},
+       {"TextSequence", "Text Sequence", "Sequence strip creating text",
+        rna_def_text, 0},
        {"", "", "", NULL, 0}
 };
 
index 5e9866fa73e348d84a8ccffcb0e3ec2e071b079b..13fda02c7c84c040bc71121cb7a12277a75c7267 100644 (file)
@@ -474,6 +474,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
                {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
                {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
                {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
+               {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
                {0, NULL, 0, NULL, NULL}
        };