Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTon Roosendaal <ton@blender.org>2009-01-12 22:02:08 +0300
committerTon Roosendaal <ton@blender.org>2009-01-12 22:02:08 +0300
commit03fc5696dc154259dea599b805c94c82b58e70b6 (patch)
tree18839fb1ba9f76fdd271022db310be7b2f8d3485 /source/blender
parentca45efba287a1758e1fa46c6316b397956dbe586 (diff)
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.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_sequence.h111
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c3145
-rw-r--r--source/blender/blenkernel/intern/sequence.c2845
-rw-r--r--source/blender/blenlib/intern/bpath.c2
-rw-r--r--source/blender/editors/interface/view2d.c8
-rw-r--r--source/blender/editors/space_sequencer/Makefile2
-rw-r--r--source/blender/editors/space_sequencer/SConscript1
-rw-r--r--source/blender/editors/space_sequencer/editseq.c3985
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c1135
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h28
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c701
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c27
12 files changed, 11940 insertions, 50 deletions
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 <peter [at] schlaile [dot] de> 2005/2006
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#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; a<pis->vars; 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<height-YOFF; y++) {
+ if(field) fac= fac1;
+ else fac= fac2;
+ field= !field;
+
+ memcpy(out, rt1, sizeof(int)*XOFF);
+ rt1+= XOFF*4;
+ out+= XOFF*4;
+
+ for (x=XOFF; x<width; x++) {
+ temp= ((fac*rt2[3])>>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; y<height-YOFF; y++) {
+ if(field) fac= fac1;
+ else fac= fac2;
+ field= !field;
+
+ memcpy(out, rt1, 4 * sizeof(float)*XOFF);
+ rt1+= XOFF*4;
+ out+= XOFF*4;
+
+ for (x=XOFF; x<width; x++) {
+ temp= fac * rt2[3];
+
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ rt2+=4;
+ }
+ rt2+=XOFF*4;
+ }
+ memcpy(out, rt1, 4 * sizeof(float)*YOFF*width);
+}
+
+
+static void do_drop_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_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;y<yo;y++) {
+ for(x=0;x<xo;x++) {
+ float check = check_zone(&wipezone,x,y,seq,facf0);
+ if (check) {
+ if (rt1) {
+ rt[0] = (int)(rt1[0]*check)+ (int)(rt2[0]*(1-check));
+ rt[1] = (int)(rt1[1]*check)+ (int)(rt2[1]*(1-check));
+ rt[2] = (int)(rt1[2]*check)+ (int)(rt2[2]*(1-check));
+ rt[3] = (int)(rt1[3]*check)+ (int)(rt2[3]*(1-check));
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 255;
+ }
+ } else {
+ if (rt2) {
+ rt[0] = rt2[0];
+ rt[1] = rt2[1];
+ rt[2] = rt2[2];
+ rt[3] = rt2[3];
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 255;
+ }
+ }
+
+ rt+=4;
+ if(rt1 !=NULL){
+ rt1+=4;
+ }
+ if(rt2 !=NULL){
+ rt2+=4;
+ }
+ }
+ }
+}
+
+static void do_wipe_effect_float(Sequence *seq, float facf0, float facf1,
+ int x, int y,
+ float *rect1,
+ float *rect2, float *out)
+{
+ WipeZone wipezone;
+ WipeVars *wipe = (WipeVars *)seq->effectdata;
+ 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;y<yo;y++) {
+ for(x=0;x<xo;x++) {
+ float check = check_zone(&wipezone,x,y,seq,facf0);
+ if (check) {
+ if (rt1) {
+ rt[0] = rt1[0]*check+ rt2[0]*(1-check);
+ rt[1] = rt1[1]*check+ rt2[1]*(1-check);
+ rt[2] = rt1[2]*check+ rt2[2]*(1-check);
+ rt[3] = rt1[3]*check+ rt2[3]*(1-check);
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 1.0;
+ }
+ } else {
+ if (rt2) {
+ rt[0] = rt2[0];
+ rt[1] = rt2[1];
+ rt[2] = rt2[2];
+ rt[3] = rt2[3];
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 1.0;
+ }
+ }
+
+ rt+=4;
+ if(rt1 !=NULL){
+ rt1+=4;
+ }
+ if(rt2 !=NULL){
+ rt2+=4;
+ }
+ }
+ }
+}
+
+static void do_wipe_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_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<height;y++){
+ /* Do the left & right strips */
+ for (x=0;x<halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ curColor2[0]=curColor2[1]=curColor2[2]=0;
+
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ if ((i>=0)&&(i<width)){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+
+ curColor2[0]+=map[(width-1-i+y*width)*4+GlowR] *
+ filter[fx];
+ curColor2[1]+=map[(width-1-i+y*width)*4+GlowG] *
+ filter[fx];
+ curColor2[2]+=map[(width-1-i+y*width)*4+GlowB] *
+ filter[fx];
+ }
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+
+ temp[((width-1-x+y*width)*4)+GlowR]=curColor2[0];
+ temp[((width-1-x+y*width)*4)+GlowG]=curColor2[1];
+ temp[((width-1-x+y*width)*4)+GlowB]=curColor2[2];
+
+ }
+ /* Do the main body */
+ for (x=halfWidth;x<width-halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+
+ /* Blur the columns */
+ for (x=0;x<width;x++){
+ /* Do the top & bottom strips */
+ for (y=0;y<halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ curColor2[0]=curColor2[1]=curColor2[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ if ((i>=0)&&(i<height)){
+ /* Bottom */
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+
+ /* Top */
+ curColor2[0]+=map[(x+(height-1-i)*width) *
+ 4+GlowR]*filter[fy];
+ curColor2[1]+=map[(x+(height-1-i)*width) *
+ 4+GlowG]*filter[fy];
+ curColor2[2]+=map[(x+(height-1-i)*width) *
+ 4+GlowB]*filter[fy];
+ }
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ temp[((x+(height-1-y)*width)*4)+GlowR]=curColor2[0];
+ temp[((x+(height-1-y)*width)*4)+GlowG]=curColor2[1];
+ temp[((x+(height-1-y)*width)*4)+GlowB]=curColor2[2];
+ }
+ /* Do the main body */
+ for (y=halfWidth;y<height-halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+ /* Tidy up */
+ MEM_freeN (filter);
+ MEM_freeN (temp);
+}
+
+static void RVBlurBitmap2_float ( float* 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. */
+/*=============================== */
+{
+ float* 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*sizeof(float)), "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<height;y++){
+ /* Do the left & right strips */
+ for (x=0;x<halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0.0f;
+ curColor2[0]=curColor2[1]=curColor2[2]=0.0f;
+
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ if ((i>=0)&&(i<width)){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+
+ curColor2[0]+=map[(width-1-i+y*width)*4+GlowR] *
+ filter[fx];
+ curColor2[1]+=map[(width-1-i+y*width)*4+GlowG] *
+ filter[fx];
+ curColor2[2]+=map[(width-1-i+y*width)*4+GlowB] *
+ filter[fx];
+ }
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+
+ temp[((width-1-x+y*width)*4)+GlowR]=curColor2[0];
+ temp[((width-1-x+y*width)*4)+GlowG]=curColor2[1];
+ temp[((width-1-x+y*width)*4)+GlowB]=curColor2[2];
+
+ }
+ /* Do the main body */
+ for (x=halfWidth;x<width-halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+
+ /* Blur the columns */
+ for (x=0;x<width;x++){
+ /* Do the top & bottom strips */
+ for (y=0;y<halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ curColor2[0]=curColor2[1]=curColor2[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ if ((i>=0)&&(i<height)){
+ /* Bottom */
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+
+ /* Top */
+ curColor2[0]+=map[(x+(height-1-i)*width) *
+ 4+GlowR]*filter[fy];
+ curColor2[1]+=map[(x+(height-1-i)*width) *
+ 4+GlowG]*filter[fy];
+ curColor2[2]+=map[(x+(height-1-i)*width) *
+ 4+GlowB]*filter[fy];
+ }
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ temp[((x+(height-1-y)*width)*4)+GlowR]=curColor2[0];
+ temp[((x+(height-1-y)*width)*4)+GlowG]=curColor2[1];
+ temp[((x+(height-1-y)*width)*4)+GlowB]=curColor2[2];
+ }
+ /* Do the main body */
+ for (y=halfWidth;y<height-halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+ /* Tidy up */
+ MEM_freeN (filter);
+ MEM_freeN (temp);
+}
+
+
+/* Adds two bitmaps and puts the results into a third map. */
+/* C must have been previously allocated but it may be A or B. */
+/* We clamp values to 255 to prevent weirdness */
+/*=============================== */
+static void RVAddBitmaps_byte (unsigned char* a, unsigned char* b, unsigned char* c, int width, int height)
+{
+ int x,y,index;
+
+ for (y=0;y<height;y++){
+ for (x=0;x<width;x++){
+ index=(x+y*width)*4;
+ c[index+GlowR]=MIN2(255,a[index+GlowR]+b[index+GlowR]);
+ c[index+GlowG]=MIN2(255,a[index+GlowG]+b[index+GlowG]);
+ c[index+GlowB]=MIN2(255,a[index+GlowB]+b[index+GlowB]);
+ c[index+GlowA]=MIN2(255,a[index+GlowA]+b[index+GlowA]);
+ }
+ }
+}
+
+static void RVAddBitmaps_float (float* a, float* b, float* c,
+ int width, int height)
+{
+ int x,y,index;
+
+ for (y=0;y<height;y++){
+ for (x=0;x<width;x++){
+ index=(x+y*width)*4;
+ c[index+GlowR]=MIN2(1.0,a[index+GlowR]+b[index+GlowR]);
+ c[index+GlowG]=MIN2(1.0,a[index+GlowG]+b[index+GlowG]);
+ c[index+GlowB]=MIN2(1.0,a[index+GlowB]+b[index+GlowB]);
+ c[index+GlowA]=MIN2(1.0,a[index+GlowA]+b[index+GlowA]);
+ }
+ }
+}
+
+/* For each pixel whose total luminance exceeds the threshold, */
+/* Multiply it's value by BOOST and add it to the output map */
+static void RVIsolateHighlights_byte (unsigned char* in, unsigned char* out,
+ int width, int height, int threshold,
+ float boost, float clamp)
+{
+ int x,y,index;
+ int 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(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; y<out->y; y++) {
+ for(x=0; x<out->x; x++, rect+=4) {
+ rect[0]= col0[0];
+ rect[1]= col0[1];
+ rect[2]= col0[2];
+ rect[3]= 255;
+ }
+ y++;
+ if (y<out->y) {
+ for(x=0; x<out->x; 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; y<out->y; y++) {
+ for(x=0; x<out->x; 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 (y<out->y) {
+ for(x=0; x<out->x; 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 <peter [at] schlaile [dot] de> 2005/2006
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
#include <stdlib.h>
#include <string.h>
+#include <math.h>
#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 <pthread.h>
+
+#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->type<SEQ_EFFECT) {
+ return seq->strip->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; a<seq->len; 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 <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <sys/types.h>
+
+#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; a<sfile->totfile; 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; a<sfile->totfile; 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; a<sfile->totfile; 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; a<sfile->totfile; 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; a<sfile->totfile; 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; a<sfile->totfile; 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; a<totfile; a++) {
+ if(files[a].flags & ACTIVE) {
+ if( (files[a].type & S_IFDIR) ) {
+ strncat(sfile->dir, 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 <seq->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 <seq->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; j<snap_point_num; j++) {\
+ /* see if this beats the current best snap point */\
+ dist = abs(snap_points[j] - test_frame);\
+ if (dist < snap_dist) {\
+ snap_ofs = test_frame - snap_points[j];\
+ snap_dist = dist;\
+ }\
+ }
+
+
+ /* Detect the best marker to snap to! */
+ for(a=0, marker= scene->markers.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 <string.h>
+#include <math.h>
+
+#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 (wavesamplemax<wavesample)
+ wavesamplemax=wavesample;
+ offset+=subsample_step;
+ }
+ /* draw the wave line, looks good up close and zoomed out */
+ glVertex2f(f, midy-(wavemulti*wavesamplemin) );
+ glVertex2f(f, midy-(wavemulti*wavesamplemax) );
+ } else {
+ while (offset < offset_next) offset+=subsample_step;
+ }
+
+ offset=offset_next;
+ }
+ glEnd();
+}
+
+/* draw a handle, for each end of a sequence strip */
+static void draw_seq_handle(SpaceSeq *sseq, Sequence *seq, float pixelx, short direction)
+{
+ float v1[2], v2[2], v3[2], rx1=0, rx2=0; //for triangles and rect
+ float x1, x2, y1, y2;
+ float handsize;
+ float minhandle, maxhandle;
+ char str[32];
+ unsigned int whichsel=0;
+ View2D *v2d;
+
+ x1= seq->startdisp;
+ 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(x1<v2d->cur.xmin) x1= v2d->cur.xmin;
+ else if(x1>v2d->cur.xmax) x1= v2d->cur.xmax;
+ if(x2<v2d->cur.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 (i<v2d->cur.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 (i<v2d->cur.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 <math.h>
+#include <string.h>
+
+#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;