== Simple Title Cards for Sequencer ==
authorJoshua Leung <aligorith@gmail.com>
Thu, 16 Jun 2011 02:46:38 +0000 (02:46 +0000)
committerJoshua Leung <aligorith@gmail.com>
Thu, 16 Jun 2011 02:46:38 +0000 (02:46 +0000)
This commit adds an experimental effect strip to the sequencer: "Title
Card".

This is useful for adding simple one-line text section headers or
"title cards" (i.e. title + author/contact details) to video clips,
which is often seen in demo videos accompanying papers and/or
animation tests.

See http://aligorith.blogspot.com/2011/06/gsoc11-simple-title-
cards.html for some more details on usage.

Code notes:
- There are a few things I've done here which will probably need
cleaning up. For instance, the hacks to get threadsafe fonts for
rendering, and also the way I've tried to piggyback the backdrop
drawing on top of the Solid Colour strips (this method was used to
keep changes here minimal, but is quite fragile if things change).

12 files changed:
release/scripts/startup/bl_ui/space_sequencer.py
source/blender/blenfont/BLF_api.h
source/blender/blenfont/intern/blf.c
source/blender/blenkernel/intern/seqeffects.c
source/blender/blenkernel/intern/sequencer.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/interface/interface_style.c
source/blender/editors/space_sequencer/sequencer_draw.c
source/blender/editors/space_sequencer/sequencer_edit.c
source/blender/makesdna/DNA_sequence_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_sequencer.c

index c477a2ff62baf15470c88e529d57644b8eb872dc..6a2f2f3a301eb9130df483aed513d77678af826d 100644 (file)
@@ -214,6 +214,7 @@ class SEQUENCER_MT_add_effect(bpy.types.Menu):
         layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED'
         layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM'
         layout.operator("sequencer.effect_strip_add", text="Adjustment Layer").type = 'ADJUSTMENT'
+        layout.operator("sequencer.effect_strip_add", text="Title Card").type = 'TITLE_CARD'
 
 
 class SEQUENCER_MT_strip(bpy.types.Menu):
@@ -392,7 +393,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel):
                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
                               'PLUGIN',
                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED',
-                              'MULTICAM', 'ADJUSTMENT'}
+                              'MULTICAM', 'ADJUSTMENT', 'TITLE_CARD'}
 
     def draw(self, context):
         layout = self.layout
@@ -460,6 +461,11 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel):
             row.label("Cut To")
             for i in range(1, strip.channel):
                 row.operator("sequencer.cut_multicam", text=str(i)).camera = i
+        elif strip.type == "TITLE_CARD":
+            layout.prop(strip, "title")
+            layout.prop(strip, "subtitle")
+            layout.prop(strip, "color_foreground")
+            layout.prop(strip, "color_background")
 
         col = layout.column(align=True)
         if strip.type == 'SPEED':
@@ -531,7 +537,8 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, bpy.types.Panel):
                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
                               'PLUGIN',
                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
-                              'MULTICAM', 'SPEED', 'ADJUSTMENT'}
+                              'MULTICAM', 'SPEED', 'ADJUSTMENT',
+                              'TITLE_CARD'}
 
     def draw(self, context):
         layout = self.layout
@@ -687,7 +694,8 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, bpy.types.Panel):
                               'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
                               'PLUGIN',
                               'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
-                              'MULTICAM', 'SPEED', 'ADJUSTMENT'}
+                              'MULTICAM', 'SPEED', 'ADJUSTMENT',
+                              'TITLE_CARD'}
 
     def draw(self, context):
         layout = self.layout
index 57f8c83eda61963661a2820cb9d2e7ecaa65b022..fba09ee9826f5b6cf081864b5156348836c527c7 100644 (file)
@@ -215,5 +215,6 @@ void BLF_dir_free(char **dirs, int count);
 // XXX, bad design
 extern int blf_mono_font;
 extern int blf_mono_font_render; // dont mess drawing with render threads.
