From 7ead9f7382846e81c2f8efb25780014e5f8834c3 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Mon, 27 May 2019 13:33:38 -0600 Subject: [PATCH] opengl upgrade to 4.3 for masks, mask function/layout rework, make_shader rework --- cinelerra-5.1/cinelerra/cwindowgui.C | 120 ++-- cinelerra-5.1/cinelerra/cwindowtool.C | 224 ++++--- cinelerra-5.1/cinelerra/cwindowtool.h | 85 ++- cinelerra-5.1/cinelerra/cwindowtool.inc | 11 +- cinelerra-5.1/cinelerra/dcraw.C | 2 +- cinelerra-5.1/cinelerra/edl.h | 2 +- cinelerra-5.1/cinelerra/maskauto.C | 197 ++---- cinelerra-5.1/cinelerra/maskauto.h | 54 +- cinelerra-5.1/cinelerra/maskauto.inc | 2 +- cinelerra-5.1/cinelerra/maskautos.C | 36 +- cinelerra-5.1/cinelerra/maskautos.h | 4 +- cinelerra-5.1/cinelerra/maskengine.C | 779 +++++++++--------------- cinelerra-5.1/cinelerra/maskengine.h | 43 +- cinelerra-5.1/cinelerra/playback3d.C | 557 +++++++++-------- cinelerra-5.1/cinelerra/playback3d.h | 12 +- cinelerra-5.1/cinelerra/virtualvnode.C | 4 +- cinelerra-5.1/guicast/bcsynchronous.C | 77 ++- cinelerra-5.1/guicast/bcsynchronous.h | 15 +- cinelerra-5.1/guicast/bctexture.C | 22 +- cinelerra-5.1/guicast/bctexture.h | 1 + cinelerra-5.1/guicast/bcwindow3d.C | 8 +- cinelerra-5.1/guicast/bcwindowbase.C | 4 + cinelerra-5.1/guicast/bcwindowbase.h | 7 +- cinelerra-5.1/guicast/vframe3d.C | 185 +++--- 24 files changed, 1201 insertions(+), 1250 deletions(-) diff --git a/cinelerra-5.1/cinelerra/cwindowgui.C b/cinelerra-5.1/cinelerra/cwindowgui.C index 701362e0..3e9bf9ec 100644 --- a/cinelerra-5.1/cinelerra/cwindowgui.C +++ b/cinelerra-5.1/cinelerra/cwindowgui.C @@ -1491,11 +1491,17 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, if(!track) return 0; //printf("CWindowCanvas::do_mask 3\n"); - + CWindowMaskGUI *mask_gui = (CWindowMaskGUI *) + (gui->tool_panel ? gui->tool_panel->tool_gui : 0); + int draw_markers = mask_gui ? mask_gui->markers : 0; + int draw_boundary = mask_gui ? mask_gui->boundary : 0; MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK]; int64_t position = track->to_units( mwindow->edl->local_session->get_selectionstart(1), 0); + Auto *prev_auto = 0; + mask_autos->get_prev_auto(position, PLAY_FORWARD, (Auto *&)prev_auto, 1); + MaskAuto *prev_mask = (MaskAuto *)prev_auto; ArrayList points; // Determine the points based on whether @@ -1503,19 +1509,16 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, // If keyframe generation occurs, use the interpolated mask. // If no keyframe generation occurs, use the previous mask. int use_interpolated = 0; - if(button_press || cursor_motion) { + if( button_press || cursor_motion ) { #ifdef USE_KEYFRAME_SPANNING double selection_start = mwindow->edl->local_session->get_selectionstart(0); double selection_end = mwindow->edl->local_session->get_selectionend(0); - - Auto *first = 0; - mask_autos->get_prev_auto(track->to_units(selection_start, 0), - PLAY_FORWARD, first, 1); - Auto *last = 0; - mask_autos->get_prev_auto(track->to_units(selection_end, 0), - PLAY_FORWARD, last, 1); - - if(last == first && (!mwindow->edl->session->auto_keyframes)) + int64_t start_pos = track->to_units(selection_start, 0); + int64_t end_pos = track->to_units(selection_end, 0); + Auto *first = 0, *last = 0; + mask_autos->get_prev_auto(start_pos, PLAY_FORWARD, first, 1); + mask_autos->get_prev_auto(end_pos, PLAY_FORWARD, last, 1); + if( last == first && (!mwindow->edl->session->auto_keyframes) ) use_interpolated = 0; else // If keyframe spanning occurs, use the interpolated points. @@ -1523,28 +1526,22 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, use_interpolated = 1; #else - if(mwindow->edl->session->auto_keyframes) + if( mwindow->edl->session->auto_keyframes ) use_interpolated = 1; #endif } else use_interpolated = 1; - if(use_interpolated) { + if( use_interpolated ) { // Interpolate the points to get exactly what is being rendered at this position. mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask, - position, - PLAY_FORWARD); + position, PLAY_FORWARD); } else { // Use the prev mask - Auto *prev = 0; - mask_autos->get_prev_auto(position, - PLAY_FORWARD, - prev, - 1); - ((MaskAuto*)prev)->get_points(&points, + prev_mask->get_points(&points, mwindow->edl->session->cwindow_mask); } @@ -1718,15 +1715,15 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y); - if(j > 0) { + if( j > 0 ) { - if(draw) { // Draw joining line + if( draw ) { // Draw joining line x_points.append((int)canvas_x); y_points.append((int)canvas_y); } - if(j == segments) { - if(draw) { // Draw second anchor + if( j == segments ) { + if( draw && draw_markers ) { // Draw second anchor if(i < points.size() - 1) { if(i == gui->affected_point - 1) get_canvas()->draw_disc( @@ -1756,23 +1753,30 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } else { // Draw first anchor - if(i == 0 && draw) { - char mask_label[BCSTRLEN]; - sprintf(mask_label, "%d", - mwindow->edl->session->cwindow_mask); - get_canvas()->draw_text( - (int)canvas_x - FIRST_CONTROL_W, - (int)canvas_y - FIRST_CONTROL_H, - mask_label); - - get_canvas()->draw_disc( - (int)canvas_x - FIRST_CONTROL_W / 2, - (int)canvas_y - FIRST_CONTROL_H / 2, - FIRST_CONTROL_W, FIRST_CONTROL_H); + if( i == 0 && draw ) { + if( draw_boundary ) { + char mask_label[BCSTRLEN]; + int k = mwindow->edl->session->cwindow_mask; + if( !prev_mask || prev_mask->is_default || + k < 0 || k >= prev_mask->masks.size() ) + sprintf(mask_label, "%d", k); + else + sprintf(mask_label, "%s", prev_mask->masks[k]->name); + get_canvas()->draw_text( + (int)canvas_x - FIRST_CONTROL_W, + (int)canvas_y - FIRST_CONTROL_H, + mask_label); + } + if( draw_markers ) { + get_canvas()->draw_disc( + (int)canvas_x - FIRST_CONTROL_W / 2, + (int)canvas_y - FIRST_CONTROL_H / 2, + FIRST_CONTROL_W, FIRST_CONTROL_H); + } } // Draw first control point. - if(draw) { + if( draw && draw_markers ) { output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1); get_canvas()->draw_line( (int)canvas_x, (int)canvas_y, @@ -1793,25 +1797,22 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, //printf("CWindowCanvas::do_mask 1\n"); BC_WindowBase *cvs_win = get_canvas(); - if(draw) { + if( draw && draw_boundary ) { cvs_win->draw_polygon(&x_points, &y_points); cvs_win->set_opaque(); } - if( draw && gui->tool_panel ) { - CWindowMaskGUI *mask_gui = (CWindowMaskGUI*)gui->tool_panel->tool_gui; - if( mask_gui && mask_gui->focused ) { - float fx = atof(mask_gui->focus_x->get_text()); - float fy = atof(mask_gui->focus_y->get_text()); - output_to_canvas(mwindow->edl, 0, fx, fy); - float r = bmax(cvs_win->get_w(), cvs_win->get_h()); - float d = 0.005*r; - cvs_win->set_line_width((int)(0.0025*r) + 1); - cvs_win->set_color(BLUE); - cvs_win->draw_line(fx-d,fy-d, fx+d, fy+d); - cvs_win->draw_line(fx-d,fy+d, fx+d, fy-d); - cvs_win->set_line_width(0); - cvs_win->set_color(WHITE); - } + if( draw && mask_gui && mask_gui->focused ) { + float fx = atof(mask_gui->focus_x->get_text()); + float fy = atof(mask_gui->focus_y->get_text()); + output_to_canvas(mwindow->edl, 0, fx, fy); + float r = bmax(cvs_win->get_w(), cvs_win->get_h()); + float d = 0.005*r; + cvs_win->set_line_width((int)(0.0025*r) + 1); + cvs_win->set_color(BLUE); + cvs_win->draw_line(fx-d,fy-d, fx+d, fy+d); + cvs_win->draw_line(fx-d,fy+d, fx+d, fy-d); + cvs_win->set_line_width(0); + cvs_win->set_color(WHITE); } //printf("CWindowCanvas::do_mask 1\n"); } @@ -2103,12 +2104,9 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, float st = sin(theta), ct = cos(theta); gui->x_origin = mask_cursor_x; gui->y_origin = mask_cursor_y; - if( gui->tool_panel ) { - CWindowMaskGUI *mask_gui = (CWindowMaskGUI*)gui->tool_panel->tool_gui; - if( mask_gui && mask_gui->focused ) { - gui->x_origin = atof(mask_gui->focus_x->get_text()); - gui->y_origin = atof(mask_gui->focus_y->get_text()); - } + if( mask_gui && mask_gui->focused ) { + gui->x_origin = atof(mask_gui->focus_x->get_text()); + gui->y_origin = atof(mask_gui->focus_y->get_text()); } for( int i=0; imarkers, _("Markers")) +{ + this->mwindow = mwindow; + this->gui = gui; +} + +CWindowMaskDrawMarkers::~CWindowMaskDrawMarkers() +{ +} + +int CWindowMaskDrawMarkers::handle_event() +{ + ((CWindowMaskGUI*)gui)->markers = get_value(); + gui->update(); + gui->update_preview(); + return 1; +} + +CWindowMaskDrawBoundary::CWindowMaskDrawBoundary(MWindow *mwindow, CWindowToolGUI *gui, int x, int y) + : BC_CheckBox(x, y, ((CWindowMaskGUI*)gui)->boundary, _("Boundary")) +{ + this->mwindow = mwindow; + this->gui = gui; +} + +CWindowMaskDrawBoundary::~CWindowMaskDrawBoundary() +{ +} + +int CWindowMaskDrawBoundary::handle_event() +{ + ((CWindowMaskGUI*)gui)->boundary = get_value(); + gui->update(); + gui->update_preview(); + return 1; +} + + CWindowMaskFeather::CWindowMaskFeather(MWindow *mwindow, CWindowToolGUI *gui, int x, int y) - : BC_TumbleTextBox(gui, 0, 0, 0xff, x, y, 64, 2) + : BC_TumbleTextBox(gui, 0, -FEATHER_MAX, FEATHER_MAX, x, y, 64, 2) { this->mwindow = mwindow; this->gui = gui; @@ -1775,16 +1814,23 @@ int CWindowMaskFeather::update_value(float v) ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, create_it); if( track ) { + int gang = ((CWindowMaskGUI*)gui)->gang_feather->get_value(); #ifdef USE_KEYFRAME_SPANNING -// Create temp keyframe MaskAuto temp_keyframe(mwindow->edl, autos); temp_keyframe.copy_data(keyframe); -// Update parameter - temp_keyframe.feather = v; -// Commit change to span of keyframes - autos->update_parameter(&temp_keyframe); -#else - keyframe->feather = v; + keyframe = &temp_keyframe; +#endif + float change = v - mask->feather; + int k = mwindow->edl->session->cwindow_mask; + int n = gang ? keyframe->masks.size() : k+1; + for( int i=gang? 0 : k; iget_submask(i); + float feather = sub_mask->feather + change; + bclamp(feather, -FEATHER_MAX, FEATHER_MAX); + sub_mask->feather = feather; + } +#ifdef USE_KEYFRAME_SPANNING + autos->update_parameter(keyframe); #endif gui->update_preview(); } @@ -1803,22 +1849,44 @@ int CWindowMaskFeather::handle_event() CWindowMaskFeatherSlider::CWindowMaskFeatherSlider(MWindow *mwindow, CWindowToolGUI *gui, int x, int y, int w, float v) - : BC_FSlider(x, y, 0, w, w, 0.f, 255.f, v) + : BC_FSlider(x, y, 0, w, w, -FEATHER_MAX, FEATHER_MAX, v) { this->mwindow = mwindow; this->gui = gui; set_precision(0.01); + timer = new Timer(); + stick = 0; + last_v = 0; } CWindowMaskFeatherSlider::~CWindowMaskFeatherSlider() { + delete timer; } int CWindowMaskFeatherSlider::handle_event() { float v = get_value(); + if( stick > 0 ) { + int64_t ms = timer->get_difference(); + if( ms < 250 && --stick > 0 ) { + if( get_value() == 0 ) return 1; + update(v = 0); + } + else { + stick = 0; + last_v = v; + } + } + else if( (last_v>=0 && v<0) || (last_v<0 && v>=0) ) { + stick = 16; + v = 0; + } + else + last_v = v; + timer->update(); CWindowMaskGUI * mask_gui = (CWindowMaskGUI*)gui; - mask_gui->feather->update(v); + mask_gui->feather->BC_TumbleTextBox::update(v); return mask_gui->feather->update_value(v); } @@ -1863,18 +1931,24 @@ int CWindowMaskFade::update_value(float v) ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, create_it); if( track ) { + int gang = ((CWindowMaskGUI*)gui)->gang_fader->get_value(); #ifdef USE_KEYFRAME_SPANNING -// Create temp keyframe MaskAuto temp_keyframe(mwindow->edl, autos); temp_keyframe.copy_data(keyframe); -// Update parameter - temp_keyframe.value = v; -// Commit change to span of keyframes - autos->update_parameter(&temp_keyframe); -#else - keyframe->value = v; + keyframe = &temp_keyframe; +#endif + float change = v - mask->fader; + int k = mwindow->edl->session->cwindow_mask; + int n = gang ? keyframe->masks.size() : k+1; + for( int i=gang? 0 : k; iget_submask(i); + float fader = sub_mask->fader + change; + bclamp(fader, -100.f, 100.f); + sub_mask->fader = fader; + } +#ifdef USE_KEYFRAME_SPANNING + autos->update_parameter(keyframe); #endif - gui->update_preview(); } @@ -1898,6 +1972,7 @@ CWindowMaskFadeSlider::CWindowMaskFadeSlider(MWindow *mwindow, CWindowToolGUI *g this->gui = gui; timer = new Timer(); stick = 0; + last_v = 0; } CWindowMaskFadeSlider::~CWindowMaskFadeSlider() @@ -1908,18 +1983,23 @@ CWindowMaskFadeSlider::~CWindowMaskFadeSlider() int CWindowMaskFadeSlider::handle_event() { float v = 100*get_value()/200; - if( !v && !stick ) - stick = 16; - else if( stick > 0 ) { + if( stick > 0 ) { int64_t ms = timer->get_difference(); - if( ms < 1000 ) { - --stick; + if( ms < 250 && --stick > 0 ) { if( get_value() == 0 ) return 1; update(v = 0); } - else + else { stick = 0; + last_v = v; + } + } + else if( (last_v>=0 && v<0) || (last_v<0 && v>=0) ) { + stick = 16; + v = 0; } + else + last_v = v; timer->update(); CWindowMaskGUI *mask_gui = (CWindowMaskGUI*)gui; mask_gui->fade->BC_TumbleTextBox::update(v); @@ -1931,46 +2011,21 @@ int CWindowMaskFadeSlider::update(int64_t v) return BC_ISlider::update(200*v/100); } -CWindowMaskMode::CWindowMaskMode(MWindow *mwindow, - CWindowToolGUI *gui, int x, int y) - : BC_Toggle(x, y, mwindow->theme->mask_mode_toggle, 0) +CWindowMaskGangFader::CWindowMaskGangFader(MWindow *mwindow, + CWindowToolGUI *gui, int x, int y) + : BC_Toggle(x, y, mwindow->theme->get_image_set("gangpatch_data"), 0) { - this->mwindow = mwindow; - this->gui = gui; - set_tooltip(_("Subtract/Multiply Alpha")); + this->mwindow = mwindow; + this->gui = gui; + set_tooltip(_("Gang fader")); } -CWindowMaskMode::~CWindowMaskMode() +CWindowMaskGangFader::~CWindowMaskGangFader() { } -int CWindowMaskMode::handle_event() +int CWindowMaskGangFader::handle_event() { - MaskAutos *autos; - MaskAuto *keyframe; - Track *track; - MaskPoint *point; - SubMask *mask; -// Get existing keyframe - ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, 0); - if( track ) { - mwindow->undo->update_undo_before(_("mask mode"), 0); -#ifdef USE_KEYFRAME_SPANNING -// Create temp keyframe - MaskAuto temp_keyframe(mwindow->edl, autos); - temp_keyframe.copy_data(keyframe); -// Update parameter - temp_keyframe.mode = get_value(); -// Commit change to span of keyframes - autos->update_parameter(&temp_keyframe); -#else - ((MaskAuto*)autos->default_auto)->mode = get_value(); -#endif - mwindow->undo->update_undo_after(_("mask mode"), LOAD_AUTOMATION); - } - -//printf("CWindowMaskMode::handle_event 1\n"); - gui->update_preview(); return 1; } @@ -2080,28 +2135,24 @@ int CWindowMaskClrMask::handle_event() return 1; } -CWindowMaskClrFeather::CWindowMaskClrFeather(MWindow *mwindow, - CWindowMaskGUI *gui, int x, int y) - : BC_Button(x, y, mwindow->theme->get_image_set("reset_button")) +CWindowMaskGangFeather::CWindowMaskGangFeather(MWindow *mwindow, + CWindowToolGUI *gui, int x, int y) + : BC_Toggle(x, y, mwindow->theme->get_image_set("gangpatch_data"), 0) { - this->mwindow = mwindow; - this->gui = gui; - set_tooltip(_("Zero Feather")); + this->mwindow = mwindow; + this->gui = gui; + set_tooltip(_("Gang feather")); } -CWindowMaskClrFeather::~CWindowMaskClrFeather() + +CWindowMaskGangFeather::~CWindowMaskGangFeather() { } -int CWindowMaskClrFeather::handle_event() +int CWindowMaskGangFeather::handle_event() { - float v = 0; - CWindowMaskGUI * mask_gui = (CWindowMaskGUI*)gui; - mask_gui->feather->update(v); - mask_gui->feather_slider->update(v); - return mask_gui->feather->update_value(v); + return 1; } - CWindowMaskGUI::CWindowMaskGUI(MWindow *mwindow, CWindowTool *thread) : CWindowToolGUI(mwindow, thread, _(PROGRAM_NAME ": Mask"), 360, 440) @@ -2112,6 +2163,8 @@ CWindowMaskGUI::CWindowMaskGUI(MWindow *mwindow, CWindowTool *thread) fade = 0; feather = 0; focused = 0; + markers = 1; + boundary = 1; } CWindowMaskGUI::~CWindowMaskGUI() { @@ -2147,16 +2200,15 @@ void CWindowMaskGUI::create_objects() int x2 = x1 + fade->get_w() + 2*margin; int w2 = clr_x-2*margin - x2; add_subwindow(fade_slider = new CWindowMaskFadeSlider(mwindow, this, x2, y, w2)); - add_subwindow(mode = new CWindowMaskMode(mwindow, this, clr_x, y)); + add_subwindow(gang_fader = new CWindowMaskGangFader(mwindow, this, clr_x, y)); y += fade->get_h() + margin; add_subwindow(title = new BC_Title(x, y, _("Feather:"))); feather = new CWindowMaskFeather(mwindow, this, x1, y); feather->create_objects(); - x2 = x1 + feather->get_w() + margin; w2 = clr_x - 2*margin - x2; feather_slider = new CWindowMaskFeatherSlider(mwindow, this, x2, y, w2, 0); add_subwindow(feather_slider); - add_subwindow(new CWindowMaskClrFeather(mwindow, this, clr_x, y)); + add_subwindow(gang_feather = new CWindowMaskGangFeather(mwindow, this, clr_x, y)); y += feather->get_h() + 3*margin; add_subwindow(title = new BC_Title(x, y, _("Point:"))); @@ -2167,10 +2219,12 @@ void CWindowMaskGUI::create_objects() add_subwindow(title = new BC_Title(x, y, "X:")); this->x = new CWindowCoord(this, x1, y, (float)0.0); this->x->create_objects(); + add_subwindow(draw_markers = new CWindowMaskDrawMarkers(mwindow, this, del_x, y)); y += this->x->get_h() + margin; add_subwindow(title = new BC_Title(x, y, "Y:")); this->y = new CWindowCoord(this, x1, y, (float)0.0); this->y->create_objects(); + add_subwindow(draw_boundary = new CWindowMaskDrawBoundary(mwindow, this, del_x, y)); y += this->y->get_h() + margin; BC_Bar *bar; add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x)); @@ -2256,22 +2310,20 @@ void CWindowMaskGUI::update() { int64_t position_i = track->to_units(position, 0); - if(point) - { + if(point) { x->update(point->x); y->update(point->y); } - if(mask) - { - feather->update(autos->get_feather(position_i, PLAY_FORWARD)); - fade->update(autos->get_value(position_i, PLAY_FORWARD)); + if(mask) { + int k = mwindow->edl->session->cwindow_mask; + feather->update(autos->get_feather(position_i, k, PLAY_FORWARD)); + fade->update(autos->get_fader(position_i, k, PLAY_FORWARD)); apply_before_plugins->update(keyframe->apply_before_plugins); disable_opengl_masking->update(keyframe->disable_opengl_masking); } } -//printf("CWindowMaskGUI::update 1\n"); active_point->update((int64_t)mwindow->cwindow->gui->affected_point); const char *text = ""; if( keyframe ) { @@ -2281,16 +2333,6 @@ void CWindowMaskGUI::update() text = keyframe->masks[k]->name; } name->update(text); - -//printf("CWindowMaskGUI::update 1\n"); - if( track ) { -#ifdef USE_KEYFRAME_SPANNING - mode->update(keyframe->mode); -#else - mode->set_text(((MaskAuto*)autos->default_auto)->mode); -#endif - } -//printf("CWindowMaskGUI::update 2\n"); } void CWindowMaskGUI::handle_event() diff --git a/cinelerra-5.1/cinelerra/cwindowtool.h b/cinelerra-5.1/cinelerra/cwindowtool.h index 4691fc07..ccdb3c26 100644 --- a/cinelerra-5.1/cinelerra/cwindowtool.h +++ b/cinelerra-5.1/cinelerra/cwindowtool.h @@ -145,6 +145,26 @@ public: void update_items(MaskAuto *keyframe); }; +class CWindowMaskDelMask : public BC_GenericButton +{ +public: + CWindowMaskDelMask(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + int handle_event(); + MWindow *mwindow; + CWindowToolGUI *gui; +}; + +class CWindowMaskClrMask : public BC_Button +{ +public: + CWindowMaskClrMask(MWindow *mwindow, CWindowMaskGUI *gui, int x, int y); + ~CWindowMaskClrMask(); + static int calculate_w(MWindow *mwindow); + int handle_event(); + MWindow *mwindow; + CWindowMaskGUI *gui; +}; + class CWindowMaskFade : public BC_TumbleTextBox { public: @@ -169,43 +189,55 @@ public: MWindow *mwindow; CWindowToolGUI *gui; int stick; + float last_v; Timer *timer; }; -class CWindowMaskMode : public BC_Toggle +class CWindowMaskGangFader : public BC_Toggle { public: - CWindowMaskMode(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); - ~CWindowMaskMode(); + CWindowMaskGangFader(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + ~CWindowMaskGangFader(); int handle_event(); MWindow *mwindow; CWindowToolGUI *gui; }; -class CWindowMaskDelMask : public BC_GenericButton +class CWindowMaskAffectedPoint : public BC_TumbleTextBox { public: - CWindowMaskDelMask(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + CWindowMaskAffectedPoint(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + ~CWindowMaskAffectedPoint(); int handle_event(); MWindow *mwindow; CWindowToolGUI *gui; }; -class CWindowMaskAffectedPoint : public BC_TumbleTextBox +class CWindowMaskFocus : public BC_CheckBox { public: - CWindowMaskAffectedPoint(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); - ~CWindowMaskAffectedPoint(); + CWindowMaskFocus(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + ~CWindowMaskFocus(); int handle_event(); MWindow *mwindow; CWindowToolGUI *gui; }; -class CWindowMaskFocus : public BC_CheckBox +class CWindowMaskDrawMarkers : public BC_CheckBox { public: - CWindowMaskFocus(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); - ~CWindowMaskFocus(); + CWindowMaskDrawMarkers(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + ~CWindowMaskDrawMarkers(); + int handle_event(); + MWindow *mwindow; + CWindowToolGUI *gui; +}; + +class CWindowMaskDrawBoundary : public BC_CheckBox +{ +public: + CWindowMaskDrawBoundary(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + ~CWindowMaskDrawBoundary(); int handle_event(); MWindow *mwindow; CWindowToolGUI *gui; @@ -244,27 +276,19 @@ public: char *get_caption() { return 0; } MWindow *mwindow; CWindowToolGUI *gui; + int stick; + float last_v; + Timer *timer; }; -class CWindowMaskClrMask : public BC_Button -{ -public: - CWindowMaskClrMask(MWindow *mwindow, CWindowMaskGUI *gui, int x, int y); - ~CWindowMaskClrMask(); - static int calculate_w(MWindow *mwindow); - int handle_event(); - MWindow *mwindow; - CWindowMaskGUI *gui; -}; - -class CWindowMaskClrFeather : public BC_Button +class CWindowMaskGangFeather : public BC_Toggle { public: - CWindowMaskClrFeather(MWindow *mwindow, CWindowMaskGUI *gui, int x, int y); - ~CWindowMaskClrFeather(); + CWindowMaskGangFeather(MWindow *mwindow, CWindowToolGUI *gui, int x, int y); + ~CWindowMaskGangFeather(); int handle_event(); MWindow *mwindow; - CWindowMaskGUI *gui; + CWindowToolGUI *gui; }; class CWindowMaskBeforePlugins : public BC_CheckBox @@ -297,19 +321,24 @@ public: void update_preview(); CWindowMaskName *name; - CWindowMaskClrMask *clr_mask; CWindowMaskDelMask *del_mask; + CWindowMaskClrMask *clr_mask; CWindowMaskFade *fade; CWindowMaskFadeSlider *fade_slider; - CWindowMaskMode *mode; + CWindowMaskGangFader *gang_fader; CWindowMaskAffectedPoint *active_point; CWindowMaskDelPoint *del_point; CWindowCoord *x, *y; CWindowMaskFocus *focus; int focused; + CWindowMaskDrawMarkers *draw_markers; + int markers; + CWindowMaskDrawBoundary *draw_boundary; + int boundary; CWindowCoord *focus_x, *focus_y; CWindowMaskFeather *feather; CWindowMaskFeatherSlider *feather_slider; + CWindowMaskGangFeather *gang_feather; CWindowMaskBeforePlugins *apply_before_plugins; CWindowDisableOpenGLMasking *disable_opengl_masking; }; diff --git a/cinelerra-5.1/cinelerra/cwindowtool.inc b/cinelerra-5.1/cinelerra/cwindowtool.inc index 9fd83c54..47e02ef9 100644 --- a/cinelerra-5.1/cinelerra/cwindowtool.inc +++ b/cinelerra-5.1/cinelerra/cwindowtool.inc @@ -30,16 +30,19 @@ class CWindowCropOK; class CWindowCropGUI; class CWindowMaskItems; class CWindowMaskName; +class CWindowMaskDelMask; +class CWindowMaskClrMask; class CWindowMaskFade; class CWindowMaskFadeSlider; -class CWindowMaskMode; -class CWindowMaskDelMask; +class CWindowMaskGangFader; class CWindowMaskAffectedPoint; +class CWindowMaskFocus; +class CWindowMaskDrawMarkers; +class CWindowMaskDrawBoundary; class CWindowMaskDelPoint; class CWindowMaskFeather; class CWindowMaskFeatherSlider; -class CWindowMaskClrMask; -class CWindowMaskClrFeather; +class CWindowMaskGangFeather; class CWindowMaskBeforePlugins; class CWindowDisableOpenGLMasking; class CWindowMaskGUI; diff --git a/cinelerra-5.1/cinelerra/dcraw.C b/cinelerra-5.1/cinelerra/dcraw.C index dcb561d5..b9ec4660 100644 --- a/cinelerra-5.1/cinelerra/dcraw.C +++ b/cinelerra-5.1/cinelerra/dcraw.C @@ -1225,7 +1225,7 @@ void CLASS nikon_yuv_load_raw() { int row, col, yuv[4], rgb[3], b, c; UINT64 bitbuf=0; - + memset(yuv,0,sizeof(yuv)); for (row=0; row < raw_height; row++) for (col=0; col < raw_width; col++) { if (!(b = col & 1)) { diff --git a/cinelerra-5.1/cinelerra/edl.h b/cinelerra-5.1/cinelerra/edl.h index 0798b408..e8dadce0 100644 --- a/cinelerra-5.1/cinelerra/edl.h +++ b/cinelerra-5.1/cinelerra/edl.h @@ -93,7 +93,7 @@ public: int direction, PlayableTracks *playable_tracks); -// Convert position to frame boundry times +// Convert position to frame boundary times double frame_align(double position, int round); // frame align if cursor alignment is enabled double align_to_frame(double position, int round); diff --git a/cinelerra-5.1/cinelerra/maskauto.C b/cinelerra-5.1/cinelerra/maskauto.C index 831b899d..8b5a2a42 100644 --- a/cinelerra-5.1/cinelerra/maskauto.C +++ b/cinelerra-5.1/cinelerra/maskauto.C @@ -69,6 +69,8 @@ SubMask::SubMask(MaskAuto *keyframe, int no) this->keyframe = keyframe; memset(name, 0, sizeof(name)); sprintf(name, "%d", no); + this->fader = 100; + this->feather = 0; } SubMask::~SubMask() @@ -78,18 +80,17 @@ SubMask::~SubMask() int SubMask::equivalent(SubMask& ptr) { - if(points.size() != ptr.points.size()) return 0; - - for(int i = 0; i < points.size(); i++) - { + if( fader != ptr.fader ) return 0; + if( feather != ptr.feather ) return 0; + int n = points.size(); + if( n != ptr.points.size() ) return 0; + for( int i=0; iread_tag(); - - if(!result) - { - if(file->tag.title_is("/MASK")) - { - result = 1; - } - else - if(file->tag.title_is("POINT")) - { - XMLBuffer data; - file->read_text_until("/POINT", &data); - - MaskPoint *point = new MaskPoint; - char *ptr = data.cstr(); -//printf("MaskAuto::load 1 %s\n", ptr); - - point->x = atof(ptr); - ptr = strchr(ptr, ','); -//printf("MaskAuto::load 2 %s\n", ptr + 1); - if(ptr) - { - point->y = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - - if(ptr) - { -//printf("MaskAuto::load 3 %s\n", ptr + 1); - point->control_x1 = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - if(ptr) - { -//printf("MaskAuto::load 4 %s\n", ptr + 1); - point->control_y1 = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - if(ptr) - { -//printf("MaskAuto::load 5 %s\n", ptr + 1); - point->control_x2 = atof(ptr + 1); - ptr = strchr(ptr + 1, ','); - if(ptr) point->control_y2 = atof(ptr + 1); - } - } - } - - } - points.append(point); - } + while( !(result = file->read_tag()) ) { + if( file->tag.title_is("/MASK") ) break; + if( file->tag.title_is("POINT") ) { + XMLBuffer data; + file->read_text_until("/POINT", &data); + MaskPoint *point = new MaskPoint; + char *cp = data.cstr(); + if( cp ) point->x = strtof(cp, &cp); + if( cp && *cp==',' ) point->y = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_x1 = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_y1 = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_x2 = strtof(cp+1, &cp); + if( cp && *cp==',' ) point->control_y2 = strtof(cp+1, &cp); + points.append(point); } } } @@ -176,6 +142,8 @@ void SubMask::copy(FileXML *file) file->tag.set_title("MASK"); file->tag.set_property("NUMBER", keyframe->masks.number_of(this)); file->tag.set_property("NAME", name); + file->tag.set_property("FADER", fader); + file->tag.set_property("FEATHER", feather); file->append_tag(); file->append_newline(); @@ -208,16 +176,13 @@ void SubMask::copy(FileXML *file) void SubMask::dump() { - for(int i = 0; i < points.total; i++) - { + for( int i=0; ix, - points.values[i]->y, - points.values[i]->control_x1, - points.values[i]->control_y1, - points.values[i]->control_x2, - points.values[i]->control_y2); + i, points.values[i]->x, points.values[i]->y, + points.values[i]->control_x1, points.values[i]->control_y1, + points.values[i]->control_x2, points.values[i]->control_y2); } } @@ -225,9 +190,6 @@ void SubMask::dump() MaskAuto::MaskAuto(EDL *edl, MaskAutos *autos) : Auto(edl, autos) { - mode = MASK_SUBTRACT_ALPHA; - feather = 0; - value = 100; apply_before_plugins = 0; disable_opengl_masking = 0; @@ -258,34 +220,25 @@ int MaskAuto::operator==(MaskAuto &that) int MaskAuto::identical(MaskAuto *src) { - if(value != src->value || - mode != src->mode || - feather != src->feather || - masks.size() != src->masks.size() || - apply_before_plugins != src->apply_before_plugins || - disable_opengl_masking != src->disable_opengl_masking) return 0; - - for(int i = 0; i < masks.size(); i++) - if(!(*masks.values[i] == *src->masks.values[i])) return 0; + if( masks.size() != src->masks.size() || + apply_before_plugins != src->apply_before_plugins || + disable_opengl_masking != src->disable_opengl_masking ) return 0; + for( int i=0; imasks.values[i])) return 0; + } return 1; } void MaskAuto::update_parameter(MaskAuto *ref, MaskAuto *src) { - if(src->value != ref->value) - this->value = src->value; - if(src->mode != ref->mode) - this->mode = src->mode; - if(src->apply_before_plugins != ref->apply_before_plugins) + if( src->apply_before_plugins != ref->apply_before_plugins ) this->apply_before_plugins = src->apply_before_plugins; - if(src->disable_opengl_masking != ref->disable_opengl_masking) + if( src->disable_opengl_masking != ref->disable_opengl_masking ) this->disable_opengl_masking = src->disable_opengl_masking; - if(!EQUIV(src->feather, ref->feather)) - this->feather = src->feather; for( int i=0; iget_submask(i)->equivalent(*ref->get_submask(i))) + if( !src->get_submask(i)->equivalent(*ref->get_submask(i)) ) this->get_submask(i)->copy_from(*src->get_submask(i)); } } @@ -303,9 +256,6 @@ void MaskAuto::copy_from(MaskAuto *src) void MaskAuto::copy_data(MaskAuto *src) { - mode = src->mode; - feather = src->feather; - value = src->value; apply_before_plugins = src->apply_before_plugins; disable_opengl_masking = src->disable_opengl_masking; @@ -328,34 +278,28 @@ int MaskAuto::interpolate_from(Auto *a1, Auto *a2, int64_t position, Auto *templ { return Auto::interpolate_from(a1, a2, position, templ); } - this->mode = mask_auto1->mode; - this->feather = mask_auto1->feather; - this->value = mask_auto1->value; this->apply_before_plugins = mask_auto1->apply_before_plugins; this->disable_opengl_masking = mask_auto1->disable_opengl_masking; this->position = position; masks.remove_all_objects(); - for(int i = 0; - i < mask_auto1->masks.total; - i++) - { + for( int i=0; imasks.total; ++i ) { SubMask *new_submask = new SubMask(this, i); masks.append(new_submask); SubMask *mask1 = mask_auto1->masks.values[i]; SubMask *mask2 = mask_auto2->masks.values[i]; + double len = mask_auto2->position - mask_auto1->position; + double weight = !len ? 0 : (position - mask_auto1->position) / len; + new_submask->fader = mask1->fader*(1-weight) + mask2->fader*weight + 0.5; + new_submask->feather = mask1->feather*(1-weight) + mask2->feather*weight + 0.5; // just in case, should never happen int total_points = MIN(mask1->points.total, mask2->points.total); - for(int j = 0; j < total_points; j++) - { + for( int j=0; jpoints.values[j], - mask2->points.values[j], - position, - mask_auto1->position, - mask_auto2->position); + mask1->points.values[j], mask2->points.values[j], + position, mask_auto1->position, mask_auto2->position); new_submask->points.append(point); } } @@ -400,13 +344,13 @@ void MaskAuto::set_points(ArrayList *points, void MaskAuto::load(FileXML *file) { - mode = file->tag.get_property("MODE", mode); - feather = file->tag.get_property("FEATHER", feather); - value = file->tag.get_property("VALUE", value); +// legacy, moved to SubMask + int old_mode = file->tag.get_property("MODE", MASK_MULTIPLY_ALPHA); + int old_feather = file->tag.get_property("FEATHER", 0); + int old_value = file->tag.get_property("VALUE", 100); apply_before_plugins = file->tag.get_property("APPLY_BEFORE_PLUGINS", apply_before_plugins); disable_opengl_masking = file->tag.get_property("DISABLE_OPENGL_MASKING", disable_opengl_masking); - for(int i = 0; i < masks.size(); i++) - { + for( int i=0; iname, 0, sizeof(mask->name)); strncpy(mask->name, name, sizeof(mask->name)); + mask->feather = file->tag.get_property("FEATHER", old_feather); + mask->fader = file->tag.get_property("FADER", old_value); + if( old_mode == MASK_SUBTRACT_ALPHA ) + mask->fader = -mask->fader; mask->load(file); } } @@ -431,25 +379,14 @@ void MaskAuto::load(FileXML *file) void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto) { file->tag.set_title("AUTO"); - file->tag.set_property("MODE", mode); - file->tag.set_property("VALUE", value); - file->tag.set_property("FEATHER", feather); file->tag.set_property("APPLY_BEFORE_PLUGINS", apply_before_plugins); file->tag.set_property("DISABLE_OPENGL_MASKING", disable_opengl_masking); - - if(default_auto) - file->tag.set_property("POSITION", 0); - else - file->tag.set_property("POSITION", position - start); + file->tag.set_property("POSITION", default_auto ? 0 : position - start); file->append_tag(); file->append_newline(); - for(int i = 0; i < masks.size(); i++) - { -//printf("MaskAuto::copy 1 %p %d %p\n", this, i, masks.values[i]); + for( int i=0; icopy(file); -//printf("MaskAuto::copy 10\n"); - } file->tag.set_title("/AUTO"); file->append_tag(); @@ -458,9 +395,7 @@ void MaskAuto::copy(int64_t start, int64_t end, FileXML *file, int default_auto) void MaskAuto::dump() { - printf(" mode=%d value=%d\n", mode, value); - for(int i = 0; i < masks.size(); i++) - { + for( int i=0; idump(); } @@ -468,11 +403,9 @@ void MaskAuto::dump() void MaskAuto::translate_submasks(float translate_x, float translate_y) { - for(int i = 0; i < masks.size(); i++) - { + for( int i=0; ipoints.total; j++) - { + for( int j=0; jpoints.total; ++j ) { mask->points.values[j]->x += translate_x; mask->points.values[j]->y += translate_y; } @@ -481,11 +414,9 @@ void MaskAuto::translate_submasks(float translate_x, float translate_y) void MaskAuto::scale_submasks(int orig_scale, int new_scale) { - for(int i = 0; i < masks.size(); i++) - { + for( int i=0; ipoints.total; j++) - { + for( int j=0; jpoints.total; ++j ) { float orig_x = mask->points.values[j]->x * orig_scale; float orig_y = mask->points.values[j]->y * orig_scale; mask->points.values[j]->x = orig_x / new_scale; diff --git a/cinelerra-5.1/cinelerra/maskauto.h b/cinelerra-5.1/cinelerra/maskauto.h index 1bae9ab8..31a11b92 100644 --- a/cinelerra-5.1/cinelerra/maskauto.h +++ b/cinelerra-5.1/cinelerra/maskauto.h @@ -44,13 +44,14 @@ public: float control_x2, control_y2; }; +#define FEATHER_MAX 100 + class SubMask { public: SubMask(MaskAuto *keyframe, int no); ~SubMask(); -// Don't use == int operator==(SubMask& ptr); int equivalent(SubMask& ptr); void copy_from(SubMask& ptr); @@ -59,6 +60,8 @@ public: void dump(); char name[BCSTRLEN]; + float fader; // 0 - 100 + float feather; // 0 - 100 ArrayList points; MaskAuto *keyframe; }; @@ -98,15 +101,56 @@ public: ArrayList masks; // These are constant for the entire track - int mode; - float feather; -// 0 - 100 - int value; int apply_before_plugins; int disable_opengl_masking; }; +class MaskCoord { public: double x, y, z; }; + +class MaskEdge : public ArrayList +{ +public: + MaskCoord &append() { return ArrayList::append(); } + MaskCoord &append(double x, double y, double z=0) { + MaskCoord &c = append(); + c.x = x; c.y = y; c.z = z; + return c; + } +}; + +// shader buffer unsized array vec only seems to work for dvec (05/2019) +class MaskSpot { public: double x, y; }; + +class MaskSpots : public ArrayList +{ +public: + MaskSpot &append() { return ArrayList::append(); } + MaskSpot &append(double x, double y) { + MaskSpot &s = append(); + s.x = x; s.y = y; + return s; + } +}; +class MaskEdges : public ArrayList { +public: + MaskEdges() {} + ~MaskEdges() { remove_all_objects(); } +}; +class MaskPointSet : public ArrayList +{ +public: + void clear() { remove_all_objects(); } + MaskPointSet() {} + ~MaskPointSet() { clear(); } +}; +class MaskPointSets : public ArrayList +{ +public: + void clear() { remove_all_objects(); } + MaskPointSets() {} + ~MaskPointSets() { clear(); } +}; #endif diff --git a/cinelerra-5.1/cinelerra/maskauto.inc b/cinelerra-5.1/cinelerra/maskauto.inc index 5d144612..8c75a660 100644 --- a/cinelerra-5.1/cinelerra/maskauto.inc +++ b/cinelerra-5.1/cinelerra/maskauto.inc @@ -28,7 +28,7 @@ class MaskAuto; class MaskPoint; class SubMask; -enum { +enum { // no longer used, legacy value MASK_MULTIPLY_ALPHA, MASK_SUBTRACT_ALPHA, }; diff --git a/cinelerra-5.1/cinelerra/maskautos.C b/cinelerra-5.1/cinelerra/maskautos.C index 62b6ad74..04feb88d 100644 --- a/cinelerra-5.1/cinelerra/maskautos.C +++ b/cinelerra-5.1/cinelerra/maskautos.C @@ -161,37 +161,35 @@ void MaskAutos::get_points(ArrayList *points, } -float MaskAutos::get_feather(int64_t position, int direction) +float MaskAutos::get_feather(int64_t position, int i, int direction) { Auto *begin = 0, *end = 0; position = (direction == PLAY_FORWARD) ? position : (position - 1); + MaskAuto*prev = (MaskAuto*)get_prev_auto(position, PLAY_FORWARD, begin, 1); + MaskAuto*next = (MaskAuto*)get_next_auto(position, PLAY_FORWARD, end, 1); + SubMask *prev_mask = prev->get_submask(i), *next_mask = next->get_submask(i); - get_prev_auto(position, PLAY_FORWARD, begin, 1); - get_next_auto(position, PLAY_FORWARD, end, 1); + double weight = end->position == begin->position ? 0.0 : + (double)(position - begin->position) / (end->position - begin->position); - double weight = 0.0; - if(end->position != begin->position) - weight = (double)(position - begin->position) / (end->position - begin->position); - - return ((MaskAuto*)begin)->feather * (1.0 - weight) + ((MaskAuto*)end)->feather * weight; + int result = prev_mask->feather * (1-weight) + next_mask->feather*weight + 0.5; + return result; } -int MaskAutos::get_value(int64_t position, int direction) +int MaskAutos::get_fader(int64_t position, int i, int direction) { Auto *begin = 0, *end = 0; position = (direction == PLAY_FORWARD) ? position : (position - 1); + MaskAuto*prev = (MaskAuto*)get_prev_auto(position, PLAY_FORWARD, begin, 1); + MaskAuto*next = (MaskAuto*)get_next_auto(position, PLAY_FORWARD, end, 1); + SubMask *prev_mask = prev->get_submask(i), *next_mask = next->get_submask(i); - get_prev_auto(position, PLAY_FORWARD, begin, 1); - get_next_auto(position, PLAY_FORWARD, end, 1); - - double weight = 0.0; - if(end->position != begin->position) - weight = (double)(position - begin->position) / (end->position - begin->position); + double weight = end->position == begin->position ? 0.0 : + (double)(position - begin->position) / (end->position - begin->position); - int result = (int)((double)((MaskAuto*)begin)->value * (1.0 - weight) + - (double)((MaskAuto*)end)->value * weight + 0.5); -// printf("MaskAutos::get_value %d %d %f %d %f %d\n", __LINE__, -// ((MaskAuto*)begin)->value, 1.0 - weight, ((MaskAuto*)end)->value, weight, result); + int result = prev_mask->fader * (1-weight) + next_mask->fader*weight + 0.5; +// printf("MaskAutos::get_fader %d %d %d %f %d %f %d\n", __LINE__, i, +// ((MaskAuto*)begin)->fader, 1.0 - weight, ((MaskAuto*)end)->fader, weight, result); return result; } diff --git a/cinelerra-5.1/cinelerra/maskautos.h b/cinelerra-5.1/cinelerra/maskautos.h index fcac125a..009069a2 100644 --- a/cinelerra-5.1/cinelerra/maskautos.h +++ b/cinelerra-5.1/cinelerra/maskautos.h @@ -55,8 +55,8 @@ public: int mask_exists(int64_t position, int direction); // Perform interpolation void get_points(ArrayList *points, int submask, int64_t position, int direction); - float get_feather(int64_t position, int direction); - int get_value(int64_t position, int direction); + float get_feather(int64_t position, int i, int direction); + int get_fader(int64_t position, int i, int direction); int total_submasks(int64_t position, int direction); // Translates all mask points void translate_masks(float translate_x, float translate_y); diff --git a/cinelerra-5.1/cinelerra/maskengine.C b/cinelerra-5.1/cinelerra/maskengine.C index fd7458e1..467ffa0b 100644 --- a/cinelerra-5.1/cinelerra/maskengine.C +++ b/cinelerra-5.1/cinelerra/maskengine.C @@ -33,6 +33,22 @@ #include #include +void write_mask(VFrame *vfrm, const char *fmt, ...) +{ + va_list ap; va_start(ap, fmt); + char fn[256]; vsnprintf(fn, sizeof(fn), fmt, ap); + va_end(ap); + FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w"); + if( fp ) { + int w = vfrm->get_w(), h = vfrm->get_h(); + int m = vfrm->get_color_model(); + fprintf(fp,"P5\n%d %d\n%d\n",w,h,m==BC_A8? 0xff : 0xffff); + int bpp = m==BC_A8? 1 : 2; + fwrite(vfrm->get_data(),bpp*w,h,fp); fflush(fp); + if( fp != stdout ) fclose(fp); + } +} + MaskPackage::MaskPackage() { } @@ -45,469 +61,253 @@ MaskUnit::MaskUnit(MaskEngine *engine) : LoadClient(engine) { this->engine = engine; - this->temp = 0; + spot = 0; + r = 0; } MaskUnit::~MaskUnit() { - if( temp ) delete temp; } - -#define OVERSAMPLE 8 - -void MaskUnit::draw_line_clamped(VFrame *frame, - int x1, int y1, int x2, int y2, unsigned char k) +void MaskUnit::draw_line(int v, int ix1, int iy1, int ix2, int iy2) { - int draw_x1, draw_y1; - int draw_x2, draw_y2; - - if( y2 < y1 ) { - draw_x1 = x2; draw_y1 = y2; - draw_x2 = x1; draw_y2 = y1; - } - else { - draw_x1 = x1; draw_y1 = y1; - draw_x2 = x2; draw_y2 = y2; - } - - unsigned char **rows = (unsigned char**)frame->get_rows(); - - if( draw_y2 != draw_y1 ) { - float slope = ((float)draw_x2 - draw_x1) / ((float)draw_y2 - draw_y1); - int w = frame->get_w() - 1; - int h = frame->get_h(); - - for( float y = draw_y1; y < draw_y2; y++ ) { - if( y >= 0 && y < h ) { - int x = (int)((y - draw_y1) * slope + draw_x1); - int y_i = (int)y; - int x_i = CLIP(x, 0, w); - - if( rows[y_i][x_i] == k ) - rows[y_i][x_i] = 0; - else - rows[y_i][x_i] = k; - } - } + if( iy1 == iy2 ) return; + int x1 = iy1 < iy2 ? ix1 : ix2; + int y1 = iy1 < iy2 ? iy1 : iy2; + int x2 = iy1 < iy2 ? ix2 : ix1; + int y2 = iy1 < iy2 ? iy2 : iy1; + float slope = (float)(x2-x1) / (y2-y1); + int dy = y1 - start_y; + int i = dy < 0 ? (y1=start_y, -dy) : 0; + if( y2 > end_y ) y2 = end_y; + if( y2 < start_y || y1 >= end_y ) return; + + VFrame *temp = engine->temp; + int w1 = temp->get_w()-1; + temp_t **rows = (temp_t **)temp->get_rows(); + for( int y=y1; ytemp; + int temp_w = temp->get_w(); + temp_t **rows = (temp_t**)temp->get_rows(); + + for( int y=start_y; y0 ) { + --total; + value = value ? 0 : v; + } + else if( value ) + row[x] = value; } - sp_p++; sp_m--; - vp++; vm--; - } - - for( int i = 0; i < size; i++ ) { - double sum = val_p[i] + val_m[i]; - CLAMP(sum, 0, max); - dst[i] = sum; } } -void MaskUnit::do_feather(VFrame *output, VFrame *input, double feather, - int start_y, int end_y, int start_x, int end_x) +void MaskUnit::draw_feather(int ix1,int iy1, int ix2,int iy2) { -//printf("MaskUnit::do_feather %f\n", feather); -// Get constants - double constants[8]; - double div; - double std_dev = sqrt(-(double)(feather * feather) / (2 * log(1.0 / 255.0))); - div = sqrt(2 * M_PI) * std_dev; - constants[0] = -1.783 / std_dev; - constants[1] = -1.723 / std_dev; - constants[2] = 0.6318 / std_dev; - constants[3] = 1.997 / std_dev; - constants[4] = 1.6803 / div; - constants[5] = 3.735 / div; - constants[6] = -0.6803 / div; - constants[7] = -0.2598 / div; - - n_p[0] = constants[4] + constants[6]; - n_p[1] = exp(constants[1]) * - (constants[7] * sin(constants[3]) - - (constants[6] + 2 * constants[4]) * cos(constants[3])) + - exp(constants[0]) * - (constants[5] * sin(constants[2]) - - (2 * constants[6] + constants[4]) * cos(constants[2])); - - n_p[2] = 2 * exp(constants[0] + constants[1]) * - ((constants[4] + constants[6]) * cos(constants[3]) * - cos(constants[2]) - constants[5] * - cos(constants[3]) * sin(constants[2]) - - constants[7] * cos(constants[2]) * sin(constants[3])) + - constants[6] * exp(2 * constants[0]) + - constants[4] * exp(2 * constants[1]); - - n_p[3] = exp(constants[1] + 2 * constants[0]) * - (constants[7] * sin(constants[3]) - - constants[6] * cos(constants[3])) + - exp(constants[0] + 2 * constants[1]) * - (constants[5] * sin(constants[2]) - constants[4] * - cos(constants[2])); - n_p[4] = 0.0; - - d_p[0] = 0.0; - d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) - - 2 * exp(constants[0]) * cos(constants[2]); - - d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) * - exp(constants[0] + constants[1]) + - exp(2 * constants[1]) + exp (2 * constants[0]); - - d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) - - 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]); - - d_p[4] = exp(2 * constants[0] + 2 * constants[1]); - - for( int i = 0; i < 5; i++ ) d_m[i] = d_p[i]; - - n_m[0] = 0.0; - for( int i = 1; i <= 4; i++ ) - n_m[i] = n_p[i] - d_p[i] * n_p[0]; - - double sum_n_p, sum_n_m, sum_d; - double a, b; - - sum_n_p = 0.0; - sum_n_m = 0.0; - sum_d = 0.0; - for( int i = 0; i < 5; i++ ) { - sum_n_p += n_p[i]; - sum_n_m += n_m[i]; - sum_d += d_p[i]; + int x1 = iy1 < iy2 ? ix1 : ix2; + int y1 = iy1 < iy2 ? iy1 : iy2; + int x2 = iy1 < iy2 ? ix2 : ix1; + int y2 = iy1 < iy2 ? iy2 : iy1; + VFrame *temp = engine->temp; + int h = temp->get_h(); + if( y2 < 0 || y1 >= h ) return; + + int x = x1, y = y1; + int dx = x2-x1, dy = y2-y1; + int dx2 = 2*dx, dy2 = 2*dy; + if( dx < 0 ) dx = -dx; + int m = dx > dy ? dx : dy, n = m; + if( dy >= dx ) { + if( dx2 >= 0 ) do { /* +Y, +X */ + draw_spot(x, y++); + if( (m -= dx2) < 0 ) { m += dy2; ++x; } + } while( --n >= 0 ); + else do { /* +Y, -X */ + draw_spot(x, y++); + if( (m += dx2) < 0 ) { m += dy2; --x; } + } while( --n >= 0 ); } - - a = sum_n_p / (1 + sum_d); - b = sum_n_m / (1 + sum_d); - - for( int i = 0; i < 5; i++ ) { - bd_p[i] = d_p[i] * a; - bd_m[i] = d_m[i] * b; + else { + if( dx2 >= 0 ) do { /* +X, +Y */ + draw_spot(x++, y); + if( (m -= dy2) < 0 ) { m += dx2; ++y; } + } while( --n >= 0 ); + else do { /* -X, +Y */ + draw_spot(x--, y); + if( (m -= dy2) < 0 ) { m -= dx2; ++y; } + } while( --n >= 0 ); } -#define DO_FEATHER(type, max) { \ - int frame_w = input->get_w(); \ - int frame_h = input->get_h(); \ - int size = MAX(frame_w, frame_h); \ - double *src = new double[size]; \ - double *dst = new double[size]; \ - double *val_p = new double[size]; \ - double *val_m = new double[size]; \ - type **in_rows = (type**)input->get_rows(); \ - type **out_rows = (type**)output->get_rows(); \ - int j; \ - \ -/* printf("DO_FEATHER 1\n"); */ \ - if( end_x > start_x ) { \ - for( j = start_x; j < end_x; j++ ) { \ - /* printf("DO_FEATHER 1.1 %d\n", j); */ \ - bzero(val_p, sizeof(double) * frame_h); \ - bzero(val_m, sizeof(double) * frame_h); \ - for( int k = 0; k < frame_h; k++ ) { \ - src[k] = (double)in_rows[k][j]; \ - } \ - blur_strip(val_p, val_m, dst, src, frame_h, max); \ - for( int k = 0; k < frame_h; k++ ) { \ - out_rows[k][j] = (type)dst[k]; \ - } \ - } \ - } \ - if( end_y > start_y ) { \ - for( j = start_y; j < end_y; j++ ) { \ - /* printf("DO_FEATHER 2 %d\n", j); */ \ - bzero(val_p, sizeof(double) * frame_w); \ - bzero(val_m, sizeof(double) * frame_w); \ - for( int k = 0; k < frame_w; k++ ) { \ - src[k] = (double)out_rows[j][k]; \ - } \ - blur_strip(val_p, val_m, dst, src, frame_w, max); \ - for( int k = 0; k < frame_w; k++ ) { \ - out_rows[j][k] = (type)dst[k]; \ - } \ - } \ - } \ -/* printf("DO_FEATHER 3\n"); */ \ - delete [] src; \ - delete [] dst; \ - delete [] val_p; \ - delete [] val_m; \ -/* printf("DO_FEATHER 4\n"); */ \ } -//printf("do_feather %d\n", frame->get_color_model()); - switch( input->get_color_model() ) { - case BC_A8: - DO_FEATHER(unsigned char, 0xff); - break; - case BC_A16: - DO_FEATHER(uint16_t, 0xffff); - break; - case BC_A_FLOAT: - DO_FEATHER(float, 1); - break; +void MaskUnit::draw_spot(int ix, int iy) +{ + int rr = r * r, n = abs(r), rv = r * v; + if( iy < start_y-n || iy >= end_y+n ) return; + VFrame *temp = engine->temp; + int w1 = temp->get_w()-1, h1 = temp->get_h()-1; + int xs = ix - n; bclamp(xs, 0, w1); + int xn = ix + n; bclamp(xn, 0, w1); + int ys = iy - n; bclamp(ys, 0, h1); + int yn = iy + n; bclamp(yn, 0, h1); + + temp_t **rows = (temp_t**)temp->get_rows(); + for( int y=ys ; y<=yn; ++y ) { + temp_t *row = rows[y]; + for( int x=xs; x<=xn; ++x ) { + int dx = x-ix, dy = y-iy; + int dd = dx*dx + dy*dy; + if( dd >= rr ) continue; + temp_t *rp = &row[x], a = spot[dd]; + if( rv*(*rp-a) < 0 ) *rp = a; + } } } void MaskUnit::process_package(LoadPackage *package) { MaskPackage *ptr = (MaskPackage*)package; - float engine_value = engine->value; - int engine_mode = engine->mode; - + start_y = ptr->start_y; + end_y = ptr->end_y; + if( start_y >= end_y ) return; + mask_model = engine->mask->get_color_model(); + VFrame *temp = engine->temp; if( engine->recalculate && engine->step == DO_MASK ) { - VFrame *mask = engine->feather > 0 ? engine->temp_mask : engine->mask; -// Generated oversampling frame - int mask_w = mask->get_w(); - //int mask_h = mask->get_h(); - int oversampled_package_w = mask_w * OVERSAMPLE; - int oversampled_package_h = (ptr->end_y - ptr->start_y) * OVERSAMPLE; - if( temp && - (temp->get_w() != oversampled_package_w || - temp->get_h() != oversampled_package_h) ) { - delete temp; temp = 0; +// Draw masked region of polygons on temp + for( int k=0; kedges.size(); ++k ) { + if( !engine->edges[k] ) continue; + MaskEdge &edge = *engine->edges[k]; + if( edge.size() < 3 ) continue; + int v = k + 1; + for( int i=0; iget_w(); + temp_t **rows = (temp_t**)temp->get_rows(); + temp_t *fade = engine->fade; + for( int y=start_y; y=0; ++tp ) *tp = fade[*tp]; } - temp->clear_frame(); -// Draw oversampled region of polygons on temp - for( int k=0; kpoint_sets.total; ++k ) { - int old_x, old_y; - unsigned char max = k + 1; - ArrayList *points = engine->point_sets.values[k]; - - if( points->total < 3 ) continue; -//printf("MaskUnit::process_package 2 %d %d\n", k, points->total); - for( int i=0; itotal; ++i ) { - MaskPoint *point1 = points->values[i]; - MaskPoint *point2 = (i >= points->total - 1) ? - points->values[0] : - points->values[i + 1]; - - float x, y; - int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y))); - if( point1->control_x2 == 0 && - point1->control_y2 == 0 && - point2->control_x1 == 0 && - point2->control_y1 == 0 ) - segments = 1; - float x0 = point1->x; - float y0 = point1->y; - float x1 = point1->x + point1->control_x2; - float y1 = point1->y + point1->control_y2; - float x2 = point2->x + point2->control_x1; - float y2 = point2->y + point2->control_y1; - float x3 = point2->x; - float y3 = point2->y; - - for( int j = 0; j <= segments; j++ ) { - float t = (float)j / segments; - float tpow2 = t * t; - float tpow3 = t * t * t; - float invt = 1 - t; - float invtpow2 = invt * invt; - float invtpow3 = invt * invt * invt; - - x = ( invtpow3 * x0 - + 3 * t * invtpow2 * x1 - + 3 * tpow2 * invt * x2 - + tpow3 * x3); - y = ( invtpow3 * y0 - + 3 * t * invtpow2 * y1 - + 3 * tpow2 * invt * y2 - + tpow3 * y3); - - y -= ptr->start_y; - x *= OVERSAMPLE; - y *= OVERSAMPLE; - - if( j > 0 ) { - draw_line_clamped(temp, old_x, old_y, (int)x, (int)y, max); - } - - old_x = (int)x; - old_y = (int)y; - } + } + if( engine->recalculate && engine->step == DO_FEATHER ) { +// draw feather + for( int k=0; kedges.size(); ++k ) { + if( !(v = engine->faders[k]) ) continue; + if( !(r = engine->feathers[k]) ) continue; + MaskEdge &edge = *engine->edges[k]; + if( !edge.size() ) continue; + float rv = r * v, vv = fabs(v); + int fg = 0xffff * (rv >= 0 ? vv : 0); + int bg = 0xffff * (rv >= 0 ? 0 : vv); + int rr = r*r; double dr = 1./rr; + temp_t psf[rr+1]; spot = psf; + for( int i=0; i<=rr; ++i ) { + double d = i*dr; + psf[i] = (1-d)*fg + d*bg; } -// Fill in the polygon in the horizontal direction - for( int i=0; iget_rows()[i]; - int value = 0, total = 0; - - for( int j=0; j 1 ) { - if( total & 0x1 ) --total; - for( int j=0; j0 ) { - --total; - value = value ? 0 : max; - } - else if( value ) - row[j] = value; - } - } + int n = edge.size(); + for( int i=0; iend_y-ptr->start_y; ++y ) { \ - type *output_row = (type*)mask->get_rows()[y + ptr->start_y]; \ - unsigned char **input_rows = (unsigned char**)temp->get_rows() + y * OVERSAMPLE; \ - for( int x=0; xget_color_model() ) { - case BC_A8: { - unsigned char value; - value = (int)(engine_value / 100 * 0xff); - if( engine->value >= 0 ) - DOWNSAMPLE(unsigned char, int64_t, value, total); - else - DOWNSAMPLE(unsigned char, int64_t, value, value-total); - break; } - - case BC_A16: { - uint16_t value; - value = (int)(engine_value / 100 * 0xffff); - if( engine->value >= 0 ) - DOWNSAMPLE(uint16_t, int64_t, value, total); - else - DOWNSAMPLE(uint16_t, int64_t, value, value-total); - break; } - - case BC_A_FLOAT: { - float value; - value = engine_value / 100; - if( engine->value >= 0 ) - DOWNSAMPLE(float, double, value, total); - else - DOWNSAMPLE(float, double, value, value-total); - break; } +#define REMAP(cmodel, type, expr) case cmodel: { \ +type **msk_rows = (type**)engine->mask->get_rows(); \ +for( int y=start_y; y=0; ++rp,++mp ) *mp = expr; \ +} } break +// map alpha to mask + const float to_flt = 1/65535.; + int temp_w = temp->get_w(); + temp_t **rows = (temp_t**)temp->get_rows(); + switch( mask_model ) { + REMAP(BC_A8, uint8_t, *rp >> 8); + REMAP(BC_A16, uint16_t, *rp); + REMAP(BC_A_FLOAT, float, *rp * to_flt); } } - if( engine->step == DO_X_FEATHER && engine->recalculate && // Feather polygon - engine->feather > 0 ) { - do_feather(engine->mask, - engine->temp_mask, engine->feather, - ptr->start_y, ptr->end_y, 0, 0); -//printf("MaskUnit::process_package 3 %f\n", engine->feather); - } - - if( engine->step == DO_Y_FEATHER && engine->recalculate && // Feather polygon - engine->feather > 0 ) { - do_feather(engine->mask, - engine->temp_mask, engine->feather, - 0, 0, ptr->start_x, ptr->end_x); - } - - if( engine->step == DO_APPLY ) { // Apply mask -#define APPLY_MASK_ALPHA(cmodel, type, max, components, do_yuv, a, b) \ +// Apply mask + if( engine->step == DO_APPLY ) { + int mask_w = engine->mask->get_w(); + uint8_t **out_rows = engine->output->get_rows(); + uint8_t **msk_rows = engine->mask->get_rows(); +#define APPLY_MASK_ALPHA(cmodel, type, max, components, do_yuv) \ case cmodel: \ for( int y=ptr->start_y; yend_y; ++y ) { \ - type *output_row = (type*)engine->output->get_rows()[y]; \ - type *mask_row = (type*)engine->mask->get_rows()[y]; \ - int chroma_offset = (int)(max + 1) / 2; \ + type *out_row = (type*)out_rows[y]; \ + type *msk_row = (type*)msk_rows[y]; \ + type chroma_offset = (int)(max + 1) / 2; \ for( int x=0; xoutput->get_color_model() ) { \ - APPLY_MASK_ALPHA(BC_RGB888, unsigned char, 0xff, 3, 0, a, b); \ - APPLY_MASK_ALPHA(BC_RGB_FLOAT, float, 1.0, 3, 0, a, b); \ - APPLY_MASK_ALPHA(BC_YUV888, unsigned char, 0xff, 3, 1, a, b); \ - APPLY_MASK_ALPHA(BC_RGBA_FLOAT, float, 1.0, 4, 0, a, b); \ - APPLY_MASK_ALPHA(BC_YUVA8888, unsigned char, 0xff, 4, 1, a, b); \ - APPLY_MASK_ALPHA(BC_RGBA8888, unsigned char, 0xff, 4, 0, a, b); \ - APPLY_MASK_ALPHA(BC_RGB161616, uint16_t, 0xffff, 3, 0, a, b); \ - APPLY_MASK_ALPHA(BC_YUV161616, uint16_t, 0xffff, 3, 1, a, b); \ - APPLY_MASK_ALPHA(BC_YUVA16161616, uint16_t, 0xffff, 4, 1, a, b); \ - APPLY_MASK_ALPHA(BC_RGBA16161616, uint16_t, 0xffff, 4, 0, a, b); \ -} break - -//printf("MaskUnit::process_package 1 %d\n", engine->mode); - int mask_w = engine->mask->get_w(); - switch( engine_mode ) { - MASK_ALPHA(MASK_MULTIPLY_ALPHA, m, n); - MASK_ALPHA(MASK_SUBTRACT_ALPHA, n, m); + switch( engine->output->get_color_model() ) { \ + APPLY_MASK_ALPHA(BC_RGB888, uint8_t, 0xff, 3, 0); \ + APPLY_MASK_ALPHA(BC_RGB_FLOAT, float, 1.0, 3, 0); \ + APPLY_MASK_ALPHA(BC_YUV888, uint8_t, 0xff, 3, 1); \ + APPLY_MASK_ALPHA(BC_RGBA_FLOAT, float, 1.0, 4, 0); \ + APPLY_MASK_ALPHA(BC_YUVA8888, uint8_t, 0xff, 4, 1); \ + APPLY_MASK_ALPHA(BC_RGBA8888, uint8_t, 0xff, 4, 0); \ + APPLY_MASK_ALPHA(BC_RGB161616, uint16_t, 0xffff, 3, 0); \ + APPLY_MASK_ALPHA(BC_YUV161616, uint16_t, 0xffff, 3, 1); \ + APPLY_MASK_ALPHA(BC_YUVA16161616, uint16_t, 0xffff, 4, 1); \ + APPLY_MASK_ALPHA(BC_RGBA16161616, uint16_t, 0xffff, 4, 0); \ } } } MaskEngine::MaskEngine(int cpus) - : LoadServer(cpus, cpus * OVERSAMPLE * 2) -// : LoadServer(1, OVERSAMPLE * 2) + : LoadServer(cpus, 2*cpus) +// : LoadServer(1, 1) { mask = 0; + temp = 0; } MaskEngine::~MaskEngine() { - if( mask ) { - delete mask; - delete temp_mask; - } - - for( int i = 0; i < point_sets.total; i++ ) { - ArrayList *points = point_sets.values[i]; - points->remove_all_objects(); - } + delete mask; + delete temp; + for( int i = 0; i < point_sets.total; i++ ) + point_sets[i]->remove_all_objects(); point_sets.remove_all_objects(); } @@ -518,133 +318,158 @@ int MaskEngine::points_equivalent(ArrayList *new_points, if( new_points->total != points->total ) return 0; for( int i = 0; i < new_points->total; i++ ) { - if( !(*new_points->values[i] == *points->values[i]) ) return 0; + if( !(*new_points->get(i) == *points->get(i)) ) return 0; } return 1; } +void MaskEngine::draw_edge(MaskEdge &edge, MaskPointSet &points) +{ + if( points.size() < 2 ) return; + edge.remove_all(); + for( int i=0; i=points.size()-1) ? + points[0] : points[i+1]; + int dx = ap->x - bp->x, dy = ap->y - bp->y; + int segments = (int)(sqrt(dx*dx + dy*dy)); + if( !segments ) continue; + if( ap->control_x2 == 0 && ap->control_y2 == 0 && + bp->control_x1 == 0 && bp->control_y1 == 0 ) + segments = 1; + float x0 = ap->x, y0 = ap->y; + float x1 = ap->x + ap->control_x2; + float y1 = ap->y + ap->control_y2; + float x2 = bp->x + bp->control_x1; + float y2 = bp->y + bp->control_y1; + float x3 = bp->x, y3 = bp->y; + + for( int j = 0; j <= segments; ++j ) { + float t = (float)j / segments; + float tpow2 = t * t; + float tpow3 = t * t * t; + float invt = 1 - t; + float invtpow2 = invt * invt; + float invtpow3 = invt * invt * invt; + + int x = (invtpow3 * x0 + + 3 * t * invtpow2 * x1 + + 3 * tpow2 * invt * x2 + + tpow3 * x3); + int y = (invtpow3 * y0 + + 3 * t * invtpow2 * y1 + + 3 * tpow2 * invt * y2 + + tpow3 * y3); + edge.append(x, y); + } + } +} + void MaskEngine::do_mask(VFrame *output, int64_t start_position_project, MaskAutos *keyframe_set, MaskAuto *keyframe, MaskAuto *default_auto) { - int new_color_model = 0; + this->output = output; recalculate = 0; + int mask_model = 0; switch( output->get_color_model() ) { case BC_RGB_FLOAT: case BC_RGBA_FLOAT: - new_color_model = BC_A_FLOAT; + mask_model = BC_A_FLOAT; break; case BC_RGB888: case BC_RGBA8888: case BC_YUV888: case BC_YUVA8888: - new_color_model = BC_A8; + mask_model = BC_A8; break; case BC_RGB161616: case BC_RGBA16161616: case BC_YUV161616: case BC_YUVA16161616: - new_color_model = BC_A16; + mask_model = BC_A16; break; } // Determine if recalculation is needed SET_TRACE - if( mask && - (mask->get_w() != output->get_w() || - mask->get_h() != output->get_h() || - mask->get_color_model() != new_color_model) ) { - delete mask; - delete temp_mask; - mask = 0; + int mask_w = output->get_w(), mask_h = output->get_h(); + if( mask && ( mask->get_color_model() != mask_model || + mask->get_w() != mask_w || mask->get_h() != mask_h ) ) { + delete mask; mask = 0; recalculate = 1; } - - if( !recalculate ) { - if( point_sets.total != keyframe_set->total_submasks(start_position_project, - PLAY_FORWARD) ) - recalculate = 1; + if( temp && ( temp->get_w() != mask_w || temp->get_h() != mask_h ) ) { + delete temp; temp = 0; } - if( !recalculate ) { - for( int i=0,n=keyframe_set->total_submasks(start_position_project, PLAY_FORWARD); - i new_points; - keyframe_set->get_points(&new_points, i, + total_submasks = keyframe_set->total_submasks(start_position_project, PLAY_FORWARD); + if( total_submasks != point_sets.size() ) + recalculate = 1; + + for( int i=0; iget_fader(start_position_project, i, PLAY_FORWARD); + if( new_fader != faders[i] ) { recalculate = 1; break; } + float new_feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD); + if( new_feather != feathers[i] ) { recalculate = 1; break; } + ArrayList new_points; + keyframe_set->get_points(&new_points, i, start_position_project, PLAY_FORWARD); - if( !points_equivalent(&new_points, point_sets.values[i]) ) - recalculate = 1; - new_points.remove_all_objects(); - } + if( !points_equivalent(&new_points, point_sets[i]) ) + recalculate = 1; + new_points.remove_all_objects(); } - int new_value = keyframe_set->get_value(start_position_project, - PLAY_FORWARD); - float new_feather = keyframe_set->get_feather(start_position_project, - PLAY_FORWARD); - - if( recalculate || - !EQUIV(new_feather, feather) || - !EQUIV(new_value, value) ) { - recalculate = 1; - if( !mask ) { - mask = new VFrame(output->get_w(), output->get_h(), - new_color_model, 0); - temp_mask = new VFrame(output->get_w(), output->get_h(), - new_color_model, 0); - } - if( new_feather > 0 ) - temp_mask->clear_frame(); - else - mask->clear_frame(); - + if( recalculate ) { for( int i = 0; i < point_sets.total; i++ ) { - ArrayList *points = point_sets.values[i]; + ArrayList *points = point_sets[i]; points->remove_all_objects(); } point_sets.remove_all_objects(); - - for( int i = 0; - i < keyframe_set->total_submasks(start_position_project, - PLAY_FORWARD); - i++ ) { - ArrayList *new_points = new ArrayList; - keyframe_set->get_points(new_points, - i, - start_position_project, - PLAY_FORWARD); + edges.remove_all_objects(); + faders.remove_all(); + feathers.remove_all(); + fade[0] = 0; + + for( int i=0; iget_fader(start_position_project, i, PLAY_FORWARD); + float v = fader / 100; + faders.append(v); + temp_t t = fabs(v) * 0xffff; + if( fader < 0 ) { + if( fade[0] < t ) fade[0] = t; + t = 0; + } + fade[i+1] = t; + float feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD); + feathers.append(feather); + MaskPointSet *new_points = new MaskPointSet(); + keyframe_set->get_points(new_points, i, start_position_project, PLAY_FORWARD); point_sets.append(new_points); + draw_edge(*edges.append(new MaskEdge()), *new_points); } +// draw mask + if( !mask ) mask = new VFrame(mask_w, mask_h, mask_model, 0); + if( !temp ) temp = new VFrame(mask_w, mask_h, BC_A16, 0); + mask->clear_frame(); + temp->clear_frame(); + step = DO_MASK; + process_packages(); + step = DO_FEATHER; + process_packages(); } - - - - this->output = output; - this->mode = default_auto->mode; - this->feather = new_feather; - this->value = new_value; - - // Run units SET_TRACE - step = DO_MASK; - process_packages(); - step = DO_Y_FEATHER; - process_packages(); - step = DO_X_FEATHER; - process_packages(); step = DO_APPLY; process_packages(); SET_TRACE - - } void MaskEngine::init_packages() diff --git a/cinelerra-5.1/cinelerra/maskengine.h b/cinelerra-5.1/cinelerra/maskengine.h index 782c3cc7..8ec51716 100644 --- a/cinelerra-5.1/cinelerra/maskengine.h +++ b/cinelerra-5.1/cinelerra/maskengine.h @@ -30,6 +30,7 @@ #include "mutex.inc" #include "vframe.inc" +typedef uint16_t temp_t; // temp is A16 class MaskEngine; @@ -37,11 +38,11 @@ class MaskEngine; enum { DO_MASK, - DO_X_FEATHER, - DO_Y_FEATHER, + DO_FEATHER, DO_APPLY }; + class MaskPackage : public LoadPackage { public: @@ -57,30 +58,25 @@ public: MaskUnit(MaskEngine *engine); ~MaskUnit(); + void draw_line(int v, int x1, int y1, int x2, int y2); + void draw_fill(int v); + void draw_feather(int ix1,int iy1, int ix2,int iy2); + void draw_spot(int ix, int iy); void process_package(LoadPackage *package); - void draw_line_clamped(VFrame *frame, - int x1, int y1, int x2, int y2, unsigned char value); - void do_feather(VFrame *output, VFrame *input, - double feather, int start_y, int end_y, int start_x, int end_x); - void blur_strip(double *val_p, double *val_m, - double *dst, double *src, int size, int max); - - double n_p[5], n_m[5]; - double d_p[5], d_m[5]; - double bd_p[5], bd_m[5]; MaskEngine *engine; - VFrame *temp; + int start_y, end_y; + int mask_model; + float v, r; + temp_t *spot; }; - class MaskEngine : public LoadServer { public: MaskEngine(int cpus); ~MaskEngine(); - void do_mask(VFrame *output, // Position relative to project, compensated for playback direction int64_t start_position_project, @@ -94,18 +90,17 @@ public: void init_packages(); LoadClient* new_client(); LoadPackage* new_package(); + void draw_edge(MaskEdge &edge, MaskPointSet &points); VFrame *output; -// State of last mask - VFrame *mask; -// Temporary for feathering - VFrame *temp_mask; - ArrayList*> point_sets; - int mode; - int step; - double feather; + VFrame *mask, *temp; + MaskEdges edges; + MaskPointSets point_sets; + ArrayList faders; + ArrayList feathers; + int step, total_submasks; int recalculate; - int value; + temp_t fade[SUBMASKS+1]; }; diff --git a/cinelerra-5.1/cinelerra/playback3d.C b/cinelerra-5.1/cinelerra/playback3d.C index eed42cd9..aefafc8e 100644 --- a/cinelerra-5.1/cinelerra/playback3d.C +++ b/cinelerra-5.1/cinelerra/playback3d.C @@ -259,39 +259,50 @@ static const char *read_texture_frag = " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" "}\n"; -static const char *multiply_mask4_frag = - "uniform sampler2D tex;\n" - "uniform sampler2D tex1;\n" - "uniform float scale;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" - " gl_FragColor.a *= texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n" +static const char *in_vertex_frag = + "#version 430 // vertex shader\n" + "in vec3 in_pos;\n" + "void main() {\n" + " gl_Position = vec4(in_pos-vec3(0.5,0.5,0.), .5);\n" "}\n"; -static const char *multiply_mask3_frag = +static const char *feather_frag = + "#version 430\n" + "layout(location=0) out vec4 color;\n" "uniform sampler2D tex;\n" - "uniform sampler2D tex1;\n" - "uniform float scale;\n" - "uniform bool is_yuv;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" - " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n" - " gl_FragColor.rgb *= vec3(a, a, a);\n" +// apparently, only doubles index properly in shared buffers + "buffer buf { dvec2 points[]; };\n" + "uniform float r;\n" + "uniform float v;\n" + "void main() {\n" + " vec2 tex_st = gl_FragCoord.xy/textureSize(tex,0);\n" + " color = texture(tex, tex_st);\n" + " if( r==0. ) return;\n" + " float rv = r*v>0. ? 1 : -1;\n" + " float rr = r*r, dr = 1./rr;\n" + " float vv = v>=0 ? 1.-v : 1.+v;\n" + " float fg = rv>=0 ? vv : 1.;\n" + " float bg = rv>=0 ? 1. : vv;\n" + " int len = points.length();\n" + " for( int i=0; i= rr ) continue;\n" + " float d = dd*dr;\n" + " float a = (1.-d)*fg + d*bg;\n" + " if( rv*(color.a-a) > 0 ) color = vec4(a);\n" + " }\n" "}\n"; -static const char *multiply_yuvmask3_frag = +static const char *alpha_frag = "uniform sampler2D tex;\n" - "uniform sampler2D tex1;\n" - "uniform float scale;\n" - "void main()\n" - "{\n" + "uniform sampler2D tex2;\n" + "uniform vec2 tex2_dimensions;\n" + "void main() {\n" \ " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n" - " float a = texture2D(tex1, gl_TexCoord[0].st / vec2(scale, scale)).r;\n" - " gl_FragColor.gb -= vec2(0.5, 0.5);\n" - " gl_FragColor.rgb *= vec3(a, a, a);\n" - " gl_FragColor.gb += vec2(0.5, 0.5);\n" + " vec4 canvas = texture2D(tex2, gl_FragCoord.xy / tex2_dimensions);\n" + " gl_FragColor.a = canvas.a;\n" "}\n"; static const char *fade_rgba_frag = @@ -357,26 +368,32 @@ void Playback3DCommand::copy_from(BC_SynchronousCommand *command) BC_SynchronousCommand::copy_from(command); } - -///static void glDebugCallback(GLenum src, GLenum typ, GLuint id, -/// GLenum svy, GLsizei len, const GLchar* msg, void* dat) -//static void glDebugCallback(unsigned int src, unsigned int typ, unsigned int id, -// unsigned int svy, int len, const char* msg, const void* dat) -//{ -// printf("glDebug: %d:%d; %d/%d %s\n",src,typ,id,svy,msg); -//} - +//#define GL_BUG 1 +#ifdef GL_BUG +static void GLAPIENTRY glDebugCallback(GLenum source, GLenum type, + GLuint id, GLenum severity, GLsizei length, const GLchar* message, + const void* userParam) +{ + fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", + ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ), + type, severity, message ); +} +#endif Playback3D::Playback3D(MWindow *mwindow) : BC_Synchronous() { this->mwindow = mwindow; temp_texture = 0; - //Enabling OpenGL debug output on nVidia drivers -// glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); -// glEnable(GL_DEBUG_OUTPUT); -// glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); -// glDebugMessageCallback(glDebugCallback, 0); +#ifdef GL_BUG + //Enabling OpenGL debug output + // this does not work + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glDebugMessageCallback(glDebugCallback, 0); + glEnable(GL_DEBUG_OUTPUT); +#endif } Playback3D::~Playback3D() @@ -469,7 +486,7 @@ void Playback3D::copy_from(Canvas *canvas, void Playback3D::copy_from_sync(Playback3DCommand *command) { #ifdef HAVE_GL - BC_WindowBase *window = + BC_WindowBase *window = command->canvas->lock_canvas("Playback3D::copy_from_sync"); if( window ) { window->enable_opengl(); @@ -1149,33 +1166,123 @@ void Playback3D::do_mask(Canvas *canvas, } +void Playback3D::draw_spots(MaskSpots &spots, int ix1,int iy1, int ix2,int iy2) +{ + int x1 = iy1 < iy2 ? ix1 : ix2; + int y1 = iy1 < iy2 ? iy1 : iy2; + int x2 = iy1 < iy2 ? ix2 : ix1; + int y2 = iy1 < iy2 ? iy2 : iy1; + + int x = x1, y = y1; + int dx = x2-x1, dy = y2-y1; + int dx2 = 2*dx, dy2 = 2*dy; + if( dx < 0 ) dx = -dx; + int m = dx > dy ? dx : dy, n = m; + if( dy >= dx ) { + if( dx2 >= 0 ) do { /* +Y, +X */ + spots.append(x, y++); + if( (m -= dx2) < 0 ) { m += dy2; ++x; } + } while( --n >= 0 ); + else do { /* +Y, -X */ + spots.append(x, y++); + if( (m += dx2) < 0 ) { m += dy2; --x; } + } while( --n >= 0 ); + } + else { + if( dx2 >= 0 ) do { /* +X, +Y */ + spots.append(x++, y); + if( (m -= dy2) < 0 ) { m += dx2; ++y; } + } while( --n >= 0 ); + else do { /* -X, +Y */ + spots.append(x--, y); + if( (m -= dy2) < 0 ) { m -= dx2; ++y; } + } while( --n >= 0 ); + } +} #ifdef HAVE_GL -struct Vertex : ListItem +class fb_texture : public BC_Texture { - GLdouble c[3]; +public: + fb_texture(int w, int h, int colormodel); + ~fb_texture(); + void bind(int texture_unit); + void read_screen(int x, int y, int w, int h); + void set_output_texture(); + GLuint fb, rb; }; -// this list is only used from the main thread, no locking needed -// this must be a list so that pointers to allocated entries remain valid -// when new entries are added -static List *vertex_cache = 0; - -static void combine_callback(GLdouble coords[3], - GLdouble *vertex_data[4], - GLfloat weight[4], - GLdouble **dataOut) + +fb_texture::fb_texture(int w, int h, int colormodel) + : BC_Texture(w, h, colormodel) { -// can't use malloc here; GLU doesn't delete the memory for us! - Vertex* vertex = vertex_cache->append(); - vertex->c[0] = coords[0]; - vertex->c[1] = coords[1]; - vertex->c[2] = coords[2]; -// we don't need to interpolate anything - - *dataOut = &vertex->c[0]; + fb = 0; rb = 0; +// glGenRenderbuffers(1, &rb); +// glBindRenderbuffer(GL_RENDERBUFFER, rb); +// glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, get_texture_w(), get_texture_w()); + glGenFramebuffers(1, &fb); + glBindFramebuffer(GL_FRAMEBUFFER, fb); +// glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb); } -#endif +fb_texture::~fb_texture() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, (GLuint *)&fb); +// glBindRenderbuffer(GL_RENDERBUFFER, 0); +// glGenRenderbuffers(1, &rb); +} + +void fb_texture::bind(int texture_unit) +{ + glBindFramebuffer(GL_FRAMEBUFFER, fb); +// glBindRenderbuffer(GL_RENDERBUFFER, rb); + BC_Texture::bind(texture_unit); +} + +void fb_texture::read_screen(int x, int y, int w, int h) +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glReadBuffer(GL_BACK); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, x,y, w,h); +} + +void fb_texture::set_output_texture() +{ + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, get_texture_id(), 0); + GLenum dbo[1] = { GL_COLOR_ATTACHMENT0, }; // bind layout(location=0) out vec4 color; + glDrawBuffers(1, dbo); + int ret = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if( ret != GL_FRAMEBUFFER_COMPLETE ) { + printf("glDrawBuffer error 0x%04x\n", ret); + return; + } +} + +static void combineData(GLdouble coords[3], + GLdouble *vertex_data[4], GLfloat weight[4], + GLdouble **outData, void *data) +{ + ArrayList *invented = (ArrayList *)data; + GLdouble *vertex = new double[6]; + invented->append(vertex); + vertex[0] = coords[0]; + vertex[1] = coords[1]; + vertex[2] = coords[2]; + for( int i=3; i<6; ++i ) { + vertex[i] = weight[0] * vertex_data[0][i] + + weight[1] * vertex_data[1][i] + + weight[2] * vertex_data[2][i] + + weight[3] * vertex_data[3][i]; + } + *outData = vertex; +} + +// dbug +static void zglBegin(GLenum mode) { glBegin(mode); } +static void zglEnd() { glEnd(); } +static void zglVertex3dv(const GLdouble *v) { glVertex3dv(v); } + +#endif void Playback3D::do_mask_sync(Playback3DCommand *command) { @@ -1187,7 +1294,7 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) switch( command->frame->get_opengl_state() ) { case VFrame::RAM: -// Time to upload to the texture +// upload frame to the texture command->frame->to_texture(); break; @@ -1198,99 +1305,61 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) command->frame->screen_to_texture(); break; } -// Create PBuffer and draw the mask on it - command->frame->enable_opengl(); // Initialize coordinate system + command->frame->enable_opengl(); + command->frame->init_screen(); + int color_model = command->frame->get_color_model(); int w = command->frame->get_w(); int h = command->frame->get_h(); - command->frame->init_screen(); - -// Clear screen - glDisable(GL_TEXTURE_2D); - float value = command->keyframe->value / 100.f; - if( value >= 0 ) { - if( command->default_auto->mode == MASK_MULTIPLY_ALPHA ) { - glClearColor(0.f, 0.f, 0.f, 0.f); - glColor4f(value, value, value, 1.f); - } - else { - glClearColor(1.f, 1.f, 1.f, 1.f); - value = 1.f - value; - glColor4f(value, value, value, 1.f); - } - } - else { - if( command->default_auto->mode == MASK_MULTIPLY_ALPHA ) { - value = -value; - glClearColor(value, value, value, 1.f); - glColor4f(0.f, 0.f, 0.f, 0.f); - } - else { - value = 1.f + value; - glClearColor(value, value, value, 1.f); - glColor4f(1.f, 1.f, 1.f, 1.f); - } - } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - -// Draw mask with scaling to simulate feathering - GLUtesselator *tesselator = gluNewTess(); - gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); - gluTessCallback(tesselator, GLU_TESS_VERTEX, (GLvoid (*) ( )) &glVertex3dv); - gluTessCallback(tesselator, GLU_TESS_BEGIN, (GLvoid (*) ( )) &glBegin); - gluTessCallback(tesselator, GLU_TESS_END, (GLvoid (*) ( )) &glEnd); - gluTessCallback(tesselator, GLU_TESS_COMBINE, (GLvoid (*) ( ))&combine_callback); - - vertex_cache = new List; - - + MaskEdges edges; + float faders[SUBMASKS], feathers[SUBMASKS], bg = 1; + MaskPointSet point_set[SUBMASKS]; // Draw every submask as a new polygon int total_submasks = command->keyframe_set->total_submasks( - command->start_position_project, - PLAY_FORWARD); - float scale = command->keyframe->feather + 1; - int display_list = glGenLists(1); - glNewList(display_list, GL_COMPILE); - for(int k = 0; k < total_submasks; k++) - { - gluTessBeginPolygon(tesselator, NULL); - gluTessBeginContour(tesselator); - ArrayList *points = new ArrayList; - command->keyframe_set->get_points(points, - k, - command->start_position_project, - PLAY_FORWARD); + command->start_position_project, PLAY_FORWARD); + + for(int k = 0; k < total_submasks; k++) { + MaskPointSet &points = point_set[k]; + command->keyframe_set->get_points(&points, + k, command->start_position_project, PLAY_FORWARD); + float fader = command->keyframe_set->get_fader( + command->start_position_project, k, PLAY_FORWARD); + float v = fader/100.; + faders[k] = v; + if( v < 0 && (v+=1) < bg ) bg = v; + float feather = command->keyframe_set->get_feather( + command->start_position_project, k, PLAY_FORWARD); + feathers[k] = feather; + } +// clear screen + glDisable(GL_TEXTURE_2D); + glClearColor(bg, bg, bg, bg); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + for(int k = 0; k < total_submasks; k++) { + MaskPointSet &points = point_set[k]; + MaskEdge &edge = *edges.append(new MaskEdge()); int first_point = 0; // Need to tabulate every vertex in persistent memory because // gluTessVertex doesn't copy them. - ArrayList coords; - coords.set_array_delete(); - for(int i = 0; i < points->total; i++) - { - MaskPoint *point1 = points->values[i]; - MaskPoint *point2 = (i >= points->total - 1) ? - points->values[0] : - points->values[i + 1]; + for(int i = 0; i < points.total; i++) { + MaskPoint *point1 = points.values[i]; + MaskPoint *point2 = (i >= points.total - 1) ? + points.values[0] : points.values[i + 1]; float x, y; int segments = 0; - if(point1->control_x2 == 0 && - point1->control_y2 == 0 && - point2->control_x1 == 0 && - point2->control_y1 == 0) + if( point1->control_x2 == 0 && point1->control_y2 == 0 && + point2->control_x1 == 0 && point2->control_y1 == 0 ) segments = 1; - float x0 = point1->x; - float y0 = point1->y; + float x0 = point1->x, y0 = point1->y; float x1 = point1->x + point1->control_x2; float y1 = point1->y + point1->control_y2; float x2 = point2->x + point2->control_x1; float y2 = point2->y + point2->control_y1; - float x3 = point2->x; - float y3 = point2->y; + float x3 = point2->x, y3 = point2->y; // forward differencing bezier curves implementation taken from GPL code at // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3 @@ -1321,8 +1390,7 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) // the absolute maximum acceleration must occur at either the beginning // (|c2|) or the end (|c2+c3|). Our bounds here are a little more // conservative than that, but that's okay. - if (segments == 0) - { + if (segments == 0) { float maxaccel1 = fabs(2*cy2) + fabs(6*cy3); float maxaccel2 = fabs(2*cx2) + fabs(6*cx3); @@ -1333,123 +1401,124 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) segments = int(1/h); } - for(int j = 0; j <= segments; j++) - { + for(int j = 0; j <= segments; j++) { float t = (float)j / segments; x = cx0 + t*(cx1 + t*(cx2 + t*cx3)); y = cy0 + t*(cy1 + t*(cy2 + t*cy3)); - if(j > 0 || first_point) - { - GLdouble *coord = new GLdouble[3]; - coord[0] = x / scale; - coord[1] = -h + y / scale; - coord[2] = 0; - coords.append(coord); + if(j > 0 || first_point) { + edge.append(x, y - h); first_point = 0; } } } - -// Now that we know the total vertices, send them to GLU - for(int i = 0; i < coords.total; i++) - gluTessVertex(tesselator, coords.values[i], coords.values[i]); - - gluTessEndContour(tesselator); - gluTessEndPolygon(tesselator); - points->remove_all_objects(); - delete points; - coords.remove_all_objects(); - } - glEndList(); - glCallList(display_list); - glDeleteLists(display_list, 1); - gluDeleteTess(tesselator); - - delete vertex_cache; - vertex_cache = 0; - - glColor4f(1, 1, 1, 1); - - -// Read mask into temporary texture. -// For feathering, just read the part of the screen after the downscaling. - - - float w_scaled = w / scale; - float h_scaled = h / scale; -// Don't vary the texture size according to scaling because that -// would waste memory. -// This enables and binds the temporary texture. - glActiveTexture(GL_TEXTURE1); - BC_Texture::new_texture(&temp_texture, - w, - h, - command->frame->get_color_model()); - temp_texture->bind(1); - glReadBuffer(GL_BACK); - -// Need to add extra size to fill in the bottom right - glCopyTexSubImage2D(GL_TEXTURE_2D, - 0, - 0, - 0, - 0, - 0, - (int)MIN(w_scaled + 2, w), - (int)MIN(h_scaled + 2, h)); - - command->frame->bind_texture(0); - - -// For feathered masks, use a shader to multiply. -// For unfeathered masks, we could use a stencil buffer -// for further optimization but we also need a YUV algorithm. - unsigned int frag_shader = 0; - switch(temp_texture->get_texture_components()) { - case 3: - frag_shader = VFrame::make_shader(0, - command->frame->get_color_model() == BC_YUV888 ? - multiply_yuvmask3_frag : multiply_mask3_frag, - 0); - break; - case 4: - frag_shader = VFrame::make_shader(0, multiply_mask4_frag, 0); - break; + if( edge.size() > 0 ) { +// draw polygon + float fader = faders[k]; + float v = fader < 0 ? 1 : 1-fader; + glColor4f(v, v, v, v); + int display_list = glGenLists(1); + glNewList(display_list, GL_COMPILE); +#if 0 + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glBegin(GL_POLYGON); + MaskCoord *c = &edge[0]; + for( int i=edge.size(); --i>=0; ++c ) + glVertex2f(c->x, c->y); + glEnd(); +#else + GLUtesselator *tess = gluNewTess(); + gluTessCallback(tess, GLU_TESS_VERTEX,(GLvoid (*)()) &zglVertex3dv); + gluTessCallback(tess, GLU_TESS_BEGIN,(GLvoid (*)()) &zglBegin); + gluTessCallback(tess, GLU_TESS_END,(GLvoid (*)()) &zglEnd); + gluTessCallback(tess, GLU_TESS_COMBINE_DATA,(GLvoid (*)()) &combineData); + ArrayList invented; + invented.set_array_delete(); + + gluTessBeginPolygon(tess, &invented); + gluTessBeginContour(tess); + MaskCoord *c = &edge[0]; + for( int i=edge.size(); --i>=0; ++c ) + gluTessVertex(tess, (GLdouble *)c, c); + gluTessEndContour(tess); + gluTessEndPolygon(tess); + gluDeleteTess(tess); + invented.remove_all_objects(); +#endif + glEndList(); + glCallList(display_list); + glDeleteLists(1, display_list); + } } - if( frag_shader ) { - int variable; - glUseProgram(frag_shader); - if((variable = glGetUniformLocation(frag_shader, "tex")) >= 0) - glUniform1i(variable, 0); - if((variable = glGetUniformLocation(frag_shader, "tex1")) >= 0) - glUniform1i(variable, 1); - if((variable = glGetUniformLocation(frag_shader, "scale")) >= 0) - glUniform1f(variable, scale); +// in/out textures + fb_texture *in = new fb_texture(w, h, color_model); + in->bind(0); + in->read_screen(0,0, w,h); + fb_texture *out = new fb_texture(w, h, color_model); + + unsigned int frag_shader = + VFrame::make_shader(0, in_vertex_frag, feather_frag, 0); + if( frag_shader > 0 ) { + GLuint points[1]; + glGenBuffers(1, points); + for(int k = 0; k < total_submasks; k++) { + MaskEdge &edge = *edges[k]; + if( !edge.size() ) continue; + if( !faders[k] ) continue; + if( !feathers[k] ) continue; + MaskSpots spots; + for( int i=0; ibind(0); + glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0); + out->set_output_texture(); + glViewport(0,0, w,h); + out->draw_texture(0,0, w,h, 0,0, w,h); + glUseProgram(0); + fb_texture *t = in; in = out; out = t; + } + glDeleteBuffers(1, points); } + glDrawBuffers(0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - -// Write texture to PBuffer with multiply and scaling for feather. - - - command->frame->draw_texture(0, 0, w, h, 0, 0, w, h); + unsigned int shader = VFrame::make_shader(0, alpha_frag, 0); + glUseProgram(shader); + if( shader > 0 ) { + command->frame->bind_texture(0); + in->BC_Texture::bind(1); + glUniform1i(glGetUniformLocation(shader, "tex"), 0); + glUniform1i(glGetUniformLocation(shader, "tex2"), 1); + glUniform2f(glGetUniformLocation(shader, "tex2_dimensions"), + (float)in->get_texture_w(), + (float)in->get_texture_h()); +// if( BC_CModels::components(color_model ) == 4) { +// glEnable(GL_BLEND); +// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +// } + } + command->frame->draw_texture(); command->frame->set_opengl_state(VFrame::SCREEN); - - -// Disable temp texture glUseProgram(0); - - glActiveTexture(GL_TEXTURE1); + delete in; + delete out; +// Default drawable glDisable(GL_TEXTURE_2D); - delete temp_texture; - temp_texture = 0; - + glColor4f(1, 1, 1, 1); glActiveTexture(GL_TEXTURE0); - glDisable(GL_TEXTURE_2D); - -// Default drawable window->enable_opengl(); } command->canvas->unlock_canvas(); @@ -1457,14 +1526,6 @@ void Playback3D::do_mask_sync(Playback3DCommand *command) } - - - - - - - - void Playback3D::convert_cmodel(Canvas *canvas, VFrame *output, int dst_cmodel) @@ -1498,7 +1559,7 @@ void Playback3D::convert_cmodel(Canvas *canvas, void Playback3D::convert_cmodel_sync(Playback3DCommand *command) { #ifdef HAVE_GL - BC_WindowBase *window = + BC_WindowBase *window = command->canvas->lock_canvas("Playback3D::convert_cmodel_sync"); if( window ) { window->enable_opengl(); @@ -1688,7 +1749,7 @@ int Playback3D::run_plugin(Canvas *canvas, PluginClient *client) void Playback3D::run_plugin_sync(Playback3DCommand *command) { - BC_WindowBase *window = + BC_WindowBase *window = command->canvas->lock_canvas("Playback3D::run_plugin_sync"); if( window ) { window->enable_opengl(); diff --git a/cinelerra-5.1/cinelerra/playback3d.h b/cinelerra-5.1/cinelerra/playback3d.h index 6a38d7aa..ba385716 100644 --- a/cinelerra-5.1/cinelerra/playback3d.h +++ b/cinelerra-5.1/cinelerra/playback3d.h @@ -29,7 +29,7 @@ #include "bcwindowbase.inc" #include "canvas.inc" #include "condition.inc" -#include "maskauto.inc" +#include "maskauto.h" #include "maskautos.inc" #include "mutex.inc" #include "mwindow.inc" @@ -285,13 +285,9 @@ public: void do_fade(Canvas *canvas, VFrame *frame, float fade); void convert_cmodel(Canvas *canvas, VFrame *output, int dst_cmodel); - void do_mask(Canvas *canvas, - VFrame *output, - int64_t start_position_project, - MaskAutos *keyframe_set, - MaskAuto *keyframe, - MaskAuto *default_auto); - + void draw_spots(MaskSpots &spots, int ix1,int iy1, int ix2,int iy2); + void do_mask(Canvas *canvas, VFrame *output, int64_t start_position_project, + MaskAutos *keyframe_set, MaskAuto *keyframe, MaskAuto *default_auto); // Overlay a virtual node on the framebuffer void overlay(Canvas *canvas, diff --git a/cinelerra-5.1/cinelerra/virtualvnode.C b/cinelerra-5.1/cinelerra/virtualvnode.C index dd7e4fe7..c96b51c9 100644 --- a/cinelerra-5.1/cinelerra/virtualvnode.C +++ b/cinelerra-5.1/cinelerra/virtualvnode.C @@ -332,7 +332,7 @@ void VirtualVNode::render_mask(VFrame *output_temp, int submask_points = mask->points.total; if(submask_points > 1) total_points += submask_points; } - +/* //printf("VirtualVNode::render_mask 1 %d %d\n", total_points, keyframe->value); // Ignore certain masks if(total_points <= 2 || @@ -347,7 +347,7 @@ void VirtualVNode::render_mask(VFrame *output_temp, output_temp->clear_frame(); return; } - +*/ if(use_opengl) { if( !((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->can_mask( start_position_project, keyframe_set) ) diff --git a/cinelerra-5.1/guicast/bcsynchronous.C b/cinelerra-5.1/guicast/bcsynchronous.C index 0bc4f104..9e49bf56 100644 --- a/cinelerra-5.1/guicast/bcsynchronous.C +++ b/cinelerra-5.1/guicast/bcsynchronous.C @@ -46,16 +46,21 @@ TextureID::TextureID(int window_id, int id, int w, int h, int components) in_use = 1; } -ShaderID::ShaderID(int window_id, unsigned int handle, char *source) +ShaderID::ShaderID(int window_id, unsigned int handle, + const char *vert, const char *frag) { this->window_id = window_id; this->handle = handle; - this->source = strdup(source); + if( !vert ) vert = ""; + if( !frag ) frag = ""; + this->vert = cstrdup(vert); + this->frag = cstrdup(frag); } ShaderID::~ShaderID() { - free(source); + delete [] vert; + delete [] frag; } #ifdef HAVE_GL @@ -240,37 +245,24 @@ void BC_Synchronous::handle_command(BC_SynchronousCommand *command) void BC_Synchronous::put_texture(int id, int w, int h, int components) { - if(id >= 0) - { + if( id >= 0 ) { table_lock->lock("BC_Resources::put_texture"); // Search for duplicate - for(int i = 0; i < texture_ids.total; i++) - { + for( int i = 0; i < texture_ids.total; i++ ) { TextureID *ptr = texture_ids.values[i]; - if(ptr->window_id == current_window->get_id() && - ptr->id == id) - { + if( ptr->window_id == current_window->get_id() && ptr->id == id ) { printf("BC_Synchronous::push_texture: texture exists\n" "exists: window=%d id=%d w=%d h=%d\n" "new: window=%d id=%d w=%d h=%d\n", - ptr->window_id, - ptr->id, - ptr->w, - ptr->h, - current_window->get_id(), - id, - w, - h); + ptr->window_id, ptr->id, ptr->w, ptr->h, + current_window->get_id(), id, w, h); table_lock->unlock(); return; } } TextureID *new_id = new TextureID(current_window->get_id(), - id, - w, - h, - components); + id, w, h, components); texture_ids.append(new_id); table_lock->unlock(); } @@ -317,30 +309,31 @@ void BC_Synchronous::release_texture(int window_id, int id) -unsigned int BC_Synchronous::get_shader(char *source, int *got_it) +int BC_Synchronous::get_shader(unsigned int *handle, + const char *vert, const char *frag) { + unsigned int shader = 0, ret = 0; + if( !vert ) vert = ""; + if( !frag ) frag = ""; table_lock->lock("BC_Resources::get_shader"); - for(int i = 0; i < shader_ids.total; i++) - { - if(shader_ids.values[i]->window_id == current_window->get_id() && - !strcmp(shader_ids.values[i]->source, source)) - { - unsigned int result = shader_ids.values[i]->handle; - table_lock->unlock(); - *got_it = 1; - return result; + for( int i=0; !ret && iget_id() && + !strcmp(sp.vert, vert) && !strcmp(sp.frag, frag) ) { + shader = shader_ids.values[i]->handle; + ret = 1; } } table_lock->unlock(); - *got_it = 0; - return 0; + *handle = shader; + return ret; } void BC_Synchronous::put_shader(unsigned int handle, - char *source) + const char *vert, const char *frag) { table_lock->lock("BC_Resources::put_shader"); - shader_ids.append(new ShaderID(current_window->get_id(), handle, source)); + shader_ids.append(new ShaderID(current_window->get_id(), handle, vert, frag)); table_lock->unlock(); } @@ -348,18 +341,18 @@ void BC_Synchronous::dump_shader(unsigned int handle) { int got_it = 0; table_lock->lock("BC_Resources::dump_shader"); - for(int i = 0; i < shader_ids.total; i++) - { - if(shader_ids.values[i]->handle == handle) - { + for( int i=0; ihandle == handle ) { printf("BC_Synchronous::dump_shader\n" - "%s", shader_ids.values[i]->source); + "vert: %s\nfrag: %s\n", + shader_ids[i]->vert, shader_ids[i]->frag); got_it = 1; break; } } table_lock->unlock(); - if(!got_it) printf("BC_Synchronous::dump_shader couldn't find %d\n", handle); + if( !got_it ) + printf("BC_Synchronous::dump_shader couldn't find %d\n", handle); } void BC_Synchronous::delete_window(BC_WindowBase *window) diff --git a/cinelerra-5.1/guicast/bcsynchronous.h b/cinelerra-5.1/guicast/bcsynchronous.h index 26d6e7f4..db81a20c 100644 --- a/cinelerra-5.1/guicast/bcsynchronous.h +++ b/cinelerra-5.1/guicast/bcsynchronous.h @@ -72,11 +72,12 @@ public: class ShaderID { public: - ShaderID(int window_id, unsigned int handle, char *source); + ShaderID(int window_id, unsigned int handle, + const char *vert, const char *frag); ~ShaderID(); // Should really use an MD5 to compare sources but this is easiest. - char *source; + char *vert, *frag; int window_id; unsigned int handle; }; @@ -182,13 +183,9 @@ public: // Can be called outside synchronous loop. void release_texture(int window_id, int id); -// Get the shader by window_id and source comparison if it exists. -// Not run in OpenGL thread because it has its own lock. -// Sets *got_it to 1 on success. - unsigned int get_shader(char *source, int *got_it); -// Add a new shader program by title if it doesn't exist. -// Doesn't check if it already exists. - void put_shader(unsigned int handle, char *source); +// Get the shader by window_id and vertex/fragment source comparison + int get_shader(unsigned int *handle, const char *vert, const char *frag); + void put_shader(unsigned int handle, const char *vert, const char *frag); void dump_shader(unsigned int handle); diff --git a/cinelerra-5.1/guicast/bctexture.C b/cinelerra-5.1/guicast/bctexture.C index 7cebeefc..1d0f7e88 100644 --- a/cinelerra-5.1/guicast/bctexture.C +++ b/cinelerra-5.1/guicast/bctexture.C @@ -100,8 +100,8 @@ void BC_Texture::create_texture(int w, int h, int colormodel) BC_WindowBase::get_synchronous()->release_texture( window_id, texture_id); - texture_id = -1; - window_id = -1; + texture_id = -1; + window_id = -1; } @@ -124,13 +124,9 @@ void BC_Texture::create_texture(int w, int h, int colormodel) glGenTextures(1, (GLuint*)&texture_id); glBindTexture(GL_TEXTURE_2D, (GLuint)texture_id); glEnable(GL_TEXTURE_2D); - if(texture_components == 4) - glTexImage2D(GL_TEXTURE_2D, 0, 4, texture_w, texture_h, + int internal_format = texture_components == 4 ? GL_RGBA8 : GL_RGB8 ; + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture_w, texture_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - else - glTexImage2D(GL_TEXTURE_2D, 0, 3, texture_w, texture_h, - 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - window_id = BC_WindowBase::get_synchronous()->current_window->get_id(); BC_WindowBase::get_synchronous()->put_texture(texture_id, texture_w, texture_h, texture_components); @@ -241,12 +237,12 @@ static void write_ppm(uint8_t *tp, int w, int h, const char *fmt, ...) } #endif -void BC_Texture::write_tex(const char *fn) +void BC_Texture::write_tex(const char *fn, int id) { #ifdef HAVE_GL int prev_id = -1; glGetIntegerv(GL_ACTIVE_TEXTURE, &prev_id); - glActiveTexture(GL_TEXTURE31); + glActiveTexture(GL_TEXTURE0+id); glBindTexture(GL_TEXTURE_2D, texture_id); glEnable(GL_TEXTURE_2D); int w = get_texture_w(), h = get_texture_h(); @@ -258,4 +254,10 @@ void BC_Texture::write_tex(const char *fn) #endif } +void BC_Texture::write_tex(const char *fn) +{ +#ifdef HAVE_GL + write_tex(fn, 31); +#endif +} diff --git a/cinelerra-5.1/guicast/bctexture.h b/cinelerra-5.1/guicast/bctexture.h index 82fcf83a..1ac9f084 100644 --- a/cinelerra-5.1/guicast/bctexture.h +++ b/cinelerra-5.1/guicast/bctexture.h @@ -66,6 +66,7 @@ public: float in_x1, float in_y1, float in_x2, float in_y2, float out_x1, float out_y1, float out_x2, float out_y2); + void write_tex(const char *fn, int id); void write_tex(const char *fn); private: void clear_objects(); diff --git a/cinelerra-5.1/guicast/bcwindow3d.C b/cinelerra-5.1/guicast/bcwindow3d.C index 57118e74..902f65e9 100644 --- a/cinelerra-5.1/guicast/bcwindow3d.C +++ b/cinelerra-5.1/guicast/bcwindow3d.C @@ -237,14 +237,14 @@ void BC_WindowBase::flip_opengl() #endif } -unsigned int BC_WindowBase::get_shader(char *source, int *got_it) +int BC_WindowBase::get_shader(unsigned int *handle, const char *vert, const char *frag) { - return get_resources()->get_synchronous()->get_shader(source, got_it); + return get_resources()->get_synchronous()->get_shader(handle, vert, frag); } -void BC_WindowBase::put_shader(unsigned int handle, char *source) +void BC_WindowBase::put_shader(unsigned int handle, const char *vert, const char *frag) { - get_resources()->get_synchronous()->put_shader(handle, source); + get_resources()->get_synchronous()->put_shader(handle, vert, frag); } int BC_WindowBase::get_opengl_server_version() diff --git a/cinelerra-5.1/guicast/bcwindowbase.C b/cinelerra-5.1/guicast/bcwindowbase.C index 5d177c93..21d6bd37 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.C +++ b/cinelerra-5.1/guicast/bcwindowbase.C @@ -149,7 +149,11 @@ BC_WindowBase::~BC_WindowBase() //printf("delete glx=%08x, win=%08x %s\n", (unsigned)glx_win, (unsigned)win, title); #ifdef HAVE_GL if( get_resources()->get_synchronous() && glx_win != 0 ) { + if( window_type == MAIN_WINDOW ) + unlock_window(); get_resources()->get_synchronous()->delete_window(this); + if( window_type == MAIN_WINDOW ) + lock_window("BC_WindowBase::delete_window"); } #endif XDestroyWindow(top_level->display, win); diff --git a/cinelerra-5.1/guicast/bcwindowbase.h b/cinelerra-5.1/guicast/bcwindowbase.h index cd4dcd08..f231c6d2 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.h +++ b/cinelerra-5.1/guicast/bcwindowbase.h @@ -237,10 +237,9 @@ public: void disable_opengl(); void flip_opengl(); -// Calls the BC_Synchronous version of the function with the window_id. -// Not run in OpenGL thread because it has its own lock. - unsigned int get_shader(char *title, int *got_it); - void put_shader(unsigned int handle, char *title); +// Calls the BC_Synchronous version of the function + int get_shader(unsigned int *handle, const char *vert, const char *frag); + void put_shader(unsigned int handle, const char *vert, const char *frag); int get_opengl_server_version(); int flash(int x, int y, int w, int h, int flush = 1); diff --git a/cinelerra-5.1/guicast/vframe3d.C b/cinelerra-5.1/guicast/vframe3d.C index 649a3b19..30c1b2be 100644 --- a/cinelerra-5.1/guicast/vframe3d.C +++ b/cinelerra-5.1/guicast/vframe3d.C @@ -307,103 +307,136 @@ void VFrame::init_screen() init_screen(get_w(), get_h()); } -static int print_error(char *source, unsigned int object, int is_program) -{ + + #ifdef HAVE_GL - char string[BCTEXTLEN]; + +static int print_error(const char *text, unsigned int object, int is_program) +{ + char info[BCTEXTLEN]; int len = 0; - if(is_program) - glGetProgramInfoLog(object, BCTEXTLEN, &len, string); + if( is_program ) + glGetProgramInfoLog(object, BCTEXTLEN, &len, info); else - glGetShaderInfoLog(object, BCTEXTLEN, &len, string); - if(len > 0) printf("Playback3D::print_error:\n%s\n%s\n", source, string); - if(len > 0) return 1; -#endif - return 0; + glGetShaderInfoLog(object, BCTEXTLEN, &len, info); + if( len > 0 ) printf("Playback3D::print_error:\n%s\n%s\n", text, info); + return !len ? 0 : 1; } - - -// call as: -// make_shader(0, frag1, .., fragn, 0); -// or make_shader(fragments); - -unsigned int VFrame::make_shader(const char **fragments, ...) +static char *shader_segs(const char **segs, int n) { - unsigned int result = 0; -#ifdef HAVE_GL -// Construct single source file out of arguments - char *program = 0; - int nb_mains = 0; - - int nb_frags = 1; - if( !fragments ) { - va_list list; va_start(list, fragments); - while( va_arg(list, char*) != 0 ) ++nb_frags; - va_end(list); - } - const char *frags[nb_frags], *text = 0; - if( !fragments ) { - va_list list; va_start(list, fragments); - for( int i=0; iget_shader(program, &got_it); - if( !got_it ) { - result = glCreateProgram(); - unsigned int shader = glCreateShader(GL_FRAGMENT_SHADER); - const GLchar *text_ptr = program; - glShaderSource(shader, 1, &text_ptr, NULL); - glCompileShader(shader); - int error = print_error(program, shader, 0); - glAttachShader(result, shader); - glDeleteShader(shader); - glLinkProgram(result); - if( !error ) - error = print_error(program, result, 1); -//printf("BC_WindowBase::make_shader: shader=%d window_id=%d\n", result, -// BC_WindowBase::get_synchronous()->current_window->get_id()); - BC_WindowBase::get_synchronous()->put_shader(result, program); + if( ret ) { + cp = cstrcat(2, ret, main_prog); + delete [] ret; ret = cp; + } + else + ret = cstrdup(main_prog); + return ret; +} + +static int compile_shader(unsigned int &shader, int type, const GLchar *text) +{ + shader = glCreateShader(type); + glShaderSource(shader, 1, &text, 0); + glCompileShader(shader); + return print_error(text, shader, 0); +} + +static unsigned int build_shader(const char *vert, const char *frag) +{ + int error = 0; + unsigned int vertex_shader = 0; + unsigned int fragment_shader = 0; + unsigned int program = glCreateProgram(); + if( !error && vert ) + error = compile_shader(vertex_shader, GL_VERTEX_SHADER, vert); + if( !error && frag ) + error = compile_shader(fragment_shader, GL_FRAGMENT_SHADER, frag); + if( !error && vert ) glAttachShader(program, vertex_shader); + if( !error && frag ) glAttachShader(program, fragment_shader); + if( !error ) glLinkProgram(program); + if( !error ) error = print_error("link", program, 1); + if( !error ) + BC_WindowBase::get_synchronous()->put_shader(program, vert, frag); + else { + glDeleteProgram(program); + program = 0; + } + return program; +} + +#endif + +// call as: +// make_shader(0, seg1, .., segn, 0); +// or make_shader(&seg); +// line 1: optional comment // vertex shader + +unsigned int VFrame::make_shader(const char **segments, ...) +{ + unsigned int program = 0; +#ifdef HAVE_GL +// Construct single source file out of arguments + int nb_segs = 1; + if( !segments ) { + va_list list; va_start(list, segments); + while( va_arg(list, char*) != 0 ) ++nb_segs; + va_end(list); + } + const char *segs[nb_segs]; + if( !segments ) { + va_list list; va_start(list, segments); + for( int i=0; iget_shader(&program, vert, frag) ) + program = build_shader(vert, frag); + delete [] vert; + delete [] frag; #endif - return result; + return program; } void VFrame::dump_shader(int shader_id) -- 2.26.2