From 03fc5696dc154259dea599b805c94c82b58e70b6 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Mon, 12 Jan 2009 19:02:08 +0000 Subject: 2.5 12k lines of sequencer back! Only seqaudio.c skipped for now. Notes: - it only draws now, nothing refreshes or edits. - fixed bug in view2d.c with vertical grid step being 0.0f - render code and fileselect code is #ifdeffed out - sequence evaluation code moved to blenkernel, so it can be used for render without bad level calls General note; sequencer code is very untidy, mixing styles too much. Tried to clean it some, but it would be nice if formatting is kept consistant from now on. --- source/blender/blenkernel/BKE_sequence.h | 111 +- source/blender/blenkernel/intern/seqeffects.c | 3145 +++++++++++++++ source/blender/blenkernel/intern/sequence.c | 2845 +++++++++++++- source/blender/blenlib/intern/bpath.c | 2 +- source/blender/editors/interface/view2d.c | 8 +- source/blender/editors/space_sequencer/Makefile | 2 + source/blender/editors/space_sequencer/SConscript | 1 + source/blender/editors/space_sequencer/editseq.c | 3985 ++++++++++++++++++++ .../editors/space_sequencer/sequencer_draw.c | 1135 ++++++ .../editors/space_sequencer/sequencer_intern.h | 28 +- .../editors/space_sequencer/sequencer_scopes.c | 701 ++++ .../editors/space_sequencer/space_sequencer.c | 27 +- 12 files changed, 11940 insertions(+), 50 deletions(-) create mode 100644 source/blender/blenkernel/intern/seqeffects.c create mode 100644 source/blender/editors/space_sequencer/editseq.c create mode 100644 source/blender/editors/space_sequencer/sequencer_draw.c create mode 100644 source/blender/editors/space_sequencer/sequencer_scopes.c diff --git a/source/blender/blenkernel/BKE_sequence.h b/source/blender/blenkernel/BKE_sequence.h index 2c4daf7fce5..bd56b100fc0 100644 --- a/source/blender/blenkernel/BKE_sequence.h +++ b/source/blender/blenkernel/BKE_sequence.h @@ -33,11 +33,17 @@ struct Editing; struct Sequence; +struct Strip; +struct StripElem; +struct ImBuf; +struct Scene; -/* free */ +#define MAXSEQ 32 + +#define BUILD_SEQAR_COUNT_NOTHING 0 +#define BUILD_SEQAR_COUNT_CURRENT 1 +#define BUILD_SEQAR_COUNT_CHILDREN 2 -void seq_free_sequence(struct Sequence *seq); -void seq_free_editing(struct Editing *ed); /* sequence iterator */ @@ -49,16 +55,21 @@ typedef struct SeqIterator { int valid; } SeqIterator; -void seq_begin(struct Editing *ed, SeqIterator *iter); +void seq_begin(struct Editing *ed, SeqIterator *iter, int use_pointer); void seq_next(SeqIterator *iter); void seq_end(SeqIterator *iter); +void seq_array(struct Editing *ed, struct Sequence ***seqarray, int *tot, int use_pointer); -void seq_array(struct Editing *ed, struct Sequence ***array, int *tot); - +#define SEQP_BEGIN(ed, seq) \ +{ \ + SeqIterator iter;\ + for(seq_begin(ed, &iter, 1); iter.valid; seq_next(&iter)) { \ + seq= iter.seq; + #define SEQ_BEGIN(ed, seq) \ { \ SeqIterator iter;\ - for(seq_begin(ed, &iter); iter.valid; seq_next(&iter)) { \ + for(seq_begin(ed, &iter, 0); iter.valid; seq_next(&iter)) { \ seq= iter.seq; #define SEQ_END \ @@ -68,3 +79,89 @@ void seq_array(struct Editing *ed, struct Sequence ***array, int *tot); #endif + +/* Wipe effect */ +enum {DO_SINGLE_WIPE, DO_DOUBLE_WIPE, DO_BOX_WIPE, DO_CROSS_WIPE, + DO_IRIS_WIPE,DO_CLOCK_WIPE}; + + +struct SeqEffectHandle { + /* constructors & destructor */ + /* init & init_plugin are _only_ called on first creation */ + void (*init)(struct Sequence *seq); + void (*init_plugin)(struct Sequence *seq, const char *fname); + + /* number of input strips needed + (called directly after construction) */ + int (*num_inputs)(); + + /* load is called first time after readblenfile in + get_sequence_effect automatically */ + void (*load)(struct Sequence *seq); + + /* duplicate */ + void (*copy)(struct Sequence *dst, struct Sequence *src); + + /* destruct */ + void (*free)(struct Sequence *seq); + + /* returns: -1: no input needed, + 0: no early out, + 1: out = ibuf1, + 2: out = ibuf2 */ + int (*early_out)(struct Sequence *seq, + float facf0, float facf1); + + /* stores the y-range of the effect IPO */ + void (*store_icu_yrange)(struct Sequence * seq, + short adrcode, float *ymin, float *ymax); + + /* stores the default facf0 and facf1 if no IPO is present */ + void (*get_default_fac)(struct Sequence *seq, int cfra, + float * facf0, float * facf1); + + /* execute the effect + sequence effects are only required to either support + float-rects or byte-rects + (mixed cases are handled one layer up...) */ + + void (*execute)(struct Sequence *seq, int cfra, + float facf0, float facf1, + int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out); +}; + +/* ********************* prototypes *************** */ + +/* sequence.c */ + +// extern +void seq_free_sequence(struct Sequence *seq); +void seq_free_strip(struct Strip *strip); +void seq_free_editing(struct Editing *ed); +char *give_seqname(struct Sequence *seq); +struct ImBuf *give_ibuf_seq(struct Scene *scene, int rectx, int recty, int cfra, int chanshown); +struct ImBuf *give_ibuf_seq_threaded(struct Scene *scene, int rectx, int recty, int cfra, int chanshown); +struct ImBuf *give_ibuf_seq_direct(struct Scene *scene, int rectx, int recty, int cfra, struct Sequence *seq); +void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown); +void calc_sequence(struct Sequence *seq); +void new_tstripdata(struct Sequence *seq); +void reload_sequence_new_file(struct Scene *scene, struct Sequence * seq); +void sort_seq(struct Scene *scene); +void build_seqar_cb(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq, + int (*test_func)(struct Sequence * seq)); +int evaluate_seq_frame(struct Scene *scene, int cfra); +struct StripElem *give_stripelem(struct Sequence *seq, int cfra); + +// intern? +void update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change); + +/* seqeffects.c */ +// intern? +struct SeqEffectHandle get_sequence_blend(struct Sequence *seq); +void sequence_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, int force); + +// extern +struct SeqEffectHandle get_sequence_effect(struct Sequence *seq); +int get_sequence_effect_num_inputs(int seq_type); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c new file mode 100644 index 00000000000..9036156d6b6 --- /dev/null +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -0,0 +1,3145 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): + * - Blender Foundation, 2003-2009 + * - Peter Schlaile 2005/2006 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" +#include "PIL_dynlib.h" + +#include "DNA_scene_types.h" +#include "DNA_sequence_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_global.h" +#include "BKE_ipo.h" +#include "BKE_plugin_types.h" +#include "BKE_sequence.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +/* **** XXX **** */ +static void error() {} + +#define INT 96 +#define FLO 128 + +/* **** XXX **** */ + +/* Glow effect */ +enum { + GlowR=0, + GlowG=1, + GlowB=2, + GlowA=3 +}; + + +/* ********************************************************************** + PLUGINS + ********************************************************************** */ + +static void open_plugin_seq(PluginSeq *pis, const char *seqname) +{ + int (*version)(); + void* (*alloc_private)(); + char *cp; + + /* to be sure: (is tested for) */ + pis->doit= 0; + pis->pname= 0; + pis->varstr= 0; + pis->cfra= 0; + pis->version= 0; + pis->instance_private_data = 0; + + /* clear the error list */ + PIL_dynlib_get_error_as_string(NULL); + + /* if(pis->handle) PIL_dynlib_close(pis->handle); */ + /* pis->handle= 0; */ + + /* open the needed object */ + pis->handle= PIL_dynlib_open(pis->name); + if(test_dlerr(pis->name, pis->name)) return; + + if (pis->handle != 0) { + /* find the address of the version function */ + version= (int (*)())PIL_dynlib_find_symbol(pis->handle, "plugin_seq_getversion"); + if (test_dlerr(pis->name, "plugin_seq_getversion")) return; + + if (version != 0) { + pis->version= version(); + if (pis->version >= 2 && pis->version <= 6) { + int (*info_func)(PluginInfo *); + PluginInfo *info= (PluginInfo*) MEM_mallocN(sizeof(PluginInfo), "plugin_info"); + + info_func= (int (*)(PluginInfo *))PIL_dynlib_find_symbol(pis->handle, "plugin_getinfo"); + + if(info_func == NULL) error("No info func"); + else { + info_func(info); + + pis->pname= info->name; + pis->vars= info->nvars; + pis->cfra= info->cfra; + + pis->varstr= info->varstr; + + pis->doit= (void(*)(void))info->seq_doit; + if (info->init) + info->init(); + } + MEM_freeN(info); + + cp= PIL_dynlib_find_symbol(pis->handle, "seqname"); + if(cp) strncpy(cp, seqname, 21); + } else { + printf ("Plugin returned unrecognized version number\n"); + return; + } + } + alloc_private = (void* (*)())PIL_dynlib_find_symbol( + pis->handle, "plugin_seq_alloc_private_data"); + if (alloc_private) { + pis->instance_private_data = alloc_private(); + } + + pis->current_private_data = (void**) + PIL_dynlib_find_symbol( + pis->handle, "plugin_private_data"); + } +} + +static PluginSeq *add_plugin_seq(const char *str, const char *seqname) +{ + PluginSeq *pis; + VarStruct *varstr; + int a; + + pis= MEM_callocN(sizeof(PluginSeq), "PluginSeq"); + + strncpy(pis->name, str, FILE_MAXDIR+FILE_MAXFILE); + open_plugin_seq(pis, seqname); + + if(pis->doit==0) { + if(pis->handle==0) error("no plugin: %s", str); + else error("in plugin: %s", str); + MEM_freeN(pis); + return 0; + } + + /* default values */ + varstr= pis->varstr; + for(a=0; avars; a++, varstr++) { + if( (varstr->type & FLO)==FLO) + pis->data[a]= varstr->def; + else if( (varstr->type & INT)==INT) + *((int *)(pis->data+a))= (int) varstr->def; + } + + return pis; +} + +static void free_plugin_seq(PluginSeq *pis) +{ + if(pis==0) return; + + /* no PIL_dynlib_close: same plugin can be opened multiple times with 1 handle */ + + if (pis->instance_private_data) { + void (*free_private)(void *); + + free_private = (void (*)(void *))PIL_dynlib_find_symbol( + pis->handle, "plugin_seq_free_private_data"); + if (free_private) { + free_private(pis->instance_private_data); + } + } + + MEM_freeN(pis); +} + +static void init_plugin(Sequence * seq, const char * fname) +{ + seq->plugin= (PluginSeq *)add_plugin_seq(fname, seq->name+2); +} + +/* + * FIXME: should query plugin! Could be generator, that needs zero inputs... + */ +static int num_inputs_plugin() +{ + return 1; +} + +static void load_plugin(Sequence * seq) +{ + if (seq) { + open_plugin_seq(seq->plugin, seq->name+2); + } +} + +static void copy_plugin(Sequence * dst, Sequence * src) +{ + if(src->plugin) { + dst->plugin= MEM_dupallocN(src->plugin); + open_plugin_seq(dst->plugin, dst->name+2); + } +} + +static ImBuf * IMB_cast_away_list(ImBuf * i) +{ + if (!i) { + return 0; + } + return (ImBuf*) (((void**) i) + 2); +} + +static void do_plugin_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + char *cp; + int float_rendering; + int use_temp_bufs = 0; /* Are needed since blur.c (and maybe some other + old plugins) do very bad stuff + with imbuf-internals */ + + if(seq->plugin && seq->plugin->doit) { + + if(seq->plugin->cfra) + *(seq->plugin->cfra)= cfra; +// XXX *(seq->plugin->cfra)= frame_to_float(scene, cfra); + + cp = PIL_dynlib_find_symbol( + seq->plugin->handle, "seqname"); + + if(cp) strncpy(cp, seq->name+2, 22); + + if (seq->plugin->current_private_data) { + *seq->plugin->current_private_data + = seq->plugin->instance_private_data; + } + + float_rendering = (out->rect_float != NULL); + + if (seq->plugin->version<=3 && float_rendering) { + use_temp_bufs = 1; + + if (ibuf1) { + ibuf1 = IMB_dupImBuf(ibuf1); + IMB_rect_from_float(ibuf1); + imb_freerectfloatImBuf(ibuf1); + ibuf1->flags &= ~IB_rectfloat; + } + if (ibuf2) { + ibuf2 = IMB_dupImBuf(ibuf2); + IMB_rect_from_float(ibuf2); + imb_freerectfloatImBuf(ibuf2); + ibuf2->flags &= ~IB_rectfloat; + } + if (ibuf3) { + ibuf3 = IMB_dupImBuf(ibuf3); + IMB_rect_from_float(ibuf3); + imb_freerectfloatImBuf(ibuf3); + ibuf3->flags &= ~IB_rectfloat; + } + if (!out->rect) imb_addrectImBuf(out); + imb_freerectfloatImBuf(out); + out->flags &= ~IB_rectfloat; + } + + if (seq->plugin->version<=2) { + if(ibuf1) IMB_convert_rgba_to_abgr(ibuf1); + if(ibuf2) IMB_convert_rgba_to_abgr(ibuf2); + if(ibuf3) IMB_convert_rgba_to_abgr(ibuf3); + } + + if (seq->plugin->version<=4) { + ((SeqDoit)seq->plugin->doit)( + seq->plugin->data, facf0, facf1, x, y, + IMB_cast_away_list(ibuf1), + IMB_cast_away_list(ibuf2), + IMB_cast_away_list(out), + IMB_cast_away_list(ibuf3)); + } else { + ((SeqDoit)seq->plugin->doit)( + seq->plugin->data, facf0, facf1, x, y, + ibuf1, ibuf2, out, ibuf3); + } + + if (seq->plugin->version<=2) { + if (!use_temp_bufs) { + if(ibuf1) IMB_convert_rgba_to_abgr(ibuf1); + if(ibuf2) IMB_convert_rgba_to_abgr(ibuf2); + if(ibuf3) IMB_convert_rgba_to_abgr(ibuf3); + } + IMB_convert_rgba_to_abgr(out); + } + if (seq->plugin->version<=3 && float_rendering) { + IMB_float_from_rect(out); + } + + if (use_temp_bufs) { + if (ibuf1) IMB_freeImBuf(ibuf1); + if (ibuf2) IMB_freeImBuf(ibuf2); + if (ibuf3) IMB_freeImBuf(ibuf3); + } + } +} + +static int do_plugin_early_out(struct Sequence *seq, + float facf0, float facf1) +{ + return 0; +} + +static void free_plugin(struct Sequence * seq) +{ + free_plugin_seq(seq->plugin); + seq->plugin = 0; +} + +/* ********************************************************************** + ALPHA OVER + ********************************************************************** */ + +static void init_alpha_over_or_under(Sequence * seq) +{ + Sequence * seq1 = seq->seq1; + Sequence * seq2 = seq->seq2; + + seq->seq2= seq1; + seq->seq1= seq2; +} + +static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, + char * rect1, char *rect2, char *out) +{ + int fac2, mfac, fac, fac4; + int xo, tempc; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac2= (int)(256.0*facf0); + fac4= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 over rt2 (alpha from rt1) */ + + fac= fac2; + mfac= 256 - ( (fac2*rt1[3])>>8 ); + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else if(mfac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else { + tempc= ( fac*rt1[0] + mfac*rt2[0])>>8; + if(tempc>255) rt[0]= 255; else rt[0]= tempc; + tempc= ( fac*rt1[1] + mfac*rt2[1])>>8; + if(tempc>255) rt[1]= 255; else rt[1]= tempc; + tempc= ( fac*rt1[2] + mfac*rt2[2])>>8; + if(tempc>255) rt[2]= 255; else rt[2]= tempc; + tempc= ( fac*rt1[3] + mfac*rt2[3])>>8; + if(tempc>255) rt[3]= 255; else rt[3]= tempc; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + fac= fac4; + mfac= 256 - ( (fac4*rt1[3])>>8 ); + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else if(mfac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else { + tempc= ( fac*rt1[0] + mfac*rt2[0])>>8; + if(tempc>255) rt[0]= 255; else rt[0]= tempc; + tempc= ( fac*rt1[1] + mfac*rt2[1])>>8; + if(tempc>255) rt[1]= 255; else rt[1]= tempc; + tempc= ( fac*rt1[2] + mfac*rt2[2])>>8; + if(tempc>255) rt[2]= 255; else rt[2]= tempc; + tempc= ( fac*rt1[3] + mfac*rt2[3])>>8; + if(tempc>255) rt[3]= 255; else rt[3]= tempc; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_alphaover_effect_float(float facf0, float facf1, int x, int y, + float * rect1, float *rect2, float *out) +{ + float fac2, mfac, fac, fac4; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac4= facf1; + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 over rt2 (alpha from rt1) */ + + fac= fac2; + mfac= 1.0 - (fac2*rt1[3]) ; + + if(fac <= 0.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else if(mfac <=0) { + memcpy(rt, rt1, 4 * sizeof(float)); + } else { + rt[0] = fac*rt1[0] + mfac*rt2[0]; + rt[1] = fac*rt1[1] + mfac*rt2[1]; + rt[2] = fac*rt1[2] + mfac*rt2[2]; + rt[3] = fac*rt1[3] + mfac*rt2[3]; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + fac= fac4; + mfac= 1.0 - (fac4*rt1[3]); + + if(fac <= 0.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else if(mfac <= 0.0) { + memcpy(rt, rt1, 4 * sizeof(float)); + } else { + rt[0] = fac*rt1[0] + mfac*rt2[0]; + rt[1] = fac*rt1[1] + mfac*rt2[1]; + rt[2] = fac*rt1[2] + mfac*rt2[2]; + rt[3] = fac*rt1[3] + mfac*rt2[3]; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_alphaover_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_alphaover_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_alphaover_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + + +/* ********************************************************************** + ALPHA UNDER + ********************************************************************** */ + +void do_alphaunder_effect_byte( + float facf0, float facf1, int x, int y, char *rect1, + char *rect2, char *out) +{ + int fac2, mfac, fac, fac4; + int xo; + char *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= (int)(256.0*facf0); + fac4= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 under rt2 (alpha from rt2) */ + + /* this complex optimalisation is because the + * 'skybuf' can be crossed in + */ + if(rt2[3]==0 && fac2==256) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else if(rt2[3]==255) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + mfac= rt2[3]; + fac= (fac2*(256-mfac))>>8; + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + rt[0]= ( fac*rt1[0] + mfac*rt2[0])>>8; + rt[1]= ( fac*rt1[1] + mfac*rt2[1])>>8; + rt[2]= ( fac*rt1[2] + mfac*rt2[2])>>8; + rt[3]= ( fac*rt1[3] + mfac*rt2[3])>>8; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + if(rt2[3]==0 && fac4==256) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else if(rt2[3]==255) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + mfac= rt2[3]; + fac= (fac4*(256-mfac))>>8; + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + rt[0]= ( fac*rt1[0] + mfac*rt2[0])>>8; + rt[1]= ( fac*rt1[1] + mfac*rt2[1])>>8; + rt[2]= ( fac*rt1[2] + mfac*rt2[2])>>8; + rt[3]= ( fac*rt1[3] + mfac*rt2[3])>>8; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + + +static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + float fac2, mfac, fac, fac4; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac4= facf1; + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 under rt2 (alpha from rt2) */ + + /* this complex optimalisation is because the + * 'skybuf' can be crossed in + */ + if( rt2[3]<=0 && fac2>=1.0) { + memcpy(rt, rt1, 4 * sizeof(float)); + } else if(rt2[3]>=1.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + mfac = rt2[3]; + fac = fac2 * (1.0 - mfac); + + if(fac == 0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + rt[0]= fac*rt1[0] + mfac*rt2[0]; + rt[1]= fac*rt1[1] + mfac*rt2[1]; + rt[2]= fac*rt1[2] + mfac*rt2[2]; + rt[3]= fac*rt1[3] + mfac*rt2[3]; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + if(rt2[3]<=0 && fac4 >= 1.0) { + memcpy(rt, rt1, 4 * sizeof(float)); + + } else if(rt2[3]>=1.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + mfac= rt2[3]; + fac= fac4*(1.0-mfac); + + if(fac == 0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + rt[0]= fac * rt1[0] + mfac * rt2[0]; + rt[1]= fac * rt1[1] + mfac * rt2[1]; + rt[2]= fac * rt1[2] + mfac * rt2[2]; + rt[3]= fac * rt1[3] + mfac * rt2[3]; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_alphaunder_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_alphaunder_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_alphaunder_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + + +/* ********************************************************************** + CROSS + ********************************************************************** */ + +void do_cross_effect_byte(float facf0, float facf1, int x, int y, + char *rect1, char *rect2, + char *out) +{ + int fac1, fac2, fac3, fac4; + int xo; + char *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= (int)(256.0*facf0); + fac1= 256-fac2; + fac4= (int)(256.0*facf1); + fac3= 256-fac4; + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= (fac1*rt1[0] + fac2*rt2[0])>>8; + rt[1]= (fac1*rt1[1] + fac2*rt2[1])>>8; + rt[2]= (fac1*rt1[2] + fac2*rt2[2])>>8; + rt[3]= (fac1*rt1[3] + fac2*rt2[3])>>8; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= (fac3*rt1[0] + fac4*rt2[0])>>8; + rt[1]= (fac3*rt1[1] + fac4*rt2[1])>>8; + rt[2]= (fac3*rt1[2] + fac4*rt2[2])>>8; + rt[3]= (fac3*rt1[3] + fac4*rt2[3])>>8; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + } +} + +void do_cross_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, float *out) +{ + float fac1, fac2, fac3, fac4; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac1= 1.0 - fac2; + fac4= facf1; + fac3= 1.0 - fac4; + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= fac1*rt1[0] + fac2*rt2[0]; + rt[1]= fac1*rt1[1] + fac2*rt2[1]; + rt[2]= fac1*rt1[2] + fac2*rt2[2]; + rt[3]= fac1*rt1[3] + fac2*rt2[3]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= fac3*rt1[0] + fac4*rt2[0]; + rt[1]= fac3*rt1[1] + fac4*rt2[1]; + rt[2]= fac3*rt1[2] + fac4*rt2[2]; + rt[3]= fac3*rt1[3] + fac4*rt2[3]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + } +} + +/* carefull: also used by speed effect! */ + +static void do_cross_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_cross_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_cross_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + + +/* ********************************************************************** + GAMMA CROSS + ********************************************************************** */ + +/* copied code from initrender.c */ +static unsigned short gamtab[65536]; +static unsigned short igamtab1[256]; +static int gamma_tabs_init = FALSE; + +#define RE_GAMMA_TABLE_SIZE 400 + +static float gamma_range_table[RE_GAMMA_TABLE_SIZE + 1]; +static float gamfactor_table[RE_GAMMA_TABLE_SIZE]; +static float inv_gamma_range_table[RE_GAMMA_TABLE_SIZE + 1]; +static float inv_gamfactor_table[RE_GAMMA_TABLE_SIZE]; +static float color_domain_table[RE_GAMMA_TABLE_SIZE + 1]; +static float color_step; +static float inv_color_step; +static float valid_gamma; +static float valid_inv_gamma; + +static void makeGammaTables(float gamma) +{ + /* we need two tables: one forward, one backward */ + int i; + + valid_gamma = gamma; + valid_inv_gamma = 1.0 / gamma; + color_step = 1.0 / RE_GAMMA_TABLE_SIZE; + inv_color_step = (float) RE_GAMMA_TABLE_SIZE; + + /* We could squeeze out the two range tables to gain some memory. */ + for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) { + color_domain_table[i] = i * color_step; + gamma_range_table[i] = pow(color_domain_table[i], + valid_gamma); + inv_gamma_range_table[i] = pow(color_domain_table[i], + valid_inv_gamma); + } + + /* The end of the table should match 1.0 carefully. In order to avoid */ + /* rounding errors, we just set this explicitly. The last segment may */ + /* have a different lenght than the other segments, but our */ + /* interpolation is insensitive to that. */ + color_domain_table[RE_GAMMA_TABLE_SIZE] = 1.0; + gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0; + inv_gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0; + + /* To speed up calculations, we make these calc factor tables. They are */ + /* multiplication factors used in scaling the interpolation. */ + for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++ ) { + gamfactor_table[i] = inv_color_step + * (gamma_range_table[i + 1] - gamma_range_table[i]) ; + inv_gamfactor_table[i] = inv_color_step + * (inv_gamma_range_table[i + 1] - inv_gamma_range_table[i]) ; + } + +} /* end of void makeGammaTables(float gamma) */ + + +static float gammaCorrect(float c) +{ + int i; + float res = 0.0; + + i = floor(c * inv_color_step); + /* Clip to range [0,1]: outside, just do the complete calculation. */ + /* We may have some performance problems here. Stretching up the LUT */ + /* may help solve that, by exchanging LUT size for the interpolation. */ + /* Negative colors are explicitly handled. */ + if (i < 0) res = -pow(abs(c), valid_gamma); + else if (i >= RE_GAMMA_TABLE_SIZE ) res = pow(c, valid_gamma); + else res = gamma_range_table[i] + + ( (c - color_domain_table[i]) * gamfactor_table[i]); + + return res; +} /* end of float gammaCorrect(float col) */ + +/* ------------------------------------------------------------------------- */ + +static float invGammaCorrect(float col) +{ + int i; + float res = 0.0; + + i = floor(col*inv_color_step); + /* Negative colors are explicitly handled. */ + if (i < 0) res = -pow(abs(col), valid_inv_gamma); + else if (i >= RE_GAMMA_TABLE_SIZE) res = pow(col, valid_inv_gamma); + else res = inv_gamma_range_table[i] + + ( (col - color_domain_table[i]) * inv_gamfactor_table[i]); + + return res; +} /* end of float invGammaCorrect(float col) */ + + +static void gamtabs(float gamma) +{ + float val, igamma= 1.0f/gamma; + int a; + + /* gamtab: in short, out short */ + for(a=0; a<65536; a++) { + val= a; + val/= 65535.0; + + if(gamma==2.0) val= sqrt(val); + else if(gamma!=1.0) val= pow(val, igamma); + + gamtab[a]= (65535.99*val); + } + /* inverse gamtab1 : in byte, out short */ + for(a=1; a<=256; a++) { + if(gamma==2.0) igamtab1[a-1]= a*a-1; + else if(gamma==1.0) igamtab1[a-1]= 256*a-1; + else { + val= a/256.0; + igamtab1[a-1]= (65535.0*pow(val, gamma)) -1 ; + } + } + +} + +static void build_gammatabs() +{ + if (gamma_tabs_init == FALSE) { + gamtabs(2.0f); + makeGammaTables(2.0f); + gamma_tabs_init = TRUE; + } +} + +static void init_gammacross(Sequence * seq) +{ +} + +static void load_gammacross(Sequence * seq) +{ +} + +static void free_gammacross(Sequence * seq) +{ +} + +static void do_gammacross_effect_byte(float facf0, float facf1, + int x, int y, + char *rect1, + char *rect2, + char *out) +{ + int fac1, fac2, col; + int xo; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac2= (int)(256.0*facf0); + fac1= 256-fac2; + + while(y--) { + + x= xo; + while(x--) { + + col= (fac1*igamtab1[rt1[0]] + fac2*igamtab1[rt2[0]])>>8; + if(col>65535) rt[0]= 255; else rt[0]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col=(fac1*igamtab1[rt1[1]] + fac2*igamtab1[rt2[1]])>>8; + if(col>65535) rt[1]= 255; else rt[1]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[2]] + fac2*igamtab1[rt2[2]])>>8; + if(col>65535) rt[2]= 255; else rt[2]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[3]] + fac2*igamtab1[rt2[3]])>>8; + if(col>65535) rt[3]= 255; else rt[3]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + col= (fac1*igamtab1[rt1[0]] + fac2*igamtab1[rt2[0]])>>8; + if(col>65535) rt[0]= 255; else rt[0]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[1]] + fac2*igamtab1[rt2[1]])>>8; + if(col>65535) rt[1]= 255; else rt[1]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[2]] + fac2*igamtab1[rt2[2]])>>8; + if(col>65535) rt[2]= 255; else rt[2]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[3]] + fac2*igamtab1[rt2[3]])>>8; + if(col>65535) rt[3]= 255; else rt[3]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + } + +} + +static void do_gammacross_effect_float(float facf0, float facf1, + int x, int y, + float *rect1, float *rect2, + float *out) +{ + float fac1, fac2; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac1= 1.0 - fac2; + + while(y--) { + + x= xo * 4; + while(x--) { + + *rt= gammaCorrect( + fac1 * invGammaCorrect(*rt1) + + fac2 * invGammaCorrect(*rt2)); + rt1++; rt2++; rt++; + } + + if(y==0) break; + y--; + + x= xo * 4; + while(x--) { + + *rt= gammaCorrect( + fac1*invGammaCorrect(*rt1) + + fac2*invGammaCorrect(*rt2)); + + rt1++; rt2++; rt++; + } + } +} + +static void do_gammacross_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + build_gammatabs(); + + if (out->rect_float) { + do_gammacross_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_gammacross_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + + +/* ********************************************************************** + ADD + ********************************************************************** */ + +static void do_add_effect_byte(float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, + unsigned char *out) +{ + int col, xo, fac1, fac3; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac1= (int)(256.0*facf0); + fac3= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + col= rt1[0]+ ((fac1*rt2[0])>>8); + if(col>255) rt[0]= 255; else rt[0]= col; + col= rt1[1]+ ((fac1*rt2[1])>>8); + if(col>255) rt[1]= 255; else rt[1]= col; + col= rt1[2]+ ((fac1*rt2[2])>>8); + if(col>255) rt[2]= 255; else rt[2]= col; + col= rt1[3]+ ((fac1*rt2[3])>>8); + if(col>255) rt[3]= 255; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + col= rt1[0]+ ((fac3*rt2[0])>>8); + if(col>255) rt[0]= 255; else rt[0]= col; + col= rt1[1]+ ((fac3*rt2[1])>>8); + if(col>255) rt[1]= 255; else rt[1]= col; + col= rt1[2]+ ((fac3*rt2[2])>>8); + if(col>255) rt[2]= 255; else rt[2]= col; + col= rt1[3]+ ((fac3*rt2[3])>>8); + if(col>255) rt[3]= 255; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_add_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + int xo; + float fac1, fac3; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac1= facf0; + fac3= facf1; + + while(y--) { + + x= xo * 4; + while(x--) { + *rt = *rt1 + fac1 * (*rt2); + + rt1++; rt2++; rt++; + } + + if(y==0) break; + y--; + + x= xo * 4; + while(x--) { + *rt = *rt1 + fac3 * (*rt2); + + rt1++; rt2++; rt++; + } + } +} + +static void do_add_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_add_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_add_effect_byte( + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} + + +/* ********************************************************************** + SUB + ********************************************************************** */ + +static void do_sub_effect_byte(float facf0, float facf1, + int x, int y, + char *rect1, char *rect2, char *out) +{ + int col, xo, fac1, fac3; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac1= (int)(256.0*facf0); + fac3= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + col= rt1[0]- ((fac1*rt2[0])>>8); + if(col<0) rt[0]= 0; else rt[0]= col; + col= rt1[1]- ((fac1*rt2[1])>>8); + if(col<0) rt[1]= 0; else rt[1]= col; + col= rt1[2]- ((fac1*rt2[2])>>8); + if(col<0) rt[2]= 0; else rt[2]= col; + col= rt1[3]- ((fac1*rt2[3])>>8); + if(col<0) rt[3]= 0; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + col= rt1[0]- ((fac3*rt2[0])>>8); + if(col<0) rt[0]= 0; else rt[0]= col; + col= rt1[1]- ((fac3*rt2[1])>>8); + if(col<0) rt[1]= 0; else rt[1]= col; + col= rt1[2]- ((fac3*rt2[2])>>8); + if(col<0) rt[2]= 0; else rt[2]= col; + col= rt1[3]- ((fac3*rt2[3])>>8); + if(col<0) rt[3]= 0; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_sub_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + int xo; + float fac1, fac3; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac1= facf0; + fac3= facf1; + + while(y--) { + + x= xo * 4; + while(x--) { + *rt = *rt1 - fac1 * (*rt2); + + rt1++; rt2++; rt++; + } + + if(y==0) break; + y--; + + x= xo * 4; + while(x--) { + *rt = *rt1 - fac3 * (*rt2); + + rt1++; rt2++; rt++; + } + } +} + +static void do_sub_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_sub_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_sub_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + +/* ********************************************************************** + DROP + ********************************************************************** */ + +/* Must be > 0 or add precopy, etc to the function */ +#define XOFF 8 +#define YOFF 8 + +static void do_drop_effect_byte(float facf0, float facf1, int x, int y, + unsigned char *rect2i, unsigned char *rect1i, + unsigned char *outi) +{ + int height, width, temp, fac, fac1, fac2; + char *rt1, *rt2, *out; + int field= 1; + + width= x; + height= y; + + fac1= (int)(70.0*facf0); + fac2= (int)(70.0*facf1); + + rt2= (char*) (rect2i + YOFF*width); + rt1= (char*) rect1i; + out= (char*) outi; + for (y=0; y>8); + + *(out++)= MAX2(0, *rt1 - temp); rt1++; + *(out++)= MAX2(0, *rt1 - temp); rt1++; + *(out++)= MAX2(0, *rt1 - temp); rt1++; + *(out++)= MAX2(0, *rt1 - temp); rt1++; + rt2+=4; + } + rt2+=XOFF*4; + } + memcpy(out, rt1, sizeof(int)*YOFF*width); +} + +static void do_drop_effect_float(float facf0, float facf1, int x, int y, + float *rect2i, float *rect1i, + float *outi) +{ + int height, width; + float temp, fac, fac1, fac2; + float *rt1, *rt2, *out; + int field= 1; + + width= x; + height= y; + + fac1= 70.0*facf0; + fac2= 70.0*facf1; + + rt2= (rect2i + YOFF*width); + rt1= rect1i; + out= outi; + for (y=0; yrect_float) { + do_drop_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_drop_effect_byte( + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} + +/* ********************************************************************** + MUL + ********************************************************************** */ + +static void do_mul_effect_byte(float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, + unsigned char *out) +{ + int xo, fac1, fac3; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac1= (int)(256.0*facf0); + fac3= (int)(256.0*facf1); + + /* formula: + * fac*(a*b) + (1-fac)*a => fac*a*(b-1)+axaux= c*px + py*s ;//+centx + yaux= -s*px + c*py;//+centy + */ + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= rt1[0] + ((fac1*rt1[0]*(rt2[0]-256))>>16); + rt[1]= rt1[1] + ((fac1*rt1[1]*(rt2[1]-256))>>16); + rt[2]= rt1[2] + ((fac1*rt1[2]*(rt2[2]-256))>>16); + rt[3]= rt1[3] + ((fac1*rt1[3]*(rt2[3]-256))>>16); + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= rt1[0] + ((fac3*rt1[0]*(rt2[0]-256))>>16); + rt[1]= rt1[1] + ((fac3*rt1[1]*(rt2[1]-256))>>16); + rt[2]= rt1[2] + ((fac3*rt1[2]*(rt2[2]-256))>>16); + rt[3]= rt1[3] + ((fac3*rt1[3]*(rt2[3]-256))>>16); + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_mul_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + int xo; + float fac1, fac3; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac1= facf0; + fac3= facf1; + + /* formula: + * fac*(a*b) + (1-fac)*a => fac*a*(b-1)+a + */ + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= rt1[0] + fac1*rt1[0]*(rt2[0]-1.0); + rt[1]= rt1[1] + fac1*rt1[1]*(rt2[1]-1.0); + rt[2]= rt1[2] + fac1*rt1[2]*(rt2[2]-1.0); + rt[3]= rt1[3] + fac1*rt1[3]*(rt2[3]-1.0); + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= rt1[0] + fac3*rt1[0]*(rt2[0]-1.0); + rt[1]= rt1[1] + fac3*rt1[1]*(rt2[1]-1.0); + rt[2]= rt1[2] + fac3*rt1[2]*(rt2[2]-1.0); + rt[3]= rt1[3] + fac3*rt1[3]*(rt2[3]-1.0); + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_mul_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_mul_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_mul_effect_byte( + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} + +/* ********************************************************************** + WIPE + ********************************************************************** */ + +typedef struct WipeZone { + float angle; + int flip; + int xo, yo; + int width; + float invwidth; + float pythangle; +} WipeZone; + +static void precalc_wipe_zone(WipeZone *wipezone, WipeVars *wipe, int xo, int yo) +{ + wipezone->flip = (wipe->angle < 0); + wipezone->angle = pow(fabs(wipe->angle)/45.0f, log(xo)/log(2.0f)); + wipezone->xo = xo; + wipezone->yo = yo; + wipezone->width = (int)(wipe->edgeWidth*((xo+yo)/2.0f)); + wipezone->pythangle = 1.0f/sqrt(wipe->angle*wipe->angle + 1.0f); + + if(wipe->wipetype == DO_SINGLE_WIPE) + wipezone->invwidth = 1.0f/wipezone->width; + else + wipezone->invwidth = 1.0f/(0.5f*wipezone->width); +} + +// This function calculates the blur band for the wipe effects +static float in_band(WipeZone *wipezone,float width,float dist,float perc,int side,int dir) +{ + float t1,t2,alpha,percwidth; + + if(width == 0) + return (float)side; + + if(side == 1) + percwidth = width * perc; + else + percwidth = width * (1 - perc); + + if(width < dist) + return side; + + t1 = dist * wipezone->invwidth; //percentange of width that is + t2 = wipezone->invwidth; //amount of alpha per % point + + if(side == 1) + alpha = (t1*t2*100) + (1-perc); // add point's alpha contrib to current position in wipe + else + alpha = (1-perc) - (t1*t2*100); + + if(dir == 0) + alpha = 1-alpha; + + return alpha; +} + +static float check_zone(WipeZone *wipezone, int x, int y, + Sequence *seq, float facf0) +{ + float posx, posy,hyp,hyp2,angle,hwidth,b1,b2,b3,pointdist; +/*some future stuff +float hyp3,hyp4,b4,b5 +*/ + float temp1,temp2,temp3,temp4; //some placeholder variables + int xo = wipezone->xo; + int yo = wipezone->yo; + float halfx = xo*0.5f; + float halfy = yo*0.5f; + float widthf,output=0; + WipeVars *wipe = (WipeVars *)seq->effectdata; + int width; + + if(wipezone->flip) x = xo - x; + angle = wipezone->angle; + + posy = facf0 * yo; + + if(wipe->forward){ + posx = facf0 * xo; + posy = facf0 * yo; + } else{ + posx = xo - facf0 * xo; + posy = yo - facf0 * yo; + } + + switch (wipe->wipetype) { + case DO_SINGLE_WIPE: + width = wipezone->width; + hwidth = width*0.5f; + + if(angle == 0.0f) { + b1 = posy; + b2 = y; + hyp = fabs(y - posy); + } + else { + b1 = posy - (-angle)*posx; + b2 = y - (-angle)*x; + hyp = fabs(angle*x+y+(-posy-angle*posx))*wipezone->pythangle; + } + + if(angle < 0) { + temp1 = b1; + b1 = b2; + b2 = temp1; + } + + if(wipe->forward) { + if(b1 < b2) + output = in_band(wipezone,width,hyp,facf0,1,1); + else + output = in_band(wipezone,width,hyp,facf0,0,1); + } + else { + if(b1 < b2) + output = in_band(wipezone,width,hyp,facf0,0,1); + else + output = in_band(wipezone,width,hyp,facf0,1,1); + } + break; + + case DO_DOUBLE_WIPE: + if(!wipe->forward) + facf0 = 1.0f-facf0; // Go the other direction + + width = wipezone->width; // calculate the blur width + hwidth = width*0.5f; + if (angle == 0) { + b1 = posy*0.5f; + b3 = yo-posy*0.5f; + b2 = y; + + hyp = abs(y - posy*0.5f); + hyp2 = abs(y - (yo-posy*0.5f)); + } + else { + b1 = posy*0.5f - (-angle)*posx*0.5f; + b3 = (yo-posy*0.5f) - (-angle)*(xo-posx*0.5f); + b2 = y - (-angle)*x; + + hyp = abs(angle*x+y+(-posy*0.5f-angle*posx*0.5f))*wipezone->pythangle; + hyp2 = abs(angle*x+y+(-(yo-posy*0.5f)-angle*(xo-posx*0.5f)))*wipezone->pythangle; + } + + temp1 = xo*(1-facf0*0.5f)-xo*facf0*0.5f; + temp2 = yo*(1-facf0*0.5f)-yo*facf0*0.5f; + pointdist = sqrt(temp1*temp1 + temp2*temp2); + + if(b2 < b1 && b2 < b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp,facf0,0,1); + } else if(b2 > b1 && b2 > b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp2,facf0,0,1); + } else { + if( hyp < hwidth && hyp2 > hwidth ) + output = in_band(wipezone,hwidth,hyp,facf0,1,1); + else if( hyp > hwidth && hyp2 < hwidth ) + output = in_band(wipezone,hwidth,hyp2,facf0,1,1); + else + output = in_band(wipezone,hwidth,hyp2,facf0,1,1) * in_band(wipezone,hwidth,hyp,facf0,1,1); + } + if(!wipe->forward)output = 1-output; + break; + case DO_CLOCK_WIPE: + /* + temp1: angle of effect center in rads + temp2: angle of line through (halfx,halfy) and (x,y) in rads + temp3: angle of low side of blur + temp4: angle of high side of blur + */ + output = 1.0f - facf0; + widthf = wipe->edgeWidth*2.0f*(float)M_PI; + temp1 = 2.0f * (float)M_PI * facf0; + + if(wipe->forward){ + temp1 = 2.0f*(float)M_PI - temp1; + } + + x = x - halfx; + y = y - halfy; + + temp2 = asin(abs(y)/sqrt(x*x + y*y)); + if(x <= 0 && y >= 0) temp2 = (float)M_PI - temp2; + else if(x<=0 && y <= 0) temp2 += (float)M_PI; + else if(x >= 0 && y <= 0) temp2 = 2.0f*(float)M_PI - temp2; + + if(wipe->forward){ + temp3 = temp1-(widthf*0.5f)*facf0; + temp4 = temp1+(widthf*0.5f)*(1-facf0); + } else{ + temp3 = temp1-(widthf*0.5f)*(1-facf0); + temp4 = temp1+(widthf*0.5f)*facf0; + } + if (temp3 < 0) temp3 = 0; + if (temp4 > 2.0f*(float)M_PI) temp4 = 2.0f*(float)M_PI; + + + if(temp2 < temp3) output = 0; + else if (temp2 > temp4) output = 1; + else output = (temp2-temp3)/(temp4-temp3); + if(x == 0 && y == 0) output = 1; + if(output != output) output = 1; + if(wipe->forward) output = 1 - output; + break; + /* BOX WIPE IS NOT WORKING YET */ + /* case DO_CROSS_WIPE: */ + /* BOX WIPE IS NOT WORKING YET */ + /* + case DO_BOX_WIPE: + if(invert)facf0 = 1-facf0; + + width = (int)(wipe->edgeWidth*((xo+yo)/2.0)); + hwidth = (float)width/2.0; + if (angle == 0)angle = 0.000001; + b1 = posy/2 - (-angle)*posx/2; + b3 = (yo-posy/2) - (-angle)*(xo-posx/2); + b2 = y - (-angle)*x; + + hyp = abs(angle*x+y+(-posy/2-angle*posx/2))*wipezone->pythangle; + hyp2 = abs(angle*x+y+(-(yo-posy/2)-angle*(xo-posx/2)))*wipezone->pythangle; + + temp1 = xo*(1-facf0/2)-xo*facf0/2; + temp2 = yo*(1-facf0/2)-yo*facf0/2; + pointdist = sqrt(temp1*temp1 + temp2*temp2); + + if(b2 < b1 && b2 < b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp,facf0,0,1); + } else if(b2 > b1 && b2 > b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp2,facf0,0,1); + } else { + if( hyp < hwidth && hyp2 > hwidth ) + output = in_band(wipezone,hwidth,hyp,facf0,1,1); + else if( hyp > hwidth && hyp2 < hwidth ) + output = in_band(wipezone,hwidth,hyp2,facf0,1,1); + else + output = in_band(wipezone,hwidth,hyp2,facf0,1,1) * in_band(wipezone,hwidth,hyp,facf0,1,1); + } + + if(invert)facf0 = 1-facf0; + angle = -1/angle; + b1 = posy/2 - (-angle)*posx/2; + b3 = (yo-posy/2) - (-angle)*(xo-posx/2); + b2 = y - (-angle)*x; + + hyp = abs(angle*x+y+(-posy/2-angle*posx/2))*wipezone->pythangle; + hyp2 = abs(angle*x+y+(-(yo-posy/2)-angle*(xo-posx/2)))*wipezone->pythangle; + + if(b2 < b1 && b2 < b3 ){ + if(hwidth < pointdist) + output *= in_band(wipezone,hwidth,hyp,facf0,0,1); + } else if(b2 > b1 && b2 > b3 ){ + if(hwidth < pointdist) + output *= in_band(wipezone,hwidth,hyp2,facf0,0,1); + } else { + if( hyp < hwidth && hyp2 > hwidth ) + output *= in_band(wipezone,hwidth,hyp,facf0,1,1); + else if( hyp > hwidth && hyp2 < hwidth ) + output *= in_band(wipezone,hwidth,hyp2,facf0,1,1); + else + output *= in_band(wipezone,hwidth,hyp2,facf0,1,1) * in_band(wipezone,hwidth,hyp,facf0,1,1); + } + + break; +*/ + case DO_IRIS_WIPE: + if(xo > yo) yo = xo; + else xo = yo; + + if(!wipe->forward) facf0 = 1-facf0; + + width = wipezone->width; + hwidth = width*0.5f; + + temp1 = (halfx-(halfx)*facf0); + pointdist = sqrt(temp1*temp1 + temp1*temp1); + + temp2 = sqrt((halfx-x)*(halfx-x) + (halfy-y)*(halfy-y)); + if(temp2 > pointdist) output = in_band(wipezone,hwidth,fabs(temp2-pointdist),facf0,0,1); + else output = in_band(wipezone,hwidth,fabs(temp2-pointdist),facf0,1,1); + + if(!wipe->forward) output = 1-output; + + break; + } + if (output < 0) output = 0; + else if(output > 1) output = 1; + return output; +} + +static void init_wipe_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct WipeVars), "wipevars"); +} + +static int num_inputs_wipe() +{ + return 1; +} + +static void free_wipe_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_wipe_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static void do_wipe_effect_byte(Sequence *seq, float facf0, float facf1, + int x, int y, + unsigned char *rect1, + unsigned char *rect2, unsigned char *out) +{ + WipeZone wipezone; + WipeVars *wipe = (WipeVars *)seq->effectdata; + int xo, yo; + char *rt1, *rt2, *rt; + + precalc_wipe_zone(&wipezone, wipe, x, y); + + rt1 = (char *)rect1; + rt2 = (char *)rect2; + rt = (char *)out; + + xo = x; + yo = y; + for(y=0;yeffectdata; + int xo, yo; + float *rt1, *rt2, *rt; + + precalc_wipe_zone(&wipezone, wipe, x, y); + + rt1 = rect1; + rt2 = rect2; + rt = out; + + xo = x; + yo = y; + for(y=0;yrect_float) { + do_wipe_effect_float(seq, + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_wipe_effect_byte(seq, + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} +/* ********************************************************************** + TRANSFORM + ********************************************************************** */ +static void init_transform_effect(Sequence *seq) +{ + TransformVars *scale; + + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct TransformVars), "transformvars"); + + scale = (TransformVars *)seq->effectdata; + scale->ScalexIni = 1; + scale->ScaleyIni = 1; + scale->ScalexFin = 1; + scale->ScaleyFin = 1; + + scale->xIni=0; + scale->xFin=0; + scale->yIni=0; + scale->yFin=0; + + scale->rotIni=0; + scale->rotFin=0; + + scale->interpolation=1; + scale->percent=1; +} + +static int num_inputs_transform() +{ + return 1; +} + +static void free_transform_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_transform_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static void do_transform(Sequence * seq,float facf0, int x, int y, + struct ImBuf *ibuf1,struct ImBuf *out) +{ + int xo, yo, xi, yi; + float xs,ys,factxScale,factyScale,tx,ty,rad,s,c,xaux,yaux,factRot,px,py; + TransformVars *scale; + + scale = (TransformVars *)seq->effectdata; + xo = x; + yo = y; + + //factor scale + factxScale = scale->ScalexIni + (scale->ScalexFin - scale->ScalexIni) * facf0; + factyScale = scale->ScaleyIni + (scale->ScaleyFin - scale->ScaleyIni) * facf0; + + //Factor translate + if(!scale->percent){ + tx = scale->xIni+(xo / 2.0f) + (scale->xFin-(xo / 2.0f) - scale->xIni+(xo / 2.0f)) * facf0; + ty = scale->yIni+(yo / 2.0f) + (scale->yFin-(yo / 2.0f) - scale->yIni+(yo / 2.0f)) * facf0; + }else{ + tx = xo*(scale->xIni/100.0f)+(xo / 2.0f) + (xo*(scale->xFin/100.0f)-(xo / 2.0f) - xo*(scale->xIni/100.0f)+(xo / 2.0f)) * facf0; + ty = yo*(scale->yIni/100.0f)+(yo / 2.0f) + (yo*(scale->yFin/100.0f)-(yo / 2.0f) - yo*(scale->yIni/100.0f)+(yo / 2.0f)) * facf0; + } + + //factor Rotate + factRot = scale->rotIni + (scale->rotFin - scale->rotIni) * facf0; + rad = (M_PI * factRot) / 180.0f; + s= sin(rad); + c= cos(rad); + + for (yi = 0; yi < yo; yi++) { + for (xi = 0; xi < xo; xi++) { + //tranlate point + px = xi-tx; + py = yi-ty; + + //rotate point with center ref + xaux = c*px + py*s ; + yaux = -s*px + c*py; + + //scale point with center ref + xs = xaux / factxScale; + ys = yaux / factyScale; + + //undo reference center point + xs += (xo / 2.0f); + ys += (yo / 2.0f); + + //interpolate + switch(scale->interpolation) { + case 0: + neareast_interpolation(ibuf1,out, xs,ys,xi,yi); + break; + case 1: + bilinear_interpolation(ibuf1,out, xs,ys,xi,yi); + break; + case 2: + bicubic_interpolation(ibuf1,out, xs,ys,xi,yi); + break; + } + } + } + +} +static void do_transform_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + do_transform(seq, facf0, x, y, ibuf1, out); +} + + +/* ********************************************************************** + GLOW + ********************************************************************** */ + +static void RVBlurBitmap2_byte ( unsigned char* map, int width,int height, + float blur, + int quality) +/* MUUUCCH better than the previous blur. */ +/* We do the blurring in two passes which is a whole lot faster. */ +/* I changed the math arount to implement an actual Gaussian */ +/* distribution. */ +/* */ +/* Watch out though, it tends to misbehaven with large blur values on */ +/* a small bitmap. Avoid avoid avoid. */ +/*=============================== */ +{ + unsigned char* temp=NULL,*swap; + float *filter=NULL; + int x,y,i,fx,fy; + int index, ix, halfWidth; + float fval, k, curColor[3], curColor2[3], weight=0; + + /* If we're not really blurring, bail out */ + if (blur<=0) + return; + + /* Allocate memory for the tempmap and the blur filter matrix */ + temp= MEM_mallocN( (width*height*4), "blurbitmaptemp"); + if (!temp) + return; + + /* Allocate memory for the filter elements */ + halfWidth = ((quality+1)*blur); + filter = (float *)MEM_mallocN(sizeof(float)*halfWidth*2, "blurbitmapfilter"); + if (!filter){ + MEM_freeN (temp); + return; + } + + /* Apparently we're calculating a bell curve */ + /* based on the standard deviation (or radius) */ + /* This code is based on an example */ + /* posted to comp.graphics.algorithms by */ + /* Blancmange (bmange@airdmhor.gen.nz) */ + + k = -1.0/(2.0*3.14159*blur*blur); + fval=0; + for (ix = 0;ix< halfWidth;ix++){ + weight = (float)exp(k*(ix*ix)); + filter[halfWidth - ix] = weight; + filter[halfWidth + ix] = weight; + } + filter[0] = weight; + + /* Normalize the array */ + fval=0; + for (ix = 0;ix< halfWidth*2;ix++) + fval+=filter[ix]; + + for (ix = 0;ix< halfWidth*2;ix++) + filter[ix]/=fval; + + /* Blur the rows */ + for (y=0;y=0)&&(i=0)&&(i=0)&&(i=0)&&(i0){ + out[index+GlowR]=MIN2(255*clamp, (in[index+GlowR]*boost*intensity)/255); + out[index+GlowG]=MIN2(255*clamp, (in[index+GlowG]*boost*intensity)/255); + out[index+GlowB]=MIN2(255*clamp, (in[index+GlowB]*boost*intensity)/255); + out[index+GlowA]=MIN2(255*clamp, (in[index+GlowA]*boost*intensity)/255); + } else{ + out[index+GlowR]=0; + out[index+GlowG]=0; + out[index+GlowB]=0; + out[index+GlowA]=0; + } + } + } +} + +static void RVIsolateHighlights_float (float* in, float* out, + int width, int height, float threshold, + float boost, float clamp) +{ + int x,y,index; + float intensity; + + + for(y=0;y< height;y++) { + for (x=0;x< width;x++) { + index= (x+y*width)*4; + + /* Isolate the intensity */ + intensity=(in[index+GlowR]+in[index+GlowG]+in[index+GlowB]-threshold); + if (intensity>0){ + out[index+GlowR]=MIN2(clamp, (in[index+GlowR]*boost*intensity)); + out[index+GlowG]=MIN2(clamp, (in[index+GlowG]*boost*intensity)); + out[index+GlowB]=MIN2(clamp, (in[index+GlowB]*boost*intensity)); + out[index+GlowA]=MIN2(clamp, (in[index+GlowA]*boost*intensity)); + } else{ + out[index+GlowR]=0; + out[index+GlowG]=0; + out[index+GlowB]=0; + out[index+GlowA]=0; + } + } + } +} + +static void init_glow_effect(Sequence *seq) +{ + GlowVars *glow; + + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct GlowVars), "glowvars"); + + glow = (GlowVars *)seq->effectdata; + glow->fMini = 0.25; + glow->fClamp = 1.0; + glow->fBoost = 0.5; + glow->dDist = 3.0; + glow->dQuality = 3; + glow->bNoComp = 0; +} + +static int num_inputs_glow() +{ + return 1; +} + +static void free_glow_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_glow_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +//void do_glow_effect(Cast *cast, float facf0, float facf1, int xo, int yo, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use) +static void do_glow_effect_byte(Sequence *seq, float facf0, float facf1, + int x, int y, char *rect1, + char *rect2, char *out) +{ + unsigned char *outbuf=(unsigned char *)out; + unsigned char *inbuf=(unsigned char *)rect1; + GlowVars *glow = (GlowVars *)seq->effectdata; + int size= 100; // renderdata XXX + + RVIsolateHighlights_byte(inbuf, outbuf , x, y, glow->fMini*765, glow->fBoost * facf0, glow->fClamp); + RVBlurBitmap2_byte (outbuf, x, y, glow->dDist * (size / 100.0f),glow->dQuality); + if (!glow->bNoComp) + RVAddBitmaps_byte (inbuf , outbuf, outbuf, x, y); +} + +static void do_glow_effect_float(Sequence *seq, float facf0, float facf1, + int x, int y, + float *rect1, float *rect2, float *out) +{ + float *outbuf = out; + float *inbuf = rect1; + GlowVars *glow = (GlowVars *)seq->effectdata; + int size= 100; // renderdata XXX + + RVIsolateHighlights_float(inbuf, outbuf , x, y, glow->fMini*3.0f, glow->fBoost * facf0, glow->fClamp); + RVBlurBitmap2_float (outbuf, x, y, glow->dDist * (size / 100.0f),glow->dQuality); + if (!glow->bNoComp) + RVAddBitmaps_float (inbuf , outbuf, outbuf, x, y); +} + +static void do_glow_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_glow_effect_float(seq, + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_glow_effect_byte(seq, + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + +/* ********************************************************************** + SOLID COLOR + ********************************************************************** */ + +static void init_solid_color(Sequence *seq) +{ + SolidColorVars *cv; + + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct SolidColorVars), "solidcolor"); + + cv = (SolidColorVars *)seq->effectdata; + cv->col[0] = cv->col[1] = cv->col[2] = 0.5; +} + +static int num_inputs_color() +{ + return 0; +} + +static void free_solid_color(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_solid_color(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static int early_out_color(struct Sequence *seq, + float facf0, float facf1) +{ + return -1; +} + +static void do_solid_color(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + SolidColorVars *cv = (SolidColorVars *)seq->effectdata; + + unsigned char *rect; + float *rect_float; + + if (out->rect) { + unsigned char col0[3]; + unsigned char col1[3]; + + col0[0] = facf0 * cv->col[0] * 255; + col0[1] = facf0 * cv->col[1] * 255; + col0[2] = facf0 * cv->col[2] * 255; + + col1[0] = facf1 * cv->col[0] * 255; + col1[1] = facf1 * cv->col[1] * 255; + col1[2] = facf1 * cv->col[2] * 255; + + rect = (unsigned char *)out->rect; + + for(y=0; yy; y++) { + for(x=0; xx; x++, rect+=4) { + rect[0]= col0[0]; + rect[1]= col0[1]; + rect[2]= col0[2]; + rect[3]= 255; + } + y++; + if (yy) { + for(x=0; xx; x++, rect+=4) { + rect[0]= col1[0]; + rect[1]= col1[1]; + rect[2]= col1[2]; + rect[3]= 255; + } + } + } + + } else if (out->rect_float) { + float col0[3]; + float col1[3]; + + col0[0] = facf0 * cv->col[0]; + col0[1] = facf0 * cv->col[1]; + col0[2] = facf0 * cv->col[2]; + + col1[0] = facf1 * cv->col[0]; + col1[1] = facf1 * cv->col[1]; + col1[2] = facf1 * cv->col[2]; + + rect_float = out->rect_float; + + for(y=0; yy; y++) { + for(x=0; xx; x++, rect_float+=4) { + rect_float[0]= col0[0]; + rect_float[1]= col0[1]; + rect_float[2]= col0[2]; + rect_float[3]= 1.0; + } + y++; + if (yy) { + for(x=0; xx; x++, rect_float+=4) { + rect_float[0]= col1[0]; + rect_float[1]= col1[1]; + rect_float[2]= col1[2]; + rect_float[3]= 1.0; + } + } + } + } +} + +/* ********************************************************************** + SPEED + ********************************************************************** */ +static void init_speed_effect(Sequence *seq) +{ + SpeedControlVars * v; + + if(seq->effectdata) MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct SpeedControlVars), + "speedcontrolvars"); + + v = (SpeedControlVars *)seq->effectdata; + v->globalSpeed = 1.0; + v->frameMap = 0; + v->flags = SEQ_SPEED_COMPRESS_IPO_Y; + v->length = 0; +} + +static void load_speed_effect(Sequence * seq) +{ + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + + v->frameMap = 0; + v->length = 0; +} + +static int num_inputs_speed() +{ + return 1; +} + +static void free_speed_effect(Sequence *seq) +{ + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + if(v->frameMap) MEM_freeN(v->frameMap); + if(seq->effectdata) MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_speed_effect(Sequence *dst, Sequence *src) +{ + SpeedControlVars * v; + dst->effectdata = MEM_dupallocN(src->effectdata); + v = (SpeedControlVars *)dst->effectdata; + v->frameMap = 0; + v->length = 0; +} + +static int early_out_speed(struct Sequence *seq, + float facf0, float facf1) +{ + return 1; +} + +static void store_icu_yrange_speed(struct Sequence * seq, + short adrcode, float * ymin, float * ymax) +{ + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + + /* if not already done, load / initialize data */ + get_sequence_effect(seq); + + if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) { + *ymin = -100.0; + *ymax = 100.0; + } else { + if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) { + *ymin = 0.0; + *ymax = 1.0; + } else { + *ymin = 0.0; + *ymax = seq->len; + } + } +} + +void sequence_effect_speed_rebuild_map(Scene *scene, Sequence * seq, int force) +{ + float facf0 = seq->facf0; + float ctime, div; + int cfra; + float fallback_fac; + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + + /* if not already done, load / initialize data */ + get_sequence_effect(seq); + + if (!(force || seq->len != v->length || !v->frameMap)) { + return; + } + + if (!v->frameMap || v->length != seq->len) { + if (v->frameMap) MEM_freeN(v->frameMap); + + v->length = seq->len; + + v->frameMap = MEM_callocN(sizeof(float) * v->length, + "speedcontrol frameMap"); + } + + fallback_fac = 1.0; + + /* if there is no IPO, try to make retiming easy by stretching the + strip */ + + if (!seq->ipo && seq->seq1 && seq->seq1->enddisp != seq->seq1->start + && seq->seq1->len != 0) { + fallback_fac = (float) seq->seq1->len / + (float) (seq->seq1->enddisp - seq->seq1->start); + /* FIXME: this strip stretching gets screwed by stripdata + handling one layer up. + + So it currently works by enlarging, never by shrinking! + + (IPOs still work, if used correctly) + */ + if (fallback_fac > 1.0) { + fallback_fac = 1.0; + } + } + + if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) { + float cursor = 0; + + v->frameMap[0] = 0; + v->lastValidFrame = 0; + + for (cfra = 1; cfra < v->length; cfra++) { + if(seq->ipo) { + if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { + ctime = frame_to_float(scene, seq->startdisp + cfra); + div = 1.0; + } else { + ctime= frame_to_float(scene, cfra); + div= v->length / 100.0f; + if(div==0.0) return; + } + + calc_ipo(seq->ipo, ctime/div); + execute_ipo((ID *)seq, seq->ipo); + } else { + seq->facf0 = fallback_fac; + } + seq->facf0 *= v->globalSpeed; + + cursor += seq->facf0; + + if (cursor >= v->length) { + v->frameMap[cfra] = v->length - 1; + } else { + v->frameMap[cfra] = cursor; + v->lastValidFrame = cfra; + } + } + } else { + v->lastValidFrame = 0; + for (cfra = 0; cfra < v->length; cfra++) { + if(seq->ipo) { + if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { + ctime = frame_to_float(scene, seq->startdisp + cfra); + div = 1.0; + } else { + ctime= frame_to_float(scene, cfra); + div= v->length / 100.0f; + if(div==0.0) return; + } + + calc_ipo(seq->ipo, ctime/div); + execute_ipo((ID *)seq, seq->ipo); + } + + if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) { + seq->facf0 *= v->length; + } + if (!seq->ipo) { + seq->facf0 = (float) cfra * fallback_fac; + } + seq->facf0 *= v->globalSpeed; + if (seq->facf0 >= v->length) { + seq->facf0 = v->length - 1; + } else { + v->lastValidFrame = cfra; + } + v->frameMap[cfra] = seq->facf0; + } + } + seq->facf0 = facf0; +} + +/* + simply reuse do_cross_effect for blending... + +static void do_speed_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + +} +*/ + + +/* ********************************************************************** + sequence effect factory + ********************************************************************** */ + + +static void init_noop(struct Sequence *seq) +{ + +} + +static void load_noop(struct Sequence *seq) +{ + +} + +static void init_plugin_noop(struct Sequence *seq, const char * fname) +{ + +} + +static void free_noop(struct Sequence *seq) +{ + +} + +static int num_inputs_default() +{ + return 2; +} + +static int early_out_noop(struct Sequence *seq, + float facf0, float facf1) +{ + return 0; +} + +static int early_out_fade(struct Sequence *seq, + float facf0, float facf1) +{ + if (facf0 == 0.0 && facf1 == 0.0) { + return 1; + } else if (facf0 == 1.0 && facf1 == 1.0) { + return 2; + } + return 0; +} + +static int early_out_mul_input2(struct Sequence *seq, + float facf0, float facf1) +{ + if (facf0 == 0.0 && facf1 == 0.0) { + return 1; + } + return 0; +} + +static void store_icu_yrange_noop(struct Sequence * seq, + short adrcode, float * ymin, float * ymax) +{ + /* defaults are fine */ +} + +static void get_default_fac_noop(struct Sequence *seq, int cfra, + float * facf0, float * facf1) +{ + *facf0 = *facf1 = 1.0; +} + +static void get_default_fac_fade(struct Sequence *seq, int cfra, + float * facf0, float * facf1) +{ + *facf0 = (float)(cfra - seq->startdisp); + *facf1 = (float)(*facf0 + 0.5); + *facf0 /= seq->len; + *facf1 /= seq->len; +} + +static void do_overdrop_effect(struct Sequence * seq, int cfra, + float fac, float facf, + int x, int y, struct ImBuf * ibuf1, + struct ImBuf * ibuf2, + struct ImBuf * ibuf3, + struct ImBuf * out) +{ + do_drop_effect(seq, cfra, fac, facf, x, y, + ibuf1, ibuf2, ibuf3, out); + do_alphaover_effect(seq, cfra, fac, facf, x, y, + ibuf1, ibuf2, ibuf3, out); +} + +static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) +{ + struct SeqEffectHandle rval; + int sequence_type = seq_type; + + rval.init = init_noop; + rval.init_plugin = init_plugin_noop; + rval.num_inputs = num_inputs_default; + rval.load = load_noop; + rval.free = free_noop; + rval.early_out = early_out_noop; + rval.get_default_fac = get_default_fac_noop; + rval.store_icu_yrange = store_icu_yrange_noop; + rval.execute = NULL; + rval.copy = NULL; + + switch (sequence_type) { + case SEQ_CROSS: + rval.execute = do_cross_effect; + rval.early_out = early_out_fade; + rval.get_default_fac = get_default_fac_fade; + break; + case SEQ_GAMCROSS: + rval.init = init_gammacross; + rval.load = load_gammacross; + rval.free = free_gammacross; + rval.early_out = early_out_fade; + rval.get_default_fac = get_default_fac_fade; + rval.execute = do_gammacross_effect; + break; + case SEQ_ADD: + rval.execute = do_add_effect; + rval.early_out = early_out_mul_input2; + break; + case SEQ_SUB: + rval.execute = do_sub_effect; + rval.early_out = early_out_mul_input2; + break; + case SEQ_MUL: + rval.execute = do_mul_effect; + rval.early_out = early_out_mul_input2; + break; + case SEQ_ALPHAOVER: + rval.init = init_alpha_over_or_under; + rval.execute = do_alphaover_effect; + break; + case SEQ_OVERDROP: + rval.execute = do_overdrop_effect; + break; + case SEQ_ALPHAUNDER: + rval.init = init_alpha_over_or_under; + rval.execute = do_alphaunder_effect; + break; + case SEQ_WIPE: + rval.init = init_wipe_effect; + rval.num_inputs = num_inputs_wipe; + rval.free = free_wipe_effect; + rval.copy = copy_wipe_effect; + rval.early_out = early_out_fade; + rval.get_default_fac = get_default_fac_fade; + rval.execute = do_wipe_effect; + break; + case SEQ_GLOW: + rval.init = init_glow_effect; + rval.num_inputs = num_inputs_glow; + rval.free = free_glow_effect; + rval.copy = copy_glow_effect; + rval.execute = do_glow_effect; + break; + case SEQ_TRANSFORM: + rval.init = init_transform_effect; + rval.num_inputs = num_inputs_transform; + rval.free = free_transform_effect; + rval.copy = copy_transform_effect; + rval.execute = do_transform_effect; + break; + case SEQ_SPEED: + rval.init = init_speed_effect; + rval.num_inputs = num_inputs_speed; + rval.load = load_speed_effect; + rval.free = free_speed_effect; + rval.copy = copy_speed_effect; + rval.execute = do_cross_effect; + rval.early_out = early_out_speed; + rval.store_icu_yrange = store_icu_yrange_speed; + break; + case SEQ_COLOR: + rval.init = init_solid_color; + rval.num_inputs = num_inputs_color; + rval.early_out = early_out_color; + rval.free = free_solid_color; + rval.copy = copy_solid_color; + rval.execute = do_solid_color; + break; + case SEQ_PLUGIN: + rval.init_plugin = init_plugin; + rval.num_inputs = num_inputs_plugin; + rval.load = load_plugin; + rval.free = free_plugin; + rval.copy = copy_plugin; + rval.execute = do_plugin_effect; + rval.early_out = do_plugin_early_out; + rval.get_default_fac = get_default_fac_fade; + break; + } + + return rval; +} + + +struct SeqEffectHandle get_sequence_effect(Sequence * seq) +{ + struct SeqEffectHandle rval; + + memset(&rval, 0, sizeof(struct SeqEffectHandle)); + + if (seq->type & SEQ_EFFECT) { + rval = get_sequence_effect_impl(seq->type); + if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) { + rval.load(seq); + seq->flag &= ~SEQ_EFFECT_NOT_LOADED; + } + } + + return rval; +} + +struct SeqEffectHandle get_sequence_blend(Sequence * seq) +{ + struct SeqEffectHandle rval; + + memset(&rval, 0, sizeof(struct SeqEffectHandle)); + + if (seq->blend_mode != 0) { + rval = get_sequence_effect_impl(seq->blend_mode); + if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) { + rval.load(seq); + seq->flag &= ~SEQ_EFFECT_NOT_LOADED; + } + } + + return rval; +} + +int get_sequence_effect_num_inputs(int seq_type) +{ + struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type); + + int cnt = rval.num_inputs(); + if (rval.execute) { + return cnt; + } + return 0; +} diff --git a/source/blender/blenkernel/intern/sequence.c b/source/blender/blenkernel/intern/sequence.c index e203c1bcb8e..5cc087e857e 100644 --- a/source/blender/blenkernel/intern/sequence.c +++ b/source/blender/blenkernel/intern/sequence.c @@ -1,19 +1,74 @@ +/** +* $Id: sequence.c 17508 2008-11-20 00:34:24Z campbellbarton $ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): + * - Blender Foundation, 2003-2009 + * - Peter Schlaile 2005/2006 + * + * ***** END GPL LICENSE BLOCK ***** + */ #include #include +#include #include "MEM_guardedalloc.h" +#include "DNA_ipo_types.h" #include "DNA_listBase.h" #include "DNA_sequence_types.h" +#include "DNA_scene_types.h" + +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_ipo.h" +#include "BKE_main.h" +#include "BKE_sequence.h" +#include "BKE_utildefines.h" #include "BLI_blenlib.h" #include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" -#include "BKE_sequence.h" +#include "BLI_threads.h" +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif -/* strip data */ +/* **** XXX ******** */ +static int seqrectx= 0; /* bad bad global! */ +static int seqrecty= 0; +static void waitcursor() {} +static int blender_test_break() {return 0;} + +/* **** XXX ******** */ + + +/* ********************************************************************** + alloc / free functions + ********************************************************************** */ static void free_tstripdata(int len, TStripElem *se) { @@ -38,8 +93,8 @@ static void free_tstripdata(int len, TStripElem *se) MEM_freeN(seo); } -/* -static void new_tstripdata(Sequence *seq) + +void new_tstripdata(Sequence *seq) { if(seq->strip) { free_tstripdata(seq->strip->len, seq->strip->tstripdata); @@ -65,11 +120,11 @@ static void new_tstripdata(Sequence *seq) seq->strip->len= seq->len; } } -*/ + /* free */ -static void seq_free_strip(Strip *strip) +void seq_free_strip(Strip *strip) { strip->us--; if(strip->us>0) return; @@ -155,6 +210,10 @@ void seq_free_editing(Editing *ed) MEM_freeN(ed); } +/* ************************* itterator ************************** */ +/* *************** (replaces old WHILE_SEQ) ********************* */ +/* **************** use now SEQ_BEGIN() SEQ_END ***************** */ + /* sequence strip iterator: * - builds a full array, recursively into meta strips */ @@ -185,7 +244,7 @@ static void seq_build_array(ListBase *seqbase, Sequence ***array, int depth) } } -void seq_array(Editing *ed, Sequence ***seqarray, int *tot) +void seq_array(Editing *ed, Sequence ***seqarray, int *tot, int use_pointer) { Sequence **array; @@ -195,19 +254,25 @@ void seq_array(Editing *ed, Sequence ***seqarray, int *tot) if(ed == NULL) return; - seq_count(&ed->seqbase, tot); + if(use_pointer) + seq_count(ed->seqbasep, tot); + else + seq_count(&ed->seqbase, tot); if(*tot == 0) return; *seqarray= array= MEM_mallocN(sizeof(Sequence *)*(*tot), "SeqArray"); - seq_build_array(&ed->seqbase, &array, 0); + if(use_pointer) + seq_build_array(ed->seqbasep, &array, 0); + else + seq_build_array(&ed->seqbase, &array, 0); } -void seq_begin(Editing *ed, SeqIterator *iter) +void seq_begin(Editing *ed, SeqIterator *iter, int use_pointer) { memset(iter, 0, sizeof(*iter)); - seq_array(ed, &iter->array, &iter->tot); + seq_array(ed, &iter->array, &iter->tot, use_pointer); if(iter->tot) { iter->cur= 0; @@ -232,4 +297,2762 @@ void seq_end(SeqIterator *iter) iter->valid= 0; } +/* + ********************************************************************** + * build_seqar + ********************************************************************** + * Build a complete array of _all_ sequencies (including those + * in metastrips!) + ********************************************************************** +*/ + +static void do_seq_count(ListBase *seqbase, int *totseq) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + (*totseq)++; + if(seq->seqbase.first) do_seq_count(&seq->seqbase, totseq); + seq= seq->next; + } +} + +static void do_build_seqar(ListBase *seqbase, Sequence ***seqar, int depth) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + seq->depth= depth; + if(seq->seqbase.first) do_build_seqar(&seq->seqbase, seqar, depth+1); + **seqar= seq; + (*seqar)++; + seq= seq->next; + } +} + +void build_seqar(ListBase *seqbase, Sequence ***seqar, int *totseq) +{ + Sequence **tseqar; + + *totseq= 0; + do_seq_count(seqbase, totseq); + + if(*totseq==0) { + *seqar= 0; + return; + } + *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar"); + tseqar= *seqar; + + do_build_seqar(seqbase, seqar, 0); + *seqar= tseqar; +} + +static void do_seq_count_cb(ListBase *seqbase, int *totseq, + int (*test_func)(Sequence * seq)) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + int test = test_func(seq); + if (test & BUILD_SEQAR_COUNT_CURRENT) { + (*totseq)++; + } + if(seq->seqbase.first && (test & BUILD_SEQAR_COUNT_CHILDREN)) { + do_seq_count_cb(&seq->seqbase, totseq, test_func); + } + seq= seq->next; + } +} + +static void do_build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int depth, + int (*test_func)(Sequence * seq)) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + int test = test_func(seq); + seq->depth= depth; + + if(seq->seqbase.first && (test & BUILD_SEQAR_COUNT_CHILDREN)) { + do_build_seqar_cb(&seq->seqbase, seqar, depth+1, + test_func); + } + if (test & BUILD_SEQAR_COUNT_CURRENT) { + **seqar= seq; + (*seqar)++; + } + seq= seq->next; + } +} + +void build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int *totseq, + int (*test_func)(Sequence * seq)) +{ + Sequence **tseqar; + + *totseq= 0; + do_seq_count_cb(seqbase, totseq, test_func); + + if(*totseq==0) { + *seqar= 0; + return; + } + *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar"); + tseqar= *seqar; + + do_build_seqar_cb(seqbase, seqar, 0, test_func); + *seqar= tseqar; +} + + +void calc_sequence_disp(Sequence *seq) +{ + if(seq->startofs && seq->startstill) seq->startstill= 0; + if(seq->endofs && seq->endstill) seq->endstill= 0; + + seq->startdisp= seq->start + seq->startofs - seq->startstill; + seq->enddisp= seq->start+seq->len - seq->endofs + seq->endstill; + + seq->handsize= 10.0; /* 10 frames */ + if( seq->enddisp-seq->startdisp < 10 ) { + seq->handsize= (float)(0.5*(seq->enddisp-seq->startdisp)); + } + else if(seq->enddisp-seq->startdisp > 250) { + seq->handsize= (float)((seq->enddisp-seq->startdisp)/25); + } +} + +void calc_sequence(Sequence *seq) +{ + Sequence *seqm; + int min, max; + + /* check all metas recursively */ + seqm= seq->seqbase.first; + while(seqm) { + if(seqm->seqbase.first) calc_sequence(seqm); + seqm= seqm->next; + } + + /* effects and meta: automatic start and end */ + + if(seq->type & SEQ_EFFECT) { + /* pointers */ + if(seq->seq2==0) seq->seq2= seq->seq1; + if(seq->seq3==0) seq->seq3= seq->seq1; + + /* effecten go from seq1 -> seq2: test */ + + /* we take the largest start and smallest end */ + + // seq->start= seq->startdisp= MAX2(seq->seq1->startdisp, seq->seq2->startdisp); + // seq->enddisp= MIN2(seq->seq1->enddisp, seq->seq2->enddisp); + + if (seq->seq1) { + seq->start= seq->startdisp= MAX3(seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp); + seq->enddisp= MIN3(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp); + seq->len= seq->enddisp - seq->startdisp; + } else { + calc_sequence_disp(seq); + } + + if(seq->strip && seq->len!=seq->strip->len) { + new_tstripdata(seq); + } + + } + else { + if(seq->type==SEQ_META) { + seqm= seq->seqbase.first; + if(seqm) { + min= 1000000; + max= -1000000; + while(seqm) { + if(seqm->startdisp < min) min= seqm->startdisp; + if(seqm->enddisp > max) max= seqm->enddisp; + seqm= seqm->next; + } + seq->start= min + seq->anim_startofs; + seq->len = max-min; + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + + if(seq->strip && seq->len!=seq->strip->len) { + new_tstripdata(seq); + } + } + } + calc_sequence_disp(seq); + } +} + +void reload_sequence_new_file(Scene *scene, Sequence * seq) +{ + char str[FILE_MAXDIR+FILE_MAXFILE]; + + if (!(seq->type == SEQ_MOVIE || seq->type == SEQ_IMAGE || + seq->type == SEQ_HD_SOUND || seq->type == SEQ_RAM_SOUND || + seq->type == SEQ_SCENE || seq->type == SEQ_META)) { + return; + } + + new_tstripdata(seq); + + if (seq->type != SEQ_SCENE && seq->type != SEQ_META && + seq->type != SEQ_IMAGE) { + BLI_join_dirfile(str, seq->strip->dir, seq->strip->stripdata->name); + BLI_convertstringcode(str, G.sce); + BLI_convertstringframe(str, scene->r.cfra); + + } + + if (seq->type == SEQ_IMAGE) { + /* Hack? */ + int olen = MEM_allocN_len(seq->strip->stripdata)/sizeof(struct StripElem); + seq->len = olen; + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } else if (seq->type == SEQ_MOVIE) { + if(seq->anim) IMB_free_anim(seq->anim); + seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0)); + + if (!seq->anim) { + return; + } + + seq->len = IMB_anim_get_duration(seq->anim); + + seq->anim_preseek = IMB_anim_get_preseek(seq->anim); + + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } else if (seq->type == SEQ_HD_SOUND) { +// XXX if(seq->hdaudio) sound_close_hdaudio(seq->hdaudio); +// seq->hdaudio = sound_open_hdaudio(str); + + if (!seq->hdaudio) { + return; + } + +// XXX seq->len = sound_hdaudio_get_duration(seq->hdaudio, FPS) - seq->anim_startofs - seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } else if (seq->type == SEQ_RAM_SOUND) { + seq->len = (int) ( ((float)(seq->sound->streamlen-1)/ + ((float)scene->audio.mixrate*4.0 )) + * FPS); + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } else if (seq->type == SEQ_SCENE) { + Scene * sce = G.main->scene.first; + int nr = 1; + + while(sce) { + if(nr == seq->scenenr) { + break; + } + nr++; + sce= sce->id.next; + } + + if (sce) { + seq->scene = sce; + } else { + sce = seq->scene; + } + + strncpy(seq->name + 2, sce->id.name + 2, + sizeof(seq->name) - 2); + + seq->len= seq->scene->r.efra - seq->scene->r.sfra + 1; + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } + + calc_sequence(seq); +} + +void sort_seq(Scene *scene) +{ + /* all strips together per kind, and in order of y location ("machine") */ + ListBase seqbase, effbase; + Editing *ed; + Sequence *seq, *seqt; + + ed= scene->ed; + if(ed==NULL) return; + + seqbase.first= seqbase.last= 0; + effbase.first= effbase.last= 0; + + while( (seq= ed->seqbasep->first) ) { + BLI_remlink(ed->seqbasep, seq); + + if(seq->type & SEQ_EFFECT) { + seqt= effbase.first; + while(seqt) { + if(seqt->machine>=seq->machine) { + BLI_insertlinkbefore(&effbase, seqt, seq); + break; + } + seqt= seqt->next; + } + if(seqt==0) BLI_addtail(&effbase, seq); + } + else { + seqt= seqbase.first; + while(seqt) { + if(seqt->machine>=seq->machine) { + BLI_insertlinkbefore(&seqbase, seqt, seq); + break; + } + seqt= seqt->next; + } + if(seqt==0) BLI_addtail(&seqbase, seq); + } + } + + addlisttolist(&seqbase, &effbase); + *(ed->seqbasep)= seqbase; +} + + +void clear_scene_in_allseqs(Scene *sce) +{ + Scene *sce1; + Editing *ed; + Sequence *seq; + + /* when a scene is deleted: test all seqs */ + + sce1= G.main->scene.first; + while(sce1) { + if(sce1!=sce && sce1->ed) { + ed= sce1->ed; + + SEQ_BEGIN(ed, seq) { + + if(seq->scene==sce) seq->scene= 0; + + } + SEQ_END + } + + sce1= sce1->id.next; + } +} + +char *give_seqname_by_type(int type) +{ + switch(type) { + case SEQ_META: return "Meta"; + case SEQ_IMAGE: return "Image"; + case SEQ_SCENE: return "Scene"; + case SEQ_MOVIE: return "Movie"; + case SEQ_RAM_SOUND: return "Audio (RAM)"; + case SEQ_HD_SOUND: return "Audio (HD)"; + case SEQ_CROSS: return "Cross"; + case SEQ_GAMCROSS: return "Gamma Cross"; + case SEQ_ADD: return "Add"; + case SEQ_SUB: return "Sub"; + case SEQ_MUL: return "Mul"; + case SEQ_ALPHAOVER: return "Alpha Over"; + case SEQ_ALPHAUNDER: return "Alpha Under"; + case SEQ_OVERDROP: return "Over Drop"; + case SEQ_WIPE: return "Wipe"; + case SEQ_GLOW: return "Glow"; + case SEQ_TRANSFORM: return "Transform"; + case SEQ_COLOR: return "Color"; + case SEQ_SPEED: return "Speed"; + default: + return 0; + } +} + +char *give_seqname(Sequence *seq) +{ + char * name = give_seqname_by_type(seq->type); + + if (!name) { + if(seq->typestrip->dir; + } else if(seq->type==SEQ_PLUGIN) { + if(!(seq->flag & SEQ_EFFECT_NOT_LOADED) && + seq->plugin && seq->plugin->doit) { + return seq->plugin->pname; + } else { + return "Plugin"; + } + } else { + return "Effect"; + } + } + return name; +} + +/* ***************** DO THE SEQUENCE ***************** */ + +static void make_black_ibuf(ImBuf *ibuf) +{ + unsigned int *rect; + float *rect_float; + int tot; + + if(ibuf==0 || (ibuf->rect==0 && ibuf->rect_float==0)) return; + + tot= ibuf->x*ibuf->y; + + rect= ibuf->rect; + rect_float = ibuf->rect_float; + + if (rect) { + memset(rect, 0, tot * sizeof(char) * 4); + } + + if (rect_float) { + memset(rect_float, 0, tot * sizeof(float) * 4); + } +} + +static void multibuf(ImBuf *ibuf, float fmul) +{ + char *rt; + float *rt_float; + + int a, mul, icol; + + mul= (int)(256.0*fmul); + rt= (char *)ibuf->rect; + rt_float = ibuf->rect_float; + + if (rt) { + a= ibuf->x*ibuf->y; + while(a--) { + + icol= (mul*rt[0])>>8; + if(icol>254) rt[0]= 255; else rt[0]= icol; + icol= (mul*rt[1])>>8; + if(icol>254) rt[1]= 255; else rt[1]= icol; + icol= (mul*rt[2])>>8; + if(icol>254) rt[2]= 255; else rt[2]= icol; + icol= (mul*rt[3])>>8; + if(icol>254) rt[3]= 255; else rt[3]= icol; + + rt+= 4; + } + } + if (rt_float) { + a= ibuf->x*ibuf->y; + while(a--) { + rt_float[0] *= fmul; + rt_float[1] *= fmul; + rt_float[2] *= fmul; + rt_float[3] *= fmul; + + rt_float += 4; + } + } +} + +static void do_effect(Scene *scene, int cfra, Sequence *seq, TStripElem * se) +{ + TStripElem *se1, *se2, *se3; + float fac, facf; + int x, y; + int early_out; + struct SeqEffectHandle sh = get_sequence_effect(seq); + + if (!sh.execute) { /* effect not supported in this version... */ + make_black_ibuf(se->ibuf); + return; + } + + if(seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + fac= seq->facf0; + facf= seq->facf1; + } else { + sh.get_default_fac(seq, cfra, &fac, &facf); + } + + if( !(scene->r.mode & R_FIELDS) ) facf = fac; + + early_out = sh.early_out(seq, fac, facf); + + if (early_out == -1) { /* no input needed */ + sh.execute(seq, cfra, fac, facf, + se->ibuf->x, se->ibuf->y, + 0, 0, 0, se->ibuf); + return; + } + + switch (early_out) { + case 0: + if (se->se1==0 || se->se2==0 || se->se3==0) { + make_black_ibuf(se->ibuf); + return; + } + + se1= se->se1; + se2= se->se2; + se3= se->se3; + + if ( (se1==0 || se2==0 || se3==0) + || (se1->ibuf==0 || se2->ibuf==0 || se3->ibuf==0)) { + make_black_ibuf(se->ibuf); + return; + } + + break; + case 1: + if (se->se1 == 0) { + make_black_ibuf(se->ibuf); + return; + } + + se1= se->se1; + + if (se1 == 0 || se1->ibuf == 0) { + make_black_ibuf(se->ibuf); + return; + } + + if (se->ibuf != se1->ibuf) { + IMB_freeImBuf(se->ibuf); + se->ibuf = se1->ibuf; + IMB_refImBuf(se->ibuf); + } + return; + case 2: + if (se->se2 == 0) { + make_black_ibuf(se->ibuf); + return; + } + + se2= se->se2; + + if (se2 == 0 || se2->ibuf == 0) { + make_black_ibuf(se->ibuf); + return; + } + if (se->ibuf != se2->ibuf) { + IMB_freeImBuf(se->ibuf); + se->ibuf = se2->ibuf; + IMB_refImBuf(se->ibuf); + } + return; + default: + make_black_ibuf(se->ibuf); + return; + } + + x= se2->ibuf->x; + y= se2->ibuf->y; + + if (!se1->ibuf->rect_float && se->ibuf->rect_float) { + IMB_float_from_rect(se1->ibuf); + } + if (!se2->ibuf->rect_float && se->ibuf->rect_float) { + IMB_float_from_rect(se2->ibuf); + } + if (!se3->ibuf->rect_float && se->ibuf->rect_float) { + IMB_float_from_rect(se3->ibuf); + } + + if (!se1->ibuf->rect && !se->ibuf->rect_float) { + IMB_rect_from_float(se1->ibuf); + } + if (!se2->ibuf->rect && !se->ibuf->rect_float) { + IMB_rect_from_float(se2->ibuf); + } + if (!se3->ibuf->rect && !se->ibuf->rect_float) { + IMB_rect_from_float(se3->ibuf); + } + + sh.execute(seq, cfra, fac, facf, x, y, se1->ibuf, se2->ibuf, se3->ibuf, + se->ibuf); +} + +static int give_stripelem_index(Sequence *seq, int cfra) +{ + int nr; + + if(seq->startdisp >cfra || seq->enddisp <= cfra) return -1; + if(seq->len == 0) return -1; + if(seq->flag&SEQ_REVERSE_FRAMES) { + /*reverse frame in this sequence */ + if(cfra <= seq->start) nr= seq->len-1; + else if(cfra >= seq->start+seq->len-1) nr= 0; + else nr= (seq->start + seq->len) - cfra; + } else { + if(cfra <= seq->start) nr= 0; + else if(cfra >= seq->start+seq->len-1) nr= seq->len-1; + else nr= cfra-seq->start; + } + if (seq->strobe < 1.0) seq->strobe = 1.0; + if (seq->strobe > 1.0) { + nr -= (int)fmod((double)nr, (double)seq->strobe); + } + + return nr; +} + +static TStripElem* alloc_tstripdata(int len, const char * name) +{ + int i; + TStripElem *se = MEM_callocN(len * sizeof(TStripElem), name); + for (i = 0; i < len; i++) { + se[i].ok = STRIPELEM_OK; + } + return se; +} + +TStripElem *give_tstripelem(Sequence *seq, int cfra) +{ + TStripElem *se; + int nr; + + se = seq->strip->tstripdata; + if (se == 0 && seq->len > 0) { + se = seq->strip->tstripdata = alloc_tstripdata(seq->len, + "tstripelems"); + } + nr = give_stripelem_index(seq, cfra); + + if (nr == -1) return 0; + if (se == 0) return 0; + + se += nr; + + /* if there are IPOs with blend modes active, one has to watch out + for startstill + endstill area: we can't use the same tstripelem + here for all ibufs, since then, blending with IPOs won't work! + + Rather common case, if you use a single image and try to fade + it in and out... or want to use your strip as a watermark in + alpha over mode... + */ + if (seq->blend_mode != SEQ_BLEND_REPLACE || + (seq->ipo && seq->ipo->curve.first && ( + !(seq->type & SEQ_EFFECT) || !seq->seq1))) { + Strip * s = seq->strip; + if (cfra < seq->start) { + se = s->tstripdata_startstill; + if (seq->startstill > s->startstill) { + free_tstripdata(s->startstill, + s->tstripdata_startstill); + se = 0; + } + + if (se == 0) { + s->startstill = seq->startstill; + se = seq->strip->tstripdata_startstill + = alloc_tstripdata( + s->startstill, + "tstripelems_startstill"); + } + se += seq->start - cfra - 1; + + } else if (cfra > seq->start + seq->len-1) { + se = s->tstripdata_endstill; + if (seq->endstill > s->endstill) { + free_tstripdata(s->endstill, + s->tstripdata_endstill); + se = 0; + } + + if (se == 0) { + s->endstill = seq->endstill; + se = seq->strip->tstripdata_endstill + = alloc_tstripdata( + s->endstill, + "tstripelems_endstill"); + } + se += cfra - (seq->start + seq->len-1) - 1; + } + } + + + se->nr= nr; + + return se; +} + +StripElem *give_stripelem(Sequence *seq, int cfra) +{ + StripElem *se; + int nr; + + se = seq->strip->stripdata; + nr = give_stripelem_index(seq, cfra); + + if (nr == -1) return 0; + if (se == 0) return 0; + + se += nr + seq->anim_startofs; + + return se; +} + +static int evaluate_seq_frame_gen(Sequence ** seq_arr, ListBase *seqbase, int cfra) +{ + Sequence *seq; + int totseq=0; + + memset(seq_arr, 0, sizeof(Sequence*) * (MAXSEQ+1)); + + seq= seqbase->first; + while(seq) { + if(seq->startdisp <=cfra && seq->enddisp > cfra) { + seq_arr[seq->machine]= seq; + totseq++; + } + seq= seq->next; + } + + return totseq; +} + +int evaluate_seq_frame(Scene *scene, int cfra) +{ + Editing *ed; + Sequence *seq_arr[MAXSEQ+1]; + + ed= scene->ed; + if(ed==NULL) return 0; + + return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra); + +} + +static int video_seq_is_rendered(Sequence * seq) +{ + return (seq + && !(seq->flag & SEQ_MUTE) + && seq->type != SEQ_RAM_SOUND + && seq->type != SEQ_HD_SOUND); +} + +static int get_shown_sequences( ListBase * seqbasep, int cfra, int chanshown, Sequence ** seq_arr_out) +{ + Sequence *seq_arr[MAXSEQ+1]; + int b = chanshown; + int cnt = 0; + + if (b > MAXSEQ) { + return 0; + } + + if(evaluate_seq_frame_gen(seq_arr, seqbasep, cfra)) { + if (b > 0) { + if (seq_arr[b] == 0) { + return 0; + } + } else { + for (b = MAXSEQ; b > 0; b--) { + if (video_seq_is_rendered(seq_arr[b])) { + break; + } + } + } + } + + chanshown = b; + + for (;b > 0; b--) { + if (video_seq_is_rendered(seq_arr[b])) { + if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) { + break; + } + } + } + + for (;b <= chanshown; b++) { + if (video_seq_is_rendered(seq_arr[b])) { + seq_arr_out[cnt++] = seq_arr[b]; + } + } + + return cnt; +} + + +/* ********************************************************************** + proxy management + ********************************************************************** */ + +#define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE) + +static int seq_proxy_get_fname(Scene *scene, Sequence * seq, int cfra, char * name) +{ + int frameno; + char dir[FILE_MAXDIR]; + + if (!seq->strip->proxy) { + return FALSE; + } + + if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) { + strcpy(dir, seq->strip->proxy->dir); + } else { + if (seq->type == SEQ_IMAGE || seq->type == SEQ_MOVIE) { + snprintf(dir, FILE_MAXDIR, "%s/BL_proxy", + seq->strip->dir); + } else { + return FALSE; + } + } + + /* generate a seperate proxy directory for each preview size */ + + if (seq->type == SEQ_IMAGE) { + StripElem * se = give_stripelem(seq, cfra); + snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", + dir, scene->r.size, se->name); + frameno = 1; + } else if (seq->type == SEQ_MOVIE) { + TStripElem * tse = give_tstripelem(seq, cfra); + + frameno = tse->nr + seq->anim_startofs; + + snprintf(name, PROXY_MAXFILE, "%s/%s/%d/####", dir, + seq->strip->stripdata->name, + scene->r.size); + } else { + TStripElem * tse = give_tstripelem(seq, cfra); + + frameno = tse->nr + seq->anim_startofs; + + snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, + scene->r.size); + } + + BLI_convertstringcode(name, G.sce); + BLI_convertstringframe(name, frameno); + + + strcat(name, ".jpg"); + + return TRUE; +} + +static struct ImBuf * seq_proxy_fetch(Scene *scene, Sequence * seq, int cfra) +{ + char name[PROXY_MAXFILE]; + + if (!(seq->flag & SEQ_USE_PROXY)) { + return 0; + } + + /* rendering at 100% ? No real sense in proxy-ing, right? */ + if (scene->r.size == 100.0) { + return 0; + } + + if (!seq_proxy_get_fname(scene, seq, cfra, name)) { + return 0; + } + + if (BLI_exists(name)) { + return IMB_loadiffname(name, IB_rect); + } else { + return 0; + } +} + +static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra, + int build_proxy_run); + +static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra) +{ + char name[PROXY_MAXFILE]; + int quality; + TStripElem * se; + int ok; + int rectx, recty; + struct ImBuf * ibuf; + + if (!(seq->flag & SEQ_USE_PROXY)) { + return; + } + + /* rendering at 100% ? No real sense in proxy-ing, right? */ + if (scene->r.size == 100.0) { + return; + } + + if (!seq_proxy_get_fname(scene, seq, cfra, name)) { + return; + } + + se = give_tstripelem(seq, cfra); + if (!se) { + return; + } + + if(se->ibuf) { + IMB_freeImBuf(se->ibuf); + se->ibuf = 0; + } + + do_build_seq_ibuf(scene, seq, se, cfra, TRUE); + + if (!se->ibuf) { + return; + } + + rectx= (scene->r.size*scene->r.xsch)/100; + recty= (scene->r.size*scene->r.ysch)/100; + + ibuf = se->ibuf; + + if (ibuf->x != rectx || ibuf->y != recty) { + IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty); + } + + /* quality is fixed, otherwise one has to generate seperate + directories for every quality... + + depth = 32 is intentionally left in, otherwise ALPHA channels + won't work... */ + quality = 90; + ibuf->ftype= JPG | quality; + + BLI_make_existing_file(name); + + ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat); + if (ok == 0) { + perror(name); + } + + IMB_freeImBuf(ibuf); + se->ibuf = 0; +} + +void seq_proxy_rebuild(Scene *scene, Sequence * seq) +{ + int cfra; + + waitcursor(1); + + G.afbreek = 0; + + /* flag management tries to account for strobe and + other "non-linearities", that might come in the future... + better way would be to "touch" the files, so that _really_ + no one is rebuild twice. + */ + + for (cfra = seq->startdisp; cfra < seq->enddisp; cfra++) { + TStripElem * tse = give_tstripelem(seq, cfra); + + tse->flag &= ~STRIPELEM_PREVIEW_DONE; + } + + /* a _lot_ faster for movie files, if we read frames in + sequential order */ + if (seq->flag & SEQ_REVERSE_FRAMES) { + for (cfra = seq->enddisp-seq->endstill-1; + cfra >= seq->startdisp + seq->startstill; cfra--) { + TStripElem * tse = give_tstripelem(seq, cfra); + + if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) { + seq_proxy_build_frame(scene, seq, cfra); + tse->flag |= STRIPELEM_PREVIEW_DONE; + } + if (blender_test_break()) { + break; + } + } + } else { + for (cfra = seq->startdisp + seq->startstill; + cfra < seq->enddisp - seq->endstill; cfra++) { + TStripElem * tse = give_tstripelem(seq, cfra); + + if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) { + seq_proxy_build_frame(scene, seq, cfra); + tse->flag |= STRIPELEM_PREVIEW_DONE; + } + if (blender_test_break()) { + break; + } + } + } + waitcursor(0); +} + + +/* ********************************************************************** + color balance + ********************************************************************** */ + +static StripColorBalance calc_cb(StripColorBalance * cb_) +{ + StripColorBalance cb = *cb_; + int c; + + if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) { + for (c = 0; c < 3; c++) { + cb.lift[c] = 1.0 - cb.lift[c]; + } + } else { + for (c = 0; c < 3; c++) { + cb.lift[c] = -(1.0 - cb.lift[c]); + } + } + if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) { + for (c = 0; c < 3; c++) { + if (cb.gain[c] != 0.0) { + cb.gain[c] = 1.0/cb.gain[c]; + } else { + cb.gain[c] = 1000000; /* should be enough :) */ + } + } + } + + if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) { + for (c = 0; c < 3; c++) { + if (cb.gamma[c] != 0.0) { + cb.gamma[c] = 1.0/cb.gamma[c]; + } else { + cb.gamma[c] = 1000000; /* should be enough :) */ + } + } + } + + return cb; +} + +static void make_cb_table_byte(float lift, float gain, float gamma, + unsigned char * table, float mul) +{ + int y; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v *= gain; + v += lift; + v = pow(v, gamma); + v *= mul; + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + table[y] = v * 255; + } + +} + +static void make_cb_table_float(float lift, float gain, float gamma, + float * table, float mul) +{ + int y; + + for (y = 0; y < 256; y++) { + float v = (float) y * 1.0 / 255.0; + v *= gain; + v += lift; + v = pow(v, gamma); + v *= mul; + table[y] = v; + } +} + +static void color_balance_byte_byte(Sequence * seq, TStripElem* se, float mul) +{ + unsigned char cb_tab[3][256]; + int c; + unsigned char * p = (unsigned char*) se->ibuf->rect; + unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y; + + StripColorBalance cb = calc_cb(seq->strip->color_balance); + + for (c = 0; c < 3; c++) { + make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c], + cb_tab[c], mul); + } + + while (p < e) { + p[0] = cb_tab[0][p[0]]; + p[1] = cb_tab[1][p[1]]; + p[2] = cb_tab[2][p[2]]; + + p += 4; + } +} + +static void color_balance_byte_float(Sequence * seq, TStripElem* se, float mul) +{ + float cb_tab[4][256]; + int c,i; + unsigned char * p = (unsigned char*) se->ibuf->rect; + unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y; + float * o; + StripColorBalance cb; + + imb_addrectfloatImBuf(se->ibuf); + + o = se->ibuf->rect_float; + + cb = calc_cb(seq->strip->color_balance); + + for (c = 0; c < 3; c++) { + make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], + cb_tab[c], mul); + } + + for (i = 0; i < 256; i++) { + cb_tab[3][i] = ((float)i)*(1.0f/255.0f); + } + + while (p < e) { + o[0] = cb_tab[0][p[0]]; + o[1] = cb_tab[1][p[1]]; + o[2] = cb_tab[2][p[2]]; + o[3] = cb_tab[3][p[3]]; + + p += 4; o += 4; + } +} + +static void color_balance_float_float(Sequence * seq, TStripElem* se, float mul) +{ + float * p = se->ibuf->rect_float; + float * e = se->ibuf->rect_float + se->ibuf->x * 4* se->ibuf->y; + StripColorBalance cb = calc_cb(seq->strip->color_balance); + + while (p < e) { + int c; + for (c = 0; c < 3; c++) { + p[c] = pow(p[c] * cb.gain[c] + cb.lift[c], + cb.gamma[c]) * mul; + } + p += 4; + } +} + +static void color_balance(Sequence * seq, TStripElem* se, float mul) +{ + if (se->ibuf->rect_float) { + color_balance_float_float(seq, se, mul); + } else if(seq->flag & SEQ_MAKE_FLOAT) { + color_balance_byte_float(seq, se, mul); + } else { + color_balance_byte_byte(seq, se, mul); + } +} + +/* + input preprocessing for SEQ_IMAGE, SEQ_MOVIE and SEQ_SCENE + + Do all the things you can't really do afterwards using sequence effects + (read: before rescaling to render resolution has been done) + + Order is important! + + - Deinterlace + - Crop and transform in image source coordinate space + - Flip X + Flip Y (could be done afterwards, backward compatibility) + - Promote image to float data (affects pipeline operations afterwards) + - Color balance (is most efficient in the byte -> float + (future: half -> float should also work fine!) + case, if done on load, since we can use lookup tables) + - Premultiply + +*/ + +static int input_have_to_preprocess(Scene *scene, Sequence * seq, TStripElem* se, int cfra) +{ + float mul; + + if ((seq->flag & SEQ_FILTERY) || + (seq->flag & SEQ_USE_CROP) || + (seq->flag & SEQ_USE_TRANSFORM) || + (seq->flag & SEQ_FLIPX) || + (seq->flag & SEQ_FLIPY) || + (seq->flag & SEQ_USE_COLOR_BALANCE) || + (seq->flag & SEQ_MAKE_PREMUL) || + (se->ibuf->x != seqrectx || se->ibuf->y != seqrecty)) { + return TRUE; + } + + mul = seq->mul; + + if(seq->blend_mode == SEQ_BLEND_REPLACE) { + if (seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + mul *= seq->facf0; + } + mul *= seq->blend_opacity / 100.0; + } + + if (mul != 1.0) { + return TRUE; + } + + return FALSE; +} + +static void input_preprocess(Scene *scene, Sequence *seq, TStripElem *se, int cfra) +{ + float mul; + + seq->strip->orx= se->ibuf->x; + seq->strip->ory= se->ibuf->y; + + if((seq->flag & SEQ_FILTERY) && seq->type != SEQ_MOVIE) { + IMB_filtery(se->ibuf); + } + + if(seq->flag & SEQ_USE_CROP || seq->flag & SEQ_USE_TRANSFORM) { + StripCrop c; + StripTransform t; + int sx,sy,dx,dy; + + memset(&c, 0, sizeof(StripCrop)); + memset(&t, 0, sizeof(StripTransform)); + + if(seq->flag & SEQ_USE_CROP && seq->strip->crop) { + c = *seq->strip->crop; + } + if(seq->flag & SEQ_USE_TRANSFORM && seq->strip->transform) { + t = *seq->strip->transform; + } + + sx = se->ibuf->x - c.left - c.right; + sy = se->ibuf->y - c.top - c.bottom; + dx = sx; + dy = sy; + + if (seq->flag & SEQ_USE_TRANSFORM) { + dx = scene->r.xsch; + dy = scene->r.ysch; + } + + if (c.top + c.bottom >= se->ibuf->y || + c.left + c.right >= se->ibuf->x || + t.xofs >= dx || t.yofs >= dy) { + make_black_ibuf(se->ibuf); + } else { + ImBuf * i; + + if (se->ibuf->rect_float) { + i = IMB_allocImBuf(dx, dy,32, IB_rectfloat, 0); + } else { + i = IMB_allocImBuf(dx, dy,32, IB_rect, 0); + } + + IMB_rectcpy(i, se->ibuf, + t.xofs, t.yofs, + c.left, c.bottom, + sx, sy); + + IMB_freeImBuf(se->ibuf); + + se->ibuf = i; + } + } + + if(seq->flag & SEQ_FLIPX) { + IMB_flipx(se->ibuf); + } + if(seq->flag & SEQ_FLIPY) { + IMB_flipy(se->ibuf); + } + + if(seq->mul == 0.0) { + seq->mul = 1.0; + } + + mul = seq->mul; + + if(seq->blend_mode == SEQ_BLEND_REPLACE) { + if (seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + mul *= seq->facf0; + } + mul *= seq->blend_opacity / 100.0; + } + + if(seq->flag & SEQ_USE_COLOR_BALANCE && seq->strip->color_balance) { + color_balance(seq, se, mul); + mul = 1.0; + } + + if(seq->flag & SEQ_MAKE_FLOAT) { + if (!se->ibuf->rect_float) { + IMB_float_from_rect(se->ibuf); + } + if (se->ibuf->rect) { + imb_freerectImBuf(se->ibuf); + } + } + + if(mul != 1.0) { + multibuf(se->ibuf, mul); + } + + if(seq->flag & SEQ_MAKE_PREMUL) { + if(se->ibuf->depth == 32 && se->ibuf->zbuf == 0) { + converttopremul(se->ibuf); + } + } + + + if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty ) { + if(scene->r.mode & R_OSA) { + IMB_scaleImBuf(se->ibuf, + (short)seqrectx, (short)seqrecty); + } else { + IMB_scalefastImBuf(se->ibuf, + (short)seqrectx, (short)seqrecty); + } + } +} + +/* test if image too small or discarded from cache: reload */ + +static void test_and_auto_discard_ibuf(TStripElem * se) +{ + if (se->ibuf) { + if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty + || !(se->ibuf->rect || se->ibuf->rect_float)) { + IMB_freeImBuf(se->ibuf); + + se->ibuf= 0; + se->ok= STRIPELEM_OK; + } + } + if (se->ibuf_comp) { + if(se->ibuf_comp->x != seqrectx || se->ibuf_comp->y != seqrecty + || !(se->ibuf_comp->rect || se->ibuf_comp->rect_float)) { + IMB_freeImBuf(se->ibuf_comp); + + se->ibuf_comp = 0; + } + } +} + +static void test_and_auto_discard_ibuf_stills(Strip * strip) +{ + if (strip->ibuf_startstill) { + if (!strip->ibuf_startstill->rect && + !strip->ibuf_startstill->rect_float) { + IMB_freeImBuf(strip->ibuf_startstill); + strip->ibuf_startstill = 0; + } + } + if (strip->ibuf_endstill) { + if (!strip->ibuf_endstill->rect && + !strip->ibuf_endstill->rect_float) { + IMB_freeImBuf(strip->ibuf_endstill); + strip->ibuf_endstill = 0; + } + } +} + +static void copy_from_ibuf_still(Sequence * seq, TStripElem * se) +{ + if (!se->ibuf) { + if (se->nr == 0 && seq->strip->ibuf_startstill) { + IMB_cache_limiter_touch(seq->strip->ibuf_startstill); + + se->ibuf = IMB_dupImBuf(seq->strip->ibuf_startstill); + } + if (se->nr == seq->len - 1 + && (seq->len != 1) + && seq->strip->ibuf_endstill) { + IMB_cache_limiter_touch(seq->strip->ibuf_endstill); + + se->ibuf = IMB_dupImBuf(seq->strip->ibuf_endstill); + } + } +} + +static void copy_to_ibuf_still(Sequence * seq, TStripElem * se) +{ + if (se->ibuf) { + if (se->nr == 0) { + seq->strip->ibuf_startstill = IMB_dupImBuf(se->ibuf); + + IMB_cache_limiter_insert(seq->strip->ibuf_startstill); + IMB_cache_limiter_touch(seq->strip->ibuf_startstill); + } + if (se->nr == seq->len - 1 && seq->len != 1) { + seq->strip->ibuf_endstill = IMB_dupImBuf(se->ibuf); + + IMB_cache_limiter_insert(seq->strip->ibuf_endstill); + IMB_cache_limiter_touch(seq->strip->ibuf_endstill); + } + } +} + +static void free_metastrip_imbufs(ListBase *seqbasep, int cfra, int chanshown) +{ + Sequence* seq_arr[MAXSEQ+1]; + int i; + TStripElem* se = 0; + + evaluate_seq_frame_gen(seq_arr, seqbasep, cfra); + + for (i = 0; i < MAXSEQ; i++) { + if (!video_seq_is_rendered(seq_arr[i])) { + continue; + } + se = give_tstripelem(seq_arr[i], cfra); + if (se) { + if (se->ibuf) { + IMB_freeImBuf(se->ibuf); + + se->ibuf= 0; + se->ok= STRIPELEM_OK; + } + + if (se->ibuf_comp) { + IMB_freeImBuf(se->ibuf_comp); + + se->ibuf_comp = 0; + } + } + } + +} + +static TStripElem* do_build_seq_array_recursively(Scene *scene, + ListBase *seqbasep, int cfra, int chanshown); + +static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra, + int build_proxy_run) +{ + char name[FILE_MAXDIR+FILE_MAXFILE]; + int use_limiter = TRUE; + + test_and_auto_discard_ibuf(se); + test_and_auto_discard_ibuf_stills(seq->strip); + + if(seq->type == SEQ_META) { + TStripElem * meta_se = 0; + use_limiter = FALSE; + + if (!build_proxy_run && se->ibuf == 0) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra); + if (se->ibuf) { + use_limiter = TRUE; + } + } + + if(!se->ibuf && seq->seqbase.first) { + meta_se = do_build_seq_array_recursively(scene, + &seq->seqbase, seq->start + se->nr, 0); + } + + se->ok = STRIPELEM_OK; + + if(!se->ibuf && meta_se) { + se->ibuf = meta_se->ibuf_comp; + if(se->ibuf && + (!input_have_to_preprocess(scene, seq, se, cfra) || + build_proxy_run)) { + IMB_refImBuf(se->ibuf); + if (build_proxy_run) { + IMB_cache_limiter_unref(se->ibuf); + } + } else if (se->ibuf) { + struct ImBuf * i = IMB_dupImBuf(se->ibuf); + + IMB_cache_limiter_unref(se->ibuf); + + se->ibuf = i; + + use_limiter = TRUE; + } + } + if (meta_se) { + free_metastrip_imbufs( + &seq->seqbase, seq->start + se->nr, 0); + } + + if (use_limiter) { + input_preprocess(scene, seq, se, cfra); + } + } else if(seq->type & SEQ_EFFECT) { + /* should the effect be recalculated? */ + + if (!build_proxy_run && se->ibuf == 0) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra); + } + + if(se->ibuf == 0) { + /* if any inputs are rectfloat, output is float too */ + if((se->se1 && se->se1->ibuf && se->se1->ibuf->rect_float) || + (se->se2 && se->se2->ibuf && se->se2->ibuf->rect_float) || + (se->se3 && se->se3->ibuf && se->se3->ibuf->rect_float)) + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); + else + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); + + do_effect(scene, cfra, seq, se); + } + } else if(seq->type == SEQ_IMAGE) { + if(se->ok == STRIPELEM_OK && se->ibuf == 0) { + StripElem * s_elem = give_stripelem(seq, cfra); + BLI_join_dirfile(name, seq->strip->dir, s_elem->name); + BLI_convertstringcode(name, G.sce); + BLI_convertstringframe(name, scene->r.cfra); + if (!build_proxy_run) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra); + } + copy_from_ibuf_still(seq, se); + + if (!se->ibuf) { + se->ibuf= IMB_loadiffname( + name, IB_rect); + copy_to_ibuf_still(seq, se); + } + + if(se->ibuf == 0) { + se->ok = STRIPELEM_FAILED; + } else if (!build_proxy_run) { + input_preprocess(scene, seq, se, cfra); + } + } + } else if(seq->type == SEQ_MOVIE) { + if(se->ok == STRIPELEM_OK && se->ibuf==0) { + if(!build_proxy_run) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra); + } + copy_from_ibuf_still(seq, se); + + if (se->ibuf == 0) { + if(seq->anim==0) { + BLI_join_dirfile(name, seq->strip->dir, seq->strip->stripdata->name); + BLI_convertstringcode(name, G.sce); + BLI_convertstringframe(name, scene->r.cfra); + + seq->anim = openanim( + name, IB_rect | + ((seq->flag & SEQ_FILTERY) + ? IB_animdeinterlace : 0)); + } + if(seq->anim) { + IMB_anim_set_preseek(seq->anim, seq->anim_preseek); + se->ibuf = IMB_anim_absolute(seq->anim, se->nr + seq->anim_startofs); + } + copy_to_ibuf_still(seq, se); + } + + if(se->ibuf == 0) { + se->ok = STRIPELEM_FAILED; + } else if (!build_proxy_run) { + input_preprocess(scene, seq, se, cfra); + } + } + } else if(seq->type == SEQ_SCENE) { // scene can be NULL after deletions +#if 0 + /* XXX move entirely to render? */ + int oldcfra = CFRA; + Sequence * oldseq = get_last_seq(); + Scene *sce= seq->scene, *oldsce= scene; + Render *re; + RenderResult rres; + int doseq, rendering= G.rendering; + char scenename[64]; + int sce_valid =sce&& (sce->camera || sce->r.scemode & R_DOSEQ); + + if (se->ibuf == NULL && sce_valid && !build_proxy_run) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra); + if (se->ibuf) { + input_preprocess(scene, seq, se, cfra); + } + } + + if (se->ibuf == NULL && sce_valid) { + copy_from_ibuf_still(seq, se); + if (se->ibuf) { + input_preprocess(scene, seq, se, cfra); + } + } + + if (!sce_valid) { + se->ok = STRIPELEM_FAILED; + } else if (se->ibuf==NULL && sce_valid) { + waitcursor(1); + + /* Hack! This function can be called from do_render_seq(), in that case + the seq->scene can already have a Render initialized with same name, + so we have to use a default name. (compositor uses scene name to + find render). + However, when called from within the UI (image preview in sequencer) + we do want to use scene Render, that way the render result is defined + for display in render/imagewindow */ + if(rendering) { + BLI_strncpy(scenename, sce->id.name+2, 64); + strcpy(sce->id.name+2, " do_build_seq_ibuf"); + } + re= RE_NewRender(sce->id.name); + + /* prevent eternal loop */ + doseq= scene->r.scemode & R_DOSEQ; + scene->r.scemode &= ~R_DOSEQ; + + BIF_init_render_callbacks(re, 0); /* 0= no display callbacks */ + + /* XXX hrms, set_scene still needed? work on that... */ + if(sce!=oldsce) set_scene_bg(sce); + RE_BlenderFrame(re, sce, + seq->sfra+se->nr+seq->anim_startofs); + if(sce!=oldsce) set_scene_bg(oldsce); + + /* UGLY WARNING, it is set to zero in RE_BlenderFrame */ + G.rendering= rendering; + if(rendering) + BLI_strncpy(sce->id.name+2, scenename, 64); + + RE_GetResultImage(re, &rres); + + if(rres.rectf) { + se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat, 0); + memcpy(se->ibuf->rect_float, rres.rectf, 4*sizeof(float)*rres.rectx*rres.recty); + if(rres.rectz) { + addzbuffloatImBuf(se->ibuf); + memcpy(se->ibuf->zbuf_float, rres.rectz, sizeof(float)*rres.rectx*rres.recty); + } + } else if (rres.rect32) { + se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect, 0); + memcpy(se->ibuf->rect, rres.rect32, 4*rres.rectx*rres.recty); + } + + BIF_end_render_callbacks(); + + /* restore */ + scene->r.scemode |= doseq; + + CFRA = oldcfra; + set_last_seq(oldseq); + + copy_to_ibuf_still(seq, se); + + if (!build_proxy_run) { + if(se->ibuf == NULL) { + se->ok = STRIPELEM_FAILED; + } else { + input_preprocess(scene, seq, se, cfra); + } + } + + } +#endif + } + if (!build_proxy_run) { + if (se->ibuf && use_limiter) { + IMB_cache_limiter_insert(se->ibuf); + IMB_cache_limiter_ref(se->ibuf); + IMB_cache_limiter_touch(se->ibuf); + } + } +} + +static TStripElem* do_build_seq_recursively(Scene *scene, Sequence *seq, int cfra); + +static void do_effect_seq_recursively(Scene *scene, Sequence *seq, TStripElem *se, int cfra) +{ + float fac, facf; + struct SeqEffectHandle sh = get_sequence_effect(seq); + int early_out; + + se->se1 = 0; + se->se2 = 0; + se->se3 = 0; + + if(seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + fac= seq->facf0; + facf= seq->facf1; + } else { + sh.get_default_fac(seq, cfra, &fac, &facf); + } + + if( scene->r.mode & R_FIELDS ); else facf= fac; + + early_out = sh.early_out(seq, fac, facf); + switch (early_out) { + case -1: + /* no input needed */ + break; + case 0: + se->se1 = do_build_seq_recursively(scene, seq->seq1, cfra); + se->se2 = do_build_seq_recursively(scene, seq->seq2, cfra); + if (seq->seq3) { + se->se3 = do_build_seq_recursively(scene, seq->seq3, cfra); + } + break; + case 1: + se->se1 = do_build_seq_recursively(scene, seq->seq1, cfra); + break; + case 2: + se->se2 = do_build_seq_recursively(scene, seq->seq2, cfra); + break; + } + + + do_build_seq_ibuf(scene, seq, se, cfra, FALSE); + + /* children are not needed anymore ... */ + + if (se->se1 && se->se1->ibuf) { + IMB_cache_limiter_unref(se->se1->ibuf); + } + if (se->se2 && se->se2->ibuf) { + IMB_cache_limiter_unref(se->se2->ibuf); + } + if (se->se3 && se->se3->ibuf) { + IMB_cache_limiter_unref(se->se3->ibuf); + } +} + +static TStripElem* do_build_seq_recursively_impl(Scene *scene, Sequence * seq, int cfra) +{ + TStripElem *se; + + se = give_tstripelem(seq, cfra); + + if(se) { + if (seq->type & SEQ_EFFECT) { + do_effect_seq_recursively(scene, seq, se, cfra); + } else { + do_build_seq_ibuf(scene, seq, se, cfra, FALSE); + } + } + return se; +} + +/* FIXME: + +If cfra was float throughout blender (especially in the render +pipeline) one could even _render_ with subframe precision +instead of faking using the blend code below... + +*/ + +static TStripElem* do_handle_speed_effect(Scene *scene, Sequence * seq, int cfra) +{ + SpeedControlVars * s = (SpeedControlVars *)seq->effectdata; + int nr = cfra - seq->start; + float f_cfra; + int cfra_left; + int cfra_right; + TStripElem * se = 0; + TStripElem * se1 = 0; + TStripElem * se2 = 0; + + sequence_effect_speed_rebuild_map(scene, seq, 0); + + f_cfra = seq->start + s->frameMap[nr]; + + cfra_left = (int) floor(f_cfra); + cfra_right = (int) ceil(f_cfra); + + se = give_tstripelem(seq, cfra); + + if (!se) { + return se; + } + + if (cfra_left == cfra_right || + (s->flags & SEQ_SPEED_BLEND) == 0) { + test_and_auto_discard_ibuf(se); + + if (se->ibuf == NULL) { + se1 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_left); + + if((se1 && se1->ibuf && se1->ibuf->rect_float)) + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); + else + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); + + if (se1 == 0 || se1->ibuf == 0) { + make_black_ibuf(se->ibuf); + } else { + if (se->ibuf != se1->ibuf) { + if (se->ibuf) { + IMB_freeImBuf(se->ibuf); + } + + se->ibuf = se1->ibuf; + IMB_refImBuf(se->ibuf); + } + } + } + } else { + struct SeqEffectHandle sh; + + if(se->ibuf) { + if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty + || !(se->ibuf->rect || se->ibuf->rect_float)) { + IMB_freeImBuf(se->ibuf); + se->ibuf= 0; + } + } + + if (se->ibuf == NULL) { + se1 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_left); + se2 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_right); + + if((se1 && se1->ibuf && se1->ibuf->rect_float)) + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); + else + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); + + if (!se1 || !se2) { + make_black_ibuf(se->ibuf); + } else { + sh = get_sequence_effect(seq); + + sh.execute(seq, cfra, + f_cfra - (float) cfra_left, + f_cfra - (float) cfra_left, + se->ibuf->x, se->ibuf->y, + se1->ibuf, se2->ibuf, 0, se->ibuf); + } + } + + } + + /* caller expects this to be referenced, so do it! */ + if (se->ibuf) { + IMB_cache_limiter_insert(se->ibuf); + IMB_cache_limiter_ref(se->ibuf); + IMB_cache_limiter_touch(se->ibuf); + } + + /* children are no longer needed */ + if (se1 && se1->ibuf) + IMB_cache_limiter_unref(se1->ibuf); + if (se2 && se2->ibuf) + IMB_cache_limiter_unref(se2->ibuf); + + return se; +} + +/* + * build all ibufs recursively + * + * if successfull, the returned TStripElem contains the (referenced!) imbuf + * that means: you _must_ call + * + * IMB_cache_limiter_unref(rval); + * + * if rval != 0 + * + */ + +static TStripElem* do_build_seq_recursively(Scene *scene, Sequence * seq, int cfra) +{ + if (seq->type == SEQ_SPEED) { + return do_handle_speed_effect(scene, seq, cfra); + } else { + return do_build_seq_recursively_impl(scene, seq, cfra); + } +} + +static TStripElem* do_build_seq_array_recursively(Scene *scene, + ListBase *seqbasep, int cfra, int chanshown) +{ + Sequence* seq_arr[MAXSEQ+1]; + int count; + int i; + TStripElem* se = 0; + + count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr); + + if (!count) { + return 0; + } + + se = give_tstripelem(seq_arr[count - 1], cfra); + + if (!se) { + return 0; + } + + test_and_auto_discard_ibuf(se); + + if (se->ibuf_comp != 0) { + IMB_cache_limiter_insert(se->ibuf_comp); + IMB_cache_limiter_ref(se->ibuf_comp); + IMB_cache_limiter_touch(se->ibuf_comp); + return se; + } + + + if(count == 1) { + se = do_build_seq_recursively(scene, seq_arr[0], cfra); + if (se->ibuf) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf_comp); + } + return se; + } + + + for (i = count - 1; i >= 0; i--) { + int early_out; + Sequence * seq = seq_arr[i]; + struct SeqEffectHandle sh; + + se = give_tstripelem(seq, cfra); + + test_and_auto_discard_ibuf(se); + + if (se->ibuf_comp != 0) { + break; + } + if (seq->blend_mode == SEQ_BLEND_REPLACE) { + do_build_seq_recursively(scene, seq, cfra); + if (se->ibuf) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf); + } else { + se->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + } + break; + } + + sh = get_sequence_blend(seq); + + seq->facf0 = seq->facf1 = 1.0; + + if(seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + } + + if( scene->r.mode & R_FIELDS ); else seq->facf0 = seq->facf1; + + seq->facf0 *= seq->blend_opacity / 100.0; + seq->facf1 *= seq->blend_opacity / 100.0; + + early_out = sh.early_out(seq, seq->facf0, seq->facf1); + + switch (early_out) { + case -1: + case 2: + do_build_seq_recursively(scene, seq, cfra); + if (se->ibuf) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf_comp); + } else { + se->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + } + break; + case 1: + if (i == 0) { + se->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + IMB_cache_limiter_insert(se->ibuf_comp); + IMB_cache_limiter_ref(se->ibuf_comp); + IMB_cache_limiter_touch(se->ibuf_comp); + } + break; + case 0: + do_build_seq_recursively(scene, seq, cfra); + if (!se->ibuf) { + se->ibuf = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + } + if (i == 0) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf_comp); + } + break; + } + + if (se->ibuf_comp) { + break; + } + } + + i++; + + for (; i < count; i++) { + Sequence * seq = seq_arr[i]; + struct SeqEffectHandle sh = get_sequence_blend(seq); + TStripElem* se1 = give_tstripelem(seq_arr[i-1], cfra); + TStripElem* se2 = give_tstripelem(seq_arr[i], cfra); + + int early_out = sh.early_out(seq, seq->facf0, seq->facf1); + switch (early_out) { + case 0: { + int x= se2->ibuf->x; + int y= se2->ibuf->y; + int swap_input = FALSE; + + if (se1->ibuf_comp->rect_float || + se2->ibuf->rect_float) { + se2->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rectfloat, 0); + } else { + se2->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + } + + + if (!se1->ibuf_comp->rect_float && + se2->ibuf_comp->rect_float) { + IMB_float_from_rect(se1->ibuf_comp); + } + if (!se2->ibuf->rect_float && + se2->ibuf_comp->rect_float) { + IMB_float_from_rect(se2->ibuf); + } + + if (!se1->ibuf_comp->rect && + !se2->ibuf_comp->rect_float) { + IMB_rect_from_float(se1->ibuf_comp); + } + if (!se2->ibuf->rect && + !se2->ibuf_comp->rect_float) { + IMB_rect_from_float(se2->ibuf); + } + + /* bad hack, to fix crazy input ordering of + those two effects */ + + if (seq->blend_mode == SEQ_ALPHAOVER || + seq->blend_mode == SEQ_ALPHAUNDER || + seq->blend_mode == SEQ_OVERDROP) { + swap_input = TRUE; + } + + if (swap_input) { + sh.execute(seq, cfra, + seq->facf0, seq->facf1, x, y, + se2->ibuf, se1->ibuf_comp, 0, + se2->ibuf_comp); + } else { + sh.execute(seq, cfra, + seq->facf0, seq->facf1, x, y, + se1->ibuf_comp, se2->ibuf, 0, + se2->ibuf_comp); + } + + IMB_cache_limiter_insert(se2->ibuf_comp); + IMB_cache_limiter_ref(se2->ibuf_comp); + IMB_cache_limiter_touch(se2->ibuf_comp); + + IMB_cache_limiter_unref(se1->ibuf_comp); + IMB_cache_limiter_unref(se2->ibuf); + + break; + } + case 1: { + se2->ibuf_comp = se1->ibuf; + IMB_refImBuf(se2->ibuf_comp); + + break; + } + } + se = se2; + } + + return se; +} + +/* + * returned ImBuf is refed! + * you have to unref after usage! + */ + +static ImBuf *give_ibuf_seq_impl(Scene *scene, int rectx, int recty, int cfra, int chanshown) +{ + Editing *ed; + int count; + ListBase *seqbasep; + TStripElem *se; + + ed= scene->ed; + if(ed==NULL) return NULL; + + count = BLI_countlist(&ed->metastack); + if((chanshown < 0) && (count > 0)) { + count = MAX2(count + chanshown, 0); + seqbasep= ((MetaStack*)BLI_findlink(&ed->metastack, count))->oldbasep; + } else { + seqbasep= ed->seqbasep; + } + + seqrectx= rectx; /* bad bad global! */ + seqrecty= recty; + + se = do_build_seq_array_recursively(scene, seqbasep, cfra, chanshown); + + if(!se) { + return 0; + } + + return se->ibuf_comp; +} + +ImBuf *give_ibuf_seq_direct(Scene *scene, int rectx, int recty, int cfra, Sequence *seq) +{ + TStripElem* se; + + seqrectx= rectx; /* bad bad global! */ + seqrecty= recty; + + se = do_build_seq_recursively(scene, seq, cfra); + + if(!se) { + return 0; + } + + if (se->ibuf) { + IMB_cache_limiter_unref(se->ibuf); + } + + return se->ibuf; +} + +ImBuf *give_ibuf_seq(Scene *scene, int rectx, int recty, int cfra, int chanshown) +{ + ImBuf* i = give_ibuf_seq_impl(scene, rectx, recty, cfra, chanshown); + + if (i) { + IMB_cache_limiter_unref(i); + } + return i; +} + +/* check used when we need to change seq->blend_mode but not to effect or audio strips */ +int seq_can_blend(Sequence *seq) +{ + if (ELEM4(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE)) { + return 1; + } else { + return 0; + } +} + +/* *********************** threading api ******************* */ + +static ListBase running_threads; +static ListBase prefetch_wait; +static ListBase prefetch_done; + +static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t wakeup_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t wakeup_cond = PTHREAD_COND_INITIALIZER; + +static pthread_mutex_t prefetch_ready_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t prefetch_ready_cond = PTHREAD_COND_INITIALIZER; + +static pthread_mutex_t frame_done_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t frame_done_cond = PTHREAD_COND_INITIALIZER; + +static volatile int seq_thread_shutdown = FALSE; +static volatile int seq_last_given_monoton_cfra = 0; +static int monoton_cfra = 0; + +typedef struct PrefetchThread { + struct PrefetchThread *next, *prev; + + Scene *scene; + struct PrefetchQueueElem *current; + pthread_t pthread; + int running; + +} PrefetchThread; + +typedef struct PrefetchQueueElem { + struct PrefetchQueueElem *next, *prev; + + int rectx; + int recty; + int cfra; + int chanshown; + + int monoton_cfra; + + struct ImBuf * ibuf; +} PrefetchQueueElem; + +static void *seq_prefetch_thread(void * This_) +{ + PrefetchThread * This = This_; + + while (!seq_thread_shutdown) { + PrefetchQueueElem *e; + int s_last; + + pthread_mutex_lock(&queue_lock); + e = prefetch_wait.first; + if (e) { + BLI_remlink(&prefetch_wait, e); + } + s_last = seq_last_given_monoton_cfra; + + This->current = e; + + pthread_mutex_unlock(&queue_lock); + + if (!e) { + pthread_mutex_lock(&prefetch_ready_lock); + + This->running = FALSE; + + pthread_cond_signal(&prefetch_ready_cond); + pthread_mutex_unlock(&prefetch_ready_lock); + + pthread_mutex_lock(&wakeup_lock); + if (!seq_thread_shutdown) { + pthread_cond_wait(&wakeup_cond, &wakeup_lock); + } + pthread_mutex_unlock(&wakeup_lock); + continue; + } + + This->running = TRUE; + + if (e->cfra >= s_last) { + e->ibuf = give_ibuf_seq_impl(This->scene, + e->rectx, e->recty, e->cfra, e->chanshown); + } + + pthread_mutex_lock(&queue_lock); + + BLI_addtail(&prefetch_done, e); + + for (e = prefetch_wait.first; e; e = e->next) { + if (s_last > e->monoton_cfra) { + BLI_remlink(&prefetch_wait, e); + MEM_freeN(e); + } + } + + for (e = prefetch_done.first; e; e = e->next) { + if (s_last > e->monoton_cfra) { + if (e->ibuf) { + IMB_cache_limiter_unref(e->ibuf); + } + BLI_remlink(&prefetch_done, e); + MEM_freeN(e); + } + } + + pthread_mutex_unlock(&queue_lock); + + pthread_mutex_lock(&frame_done_lock); + pthread_cond_signal(&frame_done_cond); + pthread_mutex_unlock(&frame_done_lock); + } + return 0; +} + +void seq_start_threads(Scene *scene) +{ + int i; + + running_threads.first = running_threads.last = NULL; + prefetch_wait.first = prefetch_wait.last = NULL; + prefetch_done.first = prefetch_done.last = NULL; + + seq_thread_shutdown = FALSE; + seq_last_given_monoton_cfra = monoton_cfra = 0; + + /* since global structures are modified during the processing + of one frame, only one render thread is currently possible... + + (but we code, in the hope, that we can remove this restriction + soon...) + */ + + fprintf(stderr, "SEQ-THREAD: seq_start_threads\n"); + + for (i = 0; i < 1; i++) { + PrefetchThread *t = MEM_callocN(sizeof(PrefetchThread), "prefetch_thread"); + t->scene= scene; + t->running = TRUE; + BLI_addtail(&running_threads, t); + + pthread_create(&t->pthread, NULL, seq_prefetch_thread, t); + } + + /* init malloc mutex */ + BLI_init_threads(0, 0, 0); +} + +void seq_stop_threads() +{ + PrefetchThread *tslot; + PrefetchQueueElem *e; + + fprintf(stderr, "SEQ-THREAD: seq_stop_threads()\n"); + + if (seq_thread_shutdown) { + fprintf(stderr, "SEQ-THREAD: ... already stopped\n"); + return; + } + + pthread_mutex_lock(&wakeup_lock); + + seq_thread_shutdown = TRUE; + + pthread_cond_broadcast(&wakeup_cond); + pthread_mutex_unlock(&wakeup_lock); + + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + pthread_join(tslot->pthread, NULL); + } + + + for (e = prefetch_wait.first; e; e = e->next) { + BLI_remlink(&prefetch_wait, e); + MEM_freeN(e); + } + + for (e = prefetch_done.first; e; e = e->next) { + if (e->ibuf) { + IMB_cache_limiter_unref(e->ibuf); + } + BLI_remlink(&prefetch_done, e); + MEM_freeN(e); + } + + BLI_freelistN(&running_threads); + + /* deinit malloc mutex */ + BLI_end_threads(0); +} + +void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown) +{ + PrefetchQueueElem *e; + if (seq_thread_shutdown) { + return; + } + + e = MEM_callocN(sizeof(PrefetchQueueElem), "prefetch_queue_elem"); + e->rectx = rectx; + e->recty = recty; + e->cfra = cfra; + e->chanshown = chanshown; + e->monoton_cfra = monoton_cfra++; + + pthread_mutex_lock(&queue_lock); + BLI_addtail(&prefetch_wait, e); + pthread_mutex_unlock(&queue_lock); + + pthread_mutex_lock(&wakeup_lock); + pthread_cond_signal(&wakeup_cond); + pthread_mutex_unlock(&wakeup_lock); +} + +void seq_wait_for_prefetch_ready() +{ + PrefetchThread *tslot; + + if (seq_thread_shutdown) { + return; + } + + fprintf(stderr, "SEQ-THREAD: rendering prefetch frames...\n"); + + pthread_mutex_lock(&prefetch_ready_lock); + + for(;;) { + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + if (tslot->running) { + break; + } + } + if (!tslot) { + break; + } + pthread_cond_wait(&prefetch_ready_cond, &prefetch_ready_lock); + } + + pthread_mutex_unlock(&prefetch_ready_lock); + + fprintf(stderr, "SEQ-THREAD: prefetch done\n"); +} + +ImBuf *give_ibuf_seq_threaded(Scene *scene, int rectx, int recty, int cfra, int chanshown) +{ + PrefetchQueueElem *e = NULL; + int found_something = FALSE; + + if (seq_thread_shutdown) { + return give_ibuf_seq(scene, rectx, recty, cfra, chanshown); + } + + while (!e) { + int success = FALSE; + pthread_mutex_lock(&queue_lock); + + for (e = prefetch_done.first; e; e = e->next) { + if (cfra == e->cfra && + chanshown == e->chanshown && + rectx == e->rectx && + recty == e->recty) { + success = TRUE; + found_something = TRUE; + break; + } + } + + if (!e) { + for (e = prefetch_wait.first; e; e = e->next) { + if (cfra == e->cfra && + chanshown == e->chanshown && + rectx == e->rectx && + recty == e->recty) { + found_something = TRUE; + break; + } + } + } + + if (!e) { + PrefetchThread *tslot; + + for(tslot = running_threads.first; + tslot; tslot= tslot->next) { + if (tslot->current && + cfra == tslot->current->cfra && + chanshown == tslot->current->chanshown && + rectx == tslot->current->rectx && + recty == tslot->current->recty) { + found_something = TRUE; + break; + } + } + } + + /* e->ibuf is unrefed by render thread on next round. */ + + if (e) { + seq_last_given_monoton_cfra = e->monoton_cfra; + } + + pthread_mutex_unlock(&queue_lock); + + if (!success) { + e = NULL; + + if (!found_something) { + fprintf(stderr, + "SEQ-THREAD: Requested frame " + "not in queue ???\n"); + break; + } + pthread_mutex_lock(&frame_done_lock); + pthread_cond_wait(&frame_done_cond, &frame_done_lock); + pthread_mutex_unlock(&frame_done_lock); + } + } + + return e ? e->ibuf : 0; +} + +/* Functions to free imbuf and anim data on changes */ + +static void free_imbuf_strip_elem(TStripElem *se) +{ + if(se->ibuf) { + IMB_freeImBuf(se->ibuf); + } + if(se->ibuf_comp) { + IMB_freeImBuf(se->ibuf_comp); + } + se->ibuf_comp = 0; + se->ibuf= 0; + se->ok= STRIPELEM_OK; + se->se1= se->se2= se->se3= 0; +} + +static void free_anim_seq(Sequence *seq) +{ + if(seq->anim) { + IMB_free_anim(seq->anim); + seq->anim = 0; + } +} + +void free_imbuf_seq_except(Scene *scene, int cfra) +{ + Editing *ed= scene->ed; + Sequence *seq; + TStripElem *se; + int a; + + if(ed==NULL) return; + + SEQ_BEGIN(ed, seq) { + if(seq->strip) { + TStripElem * curelem = give_tstripelem(seq, cfra); + + for(a = 0, se = seq->strip->tstripdata; + a < seq->strip->len && se; a++, se++) { + if(se != curelem) { + free_imbuf_strip_elem(se); + } + } + for(a = 0, se = seq->strip->tstripdata_startstill; + a < seq->strip->startstill && se; a++, se++) { + if(se != curelem) { + free_imbuf_strip_elem(se); + } + } + for(a = 0, se = seq->strip->tstripdata_endstill; + a < seq->strip->endstill && se; a++, se++) { + if(se != curelem) { + free_imbuf_strip_elem(se); + } + } + if(seq->strip->ibuf_startstill) { + IMB_freeImBuf(seq->strip->ibuf_startstill); + seq->strip->ibuf_startstill = 0; + } + + if(seq->strip->ibuf_endstill) { + IMB_freeImBuf(seq->strip->ibuf_endstill); + seq->strip->ibuf_endstill = 0; + } + + if(seq->type==SEQ_MOVIE) + if(seq->startdisp > cfra || seq->enddisp < cfra) + free_anim_seq(seq); + } + } + SEQ_END +} + +void free_imbuf_seq(Scene *scene) +{ + Editing *ed= scene->ed; + Sequence *seq; + TStripElem *se; + int a; + + if(ed==NULL) return; + + SEQ_BEGIN(ed, seq) { + if(seq->strip) { + for(a = 0, se = seq->strip->tstripdata; + a < seq->strip->len && se; a++, se++) { + free_imbuf_strip_elem(se); + } + for(a = 0, se = seq->strip->tstripdata_startstill; + a < seq->strip->startstill && se; a++, se++) { + free_imbuf_strip_elem(se); + } + for(a = 0, se = seq->strip->tstripdata_endstill; + a < seq->strip->endstill && se; a++, se++) { + free_imbuf_strip_elem(se); + } + if(seq->strip->ibuf_startstill) { + IMB_freeImBuf(seq->strip->ibuf_startstill); + seq->strip->ibuf_startstill = 0; + } + + if(seq->strip->ibuf_endstill) { + IMB_freeImBuf(seq->strip->ibuf_endstill); + seq->strip->ibuf_endstill = 0; + } + + if(seq->type==SEQ_MOVIE) + free_anim_seq(seq); + if(seq->type==SEQ_SPEED) { + sequence_effect_speed_rebuild_map(scene, seq, 1); + } + } + } + SEQ_END +} + +static int update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change) +{ + Sequence *subseq; + int a, free_imbuf = 0; + TStripElem *se; + + /* recurs downwards to see if this seq depends on the changed seq */ + + if(seq == NULL) + return 0; + + if(seq == changed_seq) + free_imbuf = 1; + + for(subseq=seq->seqbase.first; subseq; subseq=subseq->next) + if(update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + + if(seq->seq1) + if(update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + if(seq->seq2 && (seq->seq2 != seq->seq1)) + if(update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + if(seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) + if(update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + + if(free_imbuf) { + if(ibuf_change) { + se= seq->strip->tstripdata; + if (se) { + for(a=0; alen; a++, se++) + free_imbuf_strip_elem(se); + } + + if(seq->type == SEQ_MOVIE) + free_anim_seq(seq); + if(seq->type == SEQ_SPEED) { + sequence_effect_speed_rebuild_map(scene, seq, 1); + } + } + + if(len_change) + calc_sequence(seq); + } + + return free_imbuf; +} + +void update_changed_seq_and_deps(Scene *scene, Sequence *changed_seq, int len_change, int ibuf_change) +{ + Editing *ed= scene->ed; + Sequence *seq; + + if (!ed) return; + + for (seq=ed->seqbase.first; seq; seq=seq->next) + update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change); +} + +void free_imbuf_seq_with_ipo(Scene *scene, struct Ipo *ipo) +{ + /* force update of all sequences with this ipo, on ipo changes */ + Editing *ed= scene->ed; + Sequence *seq; + + if(ed==NULL) return; + + SEQ_BEGIN(ed, seq) { + if(seq->ipo == ipo) { + update_changed_seq_and_deps(scene, seq, 0, 1); + if(seq->type == SEQ_SPEED) { + sequence_effect_speed_rebuild_map(scene, seq, 1); + } + } + } + SEQ_END +} + +#if 0 +/* bad levell call... */ +void do_render_seq(RenderResult *rr, int cfra) +{ + ImBuf *ibuf; + + ibuf= give_ibuf_seq(scene, rr->rectx, rr->recty, cfra, 0); + + if(ibuf) { + if(ibuf->rect_float) { + if (!rr->rectf) + rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf"); + + memcpy(rr->rectf, ibuf->rect_float, 4*sizeof(float)*rr->rectx*rr->recty); + + /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 + can hang around when sequence render has rendered a 32 bits one before */ + if(rr->rect32) { + MEM_freeN(rr->rect32); + rr->rect32= NULL; + } + } + else if(ibuf->rect) { + if (!rr->rect32) + rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect"); + + memcpy(rr->rect32, ibuf->rect, 4*rr->rectx*rr->recty); + + /* if (ibuf->zbuf) { */ + /* if (R.rectz) freeN(R.rectz); */ + /* R.rectz = BLI_dupallocN(ibuf->zbuf); */ + /* } */ + } + + /* Let the cache limitor take care of this (schlaile) */ + /* While render let's keep all memory available for render + (ton) + At least if free memory is tight... + This can make a big difference in encoding speed + (it is around 4 times(!) faster, if we do not waste time + on freeing _all_ buffers every time on long timelines...) + (schlaile) + */ + { + uintptr_t mem_in_use; + uintptr_t mmap_in_use; + uintptr_t max; + + mem_in_use= MEM_get_memory_in_use(); + mmap_in_use= MEM_get_mapped_memory_in_use(); + max = MEM_CacheLimiter_get_maximum(); + + if (max != 0 && mem_in_use + mmap_in_use > max) { + fprintf(stderr, "Memory in use > maximum memory\n"); + fprintf(stderr, "Cleaning up, please wait...\n" + "If this happens very often,\n" + "consider " + "raising the memcache limit in the " + "user preferences.\n"); + free_imbuf_seq(); + } + } + } + else { + /* render result is delivered empty in most cases, nevertheless we handle all cases */ + if (rr->rectf) + memset(rr->rectf, 0, 4*sizeof(float)*rr->rectx*rr->recty); + else if (rr->rect32) + memset(rr->rect32, 0, 4*rr->rectx*rr->recty); + else + rr->rect32= MEM_callocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect"); + } +} +#endif diff --git a/source/blender/blenlib/intern/bpath.c b/source/blender/blenlib/intern/bpath.c index a18efb09515..5c8eb5d2aa0 100644 --- a/source/blender/blenlib/intern/bpath.c +++ b/source/blender/blenlib/intern/bpath.c @@ -218,7 +218,7 @@ static struct Sequence *seq_stepdata__internal(struct BPathIterator *bpi, int st if (bpi->seqdata.scene->ed) { if (bpi->seqdata.seqar == NULL) { /* allocate the sequencer array */ - seq_array(bpi->seqdata.scene->ed, &bpi->seqdata.seqar, &bpi->seqdata.totseq); + seq_array(bpi->seqdata.scene->ed, &bpi->seqdata.seqar, &bpi->seqdata.totseq, 0); bpi->seqdata.seq = 0; } diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index b412641284d..daca401ab50 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1522,9 +1522,11 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v fac += 0.5f * dfac; /* draw vertical steps */ - for (; fac < vert.ymax; fac+= dfac, val += grid->dy) { - scroll_printstr(vs, scene, (float)(vert.xmax)-14.0f, fac, val, grid->powery, vs->yunits, 'v'); - } + if (dfac != 0.0f) { + for (; fac < vert.ymax; fac+= dfac, val += grid->dy) { + scroll_printstr(vs, scene, (float)(vert.xmax)-14.0f, fac, val, grid->powery, vs->yunits, 'v'); + } + } } /* decoration outer bevel line */ diff --git a/source/blender/editors/space_sequencer/Makefile b/source/blender/editors/space_sequencer/Makefile index f6f837a107a..052e191cb7d 100644 --- a/source/blender/editors/space_sequencer/Makefile +++ b/source/blender/editors/space_sequencer/Makefile @@ -38,6 +38,8 @@ CFLAGS += $(LEVEL_1_C_WARNINGS) CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_BMFONT)/include + # not very neat.... CPPFLAGS += -I../../windowmanager CPPFLAGS += -I../../blenloader diff --git a/source/blender/editors/space_sequencer/SConscript b/source/blender/editors/space_sequencer/SConscript index e6c40474d25..29781202e05 100644 --- a/source/blender/editors/space_sequencer/SConscript +++ b/source/blender/editors/space_sequencer/SConscript @@ -5,5 +5,6 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' +incs += ' #intern/bmfont' env.BlenderLib ( 'bf_editors_space_sequencer', sources, Split(incs), [], libtype=['core'], priority=[100] ) diff --git a/source/blender/editors/space_sequencer/editseq.c b/source/blender/editors/space_sequencer/editseq.c new file mode 100644 index 00000000000..d9a0f4817e2 --- /dev/null +++ b/source/blender/editors/space_sequencer/editseq.c @@ -0,0 +1,3985 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2003-2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include +#include + +#ifndef WIN32 +#include +#else +#include +#endif +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_storage_types.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "DNA_ipo_types.h" +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_sequence_types.h" +#include "DNA_view2d_types.h" +#include "DNA_userdef_types.h" +#include "DNA_sound_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_plugin_types.h" +#include "BKE_sequence.h" +#include "BKE_scene.h" +#include "BKE_utildefines.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_types.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +/* own include */ +#include "sequencer_intern.h" + +/* XXX */ +static Sequence *_last_seq=0; +static int _last_seq_init=0; +/* XXX */ +static void BIF_undo_push() {} +static void error() {} +static void waitcursor() {} +static void activate_fileselect() {} +static void std_rmouse_transform() {} +static int get_mbut() {return 0;} +static int pupmenu() {return 0;} +static int pupmenu_col() {return 0;} +static int okee() {return 0;} +static void *find_nearest_marker() {return NULL;} +static void deselect_markers() {} +static void transform_markers() {} +static void transform_seq_nomarker() {} +#define SCE_MARKERS 0 +/* XXX */ + + +#ifdef WIN32 +char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "c:\\"; +#else +char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "/"; +#endif + +char last_sounddir[FILE_MAXDIR+FILE_MAXFILE]= ""; + +#define SEQ_DESEL ~(SELECT+SEQ_LEFTSEL+SEQ_RIGHTSEL) + +typedef struct TransSeq { + int start, machine; + int startstill, endstill; + int startdisp, enddisp; + int startofs, endofs; + int final_left, final_right; + int len; +} TransSeq; + +Sequence *get_last_seq(Scene *scene) +{ + if(!_last_seq_init) { + Editing *ed; + Sequence *seq; + Sequence *l_sel = NULL; + Sequence *l_act = NULL; + + ed= scene->ed; + if(!ed) return NULL; + + for(seq= ed->seqbasep->first; seq; seq=seq->next) { + if(seq->flag & SEQ_ACTIVE) + l_act = seq; + if(seq->flag & SELECT) + l_sel = seq; + } + + if (l_act) { + _last_seq = l_act; + } else { + _last_seq = l_sel; + } + + if (_last_seq) { + _last_seq->flag |= SEQ_ACTIVE; + } + + _last_seq_init = 1; + } + + return _last_seq; +} + +void set_last_seq(Sequence *seq) +{ + if (_last_seq_init && _last_seq) { + _last_seq->flag &= ~SEQ_ACTIVE; + } + + _last_seq = seq; + _last_seq_init = 1; + + if (_last_seq) { + _last_seq->flag |= SEQ_ACTIVE; + } +} + +void clear_last_seq() +{ + if (_last_seq_init && _last_seq) { + _last_seq->flag &= ~SEQ_ACTIVE; + } + _last_seq = NULL; + _last_seq_init = 0; +} + +Sequence *get_forground_frame_seq(Scene *scene, int frame) +{ + Editing *ed; + Sequence *seq, *best_seq=NULL; + int best_machine = -1; + ed= scene->ed; + if(!ed) return NULL; + + for (seq=ed->seqbasep->first; seq; seq= seq->next) { + if(seq->startdisp > frame || seq->enddisp <= frame) + continue; + /* only use elements you can see - not */ + if (ELEM6(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_MOVIE_AND_HD_SOUND, SEQ_COLOR)) { + if (seq->machine > best_machine) { + best_seq = seq; + best_machine = seq->machine; + } + } + } + return best_seq; +} + +/* seq funcs's for transforming internally + notice the difference between start/end and left/right. + + left and right are the bounds at which the sequence is rendered, +start and end are from the start and fixed length of the sequence. +*/ +int seq_tx_get_start(Sequence *seq) { + return seq->start; +} +int seq_tx_get_end(Sequence *seq) +{ + return seq->start+seq->len; +} + +int seq_tx_get_final_left(Sequence *seq, int metaclip) +{ + if (metaclip && seq->tmp) { + /* return the range clipped by the parents range */ + return MAX2( seq_tx_get_final_left(seq, 0), seq_tx_get_final_left((Sequence *)seq->tmp, 1) ); + } else { + return (seq->start - seq->startstill) + seq->startofs; + } + +} +int seq_tx_get_final_right(Sequence *seq, int metaclip) +{ + if (metaclip && seq->tmp) { + /* return the range clipped by the parents range */ + return MIN2( seq_tx_get_final_right(seq, 0), seq_tx_get_final_right((Sequence *)seq->tmp, 1) ); + } else { + return ((seq->start+seq->len) + seq->endstill) - seq->endofs; + } +} + +void seq_tx_set_final_left(Sequence *seq, int val) +{ + if (val < (seq)->start) { + seq->startstill = abs(val - (seq)->start); + (seq)->startofs = 0; + } else { + seq->startofs = abs(val - (seq)->start); + seq->startstill = 0; + } +} + +void seq_tx_set_final_right(Sequence *seq, int val) +{ + if (val > (seq)->start + (seq)->len) { + seq->endstill = abs(val - (seq->start + (seq)->len)); + (seq)->endofs = 0; + } else { + seq->endofs = abs(val - ((seq)->start + (seq)->len)); + seq->endstill = 0; + } +} + +/* check if one side can be transformed */ +int seq_tx_check_left(Sequence *seq) +{ + if (seq->flag & SELECT) { + if (seq->flag & SEQ_LEFTSEL) + return 1; + else if (seq->flag & SEQ_RIGHTSEL) + return 0; + + return 1; /* selected and neither left or right handles are, so let us move both */ + } + return 0; +} + +int seq_tx_check_right(Sequence *seq) +{ + if (seq->flag & SELECT) { + if (seq->flag & SEQ_RIGHTSEL) + return 1; + else if (seq->flag & SEQ_LEFTSEL) + return 0; + + return 1; /* selected and neither left or right handles are, so let us move both */ + } + return 0; +} + +/* used so we can do a quick check for single image seq + since they work a bit differently to normal image seq's (during transform) */ +int check_single_seq(Sequence *seq) +{ + if ( seq->len==1 && (seq->type == SEQ_IMAGE || seq->type == SEQ_COLOR)) + return 1; + else + return 0; +} + +static void fix_single_image_seq(Sequence *seq) +{ + int left, start, offset; + if (!check_single_seq(seq)) + return; + + /* make sure the image is always at the start since there is only one, + adjusting its start should be ok */ + left = seq_tx_get_final_left(seq, 0); + start = seq->start; + if (start != left) { + offset = left - start; + seq_tx_set_final_left( seq, seq_tx_get_final_left(seq, 0) - offset ); + seq_tx_set_final_right( seq, seq_tx_get_final_right(seq, 0) - offset ); + seq->start += offset; + } +} + +int test_overlap_seq(Scene *scene, Sequence *test) +{ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return 0; + + seq= ed->seqbasep->first; + while(seq) { + if(seq!=test) { + if(test->machine==seq->machine) { + if(test->depth==seq->depth) { + if( (test->enddisp <= seq->startdisp) || (test->startdisp >= seq->enddisp) ); + else return 1; + } + } + } + seq= seq->next; + } + return 0; +} + +void shuffle_seq(Scene *scene, Sequence *test) +{ + Editing *ed; + Sequence *seq; + int a, start; + + ed= scene->ed; + if(ed==NULL) return; + + /* is there more than 1 select: only shuffle y */ + a=0; + seq= ed->seqbasep->first; + while(seq) { + if(seq->flag & SELECT) a++; + seq= seq->next; + } + + if(a<2 && test->type==SEQ_IMAGE) { + start= test->start; + + for(a= 1; a<50; a++) { + test->start= start+a; + calc_sequence(test); + if( test_overlap_seq(scene, test)==0) return; + test->start= start-a; + calc_sequence(test); + if( test_overlap_seq(scene, test)==0) return; + } + test->start= start; + } + + test->machine++; + calc_sequence(test); + while( test_overlap_seq(scene, test) ) { + if(test->machine >= MAXSEQ) { + error("There is no more space to add a sequence strip"); + + BLI_remlink(ed->seqbasep, test); + seq_free_sequence(test); + return; + } + test->machine++; + calc_sequence(test); + } +} + +static void change_plugin_seq(Scene *scene, char *str) /* called from fileselect */ +{ + struct SeqEffectHandle sh; + Sequence *last_seq= get_last_seq(scene); + + if(last_seq && last_seq->type != SEQ_PLUGIN) return; + + sh = get_sequence_effect(last_seq); + sh.free(last_seq); + sh.init_plugin(last_seq, str); + + last_seq->machine = MAX3(last_seq->seq1->machine, + last_seq->seq2->machine, + last_seq->seq3->machine); + + if( test_overlap_seq(scene, last_seq) ) shuffle_seq(scene, last_seq); + + BIF_undo_push("Load/Change Plugin, Sequencer"); +} + + +void boundbox_seq(Scene *scene, rctf *rect) +{ + Sequence *seq; + Editing *ed; + float min[2], max[2]; + + ed= scene->ed; + if(ed==NULL) return; + + min[0]= 0.0; + max[0]= EFRA+1; + min[1]= 0.0; + max[1]= 8.0; + + seq= ed->seqbasep->first; + while(seq) { + + if( min[0] > seq->startdisp-1) min[0]= seq->startdisp-1; + if( max[0] < seq->enddisp+1) max[0]= seq->enddisp+1; + if( max[1] < seq->machine+2.0) max[1]= seq->machine+2.0; + + seq= seq->next; + } + + rect->xmin= min[0]; + rect->xmax= max[0]; + rect->ymin= min[1]; + rect->ymax= max[1]; + +} + +int sequence_is_free_transformable(Sequence * seq) +{ + return seq->type < SEQ_EFFECT + || (get_sequence_effect_num_inputs(seq->type) == 0); +} + +char mouse_cfra_side(View2D *v2d, int frame ) +{ + short mval[2]; + float xmouse, ymouse; +// getmouseco_areawin(mval); + + /* choose the side based on which side of the playhead the mouse is on */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse); + return (xmouse > frame) ? 'R' : 'L'; +} + +Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel) +{ +/* looks to the left on lr==1, to the right on lr==2 + sel - 0==unselected, 1==selected, -1==done care*/ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return 0; + + if (sel>0) sel = SELECT; + + seq= ed->seqbasep->first; + while(seq) { + if( (seq!=test) && + (test->machine==seq->machine) && + (test->depth==seq->depth) && + ((sel == -1) || (sel && (seq->flag & SELECT)) || (sel==0 && (seq->flag & SELECT)==0) )) + { + switch (lr) { + case 1: + if (test->startdisp == (seq->enddisp)) { + return seq; + } + break; + case 2: + if (test->enddisp == (seq->startdisp)) { + return seq; + } + break; + } + } + seq= seq->next; + } + return NULL; +} + +Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel) +{ +/* looks to the left on lr==1, to the right on lr==2 + sel - 0==unselected, 1==selected, -1==done care*/ + Sequence *seq,*best_seq = NULL; + Editing *ed; + + int dist, best_dist; + best_dist = MAXFRAME*2; + + ed= scene->ed; + if(ed==NULL) return 0; + + if (sel) sel = SELECT; + + seq= ed->seqbasep->first; + while(seq) { + if( (seq!=test) && + (test->machine==seq->machine) && + (test->depth==seq->depth) && + ((sel == -1) || (sel==(seq->flag & SELECT)))) + { + dist = MAXFRAME*2; + + switch (lr) { + case 1: + if (seq->enddisp <= test->startdisp) { + dist = test->enddisp - seq->startdisp; + } + break; + case 2: + if (seq->startdisp >= test->enddisp) { + dist = seq->startdisp - test->enddisp; + } + break; + } + + if (dist==0) { + best_seq = seq; + break; + } else if (dist < best_dist) { + best_dist = dist; + best_seq = seq; + } + } + seq= seq->next; + } + return best_seq; /* can be null */ +} + + +Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand) +{ + Sequence *seq; + Editing *ed; + float x, y; + short mval[2]; + float pixelx; + float handsize; + float displen; + *hand= 0; + + ed= scene->ed; + if(ed==NULL) return 0; + + pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin); + +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + + seq= ed->seqbasep->first; + + while(seq) { + if(seq->machine == (int)y) { + /* check for both normal strips, and strips that have been flipped horizontally */ + if( ((seq->startdisp < seq->enddisp) && (seq->startdisp<=x && seq->enddisp>=x)) || + ((seq->startdisp > seq->enddisp) && (seq->startdisp>=x && seq->enddisp<=x)) ) + { + if(sequence_is_free_transformable(seq)) { + + /* clamp handles to defined size in pixel space */ + + handsize = seq->handsize; + displen = (float)abs(seq->startdisp - seq->enddisp); + + if (displen / pixelx > 16) { /* dont even try to grab the handles of small strips */ + /* Set the max value to handle to 1/3 of the total len when its less then 28. + * This is important because otherwise selecting handles happens even when you click in the middle */ + + if ((displen/3) < 30*pixelx) { + handsize = displen/3; + } else { + CLAMP(handsize, 7*pixelx, 30*pixelx); + } + + if( handsize+seq->startdisp >=x ) + *hand= 1; + else if( -handsize+seq->enddisp <=x ) + *hand= 2; + } + } + return seq; + } + } + seq= seq->next; + } + return 0; +} + +void update_seq_ipo_rect(Scene *scene, View2D *v2d, Sequence *seq) +{ + float start; + float end; + + if (!seq || !seq->ipo) { + return; + } + start = -5.0; + end = 105.0; + + + /* Adjust IPO window to sequence and + avoid annoying snap-back to startframe + when Lock Time is on */ + if (0) { // XXX v2d->flag & V2D_VIEWLOCK) { + if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { + start = -5.0 + seq->startdisp; + end = 5.0 + seq->enddisp; + } else { + start = (float)scene->r.sfra - 0.1; + end = scene->r.efra; + } + } + + seq->ipo->cur.xmin= start; + seq->ipo->cur.xmax= end; +} + +void update_seq_icu_rects(Sequence * seq) +{ + IpoCurve *icu= NULL; + struct SeqEffectHandle sh; + + if (!seq || !seq->ipo) { + return; + } + + if(!(seq->type & SEQ_EFFECT)) { + return; + } + + sh = get_sequence_effect(seq); + + for(icu= seq->ipo->curve.first; icu; icu= icu->next) { + sh.store_icu_yrange(seq, icu->adrcode, &icu->ymin, &icu->ymax); + } +} + + +static int seq_is_parent(Sequence *par, Sequence *seq) +{ + return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq)); +} + +static int seq_is_predecessor(Sequence *pred, Sequence *seq) +{ + if (!pred) return 0; + if(pred == seq) return 0; + else if(seq_is_parent(pred, seq)) return 1; + else if(pred->seq1 && seq_is_predecessor(pred->seq1, seq)) return 1; + else if(pred->seq2 && seq_is_predecessor(pred->seq2, seq)) return 1; + else if(pred->seq3 && seq_is_predecessor(pred->seq3, seq)) return 1; + + return 0; +} + +static void deselect_all_seq(Scene *scene) +{ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return; + + SEQP_BEGIN(ed, seq) { + seq->flag &= SEQ_DESEL; + } + SEQ_END + + BIF_undo_push("(De)select all Strips, Sequencer"); +} + +static void recurs_sel_seq(Sequence *seqm) +{ + Sequence *seq; + + seq= seqm->seqbase.first; + while(seq) { + + if(seqm->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL)) seq->flag &= SEQ_DESEL; + else if(seqm->flag & SELECT) seq->flag |= SELECT; + else seq->flag &= SEQ_DESEL; + + if(seq->seqbase.first) recurs_sel_seq(seq); + + seq= seq->next; + } +} + +void select_single_seq(Scene *scene, Sequence *seq, int deselect_all) +{ + if(deselect_all) + deselect_all_seq(scene); + set_last_seq(seq); + + if((seq->type==SEQ_IMAGE) || (seq->type==SEQ_MOVIE)) { + if(seq->strip) + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + } + else if((seq->type==SEQ_HD_SOUND) || (seq->type==SEQ_RAM_SOUND)) { + if(seq->strip) + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + } + seq->flag|= SELECT; + recurs_sel_seq(seq); +} + +void swap_select_seq(Scene *scene) +{ + Sequence *seq; + Editing *ed; + int sel=0; + + ed= scene->ed; + if(ed==NULL) return; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) sel= 1; + } + SEQ_END + + SEQP_BEGIN(ed, seq) { + /* always deselect all to be sure */ + seq->flag &= SEQ_DESEL; + if(sel==0) seq->flag |= SELECT; + } + SEQ_END + + BIF_undo_push("Swap Selected Strips, Sequencer"); + +} + +void select_channel_direction(Scene *scene, Sequence *test,int lr) { +/* selects all strips in a channel to one direction of the passed strip */ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return; + + seq= ed->seqbasep->first; + while(seq) { + if(seq!=test) { + if (test->machine==seq->machine) { + if(test->depth==seq->depth) { + if (((lr==1)&&(test->startdisp > (seq->startdisp)))||((lr==2)&&(test->startdisp < (seq->startdisp)))) { + seq->flag |= SELECT; + recurs_sel_seq(seq); + } + } + } + } + seq= seq->next; + } + test->flag |= SELECT; + recurs_sel_seq(test); +} + +void select_dir_from_last(Scene *scene, int lr) +{ + Sequence *seq=get_last_seq(scene); + if (seq==NULL) + return; + + select_channel_direction(scene, seq,lr); + + if (lr==1) BIF_undo_push("Select Strips to the Left, Sequencer"); + else BIF_undo_push("Select Strips to the Right, Sequencer"); +} + +void select_surrounding_handles(Scene *scene, Sequence *test) +{ + Sequence *neighbor; + + neighbor=find_neighboring_sequence(scene, test, 1, -1); + if (neighbor) { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + } + neighbor=find_neighboring_sequence(scene, test, 2, -1); + if (neighbor) { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + } + test->flag |= SELECT; +} + +void select_surround_from_last(Scene *scene) +{ + Sequence *seq=get_last_seq(scene); + + if (seq==NULL) + return; + + select_surrounding_handles(scene, seq); + BIF_undo_push("Select Surrounding Handles, Sequencer"); +} + +void select_neighbor_from_last(Scene *scene, int lr) +{ + Sequence *seq=get_last_seq(scene); + Sequence *neighbor; + int change = 0; + if (seq) { + neighbor=find_neighboring_sequence(scene, seq, lr, -1); + if (neighbor) { + switch (lr) { + case 1: + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL; + break; + case 2: + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + seq->flag |= SEQ_RIGHTSEL; + break; + } + seq->flag |= SELECT; + change = 1; + } + } + if (change) { + + if (lr==1) BIF_undo_push("Select Left Handles, Sequencer"); + else BIF_undo_push("Select Right Handles, Sequencer"); + } +} + +void mouse_select_seq(Scene *scene, View2D *v2d) +{ + Sequence *seq,*neighbor; + int hand,seldir, shift= 0; // XXX + TimeMarker *marker; + + marker=find_nearest_marker(SCE_MARKERS, 1); + + if (marker) { + int oldflag; + /* select timeline marker */ + if (shift) { + oldflag= marker->flag; + if (oldflag & SELECT) + marker->flag &= ~SELECT; + else + marker->flag |= SELECT; + } + else { + deselect_markers(0, 0); + marker->flag |= SELECT; + } + + BIF_undo_push("Select Strips, Sequencer"); + + } else { + + seq= find_nearest_seq(scene, v2d, &hand); + if(0) // !(G.qual & LR_SHIFTKEY)&&!(G.qual & LR_ALTKEY)&&!(G.qual & LR_CTRLKEY)) + deselect_all_seq(scene); + + if(seq) { + set_last_seq(seq); + + if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) { + if(seq->strip) { + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + } + } else + if (seq->type == SEQ_HD_SOUND || seq->type == SEQ_RAM_SOUND) { + if(seq->strip) { + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + } + } + + if(0) { // XXX (G.qual & LR_SHIFTKEY) && (seq->flag & SELECT)) { + if(hand==0) seq->flag &= SEQ_DESEL; + else if(hand==1) { + if(seq->flag & SEQ_LEFTSEL) + seq->flag &= ~SEQ_LEFTSEL; + else seq->flag |= SEQ_LEFTSEL; + } + else if(hand==2) { + if(seq->flag & SEQ_RIGHTSEL) + seq->flag &= ~SEQ_RIGHTSEL; + else seq->flag |= SEQ_RIGHTSEL; + } + } + else { + seq->flag |= SELECT; + if(hand==1) seq->flag |= SEQ_LEFTSEL; + if(hand==2) seq->flag |= SEQ_RIGHTSEL; + } + + /* On Ctrl-Alt selection, select the strip and bordering handles */ + if (0) { // XXX (G.qual & LR_CTRLKEY) && (G.qual & LR_ALTKEY)) { + // XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + seq->flag |= SELECT; + select_surrounding_handles(scene, seq); + + /* Ctrl signals Left, Alt signals Right + First click selects adjacent handles on that side. + Second click selects all strips in that direction. + If there are no adjacent strips, it just selects all in that direction. */ + } else if (0) { // XXX ((G.qual & LR_CTRLKEY) || (G.qual & LR_ALTKEY)) && (seq->flag & SELECT)) { + + if (0); // G.qual & LR_CTRLKEY) seldir=1; + else seldir=2; + neighbor=find_neighboring_sequence(scene, seq, seldir, -1); + if (neighbor) { + switch (seldir) { + case 1: + if ((seq->flag & SEQ_LEFTSEL)&&(neighbor->flag & SEQ_RIGHTSEL)) { +// XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + select_channel_direction(scene, seq,1); + } else { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL; + } + break; + case 2: + if ((seq->flag & SEQ_RIGHTSEL)&&(neighbor->flag & SEQ_LEFTSEL)) { +// XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + select_channel_direction(scene, seq,2); + } else { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + seq->flag |= SEQ_RIGHTSEL; + } + break; + } + } else { +// XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + select_channel_direction(scene, seq,seldir); + } + } + + recurs_sel_seq(seq); + } + + + BIF_undo_push("Select Strips, Sequencer"); + + std_rmouse_transform(transform_seq_nomarker); + } + + /* marker transform */ + if (marker) { + short mval[2], xo, yo; +// getmouseco_areawin(mval); + xo= mval[0]; + yo= mval[1]; + + while(get_mbut()) { +// getmouseco_areawin(mval); + if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) { + transform_markers('g', 0); + return; + } + } + } +} + + +Sequence *alloc_sequence(ListBase *lb, int cfra, int machine) +{ + Sequence *seq; + + /*ed= scene->ed;*/ + + seq= MEM_callocN( sizeof(Sequence), "addseq"); + BLI_addtail(lb, seq); + + set_last_seq(seq); + + *( (short *)seq->name )= ID_SEQ; + seq->name[2]= 0; + + seq->flag= SELECT; + seq->start= cfra; + seq->machine= machine; + seq->mul= 1.0; + seq->blend_opacity = 100.0; + + return seq; +} + +static Sequence *sfile_to_sequence(Scene *scene, SpaceFile *sfile, int cfra, int machine, int last) +{ +#if 0 + /* XXX sfile recoded... */ + Sequence *seq; + Strip *strip; + StripElem *se; + int totsel, a; + char name[160]; + + /* are there selected files? */ + totsel= 0; + for(a=0; atotfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if( (sfile->filelist[a].type & S_IFDIR)==0 ) { + totsel++; + } + } + } + + if(last) { + /* if not, a file handed to us? */ + if(totsel==0 && sfile->file[0]) totsel= 1; + } + + if(totsel==0) return 0; + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totsel; + + if(totsel==1) { + seq->startstill= 25; + seq->endstill= 24; + } + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totsel; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(totsel*sizeof(StripElem), "stripelem"); + + for(a=0; atotfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if( (sfile->filelist[a].type & S_IFDIR)==0 ) { + strncpy(se->name, sfile->filelist[a].relname, FILE_MAXFILE-1); + se++; + } + } + } + /* no selected file: */ + if(totsel==1 && se==strip->stripdata) { + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + } + + /* last active name */ + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + + return seq; +#endif + return NULL; +} + + +#if 0 +static int sfile_to_mv_sequence_load(Scene *scene, SpaceFile *sfile, int cfra, + int machine, int index ) +{ + /* XXX sfile recoded... */ + Sequence *seq; + struct anim *anim; + Strip *strip; + StripElem *se; + int totframe; + char name[160]; + char str[FILE_MAXDIR+FILE_MAXFILE]; + + totframe= 0; + + strncpy(str, sfile->dir, FILE_MAXDIR-1); + if(index<0) + strncat(str, sfile->file, FILE_MAXDIR-1); + else + strncat(str, sfile->filelist[index].relname, FILE_MAXDIR-1); + + /* is it a movie? */ + anim = openanim(str, IB_rect); + if(anim==0) { + error("The selected file is not a movie or " + "FFMPEG-support not compiled in!"); + return(cfra); + } + + totframe= IMB_anim_get_duration(anim); + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totframe; + seq->type= SEQ_MOVIE; + seq->anim= anim; + seq->anim_preseek = IMB_anim_get_preseek(anim); + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totframe; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); + + /* name movie in first strip */ + if(index<0) + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + else + strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1); + + /* last active name */ + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + return(cfra+totframe); +} +#endif + +static void sfile_to_mv_sequence(SpaceFile *sfile, int cfra, int machine) +{ +#if 0 + /* XXX sfile recoded... */ + int a, totsel; + + totsel= 0; + for(a= 0; atotfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if ((sfile->filelist[a].type & S_IFDIR)==0) { + totsel++; + } + } + } + + if((totsel==0) && (sfile->file[0])) { + cfra= sfile_to_mv_sequence_load(sfile, cfra, machine, -1); + return; + } + + if(totsel==0) return; + + /* ok. check all the select file, and load it. */ + for(a= 0; atotfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if ((sfile->filelist[a].type & S_IFDIR)==0) { + /* load and update current frame. */ + cfra= sfile_to_mv_sequence_load(sfile, cfra, machine, a); + } + } + } +#endif +} + +static Sequence *sfile_to_ramsnd_sequence(Scene *scene, SpaceFile *sfile, int cfra, int machine) +{ +#if 0 + /* XXX sfile recoded... */ + Sequence *seq; + bSound *sound; + Strip *strip; + StripElem *se; + double totframe; + char name[160]; + char str[256]; + + totframe= 0.0; + + strncpy(str, sfile->dir, FILE_MAXDIR-1); + strncat(str, sfile->file, FILE_MAXFILE-1); + + sound= sound_new_sound(str); + if (!sound || sound->sample->type == SAMPLE_INVALID) { + error("Unsupported audio format"); + return 0; + } + if (sound->sample->bits != 16) { + error("Only 16 bit audio is supported"); + return 0; + } + sound->id.us=1; + sound->flags |= SOUND_FLAGS_SEQUENCE; + audio_makestream(sound); + + totframe= (int) ( ((float)(sound->streamlen-1)/ + ( (float)scene->r.audio.mixrate*4.0 ))* FPS); + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totframe; + seq->type= SEQ_RAM_SOUND; + seq->sound = sound; + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totframe; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); + + /* name sound in first strip */ + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + + /* last active name */ + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + + return seq; +#endif + return NULL; +} + +#if 0 +static int sfile_to_hdsnd_sequence_load(SpaceFile *sfile, int cfra, + int machine, int index) +{ + /* XXX sfile recoded... */ + Sequence *seq; + struct hdaudio *hdaudio; + Strip *strip; + StripElem *se; + int totframe; + char name[160]; + char str[FILE_MAXDIR+FILE_MAXFILE]; + + totframe= 0; + + strncpy(str, sfile->dir, FILE_MAXDIR-1); + if(index<0) + strncat(str, sfile->file, FILE_MAXDIR-1); + else + strncat(str, sfile->filelist[index].relname, FILE_MAXDIR-1); + + /* is it a sound file? */ + hdaudio = sound_open_hdaudio(str); + if(hdaudio==0) { + error("The selected file is not a sound file or " + "FFMPEG-support not compiled in!"); + return(cfra); + } + + totframe= sound_hdaudio_get_duration(hdaudio, FPS); + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totframe; + seq->type= SEQ_HD_SOUND; + seq->hdaudio= hdaudio; + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totframe; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); + + /* name movie in first strip */ + if(index<0) + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + else + strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1); + + /* last active name */ + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + return(cfra+totframe); +} +#endif + +static void sfile_to_hdsnd_sequence(SpaceFile *sfile, int cfra, int machine) +{ +#if 0 + /* XXX sfile recoded... */ + int totsel, a; + + totsel= 0; + for(a= 0; atotfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if((sfile->filelist[a].type & S_IFDIR)==0) { + totsel++; + } + } + } + + if((totsel==0) && (sfile->file[0])) { + cfra= sfile_to_hdsnd_sequence_load(sfile, cfra, machine, -1); + return; + } + + if(totsel==0) return; + + /* ok, check all the select file, and load it. */ + for(a= 0; atotfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if((sfile->filelist[a].type & S_IFDIR)==0) { + /* load and update current frame. */ + cfra= sfile_to_hdsnd_sequence_load(sfile, cfra, machine, a); + } + } + } +#endif +} + + +static void add_image_strips(Scene *scene, char *name) +{ +#if 0 + /* XXX sfile recoded... */ + + SpaceFile *sfile; + struct direntry *files; + float x, y; + int a, totfile, cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + + /* restore windowmatrices */ +// XXX drawseqspace(curarea, curarea->spacedata.first); + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + /* also read contents of directories */ + files= sfile->filelist; + totfile= sfile->totfile; + sfile->filelist= 0; + sfile->totfile= 0; + + for(a=0; adir, files[a].relname, FILE_MAXFILE-1); + strcat(sfile->dir,"/"); + read_dir(sfile); + + /* select all */ + swapselect_file(sfile); + + if ( sfile_to_sequence(scene, sfile, cfra, machine, 0) ) machine++; + + parent(sfile); + } + } + } + + sfile->filelist= files; + sfile->totfile= totfile; + + /* read directory itself */ + sfile_to_sequence(scene, sfile, cfra, machine, 1); + + waitcursor(0); + + BIF_undo_push("Add Image Strip, Sequencer"); + transform_seq_nomarker('g', 0); +#endif +} + +static void add_movie_strip(Scene *scene, View2D *v2d, char *name) +{ + + /* XXX sfile recoded... */ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + + /* restore windowmatrices */ +// drawseqspace(curarea, curarea->spacedata.first); + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + /* read directory itself */ + sfile_to_mv_sequence(sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Movie Strip, Sequencer"); + transform_seq_nomarker('g', 0); + +} + +static void add_movie_and_hdaudio_strip(Scene *scene, View2D *v2d, char *name) +{ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + + /* restore windowmatrices */ +// areawinset(curarea->win); +// drawseqspace(curarea, curarea->spacedata.first); + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + /* read directory itself */ + sfile_to_hdsnd_sequence(sfile, cfra, machine); + sfile_to_mv_sequence(sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Movie and HD-Audio Strip, Sequencer"); + transform_seq_nomarker('g', 0); + +} + +static void add_sound_strip_ram(Scene *scene, View2D *v2d, char *name) +{ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if (sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + sfile_to_ramsnd_sequence(scene, sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Sound (RAM) Strip, Sequencer"); + transform_seq_nomarker('g', 0); +} + +static void add_sound_strip_hd(Scene *scene, View2D *v2d, char *name) +{ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if (sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + sfile_to_hdsnd_sequence(sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Sound (HD) Strip, Sequencer"); + transform_seq_nomarker('g', 0); +} + +static void add_scene_strip(Scene *scene, View2D *v2d, short event) +{ + Sequence *seq; + Strip *strip; + float x, y; + int cfra, machine; + short mval[2]; + + if(event> -1) { + int nr= 1; + Scene * sce= G.main->scene.first; + while(sce) { + if( event==nr) break; + nr++; + sce= sce->id.next; + } + if(sce) { + + deselect_all_seq(scene); + + /* where ? */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->type= SEQ_SCENE; + seq->scene= sce; + seq->sfra= sce->r.sfra; + seq->len= sce->r.efra - sce->r.sfra + 1; + + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strncpy(seq->name + 2, sce->id.name + 2, + sizeof(seq->name) - 2); + strip->len= seq->len; + strip->us= 1; + + BIF_undo_push("Add Scene Strip, Sequencer"); + transform_seq_nomarker('g', 0); + } + } +} + +#if 0 +static void reload_sound_strip(Scene *scene, char *name) +{ + Editing *ed; + Sequence *seq, *seqact; + SpaceFile *sfile; + Sequence *last_seq= get_last_seq(scene); + + ed= scene->ed; + + if(last_seq==0 || last_seq->type!=SEQ_SOUND) return; + seqact= last_seq; /* last_seq changes in alloc_sequence */ + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + waitcursor(1); + + seq = sfile_to_snd_sequence(sfile, seqact->start, seqact->machine); + printf("seq->type: %i\n", seq->type); + if(seq && seq!=seqact) { + /* i'm not sure about this one, seems to work without it -- sgefant */ + seq_free_strip(seqact->strip); + + seqact->strip= seq->strip; + + seqact->len= seq->len; + calc_sequence(seqact); + + seq->strip= 0; + seq_free_sequence(seq); + BLI_remlink(ed->seqbasep, seq); + + seq= ed->seqbasep->first; + + } + + waitcursor(0); + +} +#endif + +static void reload_image_strip(Scene *scene, char *name) +{ + Editing *ed; + Sequence *seq, *seqact; + SpaceFile *sfile; + Sequence *last_seq= get_last_seq(scene); + + ed= scene->ed; + + if(last_seq==0 || last_seq->type!=SEQ_IMAGE) return; + seqact= last_seq; /* last_seq changes in alloc_sequence */ + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + waitcursor(1); + + seq= sfile_to_sequence(scene, sfile, seqact->start, seqact->machine, 1); + if(seq && seq!=seqact) { + seq_free_strip(seqact->strip); + + seqact->strip= seq->strip; + + seqact->len= seq->len; + calc_sequence(seqact); + + seq->strip= 0; + seq_free_sequence(seq); + BLI_remlink(ed->seqbasep, seq); + + update_changed_seq_and_deps(scene, seqact, 1, 1); + } + waitcursor(0); + +} + +static int event_to_efftype(int event) +{ + if(event==2) return SEQ_CROSS; + if(event==3) return SEQ_GAMCROSS; + if(event==4) return SEQ_ADD; + if(event==5) return SEQ_SUB; + if(event==6) return SEQ_MUL; + if(event==7) return SEQ_ALPHAOVER; + if(event==8) return SEQ_ALPHAUNDER; + if(event==9) return SEQ_OVERDROP; + if(event==10) return SEQ_PLUGIN; + if(event==13) return SEQ_WIPE; + if(event==14) return SEQ_GLOW; + if(event==15) return SEQ_TRANSFORM; + if(event==16) return SEQ_COLOR; + if(event==17) return SEQ_SPEED; + return 0; +} + +static int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3) +{ + Editing *ed = scene->ed; + Sequence *seq1= 0, *seq2= 0, *seq3= 0, *seq; + + if (!activeseq) + seq2= get_last_seq(scene); + + for(seq=ed->seqbasep->first; seq; seq=seq->next) { + if(seq->flag & SELECT) { + if (seq->type == SEQ_RAM_SOUND + || seq->type == SEQ_HD_SOUND) { + error("Can't apply effects to " + "audio sequence strips"); + return 0; + } + if((seq != activeseq) && (seq != seq2)) { + if(seq2==0) seq2= seq; + else if(seq1==0) seq1= seq; + else if(seq3==0) seq3= seq; + else { + error("Can't apply effect to more than 3 sequence strips"); + return 0; + } + } + } + } + + /* make sequence selection a little bit more intuitive + for 3 strips: the last-strip should be sequence3 */ + if (seq3 != 0 && seq2 != 0) { + Sequence *tmp = seq2; + seq2 = seq3; + seq3 = tmp; + } + + + switch(get_sequence_effect_num_inputs(type)) { + case 0: + *selseq1 = *selseq2 = *selseq3 = 0; + return 1; + case 1: + if(seq2==0) { + error("Need at least one selected sequence strip"); + return 0; + } + if(seq1==0) seq1= seq2; + if(seq3==0) seq3= seq2; + case 2: + if(seq1==0 || seq2==0) { + error("Need 2 selected sequence strips"); + return 0; + } + if(seq3==0) seq3= seq2; + } + + if (seq1==NULL && seq2==NULL && seq3==NULL) return 0; + + *selseq1= seq1; + *selseq2= seq2; + *selseq3= seq3; + + return 1; +} + +static int add_seq_effect(Scene *scene, View2D *v2d, int type, char *str) +{ + Editing *ed; + Sequence *newseq, *seq1, *seq2, *seq3; + Strip *strip; + float x, y; + int cfra, machine; + short mval[2]; + struct SeqEffectHandle sh; + + if(scene->ed==NULL) return 0; + ed= scene->ed; + + if(!seq_effect_find_selected(scene, NULL, event_to_efftype(type), &seq1, &seq2, &seq3)) + return 0; + + deselect_all_seq(scene); + + /* where will it be (cfra is not realy needed) */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + /* allocate and initialize */ + newseq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + newseq->type= event_to_efftype(type); + + sh = get_sequence_effect(newseq); + + newseq->seq1= seq1; + newseq->seq2= seq2; + newseq->seq3= seq3; + + sh.init(newseq); + + if (!seq1) { + newseq->len= 1; + newseq->startstill= 25; + newseq->endstill= 24; + } + + calc_sequence(newseq); + + newseq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= newseq->len; + strip->us= 1; + if(newseq->len>0) + strip->stripdata= MEM_callocN(newseq->len*sizeof(StripElem), "stripelem"); + + /* initialize plugin */ + if(newseq->type == SEQ_PLUGIN) { + sh.init_plugin(newseq, str); + + if(newseq->plugin==0) { + BLI_remlink(ed->seqbasep, newseq); + seq_free_sequence(newseq); + set_last_seq(NULL); + return 0; + } + } + + /* set find a free spot to but the strip */ + if (newseq->seq1) { + newseq->machine= MAX3(newseq->seq1->machine, + newseq->seq2->machine, + newseq->seq3->machine); + } + if(test_overlap_seq(scene, newseq)) shuffle_seq(scene, newseq); + + update_changed_seq_and_deps(scene, newseq, 1, 1); + + /* push undo and go into grab mode */ + if(newseq->type == SEQ_PLUGIN) { + BIF_undo_push("Add Plugin Strip, Sequencer"); + } else { + BIF_undo_push("Add Effect Strip, Sequencer"); + } + + transform_seq_nomarker('g', 0); + + return 1; +} + +static void load_plugin_seq(Scene *scene, View2D *v2d, char *str) /* called from fileselect */ +{ + add_seq_effect(scene, v2d, 10, str); +} + +void add_sequence(Scene *scene, View2D *v2d, int type) +{ + Editing *ed; + short event; + char *str; + + if (type >= 0){ + /* bypass pupmenu for calls from menus (aphex) */ + switch(type){ + case SEQ_SCENE: + event = 101; + break; + case SEQ_IMAGE: + event = 1; + break; + case SEQ_MOVIE: + event = 102; + break; + case SEQ_RAM_SOUND: + event = 103; + break; + case SEQ_HD_SOUND: + event = 104; + break; + case SEQ_MOVIE_AND_HD_SOUND: + event = 105; + break; + case SEQ_PLUGIN: + event = 10; + break; + case SEQ_CROSS: + event = 2; + break; + case SEQ_ADD: + event = 4; + break; + case SEQ_SUB: + event = 5; + break; + case SEQ_ALPHAOVER: + event = 7; + break; + case SEQ_ALPHAUNDER: + event = 8; + break; + case SEQ_GAMCROSS: + event = 3; + break; + case SEQ_MUL: + event = 6; + break; + case SEQ_OVERDROP: + event = 9; + break; + case SEQ_WIPE: + event = 13; + break; + case SEQ_GLOW: + event = 14; + break; + case SEQ_TRANSFORM: + event = 15; + break; + case SEQ_COLOR: + event = 16; + break; + case SEQ_SPEED: + event = 17; + break; + default: + event = 0; + break; + } + } + else { + event= pupmenu("Add Sequence Strip%t" + "|Image Sequence%x1" + "|Movie%x102" +#ifdef WITH_FFMPEG + "|Movie + Audio (HD)%x105" + "|Audio (RAM)%x103" + "|Audio (HD)%x104" +#else + "|Audio (Wav)%x103" +#endif + "|Scene%x101" + "|Plugin%x10" + "|Cross%x2" + "|Gamma Cross%x3" + "|Add%x4" + "|Sub%x5" + "|Mul%x6" + "|Alpha Over%x7" + "|Alpha Under%x8" + "|Alpha Over Drop%x9" + "|Wipe%x13" + "|Glow%x14" + "|Transforms%x15" + "|Color Generator%x16" + "|Speed Control%x17"); + } + + if(event<1) return; + + if(scene->ed==NULL) { + ed= scene->ed= MEM_callocN( sizeof(Editing), "addseq"); + ed->seqbasep= &ed->seqbase; + } + else ed= scene->ed; + + switch(event) { + case 1: + /* Image Dosnt work at the moment - TODO */ + //if(G.qual & LR_CTRLKEY) + // activate_imageselect(FILE_SPECIAL, "Select Images", last_imagename, add_image_strips); + //else + activate_fileselect(FILE_SPECIAL, "Select Images", last_imagename, add_image_strips); + break; + case 105: + activate_fileselect(FILE_SPECIAL, "Select Movie+Audio", last_imagename, add_movie_and_hdaudio_strip); + break; + case 102: + + activate_fileselect(FILE_SPECIAL, "Select Movie", last_imagename, add_movie_strip); + break; + case 101: + /* new menu: */ + IDnames_to_pupstring(&str, NULL, NULL, &G.main->scene, (ID *)scene, NULL); + + add_scene_strip(scene, v2d, pupmenu_col(str, 20)); + + MEM_freeN(str); + + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 13: + case 14: + case 15: + case 16: + case 17: + if(get_last_seq(scene)==0 && + get_sequence_effect_num_inputs( event_to_efftype(event))> 0) + error("Need at least one active sequence strip"); + else if(event==10) + activate_fileselect(FILE_SPECIAL, "Select Plugin", U.plugseqdir, load_plugin_seq); + else + add_seq_effect(scene, v2d, event, NULL); + + break; + case 103: + if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1); + activate_fileselect(FILE_SPECIAL, "Select Audio (RAM)", last_sounddir, add_sound_strip_ram); + break; + case 104: + if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1); + activate_fileselect(FILE_SPECIAL, "Select Audio (HD)", last_sounddir, add_sound_strip_hd); + break; + } +} + +void change_sequence(Scene *scene) +{ + Sequence *last_seq= get_last_seq(scene); + Scene *sce; + short event; + + if(last_seq==0) return; + + if(last_seq->type & SEQ_EFFECT) { + event = pupmenu("Change Effect%t" + "|Switch A <-> B %x1" + "|Switch B <-> C %x10" + "|Plugin%x11" + "|Recalculate%x12" + "|Cross%x2" + "|Gamma Cross%x3" + "|Add%x4" + "|Sub%x5" + "|Mul%x6" + "|Alpha Over%x7" + "|Alpha Under%x8" + "|Alpha Over Drop%x9" + "|Wipe%x13" + "|Glow%x14" + "|Transform%x15" + "|Color Generator%x16" + "|Speed Control%x17"); + if(event > 0) { + if(event==1) { + SWAP(Sequence *,last_seq->seq1,last_seq->seq2); + } + else if(event==10) { + SWAP(Sequence *,last_seq->seq2,last_seq->seq3); + } + else if(event==11) { + activate_fileselect( + FILE_SPECIAL, "Select Plugin", + U.plugseqdir, change_plugin_seq); + } + else if(event==12); + /* recalculate: only new_stripdata */ + else { + /* free previous effect and init new effect */ + struct SeqEffectHandle sh; + + if (get_sequence_effect_num_inputs( + last_seq->type) + < get_sequence_effect_num_inputs( + event_to_efftype(event))) { + error("New effect needs more " + "input strips!"); + } else { + sh = get_sequence_effect(last_seq); + sh.free(last_seq); + + last_seq->type + = event_to_efftype(event); + + sh = get_sequence_effect(last_seq); + sh.init(last_seq); + } + } + + update_changed_seq_and_deps(scene, last_seq, 0, 1); + BIF_undo_push("Change Strip Effect, Sequencer"); + } + } + else if(last_seq->type == SEQ_IMAGE) { + if(okee("Change images")) { + activate_fileselect(FILE_SPECIAL, + "Select Images", + last_imagename, + reload_image_strip); + } + } + else if(last_seq->type == SEQ_MOVIE) { + ; + } + else if(last_seq->type == SEQ_SCENE) { + event= pupmenu("Change Scene%t|Update Start and End"); + + if(event==1) { + sce= last_seq->scene; + + last_seq->len= sce->r.efra - sce->r.sfra + 1; + last_seq->sfra= sce->r.sfra; + + /* bad code to change seq->len? update_changed_seq_and_deps() expects the strip->len to be OK */ + new_tstripdata(last_seq); + + update_changed_seq_and_deps(scene, last_seq, 1, 1); + + } + } + +} + +void reload_sequence(Scene *scene) +{ + Editing *ed= scene->ed; + Sequence *seq; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + update_changed_seq_and_deps(scene, seq, 0, 1); + } + } + SEQ_END +} + +void reassign_inputs_seq_effect(Scene *scene) +{ + Editing *ed= scene->ed; + Sequence *seq1, *seq2, *seq3, *last_seq = get_last_seq(scene); + + if(last_seq==0 || !(last_seq->type & SEQ_EFFECT)) return; + if(ed==NULL) return; + + if(!seq_effect_find_selected(scene, last_seq, last_seq->type, &seq1, &seq2, &seq3)) + return; + + /* see reassigning would create a cycle */ + if(seq_is_predecessor(seq1, last_seq) || seq_is_predecessor(seq2, last_seq) || + seq_is_predecessor(seq3, last_seq)) { + error("Can't reassign inputs: no cycles allowed"); + return; + } + + last_seq->seq1 = seq1; + last_seq->seq2 = seq2; + last_seq->seq3 = seq3; + + update_changed_seq_and_deps(scene, last_seq, 1, 1); + +} + +static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq) +{ + Sequence *seq1, *seq2, *seq3; + + /* try to find a replacement input sequence, and flag for later deletion if + no replacement can be found */ + + if(!seq) + return NULL; + else if(!(seq->type & SEQ_EFFECT)) + return ((seq->flag & SELECT)? NULL: seq); + else if(!(seq->flag & SELECT)) { + /* try to find replacement for effect inputs */ + seq1= del_seq_find_replace_recurs(scene, seq->seq1); + seq2= del_seq_find_replace_recurs(scene, seq->seq2); + seq3= del_seq_find_replace_recurs(scene, seq->seq3); + + if(seq1==seq->seq1 && seq2==seq->seq2 && seq3==seq->seq3); + else if(seq1 || seq2 || seq3) { + seq->seq1= (seq1)? seq1: (seq2)? seq2: seq3; + seq->seq2= (seq2)? seq2: (seq1)? seq1: seq3; + seq->seq3= (seq3)? seq3: (seq1)? seq1: seq2; + + update_changed_seq_and_deps(scene, seq, 1, 1); + } + else + seq->flag |= SELECT; /* mark for delete */ + } + + if (seq->flag & SELECT) { + if((seq1 = del_seq_find_replace_recurs(scene, seq->seq1))) return seq1; + if((seq2 = del_seq_find_replace_recurs(scene, seq->seq2))) return seq2; + if((seq3 = del_seq_find_replace_recurs(scene, seq->seq3))) return seq3; + else return NULL; + } + else + return seq; +} + +static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall) +{ + Sequence *seq, *seqn; + Sequence *last_seq = get_last_seq(scene); + + seq= lb->first; + while(seq) { + seqn= seq->next; + if((seq->flag & flag) || deleteall) { + if(seq->type==SEQ_RAM_SOUND && seq->sound) + seq->sound->id.us--; + + BLI_remlink(lb, seq); + if(seq==last_seq) set_last_seq(0); + if(seq->type==SEQ_META) recurs_del_seq_flag(scene, &seq->seqbase, flag, 1); + if(seq->ipo) seq->ipo->id.us--; + seq_free_sequence(seq); + } + seq= seqn; + } +} + +void del_seq(Scene *scene) +{ + Sequence *seq; + MetaStack *ms; + Editing *ed; + int nothingSelected = TRUE; + + ed= scene->ed; + if(ed==NULL) return; + + seq=get_last_seq(scene); + if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */ + nothingSelected = FALSE; + } else { + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT) { + nothingSelected = FALSE; + break; + } + } + } + + if(nothingSelected || okee("Erase selected")==0) return; + + /* free imbufs of all dependent strips */ + for(seq=ed->seqbasep->first; seq; seq=seq->next) + if(seq->flag & SELECT) + update_changed_seq_and_deps(scene, seq, 1, 0); + + /* for effects, try to find a replacement input */ + for(seq=ed->seqbasep->first; seq; seq=seq->next) + if((seq->type & SEQ_EFFECT) && !(seq->flag & SELECT)) + del_seq_find_replace_recurs(scene, seq); + + /* delete all selected strips */ + recurs_del_seq_flag(scene, ed->seqbasep, SELECT, 0); + + /* updates lengths etc */ + seq= ed->seqbasep->first; + while(seq) { + calc_sequence(seq); + seq= seq->next; + } + + /* free parent metas */ + ms= ed->metastack.last; + while(ms) { + ms->parseq->strip->len= 0; /* force new alloc */ + calc_sequence(ms->parseq); + ms= ms->prev; + } + + BIF_undo_push("Delete Strip(s), Sequencer"); +} + +static Sequence *dupli_seq(Sequence *seq) +{ + Sequence *seqn = MEM_dupallocN(seq); + + seq->tmp = seqn; + + seqn->strip= MEM_dupallocN(seq->strip); + + if(seqn->ipo) seqn->ipo->id.us++; + + seqn->strip->tstripdata = 0; + seqn->strip->tstripdata_startstill = 0; + seqn->strip->tstripdata_endstill = 0; + seqn->strip->ibuf_startstill = 0; + seqn->strip->ibuf_endstill = 0; + + if (seq->strip->crop) { + seqn->strip->crop = MEM_dupallocN(seq->strip->crop); + } + + if (seq->strip->transform) { + seqn->strip->transform = MEM_dupallocN(seq->strip->transform); + } + + if (seq->strip->proxy) { + seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy); + } + + if (seq->strip->color_balance) { + seqn->strip->color_balance + = MEM_dupallocN(seq->strip->color_balance); + } + + if(seq->type==SEQ_META) { + seqn->strip->stripdata = 0; + + seqn->seqbase.first= seqn->seqbase.last= 0; + /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */ + /* - recurs_dupli_seq(&seq->seqbase,&seqn->seqbase);*/ + } else if(seq->type == SEQ_SCENE) { + seqn->strip->stripdata = 0; + } else if(seq->type == SEQ_MOVIE) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->anim= 0; + } else if(seq->type == SEQ_RAM_SOUND) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->sound->id.us++; + } else if(seq->type == SEQ_HD_SOUND) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->hdaudio = 0; + } else if(seq->type == SEQ_IMAGE) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + } else if(seq->type >= SEQ_EFFECT) { + if(seq->seq1 && seq->seq1->tmp) seqn->seq1= seq->seq1->tmp; + if(seq->seq2 && seq->seq2->tmp) seqn->seq2= seq->seq2->tmp; + if(seq->seq3 && seq->seq3->tmp) seqn->seq3= seq->seq3->tmp; + + if (seq->type & SEQ_EFFECT) { + struct SeqEffectHandle sh; + sh = get_sequence_effect(seq); + if(sh.copy) + sh.copy(seq, seqn); + } + + seqn->strip->stripdata = 0; + + } else { + fprintf(stderr, "Aiiiiekkk! sequence type not " + "handled in duplicate!\nExpect a crash" + " now...\n"); + } + + seqn->flag &= ~SEQ_ACTIVE; + + return seqn; +} + +static Sequence * deep_dupli_seq(Sequence * seq) +{ + Sequence * seqn = dupli_seq(seq); + if (seq->type == SEQ_META) { + Sequence * s; + for(s= seq->seqbase.first; s; s = s->next) { + Sequence * n = deep_dupli_seq(s); + if (n) { + BLI_addtail(&seqn->seqbase, n); + } + } + } + return seqn; +} + + +static void recurs_dupli_seq(Scene *scene, ListBase *old, ListBase *new) +{ + Sequence *seq; + Sequence *seqn = 0; + Sequence *last_seq = get_last_seq(scene); + + for(seq= old->first; seq; seq= seq->next) { + seq->tmp= NULL; + if(seq->flag & SELECT) { + seqn = dupli_seq(seq); + if (seqn) { /*should never fail */ + seq->flag &= SEQ_DESEL; + seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL+SEQ_LOCK); + + BLI_addtail(new, seqn); + if(seq->type==SEQ_META) + recurs_dupli_seq(scene, &seq->seqbase,&seqn->seqbase); + + if (seq == last_seq) { + set_last_seq(seqn); + } + } + } + } +} + +static Sequence *cut_seq_hard(Scene *scene, Sequence * seq, int cutframe) +{ + TransSeq ts; + Sequence *seqn = 0; + int skip_dup = FALSE; + + /* backup values */ + ts.start= seq->start; + ts.machine= seq->machine; + ts.startstill= seq->startstill; + ts.endstill= seq->endstill; + ts.startdisp= seq->startdisp; + ts.enddisp= seq->enddisp; + ts.startofs= seq->anim_startofs; + ts.endofs= seq->anim_endofs; + ts.len= seq->len; + + /* First Strip! */ + /* strips with extended stillfames before */ + + if ((seq->startstill) && (cutframe start)) { + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + seq->startstill = seq->start - cutframe; + } else { + seq->start= cutframe -1; + seq->startstill= cutframe -seq->startdisp -1; + seq->anim_endofs += seq->len - 1; + seq->endstill= 0; + } + } + /* normal strip */ + else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) { + seq->endofs = 0; + seq->endstill = 0; + seq->anim_endofs += (seq->start+seq->len) - cutframe; + } + /* strips with extended stillframes after */ + else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) { + seq->endstill -= seq->enddisp - cutframe; + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + } + } + + reload_sequence_new_file(scene, seq); + calc_sequence(seq); + + if (!skip_dup) { + /* Duplicate AFTER the first change */ + seqn = deep_dupli_seq(seq); + } + + if (seqn) { + seqn->flag |= SELECT; + + /* Second Strip! */ + /* strips with extended stillframes before */ + if ((seqn->startstill) && (cutframe == seqn->start + 1)) { + seqn->start = ts.start; + seqn->startstill= ts.start- cutframe; + seqn->anim_endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* normal strip */ + else if ((cutframe>=seqn->start)&&(cutframe<=(seqn->start+seqn->len))) { + seqn->start = cutframe; + seqn->startstill = 0; + seqn->startofs = 0; + seqn->anim_startofs += cutframe - ts.start; + seqn->anim_endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* strips with extended stillframes after */ + else if (((seqn->start+seqn->len) < cutframe) && (seqn->endstill)) { + seqn->start = cutframe; + seqn->startofs = 0; + seqn->anim_startofs += ts.len-1; + seqn->endstill = ts.enddisp - cutframe -1; + seqn->startstill = 0; + } + + reload_sequence_new_file(scene, seqn); + calc_sequence(seqn); + } + return seqn; +} + +static Sequence *cut_seq_soft(Scene *scene, Sequence * seq, int cutframe) +{ + TransSeq ts; + Sequence *seqn = 0; + int skip_dup = FALSE; + + /* backup values */ + ts.start= seq->start; + ts.machine= seq->machine; + ts.startstill= seq->startstill; + ts.endstill= seq->endstill; + ts.startdisp= seq->startdisp; + ts.enddisp= seq->enddisp; + ts.startofs= seq->startofs; + ts.endofs= seq->endofs; + ts.len= seq->len; + + /* First Strip! */ + /* strips with extended stillfames before */ + + if ((seq->startstill) && (cutframe start)) { + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + seq->startstill = seq->start - cutframe; + } else { + seq->start= cutframe -1; + seq->startstill= cutframe -seq->startdisp -1; + seq->endofs = seq->len - 1; + seq->endstill= 0; + } + } + /* normal strip */ + else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) { + seq->endofs = (seq->start+seq->len) - cutframe; + } + /* strips with extended stillframes after */ + else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) { + seq->endstill -= seq->enddisp - cutframe; + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + } + } + + calc_sequence(seq); + + if (!skip_dup) { + /* Duplicate AFTER the first change */ + seqn = deep_dupli_seq(seq); + } + + if (seqn) { + seqn->flag |= SELECT; + + /* Second Strip! */ + /* strips with extended stillframes before */ + if ((seqn->startstill) && (cutframe == seqn->start + 1)) { + seqn->start = ts.start; + seqn->startstill= ts.start- cutframe; + seqn->endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* normal strip */ + else if ((cutframe>=seqn->start)&&(cutframe<=(seqn->start+seqn->len))) { + seqn->startstill = 0; + seqn->startofs = cutframe - ts.start; + seqn->endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* strips with extended stillframes after */ + else if (((seqn->start+seqn->len) < cutframe) && (seqn->endstill)) { + seqn->start = cutframe - ts.len +1; + seqn->startofs = ts.len-1; + seqn->endstill = ts.enddisp - cutframe -1; + seqn->startstill = 0; + } + + calc_sequence(seqn); + } + return seqn; +} + + +/* like duplicate, but only duplicate and cut overlapping strips, + * strips to the left of the cutframe are ignored and strips to the right are moved into the new list */ +static int cut_seq_list(Scene *scene, ListBase *old, ListBase *new, int cutframe, + Sequence * (*cut_seq)(Scene *, Sequence *, int)) +{ + int did_something = FALSE; + Sequence *seq, *seq_next; + + seq= old->first; + + while(seq) { + seq_next = seq->next; /* we need this because we may remove seq */ + + seq->tmp= NULL; + if(seq->flag & SELECT) { + if(cutframe > seq->startdisp && + cutframe < seq->enddisp) { + Sequence * seqn = cut_seq(scene, seq, cutframe); + if (seqn) { + BLI_addtail(new, seqn); + } + did_something = TRUE; + } else if (seq->enddisp <= cutframe) { + /* do nothing */ + } else if (seq->startdisp >= cutframe) { + /* move into new list */ + BLI_remlink(old, seq); + BLI_addtail(new, seq); + } + } + seq = seq_next; + } + return did_something; +} + +void seq_cut(Scene *scene, View2D *v2d, int cutframe, int hard_cut) +{ + Editing *ed; + ListBase newlist; + char side; + int did_something; + + ed= scene->ed; + if(ed==NULL) return; + + newlist.first= newlist.last= NULL; + + if (hard_cut) { + did_something = cut_seq_list(scene, + ed->seqbasep, &newlist, cutframe, cut_seq_hard); + } else { + did_something = cut_seq_list(scene, + ed->seqbasep, &newlist, cutframe, cut_seq_soft); + } + + if (newlist.first) { /* got new strips ? */ + Sequence *seq; + addlisttolist(ed->seqbasep, &newlist); + + + /* change the selection, not strictly needed but nice */ + side = mouse_cfra_side(v2d, cutframe); + + SEQP_BEGIN(ed, seq) { + if (side=='L') { + if ( seq->startdisp >= cutframe ) { + seq->flag &= ~SELECT; + } + } else { + if ( seq->enddisp <= cutframe ) { + seq->flag &= ~SELECT; + } + } + } + SEQ_END; + + /* as last: */ + sort_seq(scene); + } + if (did_something) { + BIF_undo_push("Cut Strips, Sequencer"); + } +} + +void add_duplicate_seq(Scene *scene) +{ + Editing *ed; + ListBase new; + + ed= scene->ed; + if(ed==NULL) return; + + new.first= new.last= 0; + + recurs_dupli_seq(scene, ed->seqbasep, &new); + addlisttolist(ed->seqbasep, &new); + + BIF_undo_push("Add Duplicate, Sequencer"); + transform_seq_nomarker('g', 0); +} + +int insert_gap(Scene *scene, int gap, int cfra) +{ + Sequence *seq; + Editing *ed; + int done=0; + + /* all strips >= cfra are shifted */ + ed= scene->ed; + if(ed==NULL) return 0; + + SEQP_BEGIN(ed, seq) { + if(seq->startdisp >= cfra) { + seq->start+= gap; + calc_sequence(seq); + done= 1; + } + } + SEQ_END + + return done; +} + +void touch_seq_files(Scene *scene) +{ + Sequence *seq; + Editing *ed; + char str[256]; + + /* touch all strips with movies */ + ed= scene->ed; + if(ed==NULL) return; + + if(okee("Touch and print selected movies")==0) return; + + waitcursor(1); + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + if(seq->type==SEQ_MOVIE) { + if(seq->strip && seq->strip->stripdata) { + BLI_make_file_string(G.sce, str, seq->strip->dir, seq->strip->stripdata->name); + BLI_touch(seq->name); + } + } + + } + } + SEQ_END + + waitcursor(0); +} + +void set_filter_seq(Scene *scene) +{ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return; + + if(okee("Set Deinterlace")==0) return; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + if(seq->type==SEQ_MOVIE) { + seq->flag |= SEQ_FILTERY; + reload_sequence_new_file(scene, seq); + } + + } + } + SEQ_END + +} + +void seq_remap_paths(Scene *scene) +{ + Sequence *seq, *last_seq = get_last_seq(scene); + Editing *ed; + char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX]; + + ed= scene->ed; + if(ed==NULL || last_seq==NULL) + return; + + BLI_strncpy(from, last_seq->strip->dir, FILE_MAX); +// XXX if (0==sbutton(from, 0, sizeof(from)-1, "From: ")) +// return; + + strcpy(to, from); +// XXX if (0==sbutton(to, 0, sizeof(to)-1, "To: ")) +// return; + + if (strcmp(to, from)==0) + return; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + if(strncmp(seq->strip->dir, from, strlen(from))==0) { + printf("found %s\n", seq->strip->dir); + + /* strip off the beginning */ + stripped[0]= 0; + BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX); + + /* new path */ + BLI_strncpy(seq->strip->dir, to, FILE_MAX); + strcat(seq->strip->dir, stripped); + printf("new %s\n", seq->strip->dir); + } + } + } + SEQ_END + + BIF_undo_push("Remap Paths, Sequencer"); +} + + +void no_gaps(Scene *scene) +{ + Editing *ed; + int cfra, first= 0, done; + + ed= scene->ed; + if(ed==NULL) return; + + for(cfra= CFRA; cfra<=EFRA; cfra++) { + if(first==0) { + if( evaluate_seq_frame(scene, cfra) ) first= 1; + } + else { + done= 1; + while( evaluate_seq_frame(scene, cfra) == 0) { + done= insert_gap(scene, -1, cfra); + if(done==0) break; + } + if(done==0) break; + } + } + + BIF_undo_push("No Gaps, Sequencer"); +} + + +/* ****************** META ************************* */ + +void make_meta(Scene *scene) +{ + Sequence *seq, *seqm, *next; + Editing *ed; + int tot; + + ed= scene->ed; + if(ed==NULL) return; + + /* is there more than 1 select */ + tot= 0; + seq= ed->seqbasep->first; + while(seq) { + if(seq->flag & SELECT) { + tot++; + if (seq->type == SEQ_RAM_SOUND) { + error("Can't make Meta Strip from audio"); + return; + } + } + seq= seq->next; + } + if(tot < 1) return; + + if(okee("Make Meta Strip")==0) return; + + /* test relationships */ + seq= ed->seqbasep->first; + while(seq) { + if(seq->flag & SELECT) { + if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && + (seq->seq1->flag & SELECT)==0) tot= 0; + if(seq->seq2 && + (seq->seq2->flag & SELECT)==0) tot= 0; + if(seq->seq3 && + (seq->seq3->flag & SELECT)==0) tot= 0; + } + } + else if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && + (seq->seq1->flag & SELECT)) tot= 0; + if(seq->seq2 && + (seq->seq2->flag & SELECT)) tot= 0; + if(seq->seq3 && + (seq->seq3->flag & SELECT)) tot= 0; + } + if(tot==0) break; + seq= seq->next; + } + if(tot==0) { + error("Please select all related strips"); + return; + } + + /* remove all selected from main list, and put in meta */ + + seqm= alloc_sequence(((Editing *)scene->ed)->seqbasep, 1, 1); + seqm->type= SEQ_META; + seqm->flag= SELECT; + + seq= ed->seqbasep->first; + while(seq) { + next= seq->next; + if(seq!=seqm && (seq->flag & SELECT)) { + BLI_remlink(ed->seqbasep, seq); + BLI_addtail(&seqm->seqbase, seq); + } + seq= next; + } + calc_sequence(seqm); + + seqm->strip= MEM_callocN(sizeof(Strip), "metastrip"); + seqm->strip->len= seqm->len; + seqm->strip->us= 1; + + if( test_overlap_seq(scene, seqm) ) shuffle_seq(scene, seqm); + + BIF_undo_push("Make Meta Strip, Sequencer"); +} + +static int seq_depends_on_meta(Sequence *seq, Sequence *seqm) +{ + if (seq == seqm) return 1; + else if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) return 1; + else if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) return 1; + else if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) return 1; + else return 0; +} + +void un_meta(Scene *scene) +{ + Editing *ed; + Sequence *seq, *last_seq = get_last_seq(scene); + + ed= scene->ed; + if(ed==NULL) return; + + if(last_seq==0 || last_seq->type!=SEQ_META) return; + + if(okee("Un Meta Strip")==0) return; + + addlisttolist(ed->seqbasep, &last_seq->seqbase); + + last_seq->seqbase.first= 0; + last_seq->seqbase.last= 0; + + BLI_remlink(ed->seqbasep, last_seq); + seq_free_sequence(last_seq); + + /* emtpy meta strip, delete all effects depending on it */ + for(seq=ed->seqbasep->first; seq; seq=seq->next) + if((seq->type & SEQ_EFFECT) && seq_depends_on_meta(seq, last_seq)) + seq->flag |= SEQ_FLAG_DELETE; + + recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0); + + /* test for effects and overlap */ + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) { + shuffle_seq(scene, seq); + } + } + } + SEQ_END; + + sort_seq(scene); + + BIF_undo_push("Un-Make Meta Strip, Sequencer"); +} + +void exit_meta(Scene *scene) +{ + Sequence *seq; + MetaStack *ms; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return; + + if(ed->metastack.first==0) return; + + ms= ed->metastack.last; + BLI_remlink(&ed->metastack, ms); + + ed->seqbasep= ms->oldbasep; + + /* recalc all: the meta can have effects connected to it */ + seq= ed->seqbasep->first; + while(seq) { + calc_sequence(seq); + seq= seq->next; + } + + set_last_seq(ms->parseq); + + ms->parseq->flag |= SELECT; + recurs_sel_seq(ms->parseq); + + MEM_freeN(ms); + + BIF_undo_push("Exit Meta Strip, Sequence"); +} + + +void enter_meta(Scene *scene) +{ + MetaStack *ms; + Editing *ed; + Sequence *last_seq= get_last_seq(scene); + + ed= scene->ed; + if(ed==NULL) return; + + if(last_seq==0 || last_seq->type!=SEQ_META || (last_seq->flag & SELECT)==0) { + exit_meta(scene); + return; + } + + ms= MEM_mallocN(sizeof(MetaStack), "metastack"); + BLI_addtail(&ed->metastack, ms); + ms->parseq= last_seq; + ms->oldbasep= ed->seqbasep; + + ed->seqbasep= &last_seq->seqbase; + + set_last_seq(NULL); + BIF_undo_push("Enter Meta Strip, Sequence"); +} + + +/* ****************** END META ************************* */ + +static int seq_get_snaplimit(View2D *v2d) +{ + /* fake mouse coords to get the snap value + a bit lazy but its only done once pre transform */ + float xmouse, ymouse, x; + short mval[2] = {24, 0}; /* 24 screen px snap */ + + UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse); + x = xmouse; + mval[0] = 0; + UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse); + return (int)(x - xmouse); +} + +/* use to impose limits when dragging/extending - so impossible situations dont happen */ +static void transform_grab_xlimits(Sequence *seq, int leftflag, int rightflag) +{ + if(leftflag) { + if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_final_right(seq, 0)) { + seq_tx_set_final_left(seq, seq_tx_get_final_right(seq, 0)-1); + } + + if (check_single_seq(seq)==0) { + if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_end(seq)) { + seq_tx_set_final_left(seq, seq_tx_get_end(seq)-1); + } + + /* dosnt work now - TODO */ + /* + if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) { + int ofs; + ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0); + seq->start -= ofs; + seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs ); + }*/ + + } + } + + if(rightflag) { + if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_final_left(seq, 0)) { + seq_tx_set_final_right(seq, seq_tx_get_final_left(seq, 0)+1); + } + + if (check_single_seq(seq)==0) { + if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_start(seq)) { + seq_tx_set_final_right(seq, seq_tx_get_start(seq)+1); + } + } + } + + /* sounds cannot be extended past their endpoints */ + if (seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) { + seq->startstill= 0; + seq->endstill= 0; + } +} + +static int can_transform_seq_test_func(Sequence * seq) +{ + if((seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + return BUILD_SEQAR_COUNT_CURRENT | BUILD_SEQAR_COUNT_CHILDREN; + } + if ((seq->depth==0 && seq->flag & SEQ_LOCK) && !(seq->type & SEQ_EFFECT)) { + if (seq->type != SEQ_META) { + return BUILD_SEQAR_COUNT_NOTHING; + } else { + return BUILD_SEQAR_COUNT_CURRENT; + } + } + return BUILD_SEQAR_COUNT_CURRENT | BUILD_SEQAR_COUNT_CHILDREN; +} + +void transform_seq(Scene *scene, SpaceSeq *sseq, View2D *v2d, int mode, int context) +{ + Sequence *seq, *last_seq; + Editing *ed; + float dx, dy, dvec[2], div; + TransSeq *transmain, *ts; + int totstrip=0, firsttime=1, afbreek=0, midtog= 0, proj= 0; + int ix, iy; /* these values are used for storing the mouses offset from its original location */ + int ix_old = 0; + unsigned short event = 0; + short mval[2], xo, yo, xn, yn; + char str[32]; + char side= 'L'; /* for extend mode only - use to know which side to extend on */ + char marker_moved=0; /* if we mvoed a marker, redraw all marker views */ + /* used for extend in a number of places */ + int cfra = CFRA; + + /* for snapping */ + char snapskip = 0, snap, snap_old= 0; + int snapdist_max = seq_get_snaplimit(v2d); + /* at the moment there are only 4 possible snap points, + - last_seq (start,end) + - selected bounds (start/end) + - last_seq (next/prev) + - current frame */ + int snap_points[4], snap_point_num = 0; + int j; /* loop on snap_points */ + + /* for markers */ + int *oldframe = NULL, totmark=0, a; + TimeMarker *marker; + + /* looping on sequences, WHILE_SEQ macro allocates memory each time */ + int totseq_index, seq_index; + Sequence **seqar = 0; + + if(mode!='g' && mode!='e') return; /* from gesture */ + + /* which seqs are involved */ + ed= scene->ed; + if(ed==NULL) return; + + /* Build the sequence array once, be sure to free it */ + build_seqar_cb( ed->seqbasep, &seqar, &totseq_index, + can_transform_seq_test_func ); + + if (seqar) { + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if((seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) + totstrip++; + /* only needed for extend but can set here anyway since were alredy looping */ + seq->tmp= NULL; + } + } + + /* for extending we need the metastrip clipped left/right values, set the metastrips as parents in seq->tmp */ + if (mode=='e') { + Sequence *meta_seq; + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if (seq->type == SEQ_META) { + for (meta_seq = seq->seqbase.first; meta_seq; meta_seq= meta_seq->next){ + meta_seq->tmp= (void *)seq; + } + } + } + } + + + if (sseq->flag & SEQ_MARKER_TRANS) { + for(marker= scene->markers.first; marker; marker= marker->next) { + if(marker->flag & SELECT) totmark++; + } + } + + if(totstrip==0 && totmark==0) { + if(seqar) MEM_freeN(seqar); + return; + } + + G.moving= 1; + + last_seq = get_last_seq(scene); + + ts=transmain= MEM_callocN(totstrip*sizeof(TransSeq), "transseq"); + + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if((seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + ts->start= seq->start; + ts->machine= seq->machine; + ts->startstill= seq->startstill; + ts->endstill= seq->endstill; + ts->startofs= seq->startofs; + ts->endofs= seq->endofs; + + /* for extend only */ + if (mode=='e') { + ts->final_left = seq_tx_get_final_left(seq, 1); + ts->final_right = seq_tx_get_final_right(seq, 1); + } + ts++; + } + } + +// getmouseco_areawin(mval); + + /* choose the side based on which side of the playhead the mouse is on */ + if (mode=='e') + side = mouse_cfra_side(v2d, cfra); + + /* Markers */ + if (sseq->flag & SEQ_MARKER_TRANS && totmark) { + oldframe= MEM_mallocN(totmark*sizeof(int), "marker array"); + for(a=0, marker= scene->markers.first; marker; marker= marker->next) { + if(marker->flag & SELECT) { + if (mode=='e') { + + /* when extending, invalidate markers on the other side by using an invalid frame value */ + if ((side == 'L' && marker->frame > cfra) || (side == 'R' && marker->frame < cfra)) { + oldframe[a] = MAXFRAME+1; + } else { + oldframe[a]= marker->frame; + } + } else { + oldframe[a]= marker->frame; + } + a++; + } + } + } + + xo=xn= mval[0]; + yo=yn= mval[1]; + dvec[0]= dvec[1]= 0.0; + + while(afbreek==0) { +// getmouseco_areawin(mval); + // XXX G.qual = get_qual(); + // snap = (G.qual & LR_CTRLKEY) ? 1 : 0; + + if(mval[0]!=xo || mval[1]!=yo || firsttime || snap != snap_old) { + if (firsttime) { + snap_old = snap; + firsttime= 0; + } + + /* run for either grab or extend */ + dx= mval[0]- xo; + dy= mval[1]- yo; + + div= v2d->mask.xmax-v2d->mask.xmin; + dx= (v2d->cur.xmax-v2d->cur.xmin)*(dx)/div; + + div= v2d->mask.ymax-v2d->mask.ymin; + dy= (v2d->cur.ymax-v2d->cur.ymin)*(dy)/div; + + if(0) { // XXX G.qual & LR_SHIFTKEY) { + if(dx>1.0) dx= 1.0; else if(dx<-1.0) dx= -1.0; + } + + dvec[0]+= dx; + dvec[1]+= dy; + + if(midtog) dvec[proj]= 0.0; + ix= floor(dvec[0]+0.5); + iy= floor(dvec[1]+0.5); + + ts= transmain; + + /* SNAP! use the active Seq */ + // XXX snap = G.qual & LR_CTRLKEY ? 1 : 0; + + if (!snap) { + snapskip = 0; + } else { + int dist; + int snap_ofs= 0; + int snap_dist= snapdist_max; + + /* Get sequence points to snap to the markers */ + + snap_point_num=0; + if (last_seq && (last_seq->flag & SELECT)) { /* active seq bounds */ + if(seq_tx_check_left(last_seq)) + snap_points[snap_point_num++] = seq_tx_get_final_left(last_seq, 0); + if(seq_tx_check_right(last_seq)) + snap_points[snap_point_num++] = seq_tx_get_final_right(last_seq, 0); + + } + if (totstrip > 1) { /* selection bounds */ + int bounds_left = MAXFRAME*2; + int bounds_right = -(MAXFRAME*2); + + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT) { + if(seq_tx_check_left(seq)) + bounds_left = MIN2(bounds_left, seq_tx_get_final_left(seq, 0)); + if(seq_tx_check_right(seq)) + bounds_right = MAX2(bounds_right,seq_tx_get_final_right(seq, 0)); + } + } + + /* its possible there were no points to set on either side */ + if (bounds_left != MAXFRAME*2) + snap_points[snap_point_num++] = bounds_left; + if (bounds_right != -(MAXFRAME*2)) + snap_points[snap_point_num++] = bounds_right; + } + + + /* Define so we can snap to other points without hassle */ + +#define TESTSNAP(test_frame)\ + for(j=0; jmarkers.first; marker; a++, marker= marker->next) { + + /* dont snap to a marker on the wrong extend side */ + if (mode=='e' && ((side == 'L' && marker->frame > cfra) || (side == 'R' && marker->frame < cfra))) + continue; + + /* when we are moving markers, dont snap to selected markers, durr */ + if ((sseq->flag & SEQ_MARKER_TRANS)==0 || (marker->flag & SELECT)==0) { + + /* loop over the sticky points - max 4 */ + TESTSNAP(marker->frame); + if (snap_dist == 0) break; /* alredy snapped? - stop looking */ + } + } + + if (snap_dist) { + TESTSNAP(cfra); + } + + /* check seq's next to the active also - nice for quick snapping */ + if (snap_dist && last_seq && seq_tx_check_left(last_seq)) { + seq = find_next_prev_sequence(scene, last_seq, 1, 0); /* left */ + if(seq && !seq_tx_check_right(seq)) + TESTSNAP(seq_tx_get_final_right(seq, 0)); + } + + if (snap_dist && last_seq && seq_tx_check_right(last_seq)) { + seq = find_next_prev_sequence(scene, last_seq, 2, 0); /* right */ + if(seq && !seq_tx_check_left(seq)) + TESTSNAP(seq_tx_get_final_left(seq, 0)); + } + +#undef TESTSNAP + + if (abs(ix_old-ix) >= snapdist_max) { + /* mouse has moved out of snap range */ + snapskip = 0; + } else if (snap_dist==0) { + /* nowhere to move, dont do anything */ + snapskip = 1; + } else if (snap_dist < snapdist_max) { + /* do the snapping by adjusting the mouse offset value */ + ix = ix_old + snap_ofs; + } + } + + if (mode=='g' && !snapskip) { + /* Grab */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + int myofs; + /* flag, ignores lefsel/rightsel for nested strips */ + int sel_flag = (seq->depth==0) ? seq->flag : seq->flag & ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); + + // SEQ_DEBUG_INFO(seq); + + /* X Transformation */ + if((seq->depth==0) && (sel_flag & SEQ_LEFTSEL)) { + myofs = (ts->startofs - ts->startstill); + seq_tx_set_final_left(seq, ts->start + (myofs + ix)); + } + if((seq->depth==0) && (sel_flag & SEQ_RIGHTSEL)) { + myofs = (ts->endstill - ts->endofs); + seq_tx_set_final_right(seq, ts->start + seq->len + (myofs + ix)); + } + transform_grab_xlimits(seq, sel_flag & SEQ_LEFTSEL, sel_flag & SEQ_RIGHTSEL); + + if( (sel_flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))==0 ) { + if(sequence_is_free_transformable(seq)) seq->start= ts->start+ ix; + + /* Y Transformation */ + if(seq->depth==0) seq->machine= ts->machine+ iy; + + if(seq->machine<1) seq->machine= 1; + else if(seq->machine>= MAXSEQ) seq->machine= MAXSEQ; + } + calc_sequence(seq); + ts++; + } + } + + /* Markers */ + if (sseq->flag & SEQ_MARKER_TRANS) { + for(a=0, marker= scene->markers.first; marker; marker= marker->next) { + if(marker->flag & SELECT) { + marker->frame= oldframe[a] + ix; + marker_moved=1; + a++; + } + } + } + + /* Extend, grabs one side of the current frame */ + } else if (mode=='e' && !snapskip) { + int myofs; /* offset from start of the seq clip */ + int xnew, final_left, final_right; /* just to store results from seq_tx_get_final_left/right */ + + /* we dont use seq side selection flags for this, + instead we need to calculate which sides to move + based on its initial position from the cursor */ + int move_left, move_right; + + /* Extend, Similar to grab but operate on one side of the cursor */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + /* only move the contents of the metastrip otherwise the transformation is applied twice */ + if (sequence_is_free_transformable(seq) && seq->type != SEQ_META) { + + move_left = move_right = 0; + + //SEQ_DEBUG_INFO(seq); + + final_left = seq_tx_get_final_left(seq, 1); + final_right = seq_tx_get_final_right(seq, 1); + + /* Only X Axis moving */ + + /* work out which sides to move first */ + if (side=='L') { + if (final_left <= cfra || ts->final_left <= cfra) move_left = 1; + if (final_right <= cfra || ts->final_right <= cfra) move_right = 1; + } else { + if (final_left >= cfra || ts->final_left >= cfra) move_left = 1; + if (final_right >= cfra || ts->final_right >= cfra) move_right = 1; + } + + if (move_left && move_right) { + /* simple move - dont need to do anything complicated */ + seq->start= ts->start+ ix; + } else { + if (side=='L') { + if (move_left) { + + /* Similar to other funcs */ + myofs = (ts->startofs - ts->startstill); + xnew = ts->start + (ix + myofs); + + /* make sure the we dont resize down to 0 or less in size + also include the startstill so the contense dosnt go outside the bounds, + if the seq->startofs is 0 then its ignored */ + + /* TODO remove, add check to transform_grab_xlimits, works ok for now */ + if (xnew + seq->startstill > final_right-1) { + xnew = (final_right-1) - seq->startstill; + } + /* Note, this is the only case where the start needs to be adjusted + since its not needed when modifying the end or when moving the entire sequence */ + //seq->start = ts->start+ix; // This works when xnew is not clamped, line below takes clamping into account + seq->start= xnew - myofs; /* TODO see above */ + /* done with unique stuff */ + + seq_tx_set_final_left(seq, xnew); + transform_grab_xlimits(seq, 1, 0); + + /* Special case again - setting the end back to what it was */ + seq_tx_set_final_right(seq, final_right); + } + if (move_right) { + myofs = (ts->endstill - ts->endofs); + xnew = ts->start + seq->len + (myofs + ix); + seq_tx_set_final_right(seq, xnew); + transform_grab_xlimits(seq, 0, 1); + } + } else { /* R */ + if (move_left) { + myofs = (ts->startofs - ts->startstill); + xnew = ts->start + (myofs + ix); + seq_tx_set_final_left(seq, xnew); + transform_grab_xlimits(seq, 1, 0); + } + if (move_right) { + myofs = (ts->endstill - ts->endofs); + xnew = ts->start + seq->len + (myofs + ix); + seq_tx_set_final_right(seq, xnew); + transform_grab_xlimits(seq, 0, 1); + } + } + } + } + calc_sequence(seq); + ts++; + } + } + + /* markers */ + if (sseq->flag & SEQ_MARKER_TRANS) { + for(a=0, marker= scene->markers.first; marker; marker= marker->next) {\ + if (marker->flag & SELECT) { + if(oldframe[a] != MAXFRAME+1) { + marker->frame= oldframe[a] + ix; + marker_moved=1; + } + a++; + } + } + } + } + + sprintf(str, "X: %d Y: %d ", ix, iy); +// headerprint(str); + + /* remember the last value for snapping, + only set if we are not currently snapped, + prevents locking on a keyframe */ + if (!snapskip) + ix_old = ix; + + /* just to tell if ctrl was pressed, this means we get a recalc when pressing ctrl */ + snap_old = snap; + + /* rememver last mouse values so we can skip transform when nothing happens */ + xo= mval[0]; + yo= mval[1]; + + /* test for effect and overlap */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if((seq->depth==0) && (seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) { + seq->flag |= SEQ_OVERLAP; + } + } + else if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(seq); + else if(seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(seq); + else if(seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(seq); + } + } + /* warning, drawing should NEVER use WHILE_SEQ, + if it does the seq->depth value will be messed up and + overlap checks with metastrips will give incorrect results */ +// XXX force_draw_plus(SPACE_BUTS, 0); + + } + +#if 0 + while(qtest()) { + event= extern_qread(&val); + if(val) { + switch(event) { + case ESCKEY: + case LEFTMOUSE: + case RIGHTMOUSE: + case SPACEKEY: + case RETKEY: + afbreek= 1; + break; + case XKEY: + if(!(midtog && (proj == 0))) { + midtog= ~midtog; + } + if(midtog) { + proj= 1; + firsttime= 1; + } + break; + case YKEY: + if(!(midtog && (proj == 1))) { + midtog= ~midtog; + } + if(midtog) { + proj= 0; + firsttime= 1; + } + break; + case MIDDLEMOUSE: + midtog= ~midtog; + if(midtog) { + if( abs(mval[0]-xn) > abs(mval[1]-yn)) proj= 1; + else proj= 0; + firsttime= 1; + } + break; + default: + arrows_move_cursor(event); + } + } + if(afbreek) break; + } +#endif + } + + if((event==ESCKEY) || (event==RIGHTMOUSE)) { + + ts= transmain; + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + seq->start= ts->start; + seq->machine= ts->machine; + seq->startstill= ts->startstill; + seq->endstill= ts->endstill; + seq->startofs= ts->startofs; + seq->endofs= ts->endofs; + + calc_sequence(seq); + seq->flag &= ~SEQ_OVERLAP; + + ts++; + } else if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(seq); + else if(seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(seq); + else if(seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(seq); + } + } + + /* Markers */ + if (sseq->flag & SEQ_MARKER_TRANS) { + for(a=0, marker= scene->markers.first; marker; marker= marker->next) { + if (marker->flag & SELECT) { + if(oldframe[a] != MAXFRAME+1) { + marker->frame= oldframe[a]; + } + a++; + } + } + marker_moved = 0; + } + } else { + + /* images, effects and overlap */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + + /* fixes single image strips - makes sure their start is not out of bounds + ideally this would be done during transform since data is rendered at that time + however it ends up being a lot messier! - Campbell */ + fix_single_image_seq(seq); + + if(seq->type == SEQ_META) { + calc_sequence(seq); + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) shuffle_seq(scene, seq); + } + else if(seq->flag & SELECT) { + calc_sequence(seq); + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) shuffle_seq(scene, seq); + } + else if(seq->type & SEQ_EFFECT) calc_sequence(seq); + } + + /* as last: */ + sort_seq(scene); + } + + /* free sequence array */ + if(seqar) MEM_freeN(seqar); + + G.moving= 0; + MEM_freeN(transmain); + + if (sseq->flag & SEQ_MARKER_TRANS && totmark) + MEM_freeN(oldframe); + + if (mode=='g') + BIF_undo_push("Transform Grab, Sequencer"); + else if (mode=='e') + BIF_undo_push("Transform Extend, Sequencer"); + +} + +/* since grab can move markers, we must turn this off before adding a new sequence + I am not so happy with this, but the baddness in contained here - Campbell */ + +/* XXX temp disabled, will work differently anyway */ +void _transform_seq_nomarker_(Scene *scene, SpaceSeq *sseq, View2D *v2d, int mode, int context) +{ + int flag_back; + if (!sseq) return; /* should never happen */ + + flag_back = sseq->flag; + sseq->flag &= ~SEQ_MARKER_TRANS; + + transform_seq(scene, sseq, v2d, mode, context); + + sseq->flag = flag_back; +} + +void seq_separate_images(Scene *scene) +{ + Editing *ed; + Sequence *seq, *seq_new, *seq_next; + Strip *strip_new; + StripElem *se, *se_new; + int start_ofs, cfra, frame_end; + static int step= 1; + +// add_numbut(0, NUM|INT, "Image Duration:", 1, 256, &step, NULL); +// if (!do_clever_numbuts("Separate Images", 1, REDRAW)) +// return; + + ed= scene->ed; + if(ed==NULL) return; + + seq= ed->seqbasep->first; + + while (seq) { + if((seq->flag & SELECT) && (seq->type == SEQ_IMAGE) && (seq->len > 1)) { + /* remove seq so overlap tests dont conflict, + see seq_free_sequence below for the real free'ing */ + seq_next = seq->next; + BLI_remlink(ed->seqbasep, seq); + if(seq->ipo) seq->ipo->id.us--; + + start_ofs = cfra = seq_tx_get_final_left(seq, 0); + frame_end = seq_tx_get_final_right(seq, 0); + + while (cfra < frame_end) { + /* new seq */ + se = give_stripelem(seq, cfra); + + seq_new= alloc_sequence(((Editing *)scene->ed)->seqbasep, start_ofs, seq->machine); + seq_new->type= SEQ_IMAGE; + seq_new->len = 1; + seq_new->endstill = step-1; + + /* new strip */ + seq_new->strip= strip_new= MEM_callocN(sizeof(Strip)*1, "strip"); + strip_new->len= 1; + strip_new->us= 1; + strncpy(strip_new->dir, seq->strip->dir, FILE_MAXDIR-1); + + /* new stripdata */ + strip_new->stripdata= se_new= MEM_callocN(sizeof(StripElem)*1, "stripelem"); + strncpy(se_new->name, se->name, FILE_MAXFILE-1); + calc_sequence(seq_new); + seq_new->flag &= ~SEQ_OVERLAP; + if (test_overlap_seq(scene, seq_new)) { + shuffle_seq(scene, seq_new); + } + + cfra++; + start_ofs += step; + } + + seq_free_sequence(seq); + seq = seq->next; + } else { + seq = seq->next; + } + } + + /* as last: */ + sort_seq(scene); + BIF_undo_push("Separate Image Strips, Sequencer"); +} + +/* run recursivly to select linked */ +static int select_more_less_seq__internal(Scene *scene, int sel, int linked) { + Editing *ed; + Sequence *seq, *neighbor; + int change=0; + int isel; + + ed= scene->ed; + if(ed==NULL) return 0; + + if (sel) { + sel = SELECT; + isel = 0; + } else { + sel = 0; + isel = SELECT; + } + + if (!linked) { + /* if not linked we only want to touch each seq once, newseq */ + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + seq->tmp = NULL; + } + } + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if((int)(seq->flag & SELECT) == sel) { + if ((linked==0 && seq->tmp)==0) { + /* only get unselected nabours */ + neighbor = find_neighboring_sequence(scene, seq, 1, isel); + if (neighbor) { + if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);} + else neighbor->flag &= ~SELECT; + if (linked==0) neighbor->tmp = (Sequence *)1; + change = 1; + } + neighbor = find_neighboring_sequence(scene, seq, 2, isel); + if (neighbor) { + if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);} + else neighbor->flag &= ~SELECT; + if (linked==0) neighbor->tmp = (void *)1; + change = 1; + } + } + } + } + + return change; +} + +void select_less_seq(Scene *scene) +{ + if (select_more_less_seq__internal(scene, 0, 0)) { + BIF_undo_push("Select Less, Sequencer"); + } +} + +void select_more_seq(Scene *scene) +{ + if (select_more_less_seq__internal(scene, 1, 0)) { + BIF_undo_push("Select More, Sequencer"); + } +} + +/* TODO not all modes supported - if you feel like being picky, add them! ;) */ +void select_linked_seq(Scene *scene, View2D *v2d, int mode) +{ + Editing *ed; + Sequence *seq, *mouse_seq; + int selected, hand; + + ed= scene->ed; + if(ed==NULL) return; + + /* replace current selection */ + if (mode==0 || mode==2) { + /* this works like UV, not mesh */ + if (mode==0) { + mouse_seq= find_nearest_seq(scene, v2d, &hand); + if (!mouse_seq) + return; /* user error as with mesh?? */ + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + seq->flag &= ~SELECT; + } + mouse_seq->flag |= SELECT; + recurs_sel_seq(mouse_seq); + } + + selected = 1; + while (selected) { + selected = select_more_less_seq__internal(scene, 1, 1); + } + BIF_undo_push("Select Linked, Sequencer"); + } + /* TODO - more modes... */ +} + +void seq_snap(Scene *scene, short event) +{ + Editing *ed; + Sequence *seq; + + ed= scene->ed; + if(ed==NULL) return; + + /* problem: contents of meta's are all shifted to the same position... */ + + /* also check metas */ + SEQP_BEGIN(ed, seq) { + if (seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK) && + sequence_is_free_transformable(seq)) { + if((seq->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))==0) { + seq->start= CFRA-seq->startofs+seq->startstill; + } else { + if(seq->flag & SEQ_LEFTSEL) { + seq_tx_set_final_left(seq, CFRA); + } else { /* SEQ_RIGHTSEL */ + seq_tx_set_final_right(seq, CFRA); + } + transform_grab_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); + } + calc_sequence(seq); + } + } + SEQ_END + + /* test for effects and overlap */ + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) { + shuffle_seq(scene, seq); + } + } + else if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && (seq->seq1->flag & SELECT)) + calc_sequence(seq); + else if(seq->seq2 && (seq->seq2->flag & SELECT)) + calc_sequence(seq); + else if(seq->seq3 && (seq->seq3->flag & SELECT)) + calc_sequence(seq); + } + } + SEQ_END; + + /* as last: */ + sort_seq(scene); + + BIF_undo_push("Snap Strips, Sequencer"); +} + +void seq_snap_menu(Scene *scene) +{ + short event; + + event= pupmenu("Snap %t|To Current Frame%x1"); + if(event < 1) return; + + seq_snap(scene, event); +} + + +void seq_mute_sel(Scene *scene, int mute) { + Editing *ed; + Sequence *seq; + + ed= scene->ed; + if(!ed) return; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if ((seq->flag & SEQ_LOCK)==0) { + if (mute==-1) { /* hide unselected */ + if ((seq->flag & SELECT)==0) { + seq->flag |= SEQ_MUTE; + } + } else if (seq->flag & SELECT) { + if (mute) seq->flag |= SEQ_MUTE; + else seq->flag &= ~SEQ_MUTE; + } + } + } + BIF_undo_push(mute?"Mute Strips, Sequencer":"UnMute Strips, Sequencer"); +} + +void seq_lock_sel(Scene *scene, int lock) +{ + Editing *ed; + Sequence *seq; + + ed= scene->ed; + if(!ed) return; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if ((seq->flag & SELECT)) { + if (lock) seq->flag |= SEQ_LOCK; + else seq->flag &= ~SEQ_LOCK; + } + } + BIF_undo_push(lock?"Lock Strips, Sequencer":"Unlock Strips, Sequencer"); +} + +void borderselect_seq(Scene *scene, View2D *v2d) +{ + Sequence *seq; + Editing *ed; + rcti rect; + rctf rectf, rq; + int val; + short mval[2]; + + ed= scene->ed; + if(ed==NULL) return; + +// XXX val= get_border(&rect, 3); + + if(val) { + mval[0]= rect.xmin; + mval[1]= rect.ymin; + UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmin, &rectf.ymin); + mval[0]= rect.xmax; + mval[1]= rect.ymax; + UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmax, &rectf.ymax); + + seq= ed->seqbasep->first; + while(seq) { + + if(seq->startstill) rq.xmin= seq->start; + else rq.xmin= seq->startdisp; + rq.ymin= seq->machine+0.2; + if(seq->endstill) rq.xmax= seq->start+seq->len; + else rq.xmax= seq->enddisp; + rq.ymax= seq->machine+0.8; + + if(BLI_isect_rctf(&rq, &rectf, 0)) { + if(val==LEFTMOUSE) { + seq->flag |= SELECT; + } + else { + seq->flag &= ~SELECT; + } + recurs_sel_seq(seq); + } + + seq= seq->next; + } + + BIF_undo_push("Border Select, Sequencer"); + } +} diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c new file mode 100644 index 00000000000..b8b8f4af36c --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -0,0 +1,1135 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2003-2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BMF_Api.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "IMB_imbuf_types.h" + +#include "DNA_gpencil_types.h" +#include "DNA_sequence_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view2d_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_plugin_types.h" +#include "BKE_sequence.h" +#include "BKE_scene.h" +#include "BKE_utildefines.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +/* own include */ +#include "sequencer_intern.h" + +#define SEQ_LEFTHANDLE 1 +#define SEQ_RIGHTHANDLE 2 + +#define SEQ_STRIP_OFSBOTTOM 0.2 +#define SEQ_STRIP_OFSTOP 0.8 + +/* Note, Dont use WHILE_SEQ while drawing! - it messes up transform, - Campbell */ + +int no_rightbox=0, no_leftbox= 0; +static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2); + + +static void draw_cfra_seq(View2D *v2d, int cfra) +{ + glColor3ub(0x30, 0x90, 0x50); + glLineWidth(2.0); + glBegin(GL_LINES); + glVertex2f(cfra, v2d->cur.ymin); + glVertex2f(cfra, v2d->cur.ymax); + glEnd(); + glLineWidth(1.0); +} + +static void get_seq_color3ubv(Scene *curscene, Sequence *seq, char *col) +{ + char blendcol[3]; + float hsv[3], rgb[3]; + SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; + + switch(seq->type) { + case SEQ_IMAGE: + UI_GetThemeColor3ubv(TH_SEQ_IMAGE, col); + break; + case SEQ_META: + UI_GetThemeColor3ubv(TH_SEQ_META, col); + break; + case SEQ_MOVIE: + UI_GetThemeColor3ubv(TH_SEQ_MOVIE, col); + break; + case SEQ_SCENE: + UI_GetThemeColor3ubv(TH_SEQ_SCENE, col); + + if(seq->scene==curscene) { + UI_GetColorPtrBlendShade3ubv(col, col, col, 1.0, 20); + } + break; + + /* transitions */ + case SEQ_CROSS: + case SEQ_GAMCROSS: + case SEQ_WIPE: + /* slightly offset hue to distinguish different effects */ + UI_GetThemeColor3ubv(TH_SEQ_TRANSITION, col); + + rgb[0] = col[0]/255.0; rgb[1] = col[1]/255.0; rgb[2] = col[2]/255.0; + rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); + + if (seq->type == SEQ_CROSS) hsv[0]+= 0.04; + if (seq->type == SEQ_GAMCROSS) hsv[0]+= 0.08; + if (seq->type == SEQ_WIPE) hsv[0]+= 0.12; + + if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2); + col[0] = (char)(rgb[0]*255); col[1] = (char)(rgb[1]*255); col[2] = (char)(rgb[2]*255); + break; + + /* effects */ + case SEQ_TRANSFORM: + case SEQ_SPEED: + case SEQ_ADD: + case SEQ_SUB: + case SEQ_MUL: + case SEQ_ALPHAOVER: + case SEQ_ALPHAUNDER: + case SEQ_OVERDROP: + case SEQ_GLOW: + /* slightly offset hue to distinguish different effects */ + UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col); + + rgb[0] = col[0]/255.0; rgb[1] = col[1]/255.0; rgb[2] = col[2]/255.0; + rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); + + if (seq->type == SEQ_ADD) hsv[0]+= 0.04; + if (seq->type == SEQ_SUB) hsv[0]+= 0.08; + if (seq->type == SEQ_MUL) hsv[0]+= 0.12; + if (seq->type == SEQ_ALPHAOVER) hsv[0]+= 0.16; + if (seq->type == SEQ_ALPHAUNDER) hsv[0]+= 0.20; + if (seq->type == SEQ_OVERDROP) hsv[0]+= 0.24; + if (seq->type == SEQ_GLOW) hsv[0]+= 0.28; + if (seq->type == SEQ_TRANSFORM) hsv[0]+= 0.36; + + if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2); + col[0] = (char)(rgb[0]*255); col[1] = (char)(rgb[1]*255); col[2] = (char)(rgb[2]*255); + break; + case SEQ_COLOR: + if (colvars->col) { + col[0]= (char)(colvars->col[0]*255); + col[1]= (char)(colvars->col[1]*255); + col[2]= (char)(colvars->col[2]*255); + } else { + col[0] = col[1] = col[2] = 128; + } + break; + case SEQ_PLUGIN: + UI_GetThemeColor3ubv(TH_SEQ_PLUGIN, col); + break; + case SEQ_HD_SOUND: + case SEQ_RAM_SOUND: + UI_GetThemeColor3ubv(TH_SEQ_AUDIO, col); + blendcol[0] = blendcol[1] = blendcol[2] = 128; + if(seq->flag & SEQ_MUTE) UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5, 20); + break; + default: + col[0] = 10; col[1] = 255; col[2] = 40; + } +} + +static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2) +{ + /* Note, this used to use WHILE_SEQ, but it messes up the seq->depth value, (needed by transform when doing overlap checks) + * so for now, just use the meta's immediate children, could be fixed but its only drawing - Campbell */ + Sequence *seq; + float dx; + int nr; + char col[3]; + + nr= BLI_countlist(&seqm->seqbase); + + dx= (x2-x1)/nr; + + if (seqm->flag & SEQ_MUTE) { + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(stipple_halftone); + + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, 0x8888); + } + + for (seq= seqm->seqbase.first; seq; seq= seq->next) { + get_seq_color3ubv(scene, seq, col); + + glColor3ubv((GLubyte *)col); + + glRectf(x1, y1, x1+0.9*dx, y2); + + UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -30); + glColor3ubv((GLubyte *)col); + + fdrawbox(x1, y1, x1+0.9*dx, y2); + + x1+= dx; + } + + if (seqm->flag & SEQ_MUTE) { + glDisable(GL_POLYGON_STIPPLE); + glDisable(GL_LINE_STIPPLE); + } +} + +static void drawseqwave(Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, int winx) +{ + /* + x1 is the starting x value to draw the wave, + x2 the end x value, same for y1 and y2 + winx is the zoom level. + */ + + float + f, /* floating point value used to store the X draw location for the wave lines when openGL drawing*/ + midy, /* fast access to the middle location (y1+y2)/2 */ + clipxmin, /* the minimum X value, clip this with the window */ + clipxmax, /* the maximum X value, clip this with the window */ + sample_step, /* steps to move per sample, floating value must later translate into an int */ + fsofs, /* steps to move per sample, floating value must later translate into an int */ + feofs_sofs, /* */ + sound_width, /* convenience: x2-x1 */ + wavemulti; /* scale the samples by this value when GL_LINE drawing so it renders the right height */ + + int + offset, /* initial offset value for the wave drawing */ + offset_next, /* when in the wave drawing loop this value is the samples intil the next vert */ + sofs, /* Constrained offset value (~3) for the wave, start */ + eofs, /* ditto, end */ + wavesample, /* inner loop storage if the current wave sample value, used to make the 2 values below */ + wavesamplemin, /* used for finding the min and max wave peaks */ + wavesamplemax, /* ditto */ + subsample_step=4; /* when the sample step is 4 every sample of + the wave is evaluated for min and max values used to draw the wave, + however this is slow ehrn zoomed out so when the sample step is above + 1 (the larger the further out the zoom is) so not evaluate all samples, only some. */ + + signed short* s; + bSound *sound; + uint8_t *stream; + +// XXX audio_makestream(seq->sound); +// if(seq->sound==NULL || seq->sound->stream==NULL) return; + + if (seq->flag & SEQ_MUTE) glColor3ub(0x70, 0x80, 0x80); else glColor3ub(0x70, 0xc0, 0xc0); + + sofs = ((int)( FRA2TIME(seq->startdisp-seq->start+seq->anim_startofs)*(float)scene->r.audio.mixrate*4.0 )) & (~3); + eofs = ((int)( FRA2TIME(seq->enddisp-seq->start+seq->anim_startofs)*(float)scene->r.audio.mixrate*4.0 )) & (~3); + + /* clip the drawing area to the screen bounds to save time */ + sample_step= (v2d->cur.xmax - v2d->cur.xmin)/winx; + clipxmin= MAX2(x1, v2d->cur.xmin); + clipxmax= MIN2(x2, v2d->cur.xmax); + + if (sample_step > 1) + subsample_step= ((int)(subsample_step*sample_step*8)) & (~3); + + /* for speedy access */ + midy = (y1+y2)/2; + fsofs= (float)sofs; + feofs_sofs= (float)(eofs-sofs); + sound_width= x2-x1; + sound = seq->sound; + stream = sound->stream; + wavemulti = (y2-y1)/196605; /*y2-y1 is the height*/ + wavesample=0; + + /* we need to get the starting offset value, excuse the duplicate code */ + f=clipxmin; + offset= (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3); + + /* start the loop, draw a line per sample_step -sample_step is about 1 line drawn per pixel */ + glBegin(GL_LINES); + for (f=x1+sample_step; f<=clipxmax; f+=sample_step) { + + offset_next = (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3); + if (f > v2d->cur.xmin) { + /* if this is close to the last sample just exit */ + if (offset_next >= sound->streamlen) break; + + wavesamplemin = 131070; + wavesamplemax = -131070; + + /*find with high and low of the waveform for this draw, + evaluate small samples to find this range */ + while (offset < offset_next) { + s = (signed short*)(stream+offset); + + wavesample = s[0]*2 + s[1]; + if (wavesamplemin>wavesample) + wavesamplemin=wavesample; + if (wavesamplemaxstartdisp; + x2= seq->enddisp; + + y1= seq->machine+SEQ_STRIP_OFSBOTTOM; + y2= seq->machine+SEQ_STRIP_OFSTOP; + + v2d = &sseq->v2d; + + /* clamp handles to defined size in pixel space */ + handsize = seq->handsize; + minhandle = 7; + maxhandle = 40; + CLAMP(handsize, minhandle*pixelx, maxhandle*pixelx); + + /* set up co-ordinates/dimensions for either left or right handle */ + if (direction == SEQ_LEFTHANDLE) { + rx1 = x1; + rx2 = x1+handsize*0.75; + + v1[0]= x1+handsize/4; v1[1]= y1+( ((y1+y2)/2.0 - y1)/2); + v2[0]= x1+handsize/4; v2[1]= y2-( ((y1+y2)/2.0 - y1)/2); + v3[0]= v2[0] + handsize/4; v3[1]= (y1+y2)/2.0; + + whichsel = SEQ_LEFTSEL; + } else if (direction == SEQ_RIGHTHANDLE) { + rx1 = x2-handsize*0.75; + rx2 = x2; + + v1[0]= x2-handsize/4; v1[1]= y1+( ((y1+y2)/2.0 - y1)/2); + v2[0]= x2-handsize/4; v2[1]= y2-( ((y1+y2)/2.0 - y1)/2); + v3[0]= v2[0] - handsize/4; v3[1]= (y1+y2)/2.0; + + whichsel = SEQ_RIGHTSEL; + } + + /* draw! */ + if(seq->type < SEQ_EFFECT || + get_sequence_effect_num_inputs(seq->type) == 0) { + glEnable( GL_BLEND ); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if(seq->flag & whichsel) glColor4ub(0, 0, 0, 80); + else if (seq->flag & SELECT) glColor4ub(255, 255, 255, 30); + else glColor4ub(0, 0, 0, 22); + + glRectf(rx1, y1, rx2, y2); + + if(seq->flag & whichsel) glColor4ub(255, 255, 255, 200); + else glColor4ub(0, 0, 0, 50); + + glEnable( GL_POLYGON_SMOOTH ); + glBegin(GL_TRIANGLES); + glVertex2fv(v1); glVertex2fv(v2); glVertex2fv(v3); + glEnd(); + + glDisable( GL_POLYGON_SMOOTH ); + glDisable( GL_BLEND ); + } + + if(G.moving || (seq->flag & whichsel)) { + cpack(0xFFFFFF); + if (direction == SEQ_LEFTHANDLE) { + sprintf(str, "%d", seq->startdisp); + glRasterPos3f(rx1, y1-0.15, 0.0); + } else { + sprintf(str, "%d", seq->enddisp - 1); + glRasterPos3f((x2-BMF_GetStringWidth(G.fonts, str)*pixelx), y2+0.05, 0.0); + } + BMF_DrawString(G.fonts, str); + } +} + +static void draw_seq_extensions(Scene *scene, SpaceSeq *sseq, Sequence *seq) +{ + float x1, x2, y1, y2, pixely, a; + char col[3], blendcol[3]; + View2D *v2d; + + if(seq->type >= SEQ_EFFECT) return; + + x1= seq->startdisp; + x2= seq->enddisp; + + y1= seq->machine+SEQ_STRIP_OFSBOTTOM; + y2= seq->machine+SEQ_STRIP_OFSTOP; + + v2d = &sseq->v2d; + pixely = (v2d->cur.ymax - v2d->cur.ymin)/(v2d->mask.ymax - v2d->mask.ymin); + + blendcol[0] = blendcol[1] = blendcol[2] = 120; + + if(seq->startofs) { + glEnable( GL_BLEND ); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + get_seq_color3ubv(scene, seq, col); + + if (seq->flag & SELECT) { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); + glColor4ub(col[0], col[1], col[2], 170); + } else { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); + glColor4ub(col[0], col[1], col[2], 110); + } + + glRectf((float)(seq->start), y1-SEQ_STRIP_OFSBOTTOM, x1, y1); + + if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); + else glColor4ub(col[0], col[1], col[2], 160); + + fdrawbox((float)(seq->start), y1-SEQ_STRIP_OFSBOTTOM, x1, y1); //outline + + glDisable( GL_BLEND ); + } + if(seq->endofs) { + glEnable( GL_BLEND ); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + get_seq_color3ubv(scene, seq, col); + + if (seq->flag & SELECT) { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); + glColor4ub(col[0], col[1], col[2], 170); + } else { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); + glColor4ub(col[0], col[1], col[2], 110); + } + + glRectf(x2, y2, (float)(seq->start+seq->len), y2+SEQ_STRIP_OFSBOTTOM); + + if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); + else glColor4ub(col[0], col[1], col[2], 160); + + fdrawbox(x2, y2, (float)(seq->start+seq->len), y2+SEQ_STRIP_OFSBOTTOM); //outline + + glDisable( GL_BLEND ); + } + if(seq->startstill) { + get_seq_color3ubv(scene, seq, col); + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); + glColor3ubv((GLubyte *)col); + + draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2); + + /* feint pinstripes, helps see exactly which is extended and which isn't, + * especially when the extension is very small */ + if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -16); + + glColor3ubv((GLubyte *)col); + + for(a=y1; a< y2; a+= pixely*2.0 ) { + fdrawline(x1, a, (float)(seq->start), a); + } + } + if(seq->endstill) { + get_seq_color3ubv(scene, seq, col); + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); + glColor3ubv((GLubyte *)col); + + draw_shadedstrip(seq, col, (float)(seq->start+seq->len), y1, x2, y2); + + /* feint pinstripes, helps see exactly which is extended and which isn't, + * especially when the extension is very small */ + if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -16); + + glColor3ubv((GLubyte *)col); + + for(a=y1; a< y2; a+= pixely*2.0 ) { + fdrawline((float)(seq->start+seq->len), a, x2, a); + } + } +} + +/* draw info text on a sequence strip */ +static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float y1, float y2, char *background_col) +{ + float v1[2], v2[2]; + int len, size; + char str[32 + FILE_MAXDIR+FILE_MAXFILE], *strp; + short mval[2]; + + v1[1]= y1; + v2[1]= y2; + + v1[0]= x1; + UI_view2d_to_region_no_clip(v2d, v1[0], v1[1], mval, mval+1); + x1= mval[0]; + v2[0]= x2; + UI_view2d_to_region_no_clip(v2d, v2[0], v2[1], mval, mval+1); + x2= mval[0]; + size= x2-x1; + + if(seq->name[2]) { + sprintf(str, "%d | %s: %s", seq->len, give_seqname(seq), seq->name+2); + }else{ + if(seq->type == SEQ_META) { + sprintf(str, "%d | %s", seq->len, give_seqname(seq)); + } + else if(seq->type == SEQ_SCENE) { + if(seq->scene) sprintf(str, "%d | %s: %s", seq->len, give_seqname(seq), seq->scene->id.name+2); + else sprintf(str, "%d | %s", seq->len, give_seqname(seq)); + + } + else if(seq->type == SEQ_IMAGE) { + sprintf(str, "%d | %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name); + } + else if(seq->type & SEQ_EFFECT) { + int can_float = (seq->type != SEQ_PLUGIN) + || (seq->plugin && seq->plugin->version >= 4); + + if(seq->seq3!=seq->seq2 && seq->seq1!=seq->seq3) + sprintf(str, "%d | %s: %d>%d (use %d)%s", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine, seq->seq3->machine, can_float ? "" : " No float, upgrade plugin!"); + else if (seq->seq1 && seq->seq2) + sprintf(str, "%d | %s: %d>%d%s", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine, can_float ? "" : " No float, upgrade plugin!"); + else + sprintf(str, "%d | %s", seq->len, give_seqname(seq)); + } + else if (seq->type == SEQ_RAM_SOUND) { + sprintf(str, "%d | %s", seq->len, seq->strip->stripdata->name); + } + else if (seq->type == SEQ_HD_SOUND) { + sprintf(str, "%d | %s", seq->len, seq->strip->stripdata->name); + } + else if (seq->type == SEQ_MOVIE) { + sprintf(str, "%d | %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name); + } + } + + strp= str; + + while( (len= BMF_GetStringWidth(G.font, strp)) > size) { + if(len < 10) break; + if(strp[1]==0) break; + strp++; + } + + mval[0]= (x1+x2-len+1)/2; + mval[1]= 1; + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x1, &x2); + + if(seq->flag & SELECT){ + cpack(0xFFFFFF); + }else if ((((int)background_col[0] + (int)background_col[1] + (int)background_col[2]) / 3) < 50){ + cpack(0x505050); /* use lighter text colour for dark background */ + }else{ + cpack(0); + } + glRasterPos3f(x1, y1+SEQ_STRIP_OFSBOTTOM, 0.0); + BMF_DrawString(G.font, strp); +} + +/* draws a shaded strip, made from gradient + flat color + gradient */ +static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2) +{ + float ymid1, ymid2; + + if (seq->flag & SEQ_MUTE) { + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(stipple_halftone); + } + + ymid1 = (y2-y1)*0.25 + y1; + ymid2 = (y2-y1)*0.65 + y1; + + glShadeModel(GL_SMOOTH); + glBegin(GL_QUADS); + + if(seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -50); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 0); + + glColor3ubv((GLubyte *)col); + + glVertex2f(x1,y1); + glVertex2f(x2,y1); + + if(seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 5); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -5); + + glColor3ubv((GLubyte *)col); + + glVertex2f(x2,ymid1); + glVertex2f(x1,ymid1); + + glEnd(); + + glRectf(x1, ymid1, x2, ymid2); + + glBegin(GL_QUADS); + + glVertex2f(x1,ymid2); + glVertex2f(x2,ymid2); + + if(seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -15); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 25); + + glColor3ubv((GLubyte *)col); + + glVertex2f(x2,y2); + glVertex2f(x1,y2); + + glEnd(); + + if (seq->flag & SEQ_MUTE) { + glDisable(GL_POLYGON_STIPPLE); + } +} + +/* +Draw a sequence strip, bounds check alredy made +ARegion is currently only used to get the windows width in pixels +so wave file sample drawing precission is zoom adjusted +*/ +static void draw_seq_strip(Scene *scene, ARegion *ar, SpaceSeq *sseq, Sequence *seq, int outline_tint, float pixelx) +{ + // XXX + extern void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown); + View2D *v2d= &ar->v2d; + float x1, x2, y1, y2; + char col[3], background_col[3], is_single_image; + + /* we need to know if this is a single image/color or not for drawing */ + is_single_image = (char)check_single_seq(seq); + + /* body */ + if(seq->startstill) x1= seq->start; + else x1= seq->startdisp; + y1= seq->machine+SEQ_STRIP_OFSBOTTOM; + if(seq->endstill) x2= seq->start+seq->len; + else x2= seq->enddisp; + y2= seq->machine+SEQ_STRIP_OFSTOP; + + + /* get the correct color per strip type*/ + //get_seq_color3ubv(scene, seq, col); + get_seq_color3ubv(scene, seq, background_col); + + /* draw the main strip body */ + if (is_single_image) /* single image */ + draw_shadedstrip(seq, background_col, seq_tx_get_final_left(seq, 0), y1, seq_tx_get_final_right(seq, 0), y2); + else /* normal operation */ + draw_shadedstrip(seq, background_col, x1, y1, x2, y2); + + /* draw additional info and controls */ + if (seq->type == SEQ_RAM_SOUND) + drawseqwave(scene, v2d, seq, x1, y1, x2, y2, ar->winx); + + if (!is_single_image) + draw_seq_extensions(scene, sseq, seq); + + draw_seq_handle(sseq, seq, pixelx, SEQ_LEFTHANDLE); + draw_seq_handle(sseq, seq, pixelx, SEQ_RIGHTHANDLE); + + /* draw the strip outline */ + x1= seq->startdisp; + x2= seq->enddisp; + + get_seq_color3ubv(scene, seq, col); + if (G.moving && (seq->flag & SELECT)) { + if(seq->flag & SEQ_OVERLAP) { + col[0]= 255; col[1]= col[2]= 40; + } else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 120); + } + + UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, outline_tint); + + glColor3ubv((GLubyte *)col); + + if (seq->flag & SEQ_MUTE) { + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, 0x8888); + } + + gl_round_box_shade(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0); + + if (seq->flag & SEQ_MUTE) { + glDisable(GL_LINE_STIPPLE); + } + + /* calculate if seq is long enough to print a name */ + x1= seq->startdisp+seq->handsize; + x2= seq->enddisp-seq->handsize; + + /* but first the contents of a meta */ + if(seq->type==SEQ_META) drawmeta_contents(scene, seq, x1, y1+0.15, x2, y2-0.15); + + /* info text on the strip */ + if(x1cur.xmin) x1= v2d->cur.xmin; + else if(x1>v2d->cur.xmax) x1= v2d->cur.xmax; + if(x2cur.xmin) x2= v2d->cur.xmin; + else if(x2>v2d->cur.xmax) x2= v2d->cur.xmax; + + /* nice text here would require changing the view matrix for texture text */ + if( (x2-x1) / pixelx > 32) { + draw_seq_text(v2d, seq, x1, x2, y1, y2, background_col); + } +} + +static Sequence *special_seq_update= 0; + +void set_special_seq_update(int val) +{ +// int x; + + /* if mouse over a sequence && LEFTMOUSE */ + if(val) { +// XXX special_seq_update= find_nearest_seq(&x); + } + else special_seq_update= 0; +} + + +static void draw_image_seq(Scene *scene, ARegion *ar, SpaceSeq *sseq) +{ + extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); + struct ImBuf *ibuf; + int x1, y1, rectx, recty; + int free_ibuf = 0; + static int recursive= 0; + float zoom; + float zoomx, zoomy; + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + rectx= (scene->r.size*scene->r.xsch)/100; + recty= (scene->r.size*scene->r.ysch)/100; + + /* BIG PROBLEM: the give_ibuf_seq() can call a rendering, which in turn calls redraws... + this shouldn't belong in a window drawing.... + So: solve this once event based. + Now we check for recursion, space type and active area again (ton) */ + + if(recursive) + return; + else { + recursive= 1; + if (special_seq_update) { + ibuf= give_ibuf_seq_direct(scene, rectx, recty, (scene->r.cfra), special_seq_update); + } + else if (!U.prefetchframes) { // XXX || (G.f & G_PLAYANIM) == 0) { + ibuf= (ImBuf *)give_ibuf_seq(scene, rectx, recty, (scene->r.cfra), sseq->chanshown); + } + else { + ibuf= (ImBuf *)give_ibuf_seq_threaded(scene, rectx, recty, (scene->r.cfra), sseq->chanshown); + } + recursive= 0; + + /* XXX HURMF! the give_ibuf_seq can call image display in this window */ +// if(sa->spacetype!=SPACE_SEQ) +// return; +// if(sa!=curarea) { +// areawinset(sa->win); +// } + } + + if(ibuf==NULL) + return; + + if(ibuf->rect==NULL && ibuf->rect_float == NULL) + return; + + switch(sseq->mainb) { + case SEQ_DRAW_IMG_IMBUF: + if (sseq->zebra != 0) { + ibuf = make_zebra_view_from_ibuf(ibuf, sseq->zebra); + free_ibuf = 1; + } + break; + case SEQ_DRAW_IMG_WAVEFORM: + if ((sseq->flag & SEQ_DRAW_COLOR_SEPERATED) != 0) { + ibuf = make_sep_waveform_view_from_ibuf(ibuf); + } else { + ibuf = make_waveform_view_from_ibuf(ibuf); + } + free_ibuf = 1; + break; + case SEQ_DRAW_IMG_VECTORSCOPE: + ibuf = make_vectorscope_view_from_ibuf(ibuf); + free_ibuf = 1; + break; + case SEQ_DRAW_IMG_HISTOGRAM: + ibuf = make_histogram_view_from_ibuf(ibuf); + free_ibuf = 1; + break; + } + + if(ibuf->rect_float && ibuf->rect==NULL) + IMB_rect_from_float(ibuf); + + /* needed for gla draw */ + glaDefine2DArea(&ar->winrct); + + zoom= SEQ_ZOOM_FAC(sseq->zoom); + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + zoomx = zoom * ((float)scene->r.xasp / (float)scene->r.yasp); + zoomy = zoom; + } else { + zoomx = zoomy = zoom; + } + + /* calc location */ + x1= (ar->winx-zoomx*ibuf->x)/2 + sseq->xof; + y1= (ar->winy-zoomy*ibuf->y)/2 + sseq->yof; + + glPixelZoom(zoomx, zoomy); + + glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); + + glPixelZoom(1.0, 1.0); + + /* safety border */ + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && + (sseq->flag & SEQ_DRAW_SAFE_MARGINS) != 0) { + float fac= 0.1; + float x2 = x1 + ibuf->x * zoomx; + float y2 = y1 + ibuf->y * zoomy; + + float a= fac*(x2-x1); + x1+= a; + x2-= a; + + a= fac*(y2-y1); + y1+= a; + y2-= a; + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + setlinestyle(3); + + UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0); + + uiSetRoundBox(15); + gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 12.0); + + setlinestyle(0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + /* draw grease-pencil (image aligned) */ +// if (sseq->flag & SEQ_DRAW_GPENCIL) +// XXX draw_gpencil_2dimage(sa, ibuf); + + if (free_ibuf) { + IMB_freeImBuf(ibuf); + } + + /* draw grease-pencil (screen aligned) */ +// if (sseq->flag & SEQ_DRAW_GPENCIL) +// XXX draw_gpencil_2dview(sa, 0); + + /* ortho at pixel level sa */ +// XXX myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375); + +} + +void seq_reset_imageofs(SpaceSeq *sseq) +{ + sseq->xof = sseq->yof = sseq->zoom = 0; +} + +void seq_home(Scene *scene, ARegion *ar, SpaceSeq *sseq) +{ + View2D *v2d= &ar->v2d; + + if (!sseq->mainb) { + v2d->cur= v2d->tot; +// test_view2d(v2d, ar->winx, ar->winy); +// view2d_do_locks(ar, V2D_LOCK_COPY); + } else { + float zoomX, zoomY; + int width, height, imgwidth, imgheight; + + width = ar->winx; + height = ar->winy; + + seq_reset_imageofs(sseq); + + imgwidth= (scene->r.size*scene->r.xsch)/100; + imgheight= (scene->r.size*scene->r.ysch)/100; + + /* Apply aspect, dosnt need to be that accurate */ + imgwidth= (int)(imgwidth * ((float)scene->r.xasp / (float)scene->r.yasp)); + + if (((imgwidth >= width) || (imgheight >= height)) && + ((width > 0) && (height > 0))) { + + /* Find the zoom value that will fit the image in the image space */ + zoomX = ((float)width) / ((float)imgwidth); + zoomY = ((float)height) / ((float)imgheight); + sseq->zoom= (zoomX < zoomY) ? zoomX : zoomY; + + sseq->zoom = 1.0f / power_of_2(1/ MIN2(zoomX, zoomY) ); + } + else { + sseq->zoom= 1.0f; + } + } +} + +#if 0 +/* XXX */ +void seq_viewzoom(SpaceSeq *sseq, unsigned short event, int invert) +{ + + if(event==PAD1) + sseq->zoom= 1.0; + else if(event==PAD2) + sseq->zoom= (invert)? 2.0: 0.5; + else if(event==PAD4) + sseq->zoom= (invert)? 4.0: 0.25; + else if(event==PAD8) + sseq->zoom= (invert)? 8.0: 0.125; + + /* ensure pixel exact locations for draw */ + sseq->xof= (int)sseq->xof; + sseq->yof= (int)sseq->yof; +} + +void seq_viewmove(Scene *scene, ARegion *ar, SpaceSeq *sseq) +{ + short mval[2], mvalo[2]; + short rectx, recty, xmin, xmax, ymin, ymax, pad; + int oldcursor; + Window *win; + + sa = sseq->area; + rectx= (scene->r.size*scene->r.xsch)/100; + recty= (scene->r.size*scene->r.ysch)/100; + + pad = 10; + xmin = -(ar->winx/2) - rectx/2 + pad; + xmax = ar->winx/2 + rectx/2 - pad; + ymin = -(ar->winy/2) - recty/2 + pad; + ymax = ar->winy/2 + recty/2 - pad; + + getmouseco_sc(mvalo); + + oldcursor=get_cursor(); + win=winlay_get_active_window(); + + SetBlenderCursor(BC_NSEW_SCROLLCURSOR); + + while(get_mbut()&(L_MOUSE|M_MOUSE)) { + + getmouseco_sc(mval); + + if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) { + + sseq->xof -= (mvalo[0]-mval[0]); + sseq->yof -= (mvalo[1]-mval[1]); + + /* prevent dragging image outside of the window and losing it! */ + CLAMP(sseq->xof, xmin, xmax); + CLAMP(sseq->yof, ymin, ymax); + + mvalo[0]= mval[0]; + mvalo[1]= mval[1]; + + } + } +} +#endif + +void drawprefetchseqspace(Scene *scene, ARegion *ar, SpaceSeq *sseq) +{ + int rectx, recty; + + rectx= (scene->r.size*scene->r.xsch)/100; + recty= (scene->r.size*scene->r.ysch)/100; + + if(sseq->mainb) { + give_ibuf_prefetch_request( + rectx, recty, (scene->r.cfra), sseq->chanshown); + } +} + +void drawseqspace(const bContext *C, ARegion *ar) +{ + ScrArea *sa= CTX_wm_area(C); + SpaceSeq *sseq= sa->spacedata.first; + Scene *scene= CTX_data_scene(C); + View2D *v2d= &ar->v2d; + View2DScrollers *scrollers; + Editing *ed; + Sequence *seq; + float col[3]; + int i; + + ed= scene->ed; + + if(sseq->mainb) { + draw_image_seq(scene, ar, sseq); + return; + } + + UI_GetThemeColor3fv(TH_BACK, col); + if(ed && ed->metastack.first) glClearColor(col[0], col[1], col[2]-0.1, 0.0); + else glClearColor(col[0], col[1], col[2], 0.0); + + glClear(GL_COLOR_BUFFER_BIT); + + UI_view2d_view_ortho(C, v2d); + + UI_ThemeColorShade(TH_BACK, -20); + glRectf(v2d->cur.xmin, 0.0, v2d->cur.xmax, 1.0); + + boundbox_seq(scene, &v2d->tot); + + /* Alternating horizontal stripes */ + i= MAX2(1, ((int)v2d->cur.ymin)-1); + + glBegin(GL_QUADS); + while (icur.ymax) { + if (((int)i) & 1) + UI_ThemeColorShade(TH_BACK, -15); + else + UI_ThemeColorShade(TH_BACK, -25); + + glVertex2f(v2d->cur.xmax, i); + glVertex2f(v2d->cur.xmin, i); + glVertex2f(v2d->cur.xmin, i+1); + glVertex2f(v2d->cur.xmax, i+1); + i+=1.0; + } + glEnd(); + + /* Force grid lines */ + i= MAX2(1, ((int)v2d->cur.ymin)-1); + glBegin(GL_LINES); + + while (icur.ymax) { + UI_ThemeColor(TH_GRID); + glVertex2f(v2d->cur.xmax, i); + glVertex2f(v2d->cur.xmin, i); + i+=1.0; + } + glEnd(); + + UI_view2d_constant_grid_draw(C, v2d); + + draw_cfra_seq(v2d, scene->r.cfra); + + /* sequences: first deselect */ + if(ed) { + Sequence *last_seq = get_last_seq(scene); + int sel = 0, j; + int outline_tint; + float pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin); + /* loop through twice, first unselected, then selected */ + for (j=0; j<2; j++) { + seq= ed->seqbasep->first; + if (j==0) outline_tint = -150; + else outline_tint = -60; + + while(seq) { /* bound box test, dont draw outside the view */ + if ( ((seq->flag & SELECT) == sel) || + seq == last_seq || + MIN2(seq->startdisp, seq->start) > v2d->cur.xmax || + MAX2(seq->enddisp, seq->start+seq->len) < v2d->cur.xmin || + seq->machine+1.0 < v2d->cur.ymin || + seq->machine > v2d->cur.ymax) + { + /* dont draw */ + } else { + draw_seq_strip(scene, ar, sseq, seq, outline_tint, pixelx); + } + seq= seq->next; + } + sel= SELECT; /* draw selected next time round */ + } + /* draw the last selected last, removes some overlapping error */ + if (last_seq) { + draw_seq_strip(scene, ar, sseq, last_seq, 120, pixelx); + } + } + + /* Draw markers */ +// draw_markers_timespace(SCE_MARKERS, DRAW_MARKERS_LINES); + + /* reset view matrix */ + UI_view2d_view_restore(C); + + /* scrollers */ + scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY); + UI_view2d_scrollers_draw(C, v2d, scrollers); + UI_view2d_scrollers_free(scrollers); +} + + diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index d3eb681686b..47d2ae6ee9b 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -28,14 +28,36 @@ #ifndef ED_SEQUENCER_INTERN_H #define ED_SEQUENCER_INTERN_H -#define MAXSEQ 32 - /* internal exports only */ +struct Sequence; +struct bContext; +struct rctf; +struct SpaceSeq; +struct ARegion; +struct Scene; + +#define SEQ_ZOOM_FAC(szoom) (szoom > 0)? (szoom) : (szoom == 0)? (1.0) : (-1.0/szoom) /* sequencer_header.c */ -void sequencer_header_buttons(const bContext *C, ARegion *ar); +void sequencer_header_buttons(const struct bContext *C, struct ARegion *ar); + +/* sequencer_draw.c */ +void drawseqspace(const struct bContext *C, struct ARegion *ar); + +/* sequencer_edit.c */ +int check_single_seq(struct Sequence *seq); +int seq_tx_get_final_left(struct Sequence *seq, int metaclip); +int seq_tx_get_final_right(struct Sequence *seq, int metaclip); +void boundbox_seq(struct Scene *scene, struct rctf *rect); +struct Sequence *get_last_seq(struct Scene *scene); +/* sequencer_scope.c */ +struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf); +struct ImBuf *make_sep_waveform_view_from_ibuf(struct ImBuf * ibuf); +struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf); +struct ImBuf *make_zebra_view_from_ibuf(struct ImBuf * ibuf, float perc); +struct ImBuf *make_histogram_view_from_ibuf(struct ImBuf * ibuf); #endif /* ED_SEQUENCER_INTERN_H */ diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c new file mode 100644 index 00000000000..e26f445ae44 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -0,0 +1,701 @@ +/** + * $Id$ + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Peter Schlaile < peter [at] schlaile [dot] de > + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include +#include + +#include "BKE_utildefines.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "sequencer_intern.h" + +static void rgb_to_yuv(float rgb[3], float yuv[3]) +{ + yuv[0]= 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2]; + yuv[1]= 0.492*(rgb[2] - yuv[0]); + yuv[2]= 0.877*(rgb[0] - yuv[0]); + + /* Normalize */ + yuv[1]*= 255.0/(122*2.0); + yuv[1]+= 0.5; + + yuv[2]*= 255.0/(157*2.0); + yuv[2]+= 0.5; +} + +static void scope_put_pixel(unsigned char* table, unsigned char * pos) +{ + char newval = table[*pos]; + pos[0] = pos[1] = pos[2] = newval; + pos[3] = 255; +} + +static void scope_put_pixel_single(unsigned char* table, unsigned char * pos, + int col) +{ + char newval = table[pos[col]]; + pos[col] = newval; + pos[3] = 255; +} + +static void wform_put_line(int w, + unsigned char * last_pos, unsigned char * new_pos) +{ + if (last_pos > new_pos) { + unsigned char* temp = new_pos; + new_pos = last_pos; + last_pos = temp; + } + + while (last_pos < new_pos) { + if (last_pos[0] == 0) { + last_pos[0] = last_pos[1] = last_pos[2] = 32; + last_pos[3] = 255; + } + last_pos += 4*w; + } +} + +static void wform_put_line_single( + int w, unsigned char * last_pos, unsigned char * new_pos, int col) +{ + if (last_pos > new_pos) { + unsigned char* temp = new_pos; + new_pos = last_pos; + last_pos = temp; + } + + while (last_pos < new_pos) { + if (last_pos[col] == 0) { + last_pos[col] = 32; + last_pos[3] = 255; + } + last_pos += 4*w; + } +} + +static void wform_put_border(unsigned char * tgt, int w, int h) +{ + int x, y; + + for (x = 0; x < w; x++) { + unsigned char * p = tgt + 4 * x; + p[1] = p[3] = 255.0; + p[4 * w + 1] = p[4 * w + 3] = 255.0; + p = tgt + 4 * (w * (h - 1) + x); + p[1] = p[3] = 255.0; + p[-4 * w + 1] = p[-4 * w + 3] = 255.0; + } + + for (y = 0; y < h; y++) { + unsigned char * p = tgt + 4 * w * y; + p[1] = p[3] = 255.0; + p[4 + 1] = p[4 + 3] = 255.0; + p = tgt + 4 * (w * y + w - 1); + p[1] = p[3] = 255.0; + p[-4 + 1] = p[-4 + 3] = 255.0; + } +} + +static void wform_put_gridrow(unsigned char * tgt, float perc, int w, int h) +{ + int i; + + tgt += (int) (perc/100.0 * h) * w * 4; + + for (i = 0; i < w*2; i++) { + tgt[0] = 255; + + tgt += 4; + } +} + +static void wform_put_grid(unsigned char * tgt, int w, int h) +{ + wform_put_gridrow(tgt, 90.0, w, h); + wform_put_gridrow(tgt, 70.0, w, h); + wform_put_gridrow(tgt, 10.0, w, h); +} + +static struct ImBuf *make_waveform_view_from_ibuf_byte(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + unsigned char* src = (unsigned char*) ibuf->rect; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p = 0; + + for (x = 0; x < ibuf->x; x++) { + unsigned char * rgb = src + 4 * (ibuf->x * y + x); + float v = 1.0 * + ( 0.299*rgb[0] + + 0.587*rgb[1] + + 0.114*rgb[2]) / 255.0; + unsigned char * p = tgt; + p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1); + + scope_put_pixel(wtable, p); + p += 4 * w; + scope_put_pixel(wtable, p); + + if (last_p != 0) { + wform_put_line(w, last_p, p); + } + last_p = p; + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +static struct ImBuf *make_waveform_view_from_ibuf_float(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + float* src = ibuf->rect_float; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p = 0; + + for (x = 0; x < ibuf->x; x++) { + float * rgb = src + 4 * (ibuf->x * y + x); + float v = 1.0 * + ( 0.299*rgb[0] + + 0.587*rgb[1] + + 0.114*rgb[2]); + unsigned char * p = tgt; + + CLAMP(v, 0.0, 1.0); + + p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1); + + scope_put_pixel(wtable, p); + p += 4 * w; + scope_put_pixel(wtable, p); + + if (last_p != 0) { + wform_put_line(w, last_p, p); + } + last_p = p; + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_waveform_view_from_ibuf_float(ibuf); + } else { + return make_waveform_view_from_ibuf_byte(ibuf); + } +} + + +static struct ImBuf *make_sep_waveform_view_from_ibuf_byte(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf( + ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + unsigned char* src = (unsigned char*) ibuf->rect; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int sw = ibuf->x/3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p[3] = {0,0,0}; + + for (x = 0; x < ibuf->x; x++) { + int c; + unsigned char * rgb = src + 4 * (ibuf->x * y + x); + for (c = 0; c < 3; c++) { + unsigned char * p = tgt; + p += 4 * (w * ((rgb[c] * (h - 3))/255 + 1) + + c * sw + x/3 + 1); + + scope_put_pixel_single(wtable, p, c); + p += 4 * w; + scope_put_pixel_single(wtable, p, c); + + if (last_p[c] != 0) { + wform_put_line_single( + w, last_p[c], p, c); + } + last_p[c] = p; + } + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +static struct ImBuf *make_sep_waveform_view_from_ibuf_float( + struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf( + ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + float* src = ibuf->rect_float; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int sw = ibuf->x/3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p[3] = {0, 0, 0}; + + for (x = 0; x < ibuf->x; x++) { + int c; + float * rgb = src + 4 * (ibuf->x * y + x); + for (c = 0; c < 3; c++) { + unsigned char * p = tgt; + float v = rgb[c]; + + CLAMP(v, 0.0, 1.0); + + p += 4 * (w * ((int) (v * (h - 3)) + 1) + + c * sw + x/3 + 1); + + scope_put_pixel_single(wtable, p, c); + p += 4 * w; + scope_put_pixel_single(wtable, p, c); + + if (last_p[c] != 0) { + wform_put_line_single( + w, last_p[c], p, c); + } + last_p[c] = p; + } + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +struct ImBuf *make_sep_waveform_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_sep_waveform_view_from_ibuf_float(ibuf); + } else { + return make_sep_waveform_view_from_ibuf_byte(ibuf); + } +} + +static void draw_zebra_byte(struct ImBuf * src,struct ImBuf * ibuf, float perc) +{ + unsigned int limit = 255 * perc / 100.0; + unsigned char * p = (unsigned char*) src->rect; + unsigned char * o = (unsigned char*) ibuf->rect; + int x; + int y; + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + unsigned char r = *p++; + unsigned char g = *p++; + unsigned char b = *p++; + unsigned char a = *p++; + + if (r >= limit || g >= limit || b >= limit) { + if (((x + y) & 0x08) != 0) { + r = 255 - r; + g = 255 - g; + b = 255 - b; + } + } + *o++ = r; + *o++ = g; + *o++ = b; + *o++ = a; + } + } +} + + +static void draw_zebra_float(struct ImBuf * src,struct ImBuf * ibuf,float perc) +{ + float limit = perc / 100.0; + float * p = src->rect_float; + unsigned char * o = (unsigned char*) ibuf->rect; + int x; + int y; + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + float r = *p++; + float g = *p++; + float b = *p++; + float a = *p++; + + if (r >= limit || g >= limit || b >= limit) { + if (((x + y) & 0x08) != 0) { + r = -r; + g = -g; + b = -b; + } + } + + *o++ = FTOCHAR(r); + *o++ = FTOCHAR(g); + *o++ = FTOCHAR(b); + *o++ = FTOCHAR(a); + } + } +} + +struct ImBuf * make_zebra_view_from_ibuf(struct ImBuf * src, float perc) +{ + struct ImBuf * ibuf = IMB_allocImBuf(src->x, src->y, 32, IB_rect, 0); + + if (src->rect_float) { + draw_zebra_float(src, ibuf, perc); + } else { + draw_zebra_byte(src, ibuf, perc); + } + return ibuf; +} + +static void draw_histogram_marker(struct ImBuf * ibuf, int x) +{ + unsigned char * p = (unsigned char*) ibuf->rect; + int barh = ibuf->y * 0.1; + int i; + + p += 4 * (x + ibuf->x * (ibuf->y - barh + 1)); + + for (i = 0; i < barh-1; i++) { + p[0] = p[1] = p[2] = 255; + p += ibuf->x * 4; + } +} + +static void draw_histogram_bar(struct ImBuf * ibuf, int x,float val, int col) +{ + unsigned char * p = (unsigned char*) ibuf->rect; + int barh = ibuf->y * val * 0.9; + int i; + + p += 4 * (x + ibuf->x); + + for (i = 0; i < barh; i++) { + p[col] = 255; + p += ibuf->x * 4; + } +} + +static struct ImBuf *make_histogram_view_from_ibuf_byte( + struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 128, 32, IB_rect, 0); + int n,c,x,y; + unsigned char* src = (unsigned char*) ibuf->rect; + + unsigned int bins[3][256]; + + memset(bins, 0, 3 * 256* sizeof(unsigned int)); + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + bins[0][*src++]++; + bins[1][*src++]++; + bins[2][*src++]++; + src++; + } + } + + n = 0; + for (c = 0; c < 3; c++) { + for (x = 0; x < 256; x++) { + if (bins[c][x] > n) { + n = bins[c][x]; + } + } + } + + for (c = 0; c < 3; c++) { + for (x = 0; x < 256; x++) { + draw_histogram_bar(rval, x*2+1, + ((float) bins[c][x])/n, c); + draw_histogram_bar(rval, x*2+2, + ((float) bins[c][x])/n, c); + } + } + + wform_put_border((unsigned char*) rval->rect, rval->x, rval->y); + + return rval; +} + +static int get_bin_float(float f) +{ + if (f < -0.25) { + f = -0.25; + } else if (f > 1.25) { + f = 1.25; + } + + return (int) (((f + 0.25) / 1.5) * 512); +} + +static struct ImBuf *make_histogram_view_from_ibuf_float( + struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 128, 32, IB_rect, 0); + int n,c,x,y; + float* src = ibuf->rect_float; + + unsigned int bins[3][512]; + + memset(bins, 0, 3 * 256* sizeof(unsigned int)); + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + bins[0][get_bin_float(*src++)]++; + bins[1][get_bin_float(*src++)]++; + bins[2][get_bin_float(*src++)]++; + src++; + } + } + + draw_histogram_marker(rval, get_bin_float(0.0)); + draw_histogram_marker(rval, get_bin_float(1.0)); + + n = 0; + for (c = 0; c < 3; c++) { + for (x = 0; x < 512; x++) { + if (bins[c][x] > n) { + n = bins[c][x]; + } + } + } + for (c = 0; c < 3; c++) { + for (x = 0; x < 512; x++) { + draw_histogram_bar(rval, x+1, (float) bins[c][x]/n, c); + } + } + + wform_put_border((unsigned char*) rval->rect, rval->x, rval->y); + + return rval; +} + +struct ImBuf *make_histogram_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_histogram_view_from_ibuf_float(ibuf); + } else { + return make_histogram_view_from_ibuf_byte(ibuf); + } +} + +static void vectorscope_put_cross(unsigned char r, unsigned char g, + unsigned char b, + char * tgt, int w, int h, int size) +{ + float rgb[3], yuv[3]; + char * p; + int x = 0; + int y = 0; + + rgb[0]= (float)r/255.0; + rgb[1]= (float)g/255.0; + rgb[2]= (float)b/255.0; + rgb_to_yuv(rgb, yuv); + + p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1)) + + (int) ((yuv[1] * (w - 3) + 1))); + + if (r == 0 && g == 0 && b == 0) { + r = 255; + } + + for (y = -size; y <= size; y++) { + for (x = -size; x <= size; x++) { + char * q = p + 4 * (y * w + x); + q[0] = r; q[1] = g; q[2] = b; q[3] = 255; + } + } +} + +static struct ImBuf *make_vectorscope_view_from_ibuf_byte(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 515, 32, IB_rect, 0); + int x,y; + char* src = (char*) ibuf->rect; + char* tgt = (char*) rval->rect; + float rgb[3], yuv[3]; + int w = 515; + int h = 515; + float scope_gamma = 0.2; + unsigned char wtable[256]; + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + scope_gamma)*255); + } + + for (x = 0; x <= 255; x++) { + vectorscope_put_cross(255 , 0,255 - x, tgt, w, h, 1); + vectorscope_put_cross(255 , x, 0, tgt, w, h, 1); + vectorscope_put_cross(255- x, 255, 0, tgt, w, h, 1); + vectorscope_put_cross(0, 255, x, tgt, w, h, 1); + vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1); + vectorscope_put_cross(x, 0, 255, tgt, w, h, 1); + } + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + char * src1 = src + 4 * (ibuf->x * y + x); + char * p; + + rgb[0]= (float)src1[0]/255.0; + rgb[1]= (float)src1[1]/255.0; + rgb[2]= (float)src1[2]/255.0; + rgb_to_yuv(rgb, yuv); + + p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1)) + + (int) ((yuv[1] * (w - 3) + 1))); + scope_put_pixel(wtable, (unsigned char*)p); + } + } + + vectorscope_put_cross(0, 0, 0, tgt, w, h, 3); + + return rval; +} + +static struct ImBuf *make_vectorscope_view_from_ibuf_float(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 515, 32, IB_rect, 0); + int x,y; + float* src = ibuf->rect_float; + char* tgt = (char*) rval->rect; + float rgb[3], yuv[3]; + int w = 515; + int h = 515; + float scope_gamma = 0.2; + unsigned char wtable[256]; + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + scope_gamma)*255); + } + + for (x = 0; x <= 255; x++) { + vectorscope_put_cross(255 , 0,255 - x, tgt, w, h, 1); + vectorscope_put_cross(255 , x, 0, tgt, w, h, 1); + vectorscope_put_cross(255- x, 255, 0, tgt, w, h, 1); + vectorscope_put_cross(0, 255, x, tgt, w, h, 1); + vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1); + vectorscope_put_cross(x, 0, 255, tgt, w, h, 1); + } + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + float * src1 = src + 4 * (ibuf->x * y + x); + char * p; + + memcpy(rgb, src1, 3 * sizeof(float)); + + CLAMP(rgb[0], 0.0, 1.0); + CLAMP(rgb[1], 0.0, 1.0); + CLAMP(rgb[2], 0.0, 1.0); + + rgb_to_yuv(rgb, yuv); + + p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1)) + + (int) ((yuv[1] * (w - 3) + 1))); + scope_put_pixel(wtable, (unsigned char*)p); + } + } + + vectorscope_put_cross(0, 0, 0, tgt, w, h, 3); + + return rval; +} + +struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_vectorscope_view_from_ibuf_float(ibuf); + } else { + return make_vectorscope_view_from_ibuf_byte(ibuf); + } +} diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 08f700d1cf9..7adf042d13a 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -43,6 +43,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_screen.h" +#include "BKE_sequence.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -111,8 +112,6 @@ static SpaceLink *sequencer_new(const bContext *C) ar->v2d.keepzoom= 0; ar->v2d.keeptot= 0; - - return (SpaceLink *)sseq; } @@ -156,28 +155,6 @@ static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void sequencer_main_area_draw(const bContext *C, ARegion *ar) -{ - /* draw entirely, view changes should be handled here */ - // SpaceSeq *sseq= (SpaceSeq*)CTX_wm_space_data(C); - View2D *v2d= &ar->v2d; - float col[3]; - - /* clear and setup matrix */ - UI_GetThemeColor3fv(TH_BACK, col); - glClearColor(col[0], col[1], col[2], 0.0); - glClear(GL_COLOR_BUFFER_BIT); - - UI_view2d_view_ortho(C, v2d); - - /* data... */ - - - /* reset view matrix */ - UI_view2d_view_restore(C); - - /* scrollers? */ -} void sequencer_operatortypes(void) { @@ -241,7 +218,7 @@ void ED_spacetype_sequencer(void) art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_WINDOW; art->init= sequencer_main_area_init; - art->draw= sequencer_main_area_draw; + art->draw= drawseqspace; art->listener= sequencer_main_area_listener; art->keymapflag= ED_KEYMAP_VIEW2D; -- cgit v1.2.3