+extern int blf_default_font_render; // dont mess drawing with render threads.
 
 #endif /* BLF_API_H */
index c0e62b1c0c70340d72bcf2b58efbebc2ecc8c33d..3bfb7c220822cfec75269ee7af7d5955d12db1b6 100644 (file)
@@ -74,6 +74,7 @@ static int global_font_dpi= 72;
 // XXX, should these be made into global_font_'s too?
 int blf_mono_font= -1;
 int blf_mono_font_render= -1;
+int blf_default_font_render= -1;
 
 static FontBLF *BLF_get(int fontid)
 {
index fbb5a77fa0409bd013de4b6d2c754f8ff6501e3a..688fdd8ff49337d823bd4a8099d9729b750c1413 100644 (file)
 #include "BLI_dynlib.h"
 
 #include "BLI_math.h" /* windows needs for M_PI */
+#include "BLI_string.h"
 #include "BLI_utildefines.h"
 
+#include "BLF_api.h"
+
 #include "DNA_scene_types.h"
 #include "DNA_sequence_types.h"
 #include "DNA_anim_types.h"
@@ -2804,6 +2807,130 @@ static struct ImBuf * do_solid_color(
        return out;
 }
 
+/* **********************************************************************
+   TITLE CARD
+   ********************************************************************** */
+
+static void init_title_card(Sequence *seq)
+{
+       TitleCardVars *tv;
+       
+       if(seq->effectdata)MEM_freeN(seq->effectdata);
+       seq->effectdata = MEM_callocN(sizeof(struct TitleCardVars), "titlecard");
+       
+       tv = (TitleCardVars *)seq->effectdata;
+       
+       BLI_strncpy(tv->titlestr, "Title goes here", sizeof(tv->titlestr));
+       tv->fgcol[0] = tv->fgcol[1] = tv->fgcol[2] = 1.0f; /* white */
+}
+
+static int num_inputs_titlecard(void)
+{
+       return 0;
+}
+
+static void free_title_card(Sequence *seq)
+{
+       if(seq->effectdata)MEM_freeN(seq->effectdata);
+       seq->effectdata = NULL;
+}
+
+static void copy_title_card(Sequence *dst, Sequence *src)
+{
+       dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static int early_out_titlecard(struct Sequence *UNUSED(seq),
+                          float UNUSED(facf0), float UNUSED(facf1))
+{
+       return -1;
+}
+
+static struct ImBuf * do_title_card(
+       SeqRenderData context, Sequence *seq, float cfra,
+       float facf0, float facf1, 
+       struct ImBuf *ibuf1, struct ImBuf *ibuf2, 
+       struct ImBuf *ibuf3)
+{      
+       TitleCardVars *tv = (TitleCardVars *)seq->effectdata;
+       
+       SolidColorVars cv = {{0}};
+       struct ImBuf *out;
+       
+       int titleFontId = blf_default_font_render; // XXX: bad design!
+       
+       int width = context.rectx;
+       int height = context.recty;
+       float w, h;
+       int x, y;
+       
+       /* use fake solid-color vars to get backdrop (and an out buffer at the same time) */
+       VECCOPY(cv.col, tv->bgcol);
+       seq->effectdata = &cv;
+       
+       out = do_solid_color(context, seq, cfra,
+                       facf0, facf1,
+                       ibuf1, ibuf2, ibuf3);
+                       
+       seq->effectdata = tv;
+       
+       /* draw text */
+       /* FIXME: imbuf out->rect is unsigned int NOT unsigned char, but without passing this pointer
+        * this drawing code doesn't work. This cast really masks some potential bugs though...
+        */
+       BLF_buffer(titleFontId, out->rect_float, (unsigned char *)out->rect, width, height, 4);
+       
+       if (tv->titlestr[0]) {
+               /* automatic scale - these formulae have been derived experimentally:
+                *      - base size is based on 40pt at 960 width
+                *      - each 26 characters, size jumps down one step, 
+                *        but this decrease needs to be exponential to fit everything
+                */
+               float lfac = strlen(tv->titlestr) / 26.0f;
+               float size = (width * 0.06f) * (1.0f - 0.1f*lfac*lfac);
+               
+               BLF_size(titleFontId, size, 72);
+               BLF_buffer_col(titleFontId, tv->fgcol[0], tv->fgcol[1], tv->fgcol[2], 1.0);
+               
+               BLF_width_and_height(titleFontId, tv->titlestr, &w, &h);
+               x = width/2.0f - w/2.0f;
+               if (tv->subtitle[0])
+                       y = height/2.0f + h;
+               else
+                       y = height/2.0f;
+               
+               BLF_position(titleFontId, x, y, 0.0);
+               BLF_draw_buffer(titleFontId, tv->titlestr);
+       }
+       
+       if (tv->subtitle[0]) {
+               /* automatic scale - these formulae have been derived experimentally (as above):
+                *      - base size is based on 20pt at 960 width
+                *      - size steps aren't quite as refined here. Need a slower-growing curve!
+                */
+               float lfac = strlen(tv->subtitle) / 36.0f;
+               float size = (width * 0.03f) * (1.0f - 0.1f*lfac*lfac*log(lfac));
+               
+               BLF_size(titleFontId, size, 72);
+               BLF_buffer_col(titleFontId, tv->fgcol[0], tv->fgcol[1], tv->fgcol[2], 1.0);
+               
+               BLF_width_and_height(titleFontId, tv->subtitle, &w, &h);
+               x = width/2.0f - w/2.0f;
+               if (tv->titlestr[0])
+                       y = height/2.0f - h;
+               else
+                       y = height/2.0f;
+               
+               BLF_position(titleFontId, x, y, 0.0);
+               BLF_draw_buffer(titleFontId, tv->subtitle);
+       }
+       
+       /* cleanup the buffer. */
+       BLF_buffer(UIFONT_DEFAULT, NULL, NULL, 0, 0, 0);
+       
+       return out;
+}
+
 /* **********************************************************************
    MULTICAM
    ********************************************************************** */
@@ -3343,6 +3470,14 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
                rval.early_out = early_out_adjustment;
                rval.execute = do_adjustment;
                break;
+       case SEQ_TITLECARD:
+               rval.init = init_title_card;
+               rval.num_inputs = num_inputs_titlecard;
+               rval.early_out = early_out_titlecard;
+               rval.free = free_title_card;
+               rval.copy = copy_title_card;
+               rval.execute = do_title_card;
+               break;
        }
 
        return rval;
index b82ac69fc9e068166411a0932990fafcc1c15300..550b81e8a0f498af4af683375efcbccab1b6e696 100644 (file)
@@ -895,6 +895,7 @@ static const char *give_seqname_by_type(int type)
        case SEQ_MULTICAM:   return "Multicam";
        case SEQ_ADJUSTMENT: return "Adjustment";
        case SEQ_SPEED:      return "Speed";
+       case SEQ_TITLECARD:  return "Title Card";
        default:
                return NULL;
        }
