sketcher add alpha/fill, add alpha to vframe draw_pixel, crikey tweaks
authorGood Guy <good1.2guy@gmail.com>
Mon, 19 Nov 2018 18:06:01 +0000 (11:06 -0700)
committerGood Guy <good1.2guy@gmail.com>
Mon, 19 Nov 2018 18:06:01 +0000 (11:06 -0700)
cinelerra-5.1/cinelerra/versioninfo.h
cinelerra-5.1/guicast/vframe.C
cinelerra-5.1/guicast/vframe.h
cinelerra-5.1/plugins/crikey/crikey.C
cinelerra-5.1/plugins/sketcher/sketcher.C
cinelerra-5.1/plugins/sketcher/sketcher.h
cinelerra-5.1/plugins/sketcher/sketcherwindow.C

index 312148f526d2ed29db839b82bead0b93f0fbb5fe..72d92eca2579821ecb50cd4f14cdfd6c0156acda 100644 (file)
@@ -2,7 +2,7 @@
 #define __VERSIONINFO_H__
 
 #define CINELERRA_VERSION "Unify"
 #define __VERSIONINFO_H__
 
 #define CINELERRA_VERSION "Unify"
-#define REPOMAINTXT "git://git.cinelerra-cv.org/goodguy/cinelerra.git\n"
+#define REPOMAINTXT "git://git.cinelerra-gg.org/goodguy/cinelerra.git\n"
 #define COPYRIGHT_DATE "2018"
 #define COPYRIGHTTEXT1 "(c) 2006-2018 Heroine Virtual Ltd. by Adam Williams\n"
 #define COPYRIGHTTEXT2 "(c) 2007-2018 cin5 derivative by W.P. Morrow aka goodguy\n"
 #define COPYRIGHT_DATE "2018"
 #define COPYRIGHTTEXT1 "(c) 2006-2018 Heroine Virtual Ltd. by Adam Williams\n"
 #define COPYRIGHTTEXT2 "(c) 2007-2018 cin5 derivative by W.P. Morrow aka goodguy\n"
index 3eca676452ca8536fa3f78993e68a24bf35fd9a1..6f0dfbb18e754e8afeed54fb846628a4df0e14e6 100644 (file)
@@ -388,6 +388,15 @@ int VFrame::get_keyframe()
        return is_keyframe;
 }
 
        return is_keyframe;
 }
 
+void VFrame::get_temp(VFrame *&vfrm, int w, int h, int color_model)
+{
+        if( vfrm && ( vfrm->get_w() != w || vfrm->get_h() != h ) ) {
+                delete vfrm;  vfrm = 0;
+        }
+        if( !vfrm ) vfrm = new VFrame(w, h, color_model, 0);
+}
+
+
 
 VFrameScene* VFrame::get_scene()
 {
 
 VFrameScene* VFrame::get_scene()
 {
@@ -1341,14 +1350,17 @@ int VFrame::get_memory_usage()
        return get_h() * get_bytes_per_line();
 }
 
        return get_h() * get_bytes_per_line();
 }
 
-void VFrame::set_pixel_color(int rgb)
+// rgb component colors (eg. from colors.h)
+// a (~alpha) transparency, 0x00==solid .. 0xff==transparent
+void VFrame::set_pixel_color(int argb)
 {
 {
-       pixel_rgb = rgb;
+       pixel_rgb = argb;
+       int ia = 0xff & (pixel_rgb >> 24);
        int ir = 0xff & (pixel_rgb >> 16);
        int ig = 0xff & (pixel_rgb >> 8);
        int ib = 0xff & (pixel_rgb >> 0);
        YUV::yuv.rgb_to_yuv_8(ir, ig, ib);
        int ir = 0xff & (pixel_rgb >> 16);
        int ig = 0xff & (pixel_rgb >> 8);
        int ib = 0xff & (pixel_rgb >> 0);
        YUV::yuv.rgb_to_yuv_8(ir, ig, ib);
-       pixel_yuv =  (ir<<16) | (ig<<8) | (ib<<0);
+       pixel_yuv =  (ia<<24) | (ir<<16) | (ig<<8) | (ib<<0);
 }
 
 void VFrame::set_stiple(int mask)
 }
 
 void VFrame::set_stiple(int mask)
@@ -1360,49 +1372,51 @@ int VFrame::draw_pixel(int x, int y)
 {
        if( x < 0 || y < 0 || x >= get_w() || y >= get_h() ) return 1;
 
 {
        if( x < 0 || y < 0 || x >= get_w() || y >= get_h() ) return 1;
 
-#define DRAW_PIXEL(type, r, g, b) { \
+#define DRAW_PIXEL(type, r, g, b, comps, a) { \
        type **rows = (type**)get_rows(); \
        type **rows = (type**)get_rows(); \
-       rows[y][x * components + 0] = r; \
-       rows[y][x * components + 1] = g; \
-       rows[y][x * components + 2] = b; \
-       if( components == 4 ) \
-               rows[y][x * components + 3] = mx; \
-}
-       int components = BC_CModels::components(color_model);
-       int bch = BC_CModels::calculate_pixelsize(color_model) / components;
-       int sz = 8*bch, mx = BC_CModels::is_float(color_model) ? 1 : (1<<sz)-1;
-       int is_yuv = BC_CModels::is_yuv(color_model);
-       int pixel_color = is_yuv ? pixel_yuv : pixel_rgb;
-       int ir = 0xff & (pixel_color >> 16);  float fr = 0;
-       int ig = 0xff & (pixel_color >> 8);   float fg = 0;
-       int ib = 0xff & (pixel_color >> 0);   float fb = 0;
+       type *rp = rows[y], *bp = rp + x*comps; \
+       bp[0] = r; \
+       if( comps > 1 ) { bp[1] = g; bp[2] = b; } \
+       if( comps == 4 )  bp[3] = a; \
+}
+       float fr = 0, fg = 0, fb = 0, fa = 0;
+       int pixel_color = BC_CModels::is_yuv(color_model) ? pixel_yuv : pixel_rgb;
+       int ir = (0xff & (pixel_color >> 16));
+       int ig = (0xff & (pixel_color >> 8));
+       int ib = (0xff & (pixel_color >> 0));
+       int ia = (0xff & (pixel_color >> 24)) ^ 0xff;  // transparency, not opacity
        if( (x+y) & stipple ) {
                ir = 255 - ir;  ig = 255 - ig;  ib = 255 - ib;
        }
        if( (x+y) & stipple ) {
                ir = 255 - ir;  ig = 255 - ig;  ib = 255 - ib;
        }
