RafaMar fixed my comment error
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / crikey / crikey.C
index d5a6cd13f4c740dc711adeb03472821c14e5ce0e..8686613c3d38220188017b6af2b9954aad36a113 100644 (file)
 #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
@@ -64,8 +67,6 @@ CriKeyConfig::CriKeyConfig()
 {
        threshold = 0.5f;
        draw_mode = DRAW_ALPHA;
-       drag = 0;
-       selected = 0;
 }
 CriKeyConfig::~CriKeyConfig()
 {
@@ -75,7 +76,6 @@ int CriKeyConfig::equivalent(CriKeyConfig &that)
 {
        if( !EQUIV(this->threshold, that.threshold) ) return 0;
        if( this->draw_mode != that.draw_mode ) return 0;
-       if( this->drag != that.drag ) return 0;
        if( this->points.size() != that.points.size() ) return 0;
        for( int i=0, n=points.size(); i<n; ++i ) {
                CriKeyPoint *ap = this->points[i], *bp = that.points[i];
@@ -92,8 +92,6 @@ void CriKeyConfig::copy_from(CriKeyConfig &that)
 {
        this->threshold = that.threshold;
        this->draw_mode = that.draw_mode;
-       this->drag = that.drag;
-       this->selected = that.selected;
 
        points.remove_all_objects();
        for( int i=0,n=that.points.size(); i<n; ++i ) {
@@ -107,8 +105,6 @@ void CriKeyConfig::interpolate(CriKeyConfig &prev, CriKeyConfig &next,
 {
        this->threshold = prev.threshold;
        this->draw_mode = prev.draw_mode;
-       this->drag = prev.drag;
-       this->selected = prev.selected;
 
        double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
        double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
@@ -231,6 +227,9 @@ CriKey::CriKey(PluginServer *server)
        engine = 0;
        msk = 0;
        edg = 0;
+
+       drag = 0;
+       selected = 0;
 }
 
 CriKey::~CriKey()
@@ -262,6 +261,21 @@ int CriKey::is_realtime() { return 1; }
 NEW_WINDOW_MACRO(CriKey, CriKeyWindow);
 LOAD_CONFIGURATION_MACRO(CriKey, CriKeyConfig)
 
+void CriKey::render_gui(void *data)
+{
+       CriKey *crikey = (CriKey *)data;
+       crikey->drag = drag;
+       crikey->selected = selected;
+}
+
+int CriKey::is_dragging()
+{
+       drag = 0;
+       selected = 0;
+       send_render_gui(this);
+       return drag;
+}
+
 int CriKey::new_point()
 {
        EDLSession *session = get_edl()->session;
@@ -270,7 +284,7 @@ int CriKey::new_point()
        return config.add_point(-1, 0, x, y, 0.5f);
 }
 
-void CriKey::save_data(KeyFrame *keyframe)
+void CriKeyConfig::save_data(KeyFrame *keyframe)
 {
        FileXML output;
 
@@ -278,17 +292,15 @@ void CriKey::save_data(KeyFrame *keyframe)
        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.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);
@@ -303,21 +315,23 @@ void CriKey::save_data(KeyFrame *keyframe)
        }
        output.terminate_string();
 }
+void CriKey::save_data(KeyFrame *keyframe)
+{
+       config.save_data(keyframe);
+}
 
-void CriKey::read_data(KeyFrame *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);
+                       limits();
                }
                else if( !strncmp(input.tag.get_title(),"POINT_",6) ) {
                        int tag = atoi(input.tag.get_title() + 6);
@@ -325,11 +339,68 @@ void CriKey::read_data(KeyFrame *keyframe)
                        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();
+}
 
-       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;
+       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()
@@ -622,10 +693,10 @@ int CriKey::process_buffer(VFrame *frame, int64_t start_position, double frame_r
        case DRAW_MASK:  draw_mask(msk);   break;
        }
 
-       if( config.drag ) {
+       if( is_dragging() ) {
                for( int i=0, n=config.points.size(); i<n; ++i ) {
                        CriKeyPoint *pt = config.points[i];
-                       src->set_pixel_color(config.selected == i ? GREEN : WHITE);
+                       src->set_pixel_color(selected == i ? GREEN : WHITE);
                        draw_point(src, pt);
                }
        }
@@ -666,14 +737,14 @@ LoadClient* CriKeyEngine::new_client()
                        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); \
                } \