<KEYFRAME TITLE="gear360 sideways, 7k"><SPHERECAM ENABLED_0=1 FOV_0=194 CENTER_X_0=2.520000e+01 CENTER_Y_0=5.139998e+01 ROTATE_X_0=50 ROTATE_Y_0=50 ROTATE_Z_0=90 ENABLED_1=1 FOV_1=1.946000e+02 CENTER_X_1=7.499999e+01 CENTER_Y_1=5.079997e+01 ROTATE_X_1=0 ROTATE_Y_1=4.990000e+01 ROTATE_Z_1=-8.900002e+01 FEATHER=1 DRAW_GUIDES=0 MODE=1></KEYFRAME>
</PLUGIN>
<PLUGIN TITLE=F_drawgrid>
-<KEYFRAME TITLE=rule_of_3rds><F_DRAWGRID x=-1 y=-1 width=iw/3 w=iw/3 height=ih/3 h=ih/3 color=invert c=invert thickness=2 t=2></KEYFRAME>
+<KEYFRAME TITLE=rule_of_3rds><F_DRAWGRID x=-1 y=-1 width=iw/3 w=iw/3 height=ih/3 h=ih/3 color=invert c=invert thickness=2 t=2></KEYFRAME>
</PLUGIN>
current = new CICacheItem(this, edl, asset);
append(current); current->checked_out = tid;
file = current->file;
- total_lock->unlock();
int result = file->open_file(preferences, asset, 1, 0);
+ total_lock->unlock();
if( result ) {
SET_TRACE
delete file;
char* FileXML::get_data()
{
+ char *data = (char *)buffer->cstr();
long ofs = buffer->itell();
- return (char *)buffer->pos(ofs);
+ return data + ofs;
}
char* FileXML::string()
{
int ch = buffer->next();
// filter out first char is new line
if( ch == '\n' ) ch = buffer->next();
- long ipos = buffer->itell()-1;
+ long ipos = buffer->itell();
+ if( ch >= 0 ) --ipos;
+ long pos = ipos;
// scan for delimiter
- while( ch >= 0 && ch != left_delm ) ch = buffer->next();
- long pos = buffer->itell()-1;
- if( ch >= 0 ) buffer->iseek(pos);
+ while( ch >= 0 ) {
+ while( ch >= 0 && ch != left_delm ) ch = buffer->next();
+ if( ch < 0 ) break;
+ pos = buffer->itell()-1;
+ if( (ch = buffer->next()) != '/' ) continue;
+ char *cp = tag.title;
+ while( (ch=buffer->next()) >= 0 && ch == *cp ) ++cp;
+ if( ch < 0 ) break;
+ if( *cp ) continue;
+ while( ch == ' ' ) ch = buffer->next();
+ if( ch == right_delm ) break;
+ }
+ if( ch < 0 )
+ pos = buffer->itell();
+ buffer->iseek(pos);
long len = pos - ipos;
if( len >= output_length ) {
delete [] output;
output_length = len+1;
output = new char[output_length];
}
- decode(output,(const char *)buffer->pos(ipos), len);
+ if( len > 0 )
+ decode(output,(const char *)buffer->pos(ipos), len);
+ output[len] = 0;
return output;
}
#include "cstrdup.h"
#include "filexml.h"
#include "keyframe.h"
+#include "keyframes.h"
+#include "transportque.inc"
#include <stdio.h>
#include <string.h>
output.append_tag();
// Write anonymous text & duplicate the rest
- output.append_text(text ? text : this_text);
+ output.append_data(text ? text : this_text);
output.append_data(extra ? extra : this_extra);
output.terminate_string();
// Move output to input
delete [] src_extra;
}
+void KeyFrame::span_keyframes(int64_t start, int64_t end)
+{
+ BC_Hash *params = 0;
+ char *text = 0, *extra = 0;
+// The first one determines the changed parameters since it is the one displayed
+ KeyFrames *keyframes = (KeyFrames *)autos;
+ KeyFrame *current = keyframes->get_prev_keyframe(start, PLAY_FORWARD);
+ current->get_diff(this, ¶ms, &text, &extra);
+// Always update the first one
+ current->update_parameter(params, text, extra);
+
+// Replace changed parameter in all selected keyframes.
+ for( current = (KeyFrame*)NEXT; current; current = (KeyFrame*)NEXT ) {
+ if( current->position >= end ) break;
+ current->update_parameter(params, text, extra);
+ }
+ delete params;
+ delete [] text,
+ delete [] extra;
+}
+
int KeyFrame::operator==(Auto &that)
{
return identical((KeyFrame*)&that);
void get_contents(BC_Hash *ptr, char **text, char **extra);
// Update a single parameter or the anonymous text depending on which argument is nonzero
void update_parameter(BC_Hash *params, const char *text, const char *extra);
+ void span_keyframes(int64_t start, int64_t end);
XMLBuffer *xbuf;
};
mwindow->undo->update_undo_before();
#ifdef USE_KEYFRAME_SPANNING
- KeyFrame keyframe;
- presets_db->load_preset(plugin_title, title, &keyframe, is_factory);
- plugin->keyframes->update_parameter(&keyframe);
+ ArrayList<PluginServer*> &plugindb = *mwindow->plugindb;
+ int k = plugindb.size();
+ while( --k>=0 && strcmp(plugindb[k]->title, plugin->title) );
+ if( k >= 0 ) {
+ PluginServer server(*plugindb[k]);
+ server.open_plugin(0, mwindow->preferences, mwindow->edl, plugin);
+ KeyFrame keyframe(mwindow->edl, plugin->keyframes);
+ presets_db->load_preset(plugin_title, title, &keyframe, is_factory);
+ server.apply_keyframe(plugin, &keyframe);
+ }
#else
KeyFrame *keyframe = plugin->get_keyframe();
presets_db->load_preset(plugin_title, title, keyframe, is_factory);
#include "keyframe.h"
#include "keyframes.h"
#include "localsession.h"
+#include "plugin.h"
#include "track.h"
#include "transportque.inc"
-KeyFrames::KeyFrames(EDL *edl, Track *track)
- : Autos(edl, track)
+KeyFrames::KeyFrames(EDL *edl, Plugin *plugin)
+ : Autos(edl, plugin->track)
{
type = Autos::AUTOMATION_TYPE_PLUGIN;
+ plugin = plugin;
}
KeyFrames::~KeyFrames()
return result;
}
-
-void KeyFrames::update_parameter(KeyFrame *src)
-{
-// Create new keyframe if auto keyframes or replace entire keyframe.
- double selection_start = edl->local_session->get_selectionstart(0);
- double selection_end = edl->local_session->get_selectionend(0);
- selection_start = edl->align_to_frame(selection_start, 0);
- selection_end = edl->align_to_frame(selection_end, 0);
-
- if( !edl->session->span_keyframes ||
- EQUIV(selection_start, selection_end) ) {
-// Search for keyframe to write
- KeyFrame *dst = get_keyframe();
- dst->copy_data(src);
- }
- else {
-// Replace changed parameter in all selected keyframes.
- BC_Hash *params = 0;
- char *text = 0, *extra = 0;
-// Search all keyframes in selection but don't create a new one.
- int64_t start = track->to_units(selection_start, 0);
- int64_t end = track->to_units(selection_end, 0);
- KeyFrame *current = get_prev_keyframe(start, PLAY_FORWARD);
-// The first one determines the changed parameters since it is the one displayed
- current->get_diff(src, ¶ms, &text, &extra);
-// Always update the first one
- current->update_parameter(params, text, extra);
-
- for( current = (KeyFrame*)NEXT; current; current = (KeyFrame*)NEXT ) {
- if( current->position >= end ) break;
- current->update_parameter(params, text, extra);
- }
- delete params;
- delete [] text,
- delete [] extra;
- }
-}
-
Auto* KeyFrames::new_auto()
{
return new KeyFrame(edl, this);
#include "autos.h"
#include "filexml.inc"
#include "keyframe.inc"
+#include "plugin.inc"
// Keyframes inherit from Autos to reuse the editing commands but
class KeyFrames : public Autos
{
public:
- KeyFrames(EDL *edl, Track *track);
+ KeyFrames(EDL *edl, Plugin *plugin);
~KeyFrames();
// Get keyframes for editing with automatic creation if enabled.
virtual KeyFrame* get_keyframe();
// Get the previous, first, or default keyframe depending on how many keyframes
// exist.
- KeyFrame* get_prev_keyframe(int64_t position,
- int direction);
-
-// Keyframe updates using rules.
-// If a range is selected, the changed parameter is copied to all
-// the keyframes.
-// If no range is selected, a keyframe is created based on auto keyframe rules.
- void update_parameter(KeyFrame *src);
+ KeyFrame* get_prev_keyframe(int64_t position, int direction);
Auto* new_auto();
void dump(FILE *fp=stdout);
show = 0;
on = 1;
gui_id = -1;
- keyframes = new KeyFrames(edl, track);
+ keyframes = new KeyFrames(edl, this);
keyframes->create_objects();
}
show = 0;
on = 1;
gui_id = -1;
- keyframes = new KeyFrames(edl, track);
+ keyframes = new KeyFrames(edl, this);
keyframes->create_objects();
}
if(server->mwindow)
server->mwindow->undo->update_undo_before(_("tweek"), this);
#ifdef USE_KEYFRAME_SPANNING
- KeyFrame keyframe;
+ EDL *edl = server->edl;
+ Plugin *plugin = edl->tracks->plugin_exists(server->plugin_id);
+ KeyFrames *keyframes = plugin ? plugin->keyframes : 0;
+ KeyFrame keyframe(edl, keyframes);
save_data(&keyframe);
- server->apply_keyframe(&keyframe);
+ server->apply_keyframe(plugin, &keyframe);
#else
KeyFrame* keyframe = server->get_keyframe();
// Call save routine in plugin
return 0;
}
+// virtual default spanning keyframe update. If a range is selected,
+// then changed parameters are copied to (prev + selected) keyframes.
+// redefine per client for custom keyframe updates, see tracer, sketcher, crikey
+void PluginClient::span_keyframes(KeyFrame *src, int64_t start, int64_t end)
+{
+ src->span_keyframes(start, end);
+}
+
KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
{
return server->gui_open();
}
+
// console. This gets a keyframe from the EDL, with the position set to the
// EDL tracking position.
int send_configure_change();
-
+ virtual void span_keyframes(KeyFrame *src, int64_t start, int64_t end);
// Called from process_buffer
// Returns 1 if a GUI is open so OpenGL routines can determine if
}
-void PluginServer::apply_keyframe(KeyFrame *src)
-{
- Plugin *plugin = edl->tracks->plugin_exists(plugin_id);
- if( !plugin )
- keyframe->copy_data(src);
- else if( plugin->is_transition() )
- plugin->get_keyframe()->copy_data(src);
- else
-// Span keyframes
- plugin->keyframes->update_parameter(src);
+void PluginServer::apply_keyframe(Plugin *plugin, KeyFrame *src)
+{
+ KeyFrame* dst = !plugin ? keyframe :
+ plugin->is_transition() ? plugin->get_keyframe() : 0;
+ if( !dst ) {
+ if( edl->session->span_keyframes ) {
+ double selection_start = edl->local_session->get_selectionstart(0);
+ double selection_end = edl->local_session->get_selectionend(0);
+ selection_start = edl->align_to_frame(selection_start, 0);
+ selection_end = edl->align_to_frame(selection_end, 0);
+ Track *track = plugin->track;
+ int64_t start = track->to_units(selection_start, 1);
+ int64_t end = track->to_units(selection_end, 1);
+ if( start != end ) {
+ client->span_keyframes(src, start, end);
+ return;
+ }
+ }
+ dst = get_keyframe();
+ }
+ if( dst )
+ dst->copy_data(src);
}
KeyFrame* get_keyframe();
// Apply new settings from the plugin GUI. Called by PluginClient::send_configure_change
// Used in keyframe spanning mode.
- void apply_keyframe(KeyFrame *src);
+ void apply_keyframe(Plugin *plugin, KeyFrame *src);
// Create new theme object. Used by theme plugins.
Theme* new_theme();
const char *keyframe_title = file->tag.get_property("TITLE", string);
PresetsDBKeyframe *keyframe = new PresetsDBKeyframe(keyframe_title, is_factory);
XMLBuffer data;
- file->read_text_until("/KEYFRAME", &data);
+ file->read_data_until("/KEYFRAME", &data);
keyframe->set_data(data.cstr());
keyframes.append(keyframe);
file->tag.set_title("KEYFRAME");
file->tag.set_property("TITLE", keyframe->title);
file->append_tag();
- file->append_text(keyframe->data);
+ file->append_data(keyframe->data);
file->tag.set_title("/KEYFRAME");
file->append_tag();
file->append_newline();
int get_item_number() { return !list ? -1 : list->number_of((TYPE*)this); }
ListItem() { list = 0; previous = next = 0; }
- ListItem(List<TYPE> &me) { list = me; previous = next = 0; }
+ ListItem(List<TYPE> *me) { list = me; previous = next = 0; }
virtual ~ListItem() { if( list ) list->remove_pointer(this); }
};
#include "filexml.h"
#include "crikey.h"
#include "crikeywindow.h"
+#include "keyframe.h"
+#include "keyframes.h"
#include "language.h"
+#include "transportque.inc"
#include "vframe.h"
// chroma interpolated key, crikey
return config.add_point(-1, 0, x, y, 0.5f);
}
-void CriKey::save_data(KeyFrame *keyframe)
+void CriKeyConfig::save_data(KeyFrame *keyframe)
{
FileXML output;
output.set_shared_output(keyframe->xbuf);
output.tag.set_title("CRIKEY");
- output.tag.set_property("THRESHOLD", config.threshold);
- output.tag.set_property("DRAW_MODE", config.draw_mode);
- output.tag.set_property("DRAG", config.drag);
- output.tag.set_property("SELECTED", config.selected);
+ output.tag.set_property("THRESHOLD", threshold);
+ output.tag.set_property("DRAW_MODE", draw_mode);
+ output.tag.set_property("DRAG", drag);
+ output.tag.set_property("SELECTED", selected);
output.append_tag();
output.append_newline();
output.tag.set_title("/CRIKEY");
output.append_tag();
output.append_newline();
- for( int i=0, n = config.points.size(); i<n; ++i ) {
- CriKeyPoint *pt = config.points[i];
+ for( int i=0, n = points.size(); i<n; ++i ) {
+ CriKeyPoint *pt = points[i];
char point[BCSTRLEN];
sprintf(point,"/POINT_%d",pt->tag);
output.tag.set_title(point+1);
output.terminate_string();
}
-void CriKey::read_data(KeyFrame *keyframe)
+void CriKey::save_data(KeyFrame *keyframe)
+{
+ config.save_data(keyframe);
+}
+
+void CriKeyConfig::read_data(KeyFrame *keyframe)
{
FileXML input;
input.set_shared_input(keyframe->xbuf);
- config.points.remove_all_objects();
+ points.remove_all_objects();
int result = 0;
while( !(result=input.read_tag()) ) {
if( input.tag.title_is("CRIKEY") ) {
- config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
- config.draw_mode = input.tag.get_property("DRAW_MODE", config.draw_mode);
- config.drag = input.tag.get_property("DRAG", config.drag);
- config.selected = input.tag.get_property("SELECTED", 0);
- config.limits();
+ threshold = input.tag.get_property("THRESHOLD", threshold);
+ draw_mode = input.tag.get_property("DRAW_MODE", draw_mode);
+ drag = input.tag.get_property("DRAG", drag);
+ selected = input.tag.get_property("SELECTED", 0);
+ limits();
}
else if( !strncmp(input.tag.get_title(),"POINT_",6) ) {
int tag = atoi(input.tag.get_title() + 6);
float x = input.tag.get_property("X", 0.f);
float y = input.tag.get_property("Y", 0.f);
float t = input.tag.get_property("T", .5f);
- config.add_point(tag, e, x, y, t);
+ add_point(tag, e, x, y, t);
}
}
+}
+void CriKey::read_data(KeyFrame *keyframe)
+{
+ config.read_data(keyframe);
if( !config.points.size() ) new_point();
}
+void CriKey::span_keyframes(KeyFrame *src, int64_t start, int64_t end)
+{
+ CriKeyConfig src_config;
+ src_config.read_data(src);
+ KeyFrames *keyframes = (KeyFrames *)src->autos;
+ KeyFrame *prev = keyframes->get_prev_keyframe(start, PLAY_FORWARD);
+ CriKeyConfig prev_config;
+ prev_config.read_data(prev);
+// Always update the first one
+ update_parameter(prev_config, src_config, prev);
+ KeyFrame *curr = (KeyFrame*)prev->next;
+ while( curr && curr->position < end ) {
+ update_parameter(prev_config, src_config, curr);
+ curr = (KeyFrame*)curr->next;
+ }
+}
+
+void CriKeyPoint::update_parameter(CriKeyPoint *prev, CriKeyPoint *src)
+{
+ if( prev->e != src->e ) e = src->e;
+ if( prev->x != src->x ) x = src->x;
+ if( prev->y != src->y ) y = src->y;
+ if( prev->t != src->t ) t = src->t;
+}
+
+void CriKey::update_parameter(CriKeyConfig &prev_config, CriKeyConfig &src_config,
+ KeyFrame *keyframe)
+{
+ CriKeyConfig dst_config;
+ dst_config.read_data(keyframe);
+ if( !EQUIV(prev_config.threshold, src_config.threshold) )
+ dst_config.threshold = src_config.threshold;
+ if( prev_config.draw_mode != src_config.draw_mode )
+ dst_config.draw_mode = src_config.draw_mode;
+ if( prev_config.drag != src_config.drag )
+ dst_config.drag = src_config.drag;
+ int src_points = src_config.points.size();
+ int dst_points = dst_config.points.size();
+ int prev_points = prev_config.points.size();
+ int npoints = bmin(prev_points, bmin(src_points, dst_points));
+ for( int i=0; i<npoints; ++i ) {
+ CriKeyPoint *src_point = src_config.points[i];
+ int tag = src_point->tag, k = prev_points;
+ while( --k >= 0 && tag != prev_config.points[k]->tag );
+ if( k < 0 ) continue;
+ CriKeyPoint *prev_point = prev_config.points[k];
+ k = dst_points;
+ while( --k >= 0 && tag != dst_config.points[k]->tag );
+ if( k < 0 ) continue;
+ CriKeyPoint *dst_point = dst_config.points[k];
+ dst_point->update_parameter(prev_point, src_point);
+ }
+ dst_config.save_data(keyframe);
+}
+
void CriKey::update_gui()
{
if( !thread ) return;
float a00 = 0, a01 = 0, a10 = 0, a11 = 0; \
for( int c=0; c<comps; ++c,++r0,++r1 ) { \
float t = target_color[c]; \
- a00 += fabs(t - r0[0]); \
+ a00 += fabs(t - r0[0]); \
a01 += fabs(t - r0[components]); \
a10 += fabs(t - r1[0]); \
a11 += fabs(t - r1[components]); \
} \
float mx = scale * bmax(bmax(a00, a01), bmax(a10, a11)); \
if( mx < threshold ) continue; \
- float mn = scale * bmin(bmin(a00, a01), bmin(a10, a11)); \
+ float mn = scale * bmin(bmin(a00, a01), bmin(a10, a11)); \
if( mn >= threshold ) continue; \
*edgp += (mx - mn); \
} \
CriKeyPoint(int tag, int e, float x, float y, float t);
~CriKeyPoint();
+ void update_parameter(CriKeyPoint *prev, CriKeyPoint *src);
};
class CriKeyPoints : public ArrayList<CriKeyPoint *>
{
CriKeyConfig();
~CriKeyConfig();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
int equivalent(CriKeyConfig &that);
void copy_from(CriKeyConfig &that);
void interpolate(CriKeyConfig &prev, CriKeyConfig &next,
void draw_edge(VFrame *frm);
void draw_mask(VFrame *frm);
void draw_point(VFrame *msk, CriKeyPoint *pt);
+ void span_keyframes(KeyFrame *src, int64_t start, int64_t end);
+ void update_parameter(CriKeyConfig &prev_config, CriKeyConfig &src_config,
+ KeyFrame *keyframe);
CriKeyEngine *engine;
VFrame *src, *edg, *msk;
void PerspectiveWindow::create_objects()
{
- int xs10 = xS(10), xs20 = xS(20), xs80 = xS(80), xs100 = xS(100), xs120 = xS(120);
+ int xs10 = xS(10), xs20 = xS(20), xs100 = xS(100), xs120 = xS(120);
int ys5 = yS(5), ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
int x = xs10, y = ys10;
x, y, get_w() - xs20, get_h() - yS(290)));
canvas->set_cursor(CROSS_CURSOR, 0, 0);
y += canvas->get_h() + ys10;
- add_subwindow(new BC_Title(x, y, _("Current X:")));
- x += xs80;
+ int x1 = x;
+ BC_Title *title;
+ add_subwindow(title = new BC_Title(x1, y, _("Current: ")));
+ x1 += title->get_w() + xs10;
+ char string[BCSTRLEN];
+ sprintf(string, "%d", plugin->config.current_point+1);
+ add_subwindow(curr_point = new BC_Title(x1, y, string));
+ x1 += xs20;
+ add_subwindow(title = new BC_Title(x1, y, _("X:")));
+ x1 += title->get_w() + xs10;
this->x = new PerspectiveCoord(this,
- x, y, plugin->get_current_x(), 1);
+ x1, y, plugin->get_current_x(), 1);
this->x->create_objects();
- x += xS(140);
- add_subwindow(new BC_Title(x, y, _("Y:")));
- x += xs20;
+ x1 += this->x->get_w() + xs20;
+ add_subwindow(new BC_Title(x1, y, _("Y:")));
+ x1 += title->get_w() + xs10;
this->y = new PerspectiveCoord(this,
- x, y, plugin->get_current_y(), 0);
+ x1, y, plugin->get_current_y(), 0);
this->y->create_objects();
x = xs10; y += ys30;
add_subwindow(mode_perspective = new PerspectiveMode(this,
update_canvas();
x = xs10; y += ys30;
- BC_Title *title;
add_subwindow(title = new BC_Title(x, y, _("Zoom view:")));
- int x1 = x + title->get_w() + xs10, w1 = get_w() - x1 - xs10;
+ x1 = x + title->get_w() + xs10;
+ int w1 = get_w() - x1 - xs10;
add_subwindow(zoom_view = new PerspectiveZoomView(this, x1, y, w1));
y += ys30;
canvas->draw_line(vx2, vy2, vx1, vy2);
canvas->draw_line(vx1, vy2, vx1, vy1);
+ canvas->set_color(YELLOW);
+ canvas->draw_text(x1, y1,"1");
+ canvas->draw_text(x2, y2,"2");
+ canvas->draw_text(x3, y3,"3");
+ canvas->draw_text(x4, y4,"4");
+
//printf("PerspectiveWindow::update_canvas %d,%d %d,%d %d,%d %d,%d\n",
// x1, y1, x2, y2, x3, y3, x4, y4);
// Draw divisions
void PerspectiveWindow::update_coord()
{
+ char string[BCSTRLEN];
+ sprintf(string, "%d", plugin->config.current_point+1);
+ curr_point->update(string);
x->update(plugin->get_current_x());
y->update(plugin->get_current_y());
}
int &x3, int &y3, int &x4, int &y4);
PerspectiveCanvas *canvas;
+ BC_Title *curr_point;
PerspectiveCoord *x, *y;
PerspectiveReset *reset;
PerspectiveZoomView *zoom_view;
#include "rotate.h"
+#include "theme.h"
+
+#define MAXANGLE 360.00
+#define MINPIVOT 0.00
+#define MAXPIVOT 100.00
-#define MAXANGLE 360
REGISTER_PLUGIN(RotateEffect)
RotateConfig::RotateConfig()
{
- reset();
-}
-
-void RotateConfig::reset()
-{
- angle = 0.0;
- pivot_x = 50.0;
- pivot_y = 50.0;
- draw_pivot = 0;
+ reset(RESET_DEFAULT_SETTINGS);
+}
+
+void RotateConfig::reset(int clear)
+{
+ switch(clear) {
+ case RESET_ANGLE :
+ angle = 0.0;
+ break;
+ case RESET_PIVOT_X :
+ pivot_x = 50.0;
+ break;
+ case RESET_PIVOT_Y :
+ pivot_y = 50.0;
+ break;
+ case RESET_ALL :
+ case RESET_DEFAULT_SETTINGS :
+ default:
+ angle = 0.0;
+ pivot_x = 50.0;
+ pivot_y = 50.0;
+ draw_pivot = 0;
+ break;
+ }
}
int RotateConfig::equivalent(RotateConfig &that)
-RotateFine::RotateFine(RotateWindow *window, RotateEffect *plugin, int x, int y)
- : BC_FPot(x,
- y,
- (float)plugin->config.angle,
- (float)-360,
- (float)360)
+RotateAngleText::RotateAngleText(RotateWindow *window, RotateEffect *plugin, int x, int y)
+ : BC_TumbleTextBox(window, (float)plugin->config.angle,
+ (float)-MAXANGLE, (float)MAXANGLE, x, y, xS(60), 2)
{
this->window = window;
this->plugin = plugin;
+}
+
+int RotateAngleText::handle_event()
+{
+ plugin->config.angle = atof(get_text());
+ window->update_toggles();
+ window->update_sliders();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+RotateAngleSlider::RotateAngleSlider(RotateWindow *window, RotateEffect *plugin, int x, int y, int w)
+ : BC_FSlider(x, y, 0, w, w, (float)-MAXANGLE, (float)MAXANGLE, (float)plugin->config.angle)
+{
+ this->window = window;
+ this->plugin = plugin;
+ enable_show_value(0); // Hide caption
set_precision(0.1);
- set_use_caption(0);
}
-int RotateFine::handle_event()
+int RotateAngleSlider::handle_event()
{
plugin->config.angle = get_value();
window->update_toggles();
- window->update_text();
+ window->update_texts();
plugin->send_configure_change();
return 1;
}
-RotateText::RotateText(RotateWindow *window,
- RotateEffect *plugin,
- int x,
- int y)
- : BC_TextBox(x,
- y,
- xS(90),
- 1,
- (float)plugin->config.angle)
+RotatePivotXText::RotatePivotXText(RotateWindow *window, RotateEffect *plugin, int x, int y)
+ : BC_TumbleTextBox(window, (float)plugin->config.pivot_x,
+ (float)MINPIVOT, (float)MAXPIVOT, x, y, xS(60), 2)
{
this->window = window;
this->plugin = plugin;
- set_precision(4);
}
-int RotateText::handle_event()
+int RotatePivotXText::handle_event()
{
- plugin->config.angle = atof(get_text());
- window->update_toggles();
- window->update_fine();
+ plugin->config.pivot_x = atof(get_text());
+ window->update_sliders();
plugin->send_configure_change();
return 1;
}
-
-RotateX::RotateX(RotateWindow *window, RotateEffect *plugin, int x, int y)
- : BC_FPot(x,
- y,
- (float)plugin->config.pivot_x,
- (float)0,
- (float)100)
+RotatePivotXSlider::RotatePivotXSlider(RotateWindow *window, RotateEffect *plugin, int x, int y, int w)
+ : BC_FSlider(x, y, 0, w, w, (float)MINPIVOT, (float)MAXPIVOT, (float)plugin->config.pivot_x)
{
this->window = window;
this->plugin = plugin;
- set_precision(0.01);
- set_use_caption(1);
+ enable_show_value(0); // Hide caption
+ set_precision(0.1);
}
-int RotateX::handle_event()
+int RotatePivotXSlider::handle_event()
{
plugin->config.pivot_x = get_value();
+ window->update_toggles();
+ window->update_texts();
plugin->send_configure_change();
return 1;
}
-RotateY::RotateY(RotateWindow *window, RotateEffect *plugin, int x, int y)
- : BC_FPot(x,
- y,
- (float)plugin->config.pivot_y,
- (float)0,
- (float)100)
+
+RotatePivotYText::RotatePivotYText(RotateWindow *window, RotateEffect *plugin, int x, int y)
+ : BC_TumbleTextBox(window, (float)plugin->config.pivot_y,
+ (float)MINPIVOT, (float)MAXPIVOT, x, y, xS(60), 2)
{
this->window = window;
this->plugin = plugin;
- set_precision(0.01);
- set_use_caption(1);
}
-int RotateY::handle_event()
+int RotatePivotYText::handle_event()
+{
+ plugin->config.pivot_y = atof(get_text());
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+RotatePivotYSlider::RotatePivotYSlider(RotateWindow *window, RotateEffect *plugin, int x, int y, int w)
+ : BC_FSlider(x, y, 0, w, w, (float)MINPIVOT, (float)MAXPIVOT, (float)plugin->config.pivot_y)
+{
+ this->window = window;
+ this->plugin = plugin;
+ enable_show_value(0); // Hide caption
+ set_precision(0.1);
+}
+
+int RotatePivotYSlider::handle_event()
{
plugin->config.pivot_y = get_value();
+ window->update_toggles();
+ window->update_texts();
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+RotateClr::RotateClr(RotateWindow *window, RotateEffect *plugin, int x, int y, int clear)
+ : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
+{
+ this->window = window;
+ this->plugin = plugin;
+ this->clear = clear;
+}
+
+RotateClr::~RotateClr()
+{
+}
+
+int RotateClr::handle_event()
+{
+ plugin->config.reset(clear);
+ window->update();
plugin->send_configure_change();
return 1;
}
+
RotateReset::RotateReset(RotateEffect *plugin, RotateWindow *window, int x, int y)
: BC_GenericButton(x, y, _("Reset"))
{
}
int RotateReset::handle_event()
{
- plugin->config.reset();
+ plugin->config.reset(RESET_ALL);
window->update();
plugin->send_configure_change();
return 1;
RotateWindow::RotateWindow(RotateEffect *plugin)
- : PluginClientWindow(plugin, xS(300), yS(230), xS(300), yS(230), 0)
+ : PluginClientWindow(plugin, xS(420), yS(260), xS(420), yS(260), 0)
{
this->plugin = plugin;
}
void RotateWindow::create_objects()
{
- int xs10 = xS(10), xs50 = xS(50), xs150 = xS(150);
- int ys10 = yS(10), ys20 = yS(20), ys25 = yS(25), ys50 = yS(50), ys60 = yS(60);
+ int xs10 = xS(10), xs20 = xS(20), xs64 = xS(64), xs200 = xS(200);
+ int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40);
+ int x2 = xS(80), x3 = xS(180);
int x = xs10, y = ys10;
- BC_Title *title;
- add_tool(new BC_Title(x, y, _("Rotate")));
- x += xs50; y += ys20;
+ int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
+
+ BC_TitleBar *title_bar;
+ BC_Bar *bar;
+
+// Angle section
+ add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Rotation")));
+ x = xs10; y += ys20;
+ add_tool(new BC_Title(x, y, _("Preset:")));
+ x = x + x2;
+ add_tool(toggle180neg = new RotateToggle(this, plugin,
+ plugin->config.angle == -180, x, y, -180, "-180°"));
+ x += xs64;
+ add_tool(toggle90neg = new RotateToggle(this, plugin,
+ plugin->config.angle == -90, x, y, -90, "-90°"));
+ x += xs64;
add_tool(toggle0 = new RotateToggle(this, plugin,
- plugin->config.angle == 0, x, y, 0, "0"));
- x += RADIUS; y += RADIUS;
+ plugin->config.angle == 0, x, y, 0, "0°"));
+ x += xs64;
add_tool(toggle90 = new RotateToggle(this, plugin,
- plugin->config.angle == 90, x, y, 90, "90"));
- x -= RADIUS; y += RADIUS;
+ plugin->config.angle == 90, x, y, 90, "+90°"));
+ x += xs64;
add_tool(toggle180 = new RotateToggle(this, plugin,
- plugin->config.angle == 180, x, y, 180, "180"));
- x -= RADIUS; y -= RADIUS;
- add_tool(toggle270 = new RotateToggle(this, plugin,
- plugin->config.angle == 270, x, y, 270, "270"));
+ plugin->config.angle == 180, x, y, 180, "+180°"));
// add_subwindow(bilinear = new RotateInterpolate(plugin, xs10, y + ys60));
- x += xs150; y -= ys50;
- add_tool(fine = new RotateFine(this, plugin, x, y));
- y += fine->get_h() + ys10;
- add_tool(text = new RotateText(this, plugin, x, y));
- y += ys25;
- add_tool(new BC_Title(x, y, _("Degrees")));
-
- y += text->get_h() + ys10;
- add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
- y += title->get_h() + ys10;
- add_subwindow(this->x = new RotateX(this, plugin, x, y));
- x += this->x->get_w() + xs10;
- add_subwindow(this->y = new RotateY(this, plugin, x, y));
-
-// y += this->y->get_h() + ys10;
- x = xs10;
+ x = xs10; y += ys30;
+ add_tool(new BC_Title(x, y, _("Angle:")));
+ rotate_angle_text = new RotateAngleText(this, plugin, (x + x2), y);
+ rotate_angle_text->create_objects();
+ add_tool(rotate_angle_slider = new RotateAngleSlider(this, plugin, x3, y, xs200));
+ add_tool(rotate_angle_clr = new RotateClr(this, plugin,
+ clr_x, y, RESET_ANGLE));
+ y += ys40;
+
+// Pivot section
+ add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Pivot")));
+ y += ys20;
add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
- y += ys60;
+ y += ys30;
+ add_tool(new BC_Title(x, y, _("X:")));
+ add_tool(new BC_Title((x2-x), y, _("%")));
+ rotate_pivot_x_text = new RotatePivotXText(this, plugin, (x + x2), y);
+ rotate_pivot_x_text->create_objects();
+ add_tool(rotate_pivot_x_slider = new RotatePivotXSlider(this, plugin, x3, y, xs200));
+ add_tool(rotate_pivot_x_clr = new RotateClr(this, plugin,
+ clr_x, y, RESET_PIVOT_X));
+ y += ys30;
+ add_tool(new BC_Title(x, y, _("Y:")));
+ add_tool(new BC_Title((x2-x), y, _("%")));
+ rotate_pivot_y_text = new RotatePivotYText(this, plugin, (x + x2), y);
+ rotate_pivot_y_text->create_objects();
+ add_tool(rotate_pivot_y_slider = new RotatePivotYSlider(this, plugin, x3, y, xs200));
+ add_tool(rotate_pivot_y_clr = new RotateClr(this, plugin,
+ clr_x, y, RESET_PIVOT_Y));
+ y += ys40;
+
+// Reset section
+ add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
+ y += ys10;
add_subwindow(reset = new RotateReset(plugin, this, x, y));
show_window();
int RotateWindow::update()
{
- update_fine();
+ update_sliders();
update_toggles();
- update_text();
+ update_texts();
// bilinear->update(plugin->config.bilinear);
return 0;
}
-int RotateWindow::update_fine()
+int RotateWindow::update_sliders()
{
- fine->update(plugin->config.angle);
- x->update(plugin->config.pivot_x);
- y->update(plugin->config.pivot_y);
+ rotate_angle_slider->update(plugin->config.angle);
+ rotate_pivot_x_slider->update(plugin->config.pivot_x);
+ rotate_pivot_y_slider->update(plugin->config.pivot_y);
return 0;
}
-int RotateWindow::update_text()
+int RotateWindow::update_texts()
{
- text->update(plugin->config.angle);
+ rotate_angle_text->update(plugin->config.angle);
+ rotate_pivot_x_text->update(plugin->config.pivot_x);
+ rotate_pivot_y_text->update(plugin->config.pivot_y);
return 0;
}
int RotateWindow::update_toggles()
{
+ toggle180neg->update(EQUIV(plugin->config.angle, -180));
+ toggle90neg->update(EQUIV(plugin->config.angle, -90));
toggle0->update(EQUIV(plugin->config.angle, 0));
toggle90->update(EQUIV(plugin->config.angle, 90));
toggle180->update(EQUIV(plugin->config.angle, 180));
- toggle270->update(EQUIV(plugin->config.angle, 270));
draw_pivot->update(plugin->config.draw_pivot);
return 0;
}
class RotateEffect;
class RotateWindow;
+class RotateToggle;
+class RotateDrawPivot;
+class RotateInterpolate;
+class RotateAngleText;
+class RotateAngleSlider;
+class RotatePivotXText;
+class RotatePivotXSlider;
+class RotatePivotYText;
+class RotatePivotYSlider;
+class RotateClr;
+class RotateReset;
+
+
+#define RESET_DEFAULT_SETTINGS 10
+#define RESET_ALL 0
+#define RESET_ANGLE 1
+#define RESET_PIVOT_X 2
+#define RESET_PIVOT_Y 3
class RotateConfig
public:
RotateConfig();
- void reset();
+ void reset(int clear);
int equivalent(RotateConfig &that);
void copy_from(RotateConfig &that);
void interpolate(RotateConfig &prev,
RotateEffect *plugin;
};
-class RotateFine : public BC_FPot
+class RotateAngleText : public BC_TumbleTextBox
{
public:
- RotateFine(RotateWindow *window,
+ RotateAngleText(RotateWindow *window,
RotateEffect *plugin,
int x,
int y);
RotateWindow *window;
};
-class RotateX : public BC_FPot
+class RotateAngleSlider : public BC_FSlider
{
public:
- RotateX(RotateWindow *window,
+ RotateAngleSlider(RotateWindow *window,
RotateEffect *plugin,
- int x,
- int y);
+ int x, int y, int w);
int handle_event();
+
RotateEffect *plugin;
RotateWindow *window;
};
-class RotateY : public BC_FPot
+
+class RotatePivotXText : public BC_TumbleTextBox
{
public:
- RotateY(RotateWindow *window,
+ RotatePivotXText(RotateWindow *window,
RotateEffect *plugin,
int x,
int y);
int handle_event();
+
+ RotateEffect *plugin;
+ RotateWindow *window;
+};
+
+class RotatePivotXSlider : public BC_FSlider
+{
+public:
+ RotatePivotXSlider(RotateWindow *window,
+ RotateEffect *plugin,
+ int x, int y, int w);
+ int handle_event();
+
RotateEffect *plugin;
RotateWindow *window;
};
-class RotateText : public BC_TextBox
+class RotatePivotYText : public BC_TumbleTextBox
{
public:
- RotateText(RotateWindow *window,
+ RotatePivotYText(RotateWindow *window,
RotateEffect *plugin,
int x,
int y);
RotateWindow *window;
};
+class RotatePivotYSlider : public BC_FSlider
+{
+public:
+ RotatePivotYSlider(RotateWindow *window,
+ RotateEffect *plugin,
+ int x, int y, int w);
+ int handle_event();
+
+ RotateEffect *plugin;
+ RotateWindow *window;
+};
+
+
+
+
+class RotateClr : public BC_Button
+{
+public:
+ RotateClr(RotateWindow *window, RotateEffect *plugin,
+ int x, int y, int clear);
+ ~RotateClr();
+ int handle_event();
+ RotateEffect *plugin;
+ RotateWindow *window;
+ int clear;
+};
+
+
class RotateReset : public BC_GenericButton
{
public:
- RotateReset(RotateEffect *plugin, RotateWindow *window, int x, int y);
+ RotateReset(RotateEffect *plugin, RotateWindow *window,
+ int x, int y);
~RotateReset();
int handle_event();
RotateEffect *plugin;
void create_objects();
int update();
- int update_fine();
- int update_text();
+ int update_sliders();
+ int update_texts();
int update_toggles();
RotateEffect *plugin;
+ RotateToggle *toggle180neg;
+ RotateToggle *toggle90neg;
RotateToggle *toggle0;
RotateToggle *toggle90;
RotateToggle *toggle180;
- RotateToggle *toggle270;
+
+ RotateAngleText *rotate_angle_text;
+ RotateAngleSlider *rotate_angle_slider;
+ RotateClr *rotate_angle_clr;
+
RotateDrawPivot *draw_pivot;
- RotateFine *fine;
- RotateText *text;
- RotateX *x;
- RotateY *y;
+
+ RotatePivotXText *rotate_pivot_x_text;
+ RotatePivotXSlider *rotate_pivot_x_slider;
+ RotateClr *rotate_pivot_x_clr;
+
+ RotatePivotYText *rotate_pivot_y_text;
+ RotatePivotYSlider *rotate_pivot_y_slider;
+ RotateClr *rotate_pivot_y_clr;
+
// RotateInterpolate *bilinear;
RotateReset *reset;
};
#include "edl.h"
#include "edlsession.h"
#include "filexml.h"
+#include "keyframes.h"
#include "overlayframe.h"
#include "pluginserver.h"
#include "preferences.h"
#include "sketcher.h"
#include "sketcherwindow.h"
+#include "transportque.inc"
#include "language.h"
#include "vframe.h"
NEW_WINDOW_MACRO(Sketcher, SketcherWindow);
LOAD_CONFIGURATION_MACRO(Sketcher, SketcherConfig)
-void Sketcher::save_data(KeyFrame *keyframe)
+void SketcherConfig::save_data(KeyFrame *keyframe)
{
FileXML output;
// cause data to be stored directly in text
output.set_shared_output(keyframe->xbuf);
output.tag.set_title("SKETCHER");
- output.tag.set_property("DRAG", config.drag);
- output.tag.set_property("ALIASING", config.aliasing);
- output.tag.set_property("CV_SELECTED", config.cv_selected);
- output.tag.set_property("PT_SELECTED", config.pt_selected);
+ output.tag.set_property("DRAG", drag);
+ output.tag.set_property("ALIASING", aliasing);
+ output.tag.set_property("CV_SELECTED", cv_selected);
+ output.tag.set_property("PT_SELECTED", pt_selected);
output.append_tag();
output.append_newline();
- for( int i=0,n=config.curves.size(); i<n; ++i ) {
- config.curves[i]->save_data(output);
+ for( int i=0,n=curves.size(); i<n; ++i ) {
+ curves[i]->save_data(output);
}
output.tag.set_title("/SKETCHER");
output.append_tag();
output.terminate_string();
}
-void Sketcher::read_data(KeyFrame *keyframe)
+void Sketcher::save_data(KeyFrame *keyframe)
+{
+ config.save_data(keyframe);
+}
+
+void SketcherConfig::read_data(KeyFrame *keyframe)
{
FileXML input;
input.set_shared_input(keyframe->xbuf);
- config.curves.remove_all_objects();
+ curves.remove_all_objects();
int result = 0;
SketcherCurve *cv = 0;
while( !(result=input.read_tag()) ) {
if( input.tag.title_is("SKETCHER") ) {
- config.drag = input.tag.get_property("DRAG", config.drag);
- config.aliasing = input.tag.get_property("ALIASING", config.aliasing);
- config.cv_selected = input.tag.get_property("CV_SELECTED", 0);
- config.pt_selected = input.tag.get_property("PT_SELECTED", 0);
+ drag = input.tag.get_property("DRAG", drag);
+ aliasing = input.tag.get_property("ALIASING", aliasing);
+ cv_selected = input.tag.get_property("CV_SELECTED", 0);
+ pt_selected = input.tag.get_property("PT_SELECTED", 0);
}
else if( !strncmp(input.tag.get_title(),"CURVE_",6) ) {
cv = new SketcherCurve();
cv->read_data(input);
- config.curves.append(cv);
+ curves.append(cv);
}
else if( !strncmp(input.tag.get_title(),"/CURVE_",7) )
cv = 0;
cv->points.append(pt);
}
else
- printf("Sketcher::read_data: no curve for point\n");
+ printf("SketcherConfig::read_data: no curve for point\n");
}
}
+ limits();
+}
+
+void Sketcher::read_data(KeyFrame *keyframe)
+{
+ config.read_data(keyframe);
if( !config.curves.size() )
new_curve();
- config.limits();
+}
+
+
+void SketcherPoint::update_parameter(SketcherPoint *prev, SketcherPoint *src)
+{
+ if( prev->arc != src->arc ) arc = src->arc;
+ if( prev->x != src->x ) x = src->x;
+ if( prev->y != src->y ) y = src->y;
+}
+
+void SketcherCurve::update_parameter(SketcherCurve *prev, SketcherCurve *src)
+{
+ if( prev->pen != src->pen ) pen = src->pen;
+ if( prev->width != src->width ) width = src->width;
+ if( prev->color != src->color ) color = src->color;
+ int prev_points = prev->points.size();
+ int src_points = src->points.size();
+ int dst_points = this->points.size();
+ int npoints = bmin(prev_points, bmin(src_points, dst_points));
+ for( int i=0; i<npoints; ++i ) {
+ SketcherPoint *prev_point = prev->points[i];
+ SketcherPoint *src_point = src->points[i];
+ SketcherPoint *dst_point = this->points[i];
+ dst_point->update_parameter(prev_point, src_point);
+ }
+}
+
+void Sketcher::span_keyframes(KeyFrame *src, int64_t start, int64_t end)
+{
+ SketcherConfig src_config;
+ src_config.read_data(src);
+ KeyFrames *keyframes = (KeyFrames *)src->autos;
+ KeyFrame *prev = keyframes->get_prev_keyframe(start, PLAY_FORWARD);
+ SketcherConfig prev_config;
+ prev_config.read_data(prev);
+// Always update the first one
+ update_parameter(prev_config, src_config, prev);
+ KeyFrame *curr = (KeyFrame*)prev->next;
+ while( curr && curr->position < end ) {
+ update_parameter(prev_config, src_config, curr);
+ curr = (KeyFrame*)curr->next;
+ }
+}
+
+void Sketcher::update_parameter(SketcherConfig &prev_config, SketcherConfig &src_config,
+ KeyFrame *keyframe)
+{
+ SketcherConfig dst_config;
+ dst_config.read_data(keyframe);
+ if( prev_config.drag != src_config.drag )
+ dst_config.drag = src_config.drag;
+ if( prev_config.aliasing != src_config.aliasing )
+ dst_config.aliasing = src_config.aliasing;
+ if( prev_config.cv_selected != src_config.cv_selected )
+ dst_config.cv_selected = src_config.cv_selected;
+ if( prev_config.pt_selected != src_config.pt_selected )
+ dst_config.pt_selected = src_config.pt_selected;
+ int src_curves = src_config.curves.size();
+ int dst_curves = dst_config.curves.size();
+ int prev_curves = prev_config.curves.size();
+ int ncurves = bmin(prev_curves, bmin(src_curves, dst_curves));
+ for( int i=0; i<ncurves; ++i ) {
+ SketcherCurve *prev_curve = prev_config.curves[i];
+ SketcherCurve *src_curve = src_config.curves[i];
+ SketcherCurve *dst_curve = dst_config.curves[i];
+ dst_curve->update_parameter(prev_curve, src_curve);
+ }
+ dst_config.save_data(keyframe);
}
void Sketcher::update_gui()
void save_data(FileXML &output);
void read_data(FileXML &input);
static const char *types[ARC_SZ];
+ void update_parameter(SketcherPoint *the, SketcherPoint *src);
};
class SketcherPoints : public ArrayList<SketcherPoint *>
{
SketcherVPen *new_vpen(VFrame *out);
void draw(VFrame *img, int flags);
+ void update_parameter(SketcherCurve *the, SketcherCurve *src);
};
class SketcherCurves : public ArrayList<SketcherCurve *>
{
public:
SketcherConfig();
~SketcherConfig();
+ void read_data(KeyFrame *keyframe);
+ void save_data(KeyFrame *keyframe);
SketcherCurves curves;
int equivalent(SketcherConfig &that);
void update_gui();
void save_data(KeyFrame *keyframe);
void read_data(KeyFrame *keyframe);
+ void span_keyframes(KeyFrame *src, int64_t start, int64_t end);
+ void update_parameter(SketcherConfig &prev_config, SketcherConfig &src_config,
+ KeyFrame *keyframe);
int new_curve(int pen, int width, int color);
int new_curve();
int new_point(SketcherCurve *cv, int arc, coord x, coord y, int idx=-1);
#include "edl.h"
#include "edlsession.h"
#include "filexml.h"
+#include "keyframe.h"
+#include "keyframes.h"
#include "tracer.h"
+#include "transportque.inc"
#include "tracerwindow.h"
#include "language.h"
#include "vframe.h"
return config.add_point(x, y);
}
-void Tracer::save_data(KeyFrame *keyframe)
+void TracerConfig::save_data(KeyFrame *keyframe)
{
FileXML output;
output.set_shared_output(keyframe->xbuf);
output.tag.set_title("TRACER");
- output.tag.set_property("DRAG", config.drag);
- output.tag.set_property("DRAW", config.draw);
- output.tag.set_property("FILL", config.fill);
- output.tag.set_property("FEATHER", config.feather);
- output.tag.set_property("RADIUS", config.radius);
- output.tag.set_property("INVERT", config.invert);
- output.tag.set_property("SELECTED", config.selected);
+ output.tag.set_property("DRAG", drag);
+ output.tag.set_property("DRAW", draw);
+ output.tag.set_property("FILL", fill);
+ output.tag.set_property("FEATHER", feather);
+ output.tag.set_property("RADIUS", radius);
+ output.tag.set_property("INVERT", invert);
+ output.tag.set_property("SELECTED", selected);
output.append_tag();
output.append_newline();
output.tag.set_title("/TRACER");
output.append_tag();
output.append_newline();
- for( int i=0, n=config.points.size(); i<n; ++i ) {
- TracerPoint *pt = config.points[i];
+ for( int i=0, n=points.size(); i<n; ++i ) {
+ TracerPoint *pt = points[i];
char point[BCSTRLEN];
sprintf(point,"/POINT_%d",i+1);
output.tag.set_title(point+1);
output.terminate_string();
}
-void Tracer::read_data(KeyFrame *keyframe)
+void Tracer::save_data(KeyFrame *keyframe)
+{
+ config.save_data(keyframe);
+}
+
+void TracerConfig::read_data(KeyFrame *keyframe)
{
FileXML input;
input.set_shared_input(keyframe->xbuf);
- config.points.remove_all_objects();
+ points.remove_all_objects();
int result = 0;
while( !(result=input.read_tag()) ) {
if( input.tag.title_is("TRACER") ) {
- config.drag = input.tag.get_property("DRAG", config.drag);
- config.draw = input.tag.get_property("DRAW", config.draw);
- config.fill = input.tag.get_property("FILL", config.fill);
- config.feather = input.tag.get_property("FEATHER", config.feather);
- config.radius = input.tag.get_property("RADIUS", config.radius);
- config.invert = input.tag.get_property("INVERT", config.invert);
- config.selected = input.tag.get_property("SELECTED", 0);
- config.limits();
+ drag = input.tag.get_property("DRAG", drag);
+ draw = input.tag.get_property("DRAW", draw);
+ fill = input.tag.get_property("FILL", fill);
+ feather = input.tag.get_property("FEATHER", feather);
+ radius = input.tag.get_property("RADIUS", radius);
+ invert = input.tag.get_property("INVERT", invert);
+ selected = input.tag.get_property("SELECTED", 0);
+ limits();
}
else if( !strncmp(input.tag.get_title(),"POINT_",6) ) {
float x = input.tag.get_property("X", 0.f);
float y = input.tag.get_property("Y", 0.f);
- config.add_point(x, y);
+ add_point(x, y);
}
}
}
+void Tracer::read_data(KeyFrame *keyframe)
+{
+ config.read_data(keyframe);
+}
+
+void Tracer::span_keyframes(KeyFrame *src, int64_t start, int64_t end)
+{
+ TracerConfig src_config;
+ src_config.read_data(src);
+ KeyFrames *keyframes = (KeyFrames *)src->autos;
+ KeyFrame *prev = keyframes->get_prev_keyframe(start, PLAY_FORWARD);
+ TracerConfig prev_config;
+ prev_config.read_data(prev);
+// Always update the first one
+ update_parameter(prev_config, src_config, prev);
+ KeyFrame *curr = (KeyFrame*)prev->next;
+ while( curr && curr->position < end ) {
+ update_parameter(prev_config, src_config, curr);
+ curr = (KeyFrame*)curr->next;
+ }
+}
+
+void TracerPoint::update_parameter(TracerPoint *prev, TracerPoint *src)
+{
+ if( prev->x != src->x ) x = src->x;
+ if( prev->y != src->y ) y = src->y;
+}
+
+void Tracer::update_parameter(TracerConfig &prev_config, TracerConfig &src_config,
+ KeyFrame *keyframe)
+{
+ TracerConfig dst_config;
+ dst_config.read_data(keyframe);
+ if( prev_config.drag != src_config.drag )
+ dst_config.drag = src_config.drag;
+ if( prev_config.draw != src_config.draw )
+ dst_config.draw = src_config.draw;
+ if( prev_config.fill != src_config.fill )
+ dst_config.fill = src_config.fill;
+ if( prev_config.feather != src_config.feather )
+ dst_config.feather = src_config.feather;
+ if( prev_config.invert != src_config.invert )
+ dst_config.invert = src_config.invert;
+ if( prev_config.radius != src_config.radius )
+ dst_config.radius = src_config.radius;
+ int src_points = src_config.points.size();
+ int dst_points = dst_config.points.size();
+ int prev_points = prev_config.points.size();
+ int npoints = bmin(prev_points, bmin(src_points, dst_points));
+ for( int i=0; i<npoints; ++i ) {
+ TracerPoint *prev_point = prev_config.points[i];
+ TracerPoint *src_point = src_config.points[i];
+ TracerPoint *dst_point = dst_config.points[i];
+ dst_point->update_parameter(prev_point, src_point);
+ }
+ dst_config.save_data(keyframe);
+}
+
void Tracer::update_gui()
{
if( !thread ) return;
if( !edg ) redraw = 1;
VFrame::get_temp(edg, w, h, BC_GREY8);
if( redraw ) {
- edg->clear_frame();
+ edg->black_frame();
edg_rows = edg->get_rows();
int n = config.points.size()-1;
TracePoint *pt0 = &points[0], *pt1 = &points[l2];
int cx = (pt0->x+pt1->x)/2, cy = (pt0->y+pt1->y)/2;
VFrame::get_temp(msk, w, h, BC_GREY8);
- msk->clear_frame();
+ msk->black_frame();
msk_rows = msk->get_rows();
FillRegion fill_region(edg, msk);
TracerPoint(float x, float y);
~TracerPoint();
+ void update_parameter(TracerPoint *prev, TracerPoint *src);
};
class TracerPoints : public ArrayList<TracerPoint *>
{
TracerConfig();
~TracerConfig();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
int equivalent(TracerConfig &that);
void copy_from(TracerConfig &that);
void interpolate(TracerConfig &prev, TracerConfig &next,
int smooth();
void feather(int r, double s);
int load_configuration1();
+ void span_keyframes(KeyFrame *src, int64_t start, int64_t end);
+ void update_parameter(TracerPoint *prev, TracerPoint *src);
+ void update_parameter(TracerConfig &prev_config, TracerConfig &src_config,
+ KeyFrame *keyframe);
VFrame *edg, *msk, *frm;
uint8_t **edg_rows;