+       int rr = (ir<<8) | ir, gg = (ig<<8) | ig, bb = (ib<<8) | ib, aa = (ia<<8) | ia;
        if( BC_CModels::is_float(color_model) ) {
        if( BC_CModels::is_float(color_model) ) {
-               fr = ir / 255.;  fg = ig / 255.;  fb = ib / 255.;
-               mx = 1;
-       }
-       else if( (sz-=8) > 0 ) {
-               ir <<= sz;  ig <<= sz;  ib <<= sz;
+               fr = rr/65535.f;  fg = gg/65535.f;  fb = bb/65535.f;  fa = aa/65535.f;
        }
 
        switch(get_color_model()) {
        }
 
        switch(get_color_model()) {
-       case BC_RGB888:
+       case BC_A8:
+               DRAW_PIXEL(uint8_t, ib, 0, 0, 1, 0);
+               break;
        case BC_YUV888:
        case BC_YUV888:
+               DRAW_PIXEL(uint8_t, ir, ig, ib, 3, 0);
+               break;
        case BC_RGBA8888:
        case BC_YUVA8888:
        case BC_RGBA8888:
        case BC_YUVA8888:
-               DRAW_PIXEL(uint8_t, ir, ig, ib);
+               DRAW_PIXEL(uint8_t, ir, ig, ib, 4, ia);
                break;
        case BC_RGB161616:
        case BC_YUV161616:
                break;
        case BC_RGB161616:
        case BC_YUV161616:
+               DRAW_PIXEL(uint16_t, rr, gg, bb, 3, 0);
+               break;
        case BC_RGBA16161616:
        case BC_YUVA16161616:
        case BC_RGBA16161616:
        case BC_YUVA16161616:
-               DRAW_PIXEL(uint16_t, ir, ig, ib);
+               DRAW_PIXEL(uint16_t, rr, gg, bb, 4, aa);
                break;
        case BC_RGB_FLOAT:
                break;
        case BC_RGB_FLOAT:
+               DRAW_PIXEL(float, fr, fg, fb, 3, 0);
+               break;
        case BC_RGBA_FLOAT:
        case BC_RGBA_FLOAT:
-               DRAW_PIXEL(float, fr, fg, fb);
+               DRAW_PIXEL(float, fr, fg, fb, 4, fa);
                break;
        }
        return 0;
                break;
        }
        return 0;
index da53bfdda22bdb315613238362c512b1061f2ec6..e6bbc23652ac8a8d1ca082a7a85af386ca52e289 100644 (file)
@@ -180,14 +180,14 @@ public:
        long get_bytes_per_line();
        int get_memory_type();
 
        long get_bytes_per_line();
        int get_memory_type();
 
-
-
        static int calculate_bytes_per_pixel(int colormodel);
 // Get size + 4 for assembly language
        static long calculate_data_size(int w, int h,
                int bytes_per_line = -1, int color_model = BC_RGB888);
 // Get size of uncompressed frame buffer without extra 4 bytes
        long get_data_size();
        static int calculate_bytes_per_pixel(int colormodel);
 // Get size + 4 for assembly language
        static long calculate_data_size(int w, int h,
                int bytes_per_line = -1, int color_model = BC_RGB888);
 // Get size of uncompressed frame buffer without extra 4 bytes
        long get_data_size();
+// alloc/reset temp vframe to spec
+       static void get_temp(VFrame *&vfrm, int w, int h, int color_model);
 
        void rotate270();
        void rotate90();
 
        void rotate270();
        void rotate90();
@@ -347,6 +347,7 @@ public:
        int pixel_rgb, pixel_yuv, stipple;
 
        void set_pixel_color(int rgb);
        int pixel_rgb, pixel_yuv, stipple;
 
        void set_pixel_color(int rgb);
+       void set_pixel_color(int rgb, int a) { set_pixel_color((rgb&0xffffff)|((~a&0xff)<<24)); }
        void set_stiple(int mask);
        void draw_line(int x1, int y1, int x2, int y2);
        void draw_smooth(int x1, int y1, int x2, int y2, int x3, int y3);
        void set_stiple(int mask);
        void draw_line(int x1, int y1, int x2, int y2);
        void draw_smooth(int x1, int y1, int x2, int y2, int x3, int y3);
index 46d2402f2f58e0f630328bad62876d2b3a3b9083..250397a13452f73020a41b17864b798c42657599 100644 (file)
@@ -212,7 +212,7 @@ void FillRegion::run()
                                if( edge_pixel(lofs) ) break;
                        }
                        int rofs = ofs;
                                if( edge_pixel(lofs) ) break;
                        }
                        int rofs = ofs;
-                       for( int i=rt; ++i< w; rt=i,msk[rofs]=0 ) {
+                       for( int i=rt; ++i< w; ) {
                                if( !msk[++rofs] ) break;
                                msk[rofs] = 0;  rt = i;
                                if( edge_pixel(rofs) ) break;
                                if( !msk[++rofs] ) break;
                                msk[rofs] = 0;  rt = i;
                                if( edge_pixel(rofs) ) break;
@@ -570,14 +570,6 @@ void CriKey::draw_point(VFrame *src, CriKeyPoint *pt)
 }
 
 
 }
 
 
