== Simple Title Cards for Sequencer ==

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).
This commit is contained in:
Joshua Leung 2011-06-16 02:46:38 +00:00
parent 4ef1e67ce8
commit cfcc4b4fcd
12 changed files with 215 additions and 7 deletions

@ -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

@ -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 */

@ -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)
{

@ -40,8 +40,11 @@
#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;

@ -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;

@ -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;
}
}

@ -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)

@ -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 */

@ -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);

@ -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

@ -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;

@ -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