@@ -3020,7 +3021,7 @@ Sequence *seq_foreground_frame_get(Scene *scene, int frame)
                if(seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame)
                        continue;
                /* only use elements you can see - not */
-               if (ELEM5(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_COLOR)) {
+               if (ELEM6(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_COLOR, SEQ_TITLECARD)) {
                        if (seq->machine > best_machine) {
                                best_seq = seq;
                                best_machine = seq->machine;
index 240e8d00ab8d1b825652c9c850fba57248f9b4e9..fb5c96cd85491a60fc5e99857bc3ae421bc92501 100644 (file)
@@ -1892,6 +1892,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                                                case SEQ_TRANSFORM:
                                                        writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
                                                        break;
+                                               case SEQ_TITLECARD:
+                                                       writestruct(wd, DATA, "TitleCardVars", 1, seq->effectdata);
+                                                       break;
                                                }
                                        }
                                        
index 2e4106b3c046d3b92a23b39f3e49e5484531d471..1352648b271ce4662c80b56b2ee072fc942c24cb 100644 (file)
@@ -295,6 +295,7 @@ void uiStyleInit(void)
 {
        uiFont *font= U.uifonts.first;
        uiStyle *style= U.uistyles.first;
+       int defaultFontId = -1;
        
        /* recover from uninitialized dpi */
        if(U.dpi == 0)
@@ -314,6 +315,7 @@ void uiStyleInit(void)
                
                if(font->uifont_id==UIFONT_DEFAULT) {
                        font->blf_id= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
+                       defaultFontId = font->blf_id;
                }               
                else {
                        font->blf_id= BLF_load(font->filename);
@@ -351,6 +353,14 @@ void uiStyleInit(void)
                blf_mono_font_render= BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
 
        BLF_size(blf_mono_font_render, 12, 72);
+       
+       /* also another copy of default for rendering else we get threading problems */
+       if (defaultFontId != -1) {
+               if (blf_default_font_render == -1)
+                       blf_default_font_render= BLF_load_mem_unique("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
+                       
+               BLF_size(blf_default_font_render, 12, 72);
+       }
 }
 
 void uiStyleFontSet(uiFontStyle *fs)
index 119c5da309ee892e43100814017f9227566292c4..e1efd5b4622835498627083945c9cc2f3ad1ae7e 100644 (file)
@@ -127,6 +127,7 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[
        case SEQ_GLOW:
        case SEQ_MULTICAM:
        case SEQ_ADJUSTMENT:
+       case SEQ_TITLECARD:
                UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col);
                
                /* slightly offset hue to distinguish different effects */
index c8965c4d3db96ececbd552e7e4c546f7eb91a5ab..46638007fb1d038f72d9c7a04c3f6c9158eeba8b 100644 (file)
@@ -98,9 +98,10 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
        {SEQ_GLOW, "GLOW", 0, "Glow", "Glow effect strip type"},
        {SEQ_TRANSFORM, "TRANSFORM", 0, "Transform", "Transform effect strip type"},
        {SEQ_COLOR, "COLOR", 0, "Color", "Color effect strip type"},
-       {SEQ_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
+       {SEQ_SPEED, "SPEED", 0, "Speed", ""},
        {SEQ_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
        {SEQ_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
+       {SEQ_TITLECARD, "TITLE_CARD", 0, "Title Card", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
@@ -408,6 +409,7 @@ int event_to_efftype(int event)
        if(event==16) return SEQ_COLOR;
        if(event==17) return SEQ_SPEED;
        if(event==18) return SEQ_ADJUSTMENT;
+       if(event==19) return SEQ_TITLECARD;
        return 0;
 }
 
@@ -520,7 +522,8 @@ static void change_sequence(Scene *scene)
                                "|Transform%x15"
                                "|Color Generator%x16"
                                "|Speed Control%x17"
-                               "|Adjustment Layer%x18");
+                               "|Adjustment Layer%x18"
+                               "|Title Card%x19");
                if(event > 0) {
                        if(event==1) {
                                SWAP(Sequence *,last_seq->seq1,last_seq->seq2);
index 3e7654bcf47d000eda88493ea273eb3a447a74c5..b9bea7a89b03f43afbd1e5225fe2b85129b9f65d 100644 (file)
@@ -227,6 +227,14 @@ typedef struct SolidColorVars {
        float pad;
 } SolidColorVars;
 
+typedef struct TitleCardVars {
+       char titlestr[64];
+       char subtitle[128];
+       
+       float fgcol[3];
+       float bgcol[3];
+} TitleCardVars;
+
 typedef struct SpeedControlVars {
        float * frameMap;
        float globalSpeed;
@@ -314,7 +322,8 @@ typedef struct SpeedControlVars {
 #define SEQ_SPEED               29
 #define SEQ_MULTICAM            30
 #define SEQ_ADJUSTMENT          31
-#define SEQ_EFFECT_MAX          31
+#define SEQ_TITLECARD                  40
+#define SEQ_EFFECT_MAX          40
 
 #define STRIPELEM_FAILED       0
 #define STRIPELEM_OK           1
index ca19a86e42cd231c16d51542d6d5470a6df254a4..d1883b776975340175a352626a1e21947a5ff5bd 100644 (file)
@@ -534,6 +534,7 @@ extern StructRNA RNA_ThemeWidgetColors;
 extern StructRNA RNA_ThemeWidgetStateColors;
 extern StructRNA RNA_TimelineMarker;
 extern StructRNA RNA_Timer;
+extern StructRNA RNA_TitleCardSequence;
 extern StructRNA RNA_ToolSettings;
 extern StructRNA RNA_TouchSensor;
 extern StructRNA RNA_TrackToConstraint;
index 8c4e4d9e736aa7af32c20da702f0a06b8b901ffc..eb2d38e97780e51d18f6acf8d81a98be34fe2210 100644 (file)
@@ -418,6 +418,8 @@ static StructRNA* rna_Sequence_refine(struct PointerRNA *ptr)
                        return &RNA_ColorSequence;
                case SEQ_SPEED:
                        return &RNA_SpeedControlSequence;
+               case SEQ_TITLECARD:
+                       return &RNA_TitleCardSequence;
                default:
                        return &RNA_Sequence;
        }
@@ -886,6 +888,7 @@ static void rna_def_sequence(BlenderRNA *brna)
                {SEQ_SPEED, "SPEED", 0, "Speed", ""}, 
                {SEQ_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
                {SEQ_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
+               {SEQ_TITLECARD, "TITLE_CARD", 0, "Title Card", ""},
                {0, NULL, 0, NULL, NULL}};
 
        static const EnumPropertyItem blend_mode_items[]= {
@@ -1666,6 +1669,37 @@ static void rna_def_speed_control(BlenderRNA *brna)
        RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
 }
 
+static void rna_def_title_card(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+
+       srna = RNA_def_struct(brna, "TitleCardSequence", "EffectSequence");
+       RNA_def_struct_ui_text(srna, "Title Card Sequence", "Sequence strip creating an image displaying some text on a plain color background");
+       RNA_def_struct_sdna_from(srna, "TitleCardVars", "effectdata");
+       
+       /* texts */
+       prop= RNA_def_property(srna, "title", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "titlestr");
+       RNA_def_property_ui_text(prop, "Title", "Text for main heading");
+       RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
+       
+       prop= RNA_def_property(srna, "subtitle", PROP_STRING, PROP_NONE);
+       RNA_def_property_ui_text(prop, "Subtitle", "Additional text to be shown under the main heading");
+       RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
+       
+       /* colors */
+       prop= RNA_def_property(srna, "color_background", PROP_FLOAT, PROP_COLOR);
+       RNA_def_property_float_sdna(prop, NULL, "bgcol");
+       RNA_def_property_ui_text(prop, "Background Color", "");
+       RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
+       
+       prop= RNA_def_property(srna, "color_foreground", PROP_FLOAT, PROP_COLOR);
+       RNA_def_property_float_sdna(prop, NULL, "fgcol");
+       RNA_def_property_ui_text(prop, "Text Color", "");
+       RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
+}
+
 void RNA_def_sequencer(BlenderRNA *brna)
 {
        rna_def_strip_element(brna);
@@ -1691,6 +1725,7 @@ void RNA_def_sequencer(BlenderRNA *brna)
        rna_def_transform(brna);
        rna_def_solid_color(brna);
        rna_def_speed_control(brna);
+       rna_def_title_card(brna);
 }
 
 #endif