-static void get_vframe(VFrame *&vfrm, int w, int h, int color_model)
-{
-       if( vfrm && ( vfrm->get_w() != w || vfrm->get_h() != h ) ) {
-               delete vfrm;  vfrm = 0;
-       }
-       if( !vfrm ) vfrm = new VFrame(w, h, color_model, 0);
-}
-
 static void fill_edge(VFrame *vfrm, int w, int h)
 {
        int w1 = w-1, h1 = h-1;
 static void fill_edge(VFrame *vfrm, int w, int h)
 {
        int w1 = w-1, h1 = h-1;
@@ -599,14 +591,14 @@ int CriKey::process_buffer(VFrame *frame, int64_t start_position, double frame_r
        if( comp > 3 ) comp = 3;
 
        read_frame(src, 0, start_position, frame_rate, 0);
        if( comp > 3 ) comp = 3;
 
        read_frame(src, 0, start_position, frame_rate, 0);
-       get_vframe(edg, w, h, BC_A_FLOAT);
+       VFrame::get_temp(edg, w, h, BC_A_FLOAT);
 
        if( !engine )
                engine = new CriKeyEngine(this,
                        PluginClient::get_project_smp() + 1,
                        PluginClient::get_project_smp() + 1);
 
 
        if( !engine )
                engine = new CriKeyEngine(this,
                        PluginClient::get_project_smp() + 1,
                        PluginClient::get_project_smp() + 1);
 
-       get_vframe(msk, w, h, BC_A8);
+       VFrame::get_temp(msk, w, h, BC_A8);
        memset(msk->get_data(), 0xff, msk->get_data_size());
 
        for( int i=0, n=config.points.size(); i<n; ++i ) {
        memset(msk->get_data(), 0xff, msk->get_data_size());
 
        for( int i=0, n=config.points.size(); i<n; ++i ) {
index e3b61b192e15f85f030c4b69d80660c95a011ba0..954f7a2c64515679b1d80080e36840fe215344a7 100644 (file)
@@ -29,6 +29,9 @@
 #include "clip.h"
 #include "edlsession.h"
 #include "filexml.h"
 #include "clip.h"
 #include "edlsession.h"
 #include "filexml.h"
+#include "overlayframe.h"
+#include "pluginserver.h"
+#include "preferences.h"
 #include "sketcher.h"
 #include "sketcherwindow.h"
 #include "language.h"
 #include "sketcher.h"
 #include "sketcherwindow.h"
 #include "language.h"
@@ -205,6 +208,35 @@ int Sketcher::new_point(int idx)
        return new_point(cv, PTY_LINE, x, y, idx);
 }
 
        return new_point(cv, PTY_LINE, x, y, idx);
 }
 
+double SketcherCurve::nearest_point(int &pi, float x, float y)
+{
+       pi = -1;
+       double dist = DBL_MAX;
+       for( int i=0; i<points.size(); ++i ) {
+               SketcherPoint *p = points[i];
+               double d = DISTANCE(x,y, p->x,p->y);
+               if( d < dist ) { dist = d;  pi = i;  }
+       }
+       return pi >= 0 ? dist : -1.;
+}
+
+double SketcherConfig::nearest_point(int &ci, int &pi, float x, float y)
+{
+       double dist = DBL_MAX;
+       ci = -1;  pi = -1;
+       for( int i=0; i<curves.size(); ++i ) {
+               SketcherCurve *crv = curves[i];
+               SketcherPoints &points = crv->points;
+               for( int k=0; k<points.size(); ++k ) {
+                       SketcherPoint *p = points[k];
+                       double d = DISTANCE(x,y, p->x,p->y);
+                       if( d < dist ) {  dist = d; ci = i;  pi = k; }
+               }
+       }
+       return pi >= 0 ? dist : -1.;
+}
+
+
 REGISTER_PLUGIN(Sketcher)
 
 SketcherConfig::SketcherConfig()
 REGISTER_PLUGIN(Sketcher)
 
 SketcherConfig::SketcherConfig()
@@ -289,10 +321,16 @@ void SketcherConfig::limits()
 Sketcher::Sketcher(PluginServer *server)
  : PluginVClient(server)
 {
 Sketcher::Sketcher(PluginServer *server)
  : PluginVClient(server)
 {
+       img = 0;
+       out = 0;
+       overlay_frame = 0;
 }
 
 Sketcher::~Sketcher()
 {
 }
 
 Sketcher::~Sketcher()
 {
+       delete img;
+       delete out;
+       delete overlay_frame;
 }
 
 const char* Sketcher::plugin_title() { return N_("Sketcher"); }
 }
 
 const char* Sketcher::plugin_title() { return N_("Sketcher"); }
@@ -374,7 +412,7 @@ void Sketcher::update_gui()
 void Sketcher::draw_point(VFrame *vfrm, SketcherPoint *pt, int color, int d)
 {
        int r = d/2+1, x = pt->x, y = pt->y;
 void Sketcher::draw_point(VFrame *vfrm, SketcherPoint *pt, int color, int d)
 {
        int r = d/2+1, x = pt->x, y = pt->y;
-       vfrm->set_pixel_color(color);
+       vfrm->set_pixel_color(color, 0xff);
        vfrm->draw_smooth(x-r,y+0, x-r, y-r, x+0,y-r);
        vfrm->draw_smooth(x+0,y-r, x+r, y-r, x+r,y+0);
        vfrm->draw_smooth(x+r,y+0, x+r, y+r, x+0,y+r);
        vfrm->draw_smooth(x-r,y+0, x-r, y-r, x+0,y-r);
        vfrm->draw_smooth(x+0,y-r, x+r, y-r, x+r,y+0);
        vfrm->draw_smooth(x+r,y+0, x+r, y+r, x+0,y+r);
@@ -387,12 +425,20 @@ void Sketcher::draw_point(VFrame *vfrm, SketcherPoint *pt, int color)
 }
 
 
 }
 
 
+int SketcherVPen::draw_pixel(int x, int y)
+{
+       if( x >= 0 && x < vfrm->get_w() &&
+           y >= 0 && y < vfrm->get_h() )
+               msk[vfrm->get_w()*y + x] = 0xff;
+       return 0;
+}
+
 int SketcherPenSquare::draw_pixel(int x, int y)
 {
        vfrm->draw_line(x-n, y, x+n, y);
        for( int i=-n; i<n; ++i )
                vfrm->draw_line(x-n, y+i, x+n, y+i);
 int SketcherPenSquare::draw_pixel(int x, int y)
 {
        vfrm->draw_line(x-n, y, x+n, y);
        for( int i=-n; i<n; ++i )
                vfrm->draw_line(x-n, y+i, x+n, y+i);
-       return 0;
+       return SketcherVPen::draw_pixel(x, y);
 }
 int SketcherPenPlus::draw_pixel(int x, int y)
 {
 }
 int SketcherPenPlus::draw_pixel(int x, int y)
 {
@@ -402,14 +448,14 @@ int SketcherPenPlus::draw_pixel(int x, int y)
        }
        else
                vfrm->draw_pixel(x, y);
        }
        else
                vfrm->draw_pixel(x, y);
-       return 0;
+       return SketcherVPen::draw_pixel(x, y);
 }
 int SketcherPenSlant::draw_pixel(int x, int y)
 {
        vfrm->draw_line(x-n,   y+n,   x+n,   y-n);
        vfrm->draw_line(x-n+1, y+n,   x+n+1, y-n);
        vfrm->draw_line(x-n,   y+n+1, x+n,   y-n+1);
 }
 int SketcherPenSlant::draw_pixel(int x, int y)
 {
        vfrm->draw_line(x-n,   y+n,   x+n,   y-n);
        vfrm->draw_line(x-n+1, y+n,   x+n+1, y-n);
        vfrm->draw_line(x-n,   y+n+1, x+n,   y-n+1);
-       return 0;
+       return SketcherVPen::draw_pixel(x, y);
 }
 int SketcherPenXlant::draw_pixel(int x, int y)
 {
 }
 int SketcherPenXlant::draw_pixel(int x, int y)
 {
@@ -419,11 +465,11 @@ int SketcherPenXlant::draw_pixel(int x, int y)
        vfrm->draw_line(x-n,   y-n,   x+n,   y+n);
        vfrm->draw_line(x-n+1, y-n,   x+n+1, y+n);
        vfrm->draw_line(x-n,   y-n+1, x+n,   y-n+1);
        vfrm->draw_line(x-n,   y-n,   x+n,   y+n);
        vfrm->draw_line(x-n+1, y-n,   x+n+1, y+n);
        vfrm->draw_line(x-n,   y-n+1, x+n,   y-n+1);
-       return 0;
+       return SketcherVPen::draw_pixel(x, y);
 }
 
 
 }
 
 
-VFrame *SketcherCurve::new_vpen(VFrame *out)
+SketcherVPen *SketcherCurve::new_vpen(VFrame *out)
 {
        switch( pen ) {
        case PEN_SQUARE: return new SketcherPenSquare(out, radius);
 {
        switch( pen ) {
        case PEN_SQUARE: return new SketcherPenSquare(out, radius);
@@ -454,7 +500,7 @@ static void smooth_axy(float &ax, float &ay,
        float bx, float by, float cx, float cy, float dx, float dy)
 {
 //middle of bd reflected around ctr
        float bx, float by, float cx, float cy, float dx, float dy)
 {
 //middle of bd reflected around ctr
-// point ctr = b+d/2, dv=c-ctr, a=ctr-dv;
+// point ctr = (b+d)/2, dv=c-ctr, a=ctr-dv;
        float xc = (bx+dx)*.5f, yc = (by+dy)*.5f;
        float xd = cx - xc, yd = cy - yc;
        ax = xc - xd;  ay = yc - yd;
        float xc = (bx+dx)*.5f, yc = (by+dy)*.5f;
        float xd = cx - xc, yd = cy - yc;
        ax = xc - xd;  ay = yc - yd;
@@ -463,7 +509,7 @@ static void smooth_dxy(float &dx, float &dy,
        float ax, float ay, float bx, float by, float cx, float cy)
 {
 //middle of ac reflected around ctr
        float ax, float ay, float bx, float by, float cx, float cy)
 {
 //middle of ac reflected around ctr
-// point ctr = a+c/2, dv=c-ctr, d=ctr-dv;
+// point ctr = (a+c)/2, dv=c-ctr, d=ctr-dv;
        float xc = (ax+cx)*.5f, yc = (ay+cy)*.5f;
        float xd = bx - xc, yd = by - yc;
        dx = xc - xd;  dy = yc - yd;
        float xc = (ax+cx)*.5f, yc = (ay+cy)*.5f;
        float xd = bx - xc, yd = by - yc;
        dx = xc - xd;  dy = yc - yd;
@@ -484,27 +530,115 @@ static int convex(float ax,float ay, float bx,float by,
 }
 #endif
 
 }
 #endif
 
-void SketcherCurve::draw(VFrame *out)
+
+class FillRegion
+{
+       class segment { public: int y, lt, rt; };
+       ArrayList<segment> stack;
+
+       void push(int y, int lt, int rt) {
+               segment &seg = stack.append();
+               seg.y = y;  seg.lt = lt;  seg.rt = rt;
+       }
+       void pop(int &y, int &lt, int &rt) {
+               segment &seg = stack.last();
+               y = seg.y;  lt = seg.lt;  rt = seg.rt;
+               stack.remove();
+       }
+       VFrame *img;
+       uint8_t *msk;
+       int w, h, nxt;
+       SketcherPoints &points;
+public:
+       SketcherPoint *next();
+       bool exists() { return stack.size() > 0; }
+       void start_at(int x, int y);
+       void run();
+       FillRegion(SketcherPoints &pts, SketcherVPen *vpen);
+       ~FillRegion();
+};
+
+FillRegion::FillRegion(SketcherPoints &pts, SketcherVPen *vpen)
+ : points(pts)
+{
+       this->img = vpen->vfrm;
+       this->msk = vpen->msk;
+       this->w = img->get_w();
+       this->h = img->get_h();
+       nxt = 0;
+}
+FillRegion::~FillRegion()
+{
+}
+
+void FillRegion::start_at(int x, int y)
+{
+       bclamp(x, 0, w-1);
+       bclamp(y, 0, h-1);
+       push(y, x, x);
+}
+
+void FillRegion::run()
+{
+       while( stack.size() > 0 ) {
+               int y, ilt, irt;
+               pop(y, ilt, irt);
+               int ofs = y*w + ilt;
+               for( int x=ilt; x<=irt; ++x,++ofs ) {
+                       if( msk[ofs] ) continue;
+                       msk[ofs] = 0xff;
+                       img->draw_pixel(x, y);
+                       int lt = x, rt = x;
+                       int lofs = ofs;
+                       for( int i=lt; --i>=0; ) {
+                               if( msk[--lofs] ) break;
+                               img->draw_pixel(i, y);
+                               msk[lofs] = 0xff;  lt = i;
+                       }
+                       int rofs = ofs;
+                       for( int i=rt; ++i< w; ) {
+                               if( msk[++rofs] ) break;
+                               img->draw_pixel(i, y);
+                               msk[rofs] = 0xff;  rt = i;
+                       }
+                       if( y+1 <  h ) push(y+1, lt, rt);
+                       if( y-1 >= 0 ) push(y-1, lt, rt);
+               }
+       }
+}
+
+SketcherPoint *FillRegion::next()
+{
+       while( nxt < points.size() ) {
+               SketcherPoint *pt = points[nxt];
+               if( pt->pty != PTY_FILL ) break;
+               start_at(pt->x, pt->y);
+               ++nxt;
+       }
+       return nxt < points.size() ? points[nxt++] : 0;
+}
+
+
+void SketcherCurve::draw(VFrame *img)
 {
 {
+       if( !points.size() ) return;
        const float fmx = 16383;
        const float fmx = 16383;
-       VFrame *vpen = new_vpen(out);
-       out->set_pixel_color(color);
-       int n = points.size();
-       if( !n ) return;
-       if( n > 2 ) {
-               int n2 = n - 2;
-               SketcherPoint *pt0 = points[0];
-               SketcherPoint *pt1 = points[1];
-               SketcherPoint *pt2 = points[2];
+       SketcherVPen *vpen = new_vpen(img);
+       FillRegion fill(points, vpen);
+       SketcherPoint *pnt0 = fill.next();
+       SketcherPoint *pnt1 = pnt0 ? fill.next() : 0;
+       SketcherPoint *pnt2 = pnt1 ? fill.next() : 0;
+       if( pnt0 && pnt1 && pnt2 ) {
+               SketcherPoint *pt0 = pnt0, *pt1 = pnt1, *pt2 = pnt2;
                float ax,ay, bx,by, cx,cy, dx,dy, sx,sy;
                bx = pt0->x;  by = pt0->y;
                cx = pt1->x;  cy = pt1->y;
                dx = pt2->x;  dy = pt2->y;
                smooth_axy(ax,ay, bx,by, cx,cy, dx,dy);
                float ax,ay, bx,by, cx,cy, dx,dy, sx,sy;
                bx = pt0->x;  by = pt0->y;
                cx = pt1->x;  cy = pt1->y;
                dx = pt2->x;  dy = pt2->y;
                smooth_axy(ax,ay, bx,by, cx,cy, dx,dy);
-               for( int pi=0; pi<n2; ++pi ) {
-                       int pty = points[pi]->pty;
-                       dx = points[pi+2]->x;  dy = points[pi+2]->y;
-                       switch( pty ) {
+               while( pt2 ) {
+                       dx = pt2->x;  dy = pt2->y;
+                       switch( pt0->pty ) {
                        case PTY_LINE:
                                vpen->draw_line(bx, by, cx, cy);
                                break;
                        case PTY_LINE:
                                vpen->draw_line(bx, by, cx, cy);
                                break;
@@ -514,28 +648,41 @@ void SketcherCurve::draw(VFrame *out)
                                vpen->draw_smooth(bx,by, sx,sy, cx,cy);
                                break; }
                        }
                                vpen->draw_smooth(bx,by, sx,sy, cx,cy);
                                break; }
                        }
-                       ax = bx;  ay = by;
-                       bx = cx;  by = cy;
-                       cx = dx;  cy = dy;
+                       ax = bx;  ay = by;  pt0 = pt1;
+                       bx = cx;  by = cy;  pt1 = pt2;
+                       cx = dx;  cy = dy;  pt2 = fill.next();
                }
                }
-               switch( points[n2]->pty ) {
+               switch( pt1->pty ) {
                case PTY_LINE:
                        vpen->draw_line(bx, by, cx, cy);
                case PTY_LINE:
                        vpen->draw_line(bx, by, cx, cy);
+                       if( fill.exists() ) {
+                               dx = pnt0->x;  dy = pnt0->y;
+                               vpen->draw_line(cx,cy, dx,dy);
+                       }
                        break;
                case PTY_CURVE: {
                        break;
                case PTY_CURVE: {
-                       smooth_dxy(dx,dy, ax,ay, bx,by, cx,cy);
+                       if( fill.exists() ) {
+                               dx = pnt0->x;  dy = pnt0->y;
+                               intersects_at(sx,sy, ax,ay,cx,cy,bx,by, bx,by,dx,dy,cx,cy,fmx);
+                               vpen->draw_smooth(bx,by, sx,sy, cx,cy);
+                               ax = bx;  ay = by;
+                               bx = cx;  by = cy;
+                               cx = dx;  cy = dy;
+                               dx = pnt1->x;  dy = pnt1->y;
+                       }
+                       else
+                               smooth_dxy(dx,dy, ax,ay, bx,by, cx,cy);
                        intersects_at(sx,sy, ax,ay,cx,cy,bx,by, bx,by,dx,dy,cx,cy,fmx);
                        vpen->draw_smooth(bx,by, sx,sy, cx,cy);
                        break; }
                }
                        intersects_at(sx,sy, ax,ay,cx,cy,bx,by, bx,by,dx,dy,cx,cy,fmx);
                        vpen->draw_smooth(bx,by, sx,sy, cx,cy);
                        break; }
                }
+               fill.run();
        }
        }
-       else if( n == 2 ) {
-               SketcherPoint *pt0 = points[0], *pt1 = points[1];
-               vpen->draw_line(pt0->x, pt0->y, pt1->x, pt1->y);
+       else if( pnt0 && pnt1 ) {
+               vpen->draw_line(pnt0->x, pnt0->y, pnt1->x, pnt1->y);
        }
        }
-       else if( n > 0 ) {
-               SketcherPoint *pt0 = points[0];
-               vpen->draw_pixel(pt0->x, pt0->y);
+       else if( pnt0 ) {
+               vpen->draw_pixel(pnt0->x, pnt0->y);
        }
        delete vpen;
 }
        }
        delete vpen;
 }
@@ -544,47 +691,90 @@ int Sketcher::process_realtime(VFrame *input, VFrame *output)
 {
        this->input = input;  this->output = output;
        w = output->get_w();  h = output->get_h();
 {
        this->input = input;  this->output = output;
        w = output->get_w();  h = output->get_h();
-       if( input != output ) output->transfer_from(input);
 
        load_configuration();
 
 
        load_configuration();
 
+       int out_color_model = output->get_color_model();
+       int color_model = out_color_model;
+       switch( color_model ) { // add alpha if needed
+       case BC_RGB888:         color_model = BC_RGBA8888;      break;
+       case BC_YUV888:         color_model = BC_YUVA8888;      break;
+       case BC_RGB161616:      color_model = BC_RGBA16161616;  break;
+       case BC_YUV161616:      color_model = BC_YUVA16161616;  break;
+       case BC_RGB_FLOAT:      color_model = BC_RGBA_FLOAT;    break;
+       case BC_RGB_FLOATP:     color_model = BC_RGBA_FLOATP;   break;
+       }
+       if( color_model == out_color_model ) {
+               delete out;  out = output;
+               if( output != input )
+                       output->transfer_from(input);
+       }
+       else {
+               VFrame::get_temp(out, w, h, color_model);
+               out->transfer_from(input);
+       }
+       VFrame::get_temp(img, w, h, color_model);
+       
+       if( !overlay_frame ) {
+               int cpus = server->preferences->project_smp;
+               int max = (w*h)/0x80000 + 2;
+               if( cpus > max ) cpus = max;
+               overlay_frame = new OverlayFrame(cpus);
+       }
+
        for( int ci=0, n=config.curves.size(); ci<n; ++ci ) {
                SketcherCurve *cv = config.curves[ci];
                int m = cv->points.size();
                if( !m || cv->pen == PTY_OFF ) continue;
        for( int ci=0, n=config.curves.size(); ci<n; ++ci ) {
                SketcherCurve *cv = config.curves[ci];
                int m = cv->points.size();
                if( !m || cv->pen == PTY_OFF ) continue;
-               cv->draw(output);
+               img->clear_frame();
+               img->set_pixel_color(cv->color);
+               cv->draw(img);
+               overlay_frame->overlay(out, img, 0,0,w,h, 0,0,w,h,
+                               1.f, TRANSFER_NORMAL, NEAREST_NEIGHBOR);
        }
 
        if( config.drag ) {
                for( int ci=0, n=config.curves.size(); ci<n; ++ci ) {
                        SketcherCurve *cv = config.curves[ci];
                        for( int pi=0,m=cv->points.size(); pi<m; ++pi ) {
        }
 
        if( config.drag ) {
                for( int ci=0, n=config.curves.size(); ci<n; ++ci ) {
                        SketcherCurve *cv = config.curves[ci];
                        for( int pi=0,m=cv->points.size(); pi<m; ++pi ) {
-                               int color = ci==config.cv_selected && pi==config.pt_selected ?
+                               int color = pi==config.pt_selected && ci==config.cv_selected ?
                                        RED : cv->color ; 
                                        RED : cv->color ; 
-                               draw_point(output, cv->points[pi], color);
+                               draw_point(out, cv->points[pi], color);
                        }
                }
        }
 
                        }
                }
        }
 
+       if( output != out )
+               output->transfer_from(out);
+       else
+               out = 0;
+
        return 0;
 }
 
        return 0;
 }
 
+void SketcherPoints::dump()
+{
+       for( int i=0; i<size(); ++i ) {
+               SketcherPoint *pt = get(i);
+               printf("  Pt %d, id=%d, pty=%s, x=%d, y=%d\n",
+                       i, pt->id, pt_type[pt->pty], pt->x, pt->y);
+       }
+}
 void SketcherCurves::dump()
 {
        for( int i=0; i<size(); ++i ) {
                SketcherCurve *cv = get(i);
 void SketcherCurves::dump()
 {
        for( int i=0; i<size(); ++i ) {
                SketcherCurve *cv = get(i);
-               printf("Curve %d, id=%d, pen=%s, r=%d, color=%02x%02x%02x\n",
+               printf("Curve %d, id=%d, pen=%s, r=%d, color=%02x%02x%02x, %d points\n",
                        i, cv->id, cv_pen[cv->pen], cv->radius,
                        i, cv->id, cv_pen[cv->pen], cv->radius,
-                       (cv->color>>16)&0xff, (cv->color>>8)&0xff, (cv->color>>0)&0xff);
+                       (cv->color>>16)&0xff, (cv->color>>8)&0xff, (cv->color>>0)&0xff,
+                       cv->points.size());
                cv->points.dump();
        }
 }
                cv->points.dump();
        }
 }
-void SketcherPoints::dump()
+void SketcherConfig::dump()
 {
 {
-       for( int i=0; i<size(); ++i ) {
-               SketcherPoint *pt = get(i);
-               printf("  Pt %d, id=%d, pty=%s, x=%d, y=%d\n",
-                       i, pt->id, pt_type[pt->pty], pt->x, pt->y);
-       }
+       printf("Config drag=%d, cv_selected=%d, pt_selected=%d %d curves\n",
+                       drag, cv_selected, pt_selected, curves.size());
+       curves.dump();
 }
 
 }
 
index be0f46b9f1e478289f3d001f183d96a48a59852f..443e8e9134abc8f25826566236a713233d7735a9 100644 (file)
@@ -24,6 +24,8 @@
 #define __SKETCHERS_H__
 
 #include "pluginvclient.h"
 #define __SKETCHERS_H__
 
 #include "pluginvclient.h"
+#include "overlayframe.inc"
+#include "vframe.h"
 
 class Sketcher;
 
 
 class Sketcher;
 
@@ -33,22 +35,28 @@ class Sketcher;
 
 enum { PT_ID, PT_TY, PT_X, PT_Y, PT_SZ };
 enum { CV_ID, CV_RAD, CV_PEN, CV_CLR, CV_SZ };
 
 enum { PT_ID, PT_TY, PT_X, PT_Y, PT_SZ };
 enum { CV_ID, CV_RAD, CV_PEN, CV_CLR, CV_SZ };
-enum { PTY_OFF, PTY_LINE, PTY_CURVE, PTY_SZ };
+enum { PTY_OFF, PTY_LINE, PTY_CURVE, PTY_FILL, PTY_SZ };
 enum { PEN_OFF, PEN_SQUARE, PEN_PLUS, PEN_SLANT, PEN_XLANT, PEN_SZ };
 
 class SketcherVPen : public VFrame
 {
 public:
 enum { PEN_OFF, PEN_SQUARE, PEN_PLUS, PEN_SLANT, PEN_XLANT, PEN_SZ };
 
 class SketcherVPen : public VFrame
 {
 public:
+       VFrame *vfrm;
+       int n;
+       uint8_t *msk;
+
        SketcherVPen(VFrame *vfrm, int n)
         : VFrame(vfrm->get_data(), -1, vfrm->get_y()-vfrm->get_data(),
            vfrm->get_u()-vfrm->get_data(), vfrm->get_v()-vfrm->get_data(),
            vfrm->get_w(), vfrm->get_h(), vfrm->get_color_model(),
            vfrm->get_bytes_per_line()) {
                this->vfrm = vfrm;  this->n = n;
        SketcherVPen(VFrame *vfrm, int n)
         : VFrame(vfrm->get_data(), -1, vfrm->get_y()-vfrm->get_data(),
            vfrm->get_u()-vfrm->get_data(), vfrm->get_v()-vfrm->get_data(),
            vfrm->get_w(), vfrm->get_h(), vfrm->get_color_model(),
            vfrm->get_bytes_per_line()) {
                this->vfrm = vfrm;  this->n = n;
+               int sz = vfrm->get_w()*vfrm->get_h();
+               this->msk = (uint8_t*)memset(new uint8_t[sz],0,sz);
        }
        }
+       ~SketcherVPen() { delete [] msk; }
+
        virtual int draw_pixel(int x, int y) = 0;
        virtual int draw_pixel(int x, int y) = 0;
-       VFrame *vfrm;
-       int n;
 };
 
 class SketcherPenSquare : public SketcherVPen
 };
 
 class SketcherPenSquare : public SketcherVPen
@@ -120,8 +128,10 @@ public:
        void copy_from(SketcherCurve &that);
        void save_data(FileXML &output);
        void read_data(FileXML &input);
        void copy_from(SketcherCurve &that);
        void save_data(FileXML &output);
        void read_data(FileXML &input);
-       VFrame *new_vpen(VFrame *out);
-       void draw(VFrame *out);
+       double nearest_point(int &pi, float x, float y);
+
+       SketcherVPen *new_vpen(VFrame *out);
+       void draw(VFrame *img);
 };
 class SketcherCurves : public ArrayList<SketcherCurve *>
 {
 };
 class SketcherCurves : public ArrayList<SketcherCurve *>
 {
@@ -142,7 +152,9 @@ public:
        void copy_from(SketcherConfig &that);
        void interpolate(SketcherConfig &prev, SketcherConfig &next,
                long prev_frame, long next_frame, long current_frame);
        void copy_from(SketcherConfig &that);
        void interpolate(SketcherConfig &prev, SketcherConfig &next,
                long prev_frame, long next_frame, long current_frame);
+       double nearest_point(int &ci, int &pi, float x, float y);
        void limits();
        void limits();
+       void dump();
 
        int drag;
        int cv_selected, pt_selected;
 
        int drag;
        int cv_selected, pt_selected;
@@ -167,6 +179,8 @@ public:
        void draw_point(VFrame *vfrm, SketcherPoint *pt, int color);
 
        VFrame *input, *output;
        void draw_point(VFrame *vfrm, SketcherPoint *pt, int color);
 
        VFrame *input, *output;
+       VFrame *img, *out;
+       OverlayFrame *overlay_frame;
        int w, h, color_model, bpp, comp;
        int is_yuv, is_float;
 };
        int w, h, color_model, bpp, comp;
        int is_yuv, is_float;
 };
index 2f984cddb372a9519a51a5427a0a56d12bcb7227..fc2ca4fcc7729ac25f5a1ad750340f7c23b774b7 100644 (file)
@@ -46,6 +46,7 @@ const char *SketcherPoint::types[] = {
        N_("off"),
        N_("line"),
        N_("curve"),
        N_("off"),
        N_("line"),
        N_("curve"),
+       N_("fill"),
 };
 const char *SketcherCurve::pens[] = {
        N_("off"),
 };
 const char *SketcherCurve::pens[] = {
        N_("off"),
@@ -159,7 +160,7 @@ int SketcherCurveColor::handle_event()
 }
 
 SketcherCurveColorPicker::SketcherCurveColorPicker(SketcherWindow *gui, SketcherCurveColor *color_button)
 }
 
 SketcherCurveColorPicker::SketcherCurveColorPicker(SketcherWindow *gui, SketcherCurveColor *color_button)
- : ColorPicker(0, _("Color"))
+ : ColorPicker(1, _("Color"))
 {
        this->gui = gui;
        this->color_button = color_button;
 {
        this->gui = gui;
        this->color_button = color_button;
@@ -174,7 +175,7 @@ SketcherCurveColorPicker::~SketcherCurveColorPicker()
 
 void SketcherCurveColorPicker::start(int color)
 {
 
 void SketcherCurveColorPicker::start(int color)
 {
-       start_window(color, 0, 1);
+       start_window(color & 0xffffff, ((~color>>24)&0xff), 1);
        color_update->start();
 }
 
        color_update->start();
 }
 
@@ -197,7 +198,7 @@ void SketcherCurveColorPicker::handle_done_event(int result)
 
 int SketcherCurveColorPicker::handle_new_color(int color, int alpha)
 {
 
 int SketcherCurveColorPicker::handle_new_color(int color, int alpha)
 {
-       this->color = color;
+       this->color = color | (~alpha<<24);
        color_update->update_lock->unlock();
        return 1;
 }
        color_update->update_lock->unlock();
        return 1;
 }
@@ -485,14 +486,14 @@ void SketcherWindow::create_objects()
                   "new line point\n"
                   "select point\n"
                   "drag point\n"
                   "new line point\n"
                   "select point\n"
                   "drag point\n"
-                  "new curve\n"
+                  "drag all curves\n"
                   "deletes point\n")));
        add_subwindow(notes2 = new BC_Title(x+200, y,
                 _("      RMB\n"
                   "new arc point\n"
                   "select curve\n"
                   "drag curve\n"
                   "deletes point\n")));
        add_subwindow(notes2 = new BC_Title(x+200, y,
                 _("      RMB\n"
                   "new arc point\n"
                   "select curve\n"
                   "drag curve\n"
-                  "drag all curves\n"
+                  "new curve\n"
                   "deletes curve\n")));
        show_window(1);
 }
                   "deletes curve\n")));
        show_window(1);
 }
@@ -550,6 +551,8 @@ int SketcherWindow::do_grab_event(XEvent *event)
                dragging = 1;
                break;
        case ButtonRelease:
                dragging = 1;
                break;
        case ButtonRelease:
+               dragging = 0;
+               break;
        case MotionNotify:
                if( !dragging ) return 0;
                break;
        case MotionNotify:
                if( !dragging ) return 0;
                break;
@@ -561,8 +564,10 @@ int SketcherWindow::do_grab_event(XEvent *event)
        int ci = config.cv_selected;
        if( ci < 0 || ci >= plugin->config.curves.size() )
                return 1;
        int ci = config.cv_selected;
        if( ci < 0 || ci >= plugin->config.curves.size() )
                return 1;
+
        SketcherCurves &curves = config.curves;
        SketcherCurve *cv = curves[ci];
        SketcherCurves &curves = config.curves;
        SketcherCurve *cv = curves[ci];
+       SketcherPoints &points = cv->points;
        int pi = config.pt_selected;
 
        float cursor_x = cx, cursor_y = cy;
        int pi = config.pt_selected;
 
        float cursor_x = cx, cursor_y = cy;
@@ -578,7 +583,6 @@ int SketcherWindow::do_grab_event(XEvent *event)
        projector_y += mwindow->edl->session->output_h / 2;
        float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
        float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
        projector_y += mwindow->edl->session->output_h / 2;
        float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
        float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
-       SketcherPoints &points = cv->points;
        int state = event->xmotion.state;
 
        switch( event->type ) {
        int state = event->xmotion.state;
 
        switch( event->type ) {
@@ -592,29 +596,16 @@ int SketcherWindow::do_grab_event(XEvent *event)
                                point_list->update(pi);
                                break;
                        }
                                point_list->update(pi);
                                break;
                        }
-                       if( (state & AltMask) ) { // create new curve
-                               ci = plugin->new_curve(cv->pen, cv->radius, cv->color);
-                               curve_list->update(ci);
-                               point_list->update(-1);
-                               break;
-                       }
                        SketcherPoint *pt = 0; // select point
                        SketcherPoint *pt = 0; // select point
-                       int last_point = pi;  pi = -1;
-                       int n = points.size();
-                       double dist = DBL_MAX;
-                       for( int i=0; i<n; ++i ) {
-                               SketcherPoint *p = points[i];
-                               double d = DISTANCE(output_x,output_y, p->x,p->y);
-                               if( d < dist ) { dist = d;  pi = i;  pt = p; }
-                       }
-                       if( pt ) {
+                       double dist = cv->nearest_point(pi, output_x,output_y);
+                       if( dist >= 0 ) {
+                               pt = points[pi];
                                float px = (pt->x - track_w / 2) * projector_z + projector_x;
                                float py = (pt->y - track_h / 2) * projector_z + projector_y;
                                float pix = DISTANCE(px, py, cursor_x,cursor_y);
                                float px = (pt->x - track_w / 2) * projector_z + projector_x;
                                float py = (pt->y - track_h / 2) * projector_z + projector_y;
                                float pix = DISTANCE(px, py, cursor_x,cursor_y);
-                               if( pix >= HANDLE_W ) { pi = -1;  pt = 0; }
+                               if( (state & ControlMask) && pix >= HANDLE_W ) { pi = -1;  pt = 0; }
                        }
                        }
-                       if( pi != last_point )
-                               point_list->set_selected(pi);
+                       point_list->set_selected(pi);
                        break; }
                case RIGHT_BUTTON: {
                        if( (state & ShiftMask) ) { // create new curve point
                        break; }
                case RIGHT_BUTTON: {
                        if( (state & ShiftMask) ) { // create new curve point
@@ -624,29 +615,22 @@ int SketcherWindow::do_grab_event(XEvent *event)
                                point_list->update(pi);
                                break;
                        }
                                point_list->update(pi);
                                break;
                        }
-                       SketcherPoint *pt = 0; // select point
-                       double dist = DBL_MAX;
-                       ci = -1;
-                       for( int i=0; i<curves.size(); ++i ) {
-                               SketcherCurve *crv = curves[i];
-                               int pts = crv->points.size();
-                               for( int k=0; k<pts; ++k ) {
-                                       SketcherPoint *p = crv->points[k];
-                                       double d = DISTANCE(output_x,output_y, p->x,p->y);
-                                       if( d < dist ) {
-                                               dist = d;
-                                               pt = p;    pi = k;
-                                               cv = crv;  ci = i;
-                                       }
-                               }
+                       if( (state & AltMask) ) { // create new curve
+                               ci = plugin->new_curve(cv->pen, cv->radius, cv->color);
+                               curve_list->update(ci);
+                               point_list->update(-1);
+                               break;
                        }
                        }
-                       if( pt ) {
+                       SketcherPoint *pt = 0;
+                       double dist = config.nearest_point(ci, pi, output_x,output_y);
+                       if( dist >= 0 ) {
+                               pt = curves[ci]->points[pi];
                                float px = (pt->x - track_w / 2) * projector_z + projector_x;
                                float py = (pt->y - track_h / 2) * projector_z + projector_y;
                                float pix = DISTANCE(px, py, cursor_x,cursor_y);
                                float px = (pt->x - track_w / 2) * projector_z + projector_x;
                                float py = (pt->y - track_h / 2) * projector_z + projector_y;
                                float pix = DISTANCE(px, py, cursor_x,cursor_y);
-                               if( pix >= HANDLE_W ) { pi = -1;  pt = 0; }
+                               if( (state & ControlMask) && pix >= HANDLE_W ) { ci = pi = -1;  pt = 0; }
                        }
                        }
-                       if( pi >= 0 ) {
+                       if( pt ) {
                                curve_list->update(ci);
                                point_list->update(pi);
                        }
                                curve_list->update(ci);
                                point_list->update(pi);
                        }
@@ -655,23 +639,22 @@ int SketcherWindow::do_grab_event(XEvent *event)
                break; }
        case MotionNotify: {
                if( (state & ShiftMask) ) {  // string of points
                break; }
        case MotionNotify: {
                if( (state & ShiftMask) ) {  // string of points
-                   if( (state & (Button1Mask|Button3Mask)) ) {
-                               if( pi < 0 ) pi = points.size()-1;
-                               if( pi >= 0 ) {
-                                       SketcherPoint *pt = pi >= 0 && pi < points.size() ?  points[pi] : 0;
-                                       float frac_w = DISTANCE(pt->x, pt->y, output_x, output_y) / get_w();
-                                       if( frac_w < 0.01 ) break; // 1 percent w
+                       if( (state & (Button1Mask|Button3Mask)) ) {
+                               SketcherPoint *pt = pi >= 0 && pi < points.size() ? points[pi] : 0;
+                               if( pt ) {
+                                       float dist = DISTANCE(pt->x, pt->y, output_x, output_y);
+                                       if( dist < get_w()*0.1 ) break; // tolerance w/10
                                }
                                ++new_points;
                                int pty = (state & Button1Mask) ? PTY_LINE : PTY_CURVE;
                                pi = plugin->new_point(cv, pty, output_x, output_y, pi+1);
                                point_list->update(pi);
                                }
                                ++new_points;
                                int pty = (state & Button1Mask) ? PTY_LINE : PTY_CURVE;
                                pi = plugin->new_point(cv, pty, output_x, output_y, pi+1);
                                point_list->update(pi);
-                               break;
                        }
                        }
+                       break;
                }
                if( (state & Button1Mask) ) {
                        if( (state & ControlMask) ) { // drag selected point
                }
                if( (state & Button1Mask) ) {
                        if( (state & ControlMask) ) { // drag selected point
-                               SketcherPoint *pt = pi >= 0 && pi < points.size() ?  points[pi] : 0;
+                               SketcherPoint *pt = pi >= 0 && pi < points.size() ? points[pi] : 0;
                                if( pt ) {
                                        point_list->set_point(pi, PT_X, pt->x = output_x);
                                        point_list->set_point(pi, PT_Y, pt->y = output_y);
                                if( pt ) {
                                        point_list->set_point(pi, PT_X, pt->x = output_x);
                                        point_list->set_point(pi, PT_Y, pt->y = output_y);
@@ -681,15 +664,10 @@ int SketcherWindow::do_grab_event(XEvent *event)
                                }
                                break;
                        }
                                }
                                break;
                        }
-               }
-               if( (state & Button3Mask) ) {
-                       if( (state & (ControlMask | AltMask)) ) { // drag selected curve(s)
-                               SketcherCurves &curves = plugin->config.curves;
+                       if( (state & AltMask) ) { // drag all curves
                                int dx = round(output_x - last_x);
                                int dy = round(output_y - last_y);
                                int dx = round(output_x - last_x);
                                int dy = round(output_y - last_y);
-                               int mnc = (state & AltMask) || ci<0 ? 0 : ci;
-                               int mxc = (state & AltMask) ? curves.size() : ci+1;
-                               for( int i=mnc; i<mxc; ++i ) {
+                               for( int i=0; i<curves.size(); ++i ) {
                                        SketcherCurve *crv = plugin->config.curves[i];
                                        int pts = crv->points.size();
                                        for( int k=0; k<pts; ++k ) {
                                        SketcherCurve *crv = plugin->config.curves[i];
                                        int pts = crv->points.size();
                                        for( int k=0; k<pts; ++k ) {
@@ -704,11 +682,36 @@ int SketcherWindow::do_grab_event(XEvent *event)
                                point_list->update(pi);
                                break;
                        }
                                point_list->update(pi);
                                break;
                        }
+                       double dist = cv->nearest_point(pi, output_x,output_y);
+                       if( dist >= 0 )
+                               point_list->set_selected(pi);
+                       break;
+               }
+               if( (state & Button3Mask) ) {
+                       if( (state & (ControlMask | AltMask)) ) { // drag selected curve(s)
+                               int dx = round(output_x - last_x);
+                               int dy = round(output_y - last_y);
+                               for( int i=0; i<points.size(); ++i ) {
+                                       SketcherPoint *pt = points[i];
+                                       pt->x += dx;  pt->y += dy;
+                               }
+                               SketcherPoint *pt = pi >= 0 && pi < points.size() ?
+                                       points[pi] : 0;
+                               point_x->update(pt ? pt->x : 0.f);
+                               point_y->update(pt ? pt->y : 0.f);
+                               point_list->update(pi);
+                               break;
+                       }
+                       double dist = config.nearest_point(ci, pi, output_x,output_y);
+                       if( dist >= 0 ) {
+                               curve_list->update(ci);
+                               point_list->update(pi);
+                       }
+                       break;
                }
                break; }
        case ButtonRelease: {
                new_points = 0;
                }
                break; }
        case ButtonRelease: {
                new_points = 0;
-               dragging = 0;
                break; }
        }
 
                break; }
        }