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<MaskPoint*> points;
// Determine the points based on whether
// 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.
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);
}
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(
}
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,
//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");
}
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; i<mask_points.size(); ++i ) {
MaskPoint *point = mask_points.values[i];
return 1;
}
+CWindowMaskDrawMarkers::CWindowMaskDrawMarkers(MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
+ : BC_CheckBox(x, y, ((CWindowMaskGUI*)gui)->markers, _("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;
((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; i<n; ++i ) {
+ SubMask *sub_mask = keyframe->get_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();
}
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);
}
((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; i<n; ++i ) {
+ SubMask *sub_mask = keyframe->get_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();
}
this->gui = gui;
timer = new Timer();
stick = 0;
+ last_v = 0;
}
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);
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;
}
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)
fade = 0;
feather = 0;
focused = 0;
+ markers = 1;
+ boundary = 1;
}
CWindowMaskGUI::~CWindowMaskGUI()
{
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:")));
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));
{
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 ) {
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()
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:
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;
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
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;
};
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;
{
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)) {
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);
this->keyframe = keyframe;
memset(name, 0, sizeof(name));
sprintf(name, "%d", no);
+ this->fader = 100;
+ this->feather = 0;
}
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; i<n; ++i ) {
if(!(*points.get(i) == *ptr.points.get(i)))
return 0;
}
-
return 1;
}
-
int SubMask::operator==(SubMask& ptr)
{
return equivalent(ptr);
{
memset(name, 0, sizeof(name));
strncpy(name, ptr.name, sizeof(name-1));
+ fader = ptr.fader;
+ feather = ptr.feather;
points.remove_all_objects();
//printf("SubMask::copy_from 1 %p %d\n", this, ptr.points.total);
for(int i = 0; i < ptr.points.total; i++)
points.remove_all_objects();
int result = 0;
- while(!result)
- {
- result = file->read_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);
}
}
}
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();
void SubMask::dump()
{
- for(int i = 0; i < points.total; i++)
- {
+ for( int i=0; i<points.size(); ++i ) {
+ printf(" mask: %d, name: %s, fader: %f, feather %f\n", i,
+ name, fader, feather);
printf(" point=%d x=%.2f y=%.2f in_x=%.2f in_y=%.2f out_x=%.2f out_y=%.2f\n",
- 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);
+ 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);
}
}
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;
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; i<masks.size(); ++i ) {
+ if(!(*masks.values[i] == *src->masks.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; i<masks.size(); ++i ) {
- if(!src->get_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));
}
}
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;
{
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; i<mask_auto1->masks.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; j<total_points; ++j ) {
MaskPoint *point = new MaskPoint;
MaskAutos::avg_points(point,
- mask1->points.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);
}
}
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; i<masks.size(); ++i ) {
delete masks.values[i];
masks.values[i] = new SubMask(this, i);
}
SubMask *mask = masks.values[no];
memset(mask->name, 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);
}
}
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; i<masks.size(); ++i )
masks.values[i]->copy(file);
-//printf("MaskAuto::copy 10\n");
- }
file->tag.set_title("/AUTO");
file->append_tag();
void MaskAuto::dump()
{
- printf(" mode=%d value=%d\n", mode, value);
- for(int i = 0; i < masks.size(); i++)
- {
+ for( int i=0; i<masks.size(); ++i ) {
printf(" submask %d\n", i);
masks.values[i]->dump();
}
void MaskAuto::translate_submasks(float translate_x, float translate_y)
{
- for(int i = 0; i < masks.size(); i++)
- {
+ for( int i=0; i<masks.size(); ++i ) {
SubMask *mask = get_submask(i);
- for (int j = 0; j < mask->points.total; j++)
- {
+ for( int j=0; j<mask->points.total; ++j ) {
mask->points.values[j]->x += translate_x;
mask->points.values[j]->y += translate_y;
}
void MaskAuto::scale_submasks(int orig_scale, int new_scale)
{
- for(int i = 0; i < masks.size(); i++)
- {
+ for( int i=0; i<masks.size(); ++i ) {
SubMask *mask = get_submask(i);
- for (int j = 0; j < mask->points.total; j++)
- {
+ for( int j=0; j<mask->points.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;
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);
void dump();
char name[BCSTRLEN];
+ float fader; // 0 - 100
+ float feather; // 0 - 100
ArrayList<MaskPoint*> points;
MaskAuto *keyframe;
};
ArrayList<SubMask*> 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<MaskCoord>
+{
+public:
+ MaskCoord &append() { return ArrayList<MaskCoord>::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<MaskSpot>
+{
+public:
+ MaskSpot &append() { return ArrayList<MaskSpot>::append(); }
+ MaskSpot &append(double x, double y) {
+ MaskSpot &s = append();
+ s.x = x; s.y = y;
+ return s;
+ }
+};
+class MaskEdges : public ArrayList<MaskEdge*> {
+public:
+ MaskEdges() {}
+ ~MaskEdges() { remove_all_objects(); }
+};
+class MaskPointSet : public ArrayList<MaskPoint*>
+{
+public:
+ void clear() { remove_all_objects(); }
+ MaskPointSet() {}
+ ~MaskPointSet() { clear(); }
+};
+class MaskPointSets : public ArrayList<MaskPointSet*>
+{
+public:
+ void clear() { remove_all_objects(); }
+ MaskPointSets() {}
+ ~MaskPointSets() { clear(); }
+};
#endif
class MaskPoint;
class SubMask;
-enum {
+enum { // no longer used, legacy value
MASK_MULTIPLY_ALPHA,
MASK_SUBTRACT_ALPHA,
};
}
-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;
}
int mask_exists(int64_t position, int direction);
// Perform interpolation
void get_points(ArrayList<MaskPoint*> *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);
#include <stdint.h>
#include <string.h>
+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()
{
}
: 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; y<y2; ++i,++y ) {
+ int x = (int)(i*slope + x1);
+ bclamp(x, 0, w1);
+ rows[y][x] = rows[y][x] == v ? 0 : v;
}
}
-void MaskUnit::blur_strip(double *val_p, double *val_m,
- double *dst, double *src, int size, int max)
+void MaskUnit::draw_fill(int v)
{
- double *sp_p = src;
- double *sp_m = src + size - 1;
- double *vp = val_p;
- double *vm = val_m + size - 1;
- double initial_p = sp_p[0];
- double initial_m = sp_m[0];
-
-//printf("MaskUnit::blur_strip %d\n", size);
- for( int k = 0; k < size; k++ ) {
- int terms = (k < 4) ? k : 4;
- int l;
- for( l = 0; l <= terms; l++ ) {
- *vp += n_p[l] * sp_p[-l] - d_p[l] * vp[-l];
- *vm += n_m[l] * sp_m[l] - d_m[l] * vm[l];
- }
-
- for( ; l <= 4; l++) {
- *vp += (n_p[l] - bd_p[l]) * initial_p;
- *vm += (n_m[l] - bd_m[l]) * initial_m;
+ VFrame *temp = engine->temp;
+ int temp_w = temp->get_w();
+ temp_t **rows = (temp_t**)temp->get_rows();
+
+ for( int y=start_y; y<end_y; ++y ) {
+ temp_t *row = rows[y];
+ int value = 0, total = 0;
+ for( int x=0; x<temp_w; ++x )
+ if( row[x] == v ) ++total;
+ if( total < 2 ) continue;
+ if( total & 0x1 ) --total;
+ for( int x=0; x<temp_w; ++x ) {
+ if( row[x]==v && total>0 ) {
+ --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; k<engine->edges.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; i<edge.size(); ++i ) {
+ MaskCoord a = edge[i];
+ MaskCoord b = i<edge.size()-1 ? edge[i+1] : edge[0];
+ draw_line(v, a.x,a.y, b.x,b.y);
+ }
+ draw_fill(v);
}
- if( !temp ) {
- temp = new VFrame(oversampled_package_w, oversampled_package_h, BC_A8, 0);
+// map temp to fader alpha
+ int temp_w = temp->get_w();
+ temp_t **rows = (temp_t**)temp->get_rows();
+ temp_t *fade = engine->fade;
+ for( int y=start_y; y<end_y; ++y ) {
+ temp_t *tp = rows[y];
+ for( int i=temp_w; --i>=0; ++tp ) *tp = fade[*tp];
}
- temp->clear_frame();
-// Draw oversampled region of polygons on temp
- for( int k=0; k<engine->point_sets.total; ++k ) {
- int old_x, old_y;
- unsigned char max = k + 1;
- ArrayList<MaskPoint*> *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; 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 = (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; k<engine->edges.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; i<oversampled_package_h; ++i ) {
- unsigned char *row = (unsigned char*)temp->get_rows()[i];
- int value = 0, total = 0;
-
- for( int j=0; j<oversampled_package_w; ++j )
- if( row[j] == max ) ++total;
-
- if( total > 1 ) {
- if( total & 0x1 ) --total;
- for( int j=0; j<oversampled_package_w; ++j ) {
- if( row[j]==max && total>0 ) {
- --total;
- value = value ? 0 : max;
- }
- else if( value )
- row[j] = value;
- }
- }
+ int n = edge.size();
+ for( int i=0; i<n; ++i ) {
+ MaskCoord &a = edge[i];
+ MaskCoord &b = i<edge.size()-1 ? edge[i+1] : edge[0];
+ draw_feather(a.x,a.y, b.x,b.y);
}
}
-#define DOWNSAMPLE(type, temp_type, value, v) do { \
-for( int y=0; y<ptr->end_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; x<mask_w; ++x ) { \
- temp_type total = 0; \
-/* Accumulate pixel */ \
- for( int k=0; k<OVERSAMPLE; ++k ) { \
- unsigned char *input_vector = input_rows[k] + x * OVERSAMPLE; \
- for( int l=0; l<OVERSAMPLE; ++l ) { \
- total += (input_vector[l] ? value : 0); \
- } \
- } \
-/* Divide pixel */ \
- total /= OVERSAMPLE * OVERSAMPLE; \
- output_row[x] = v; \
- } \
-} } while(0)
- if( engine_value < 0 ) {
- engine_value = -engine_value;
- engine_mode = 1-engine_mode;
- }
-// Downsample polygon
- switch( mask->get_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<end_y; ++y ) { \
+ temp_t *rp = rows[y]; \
+ type *mp = msk_rows[y]; \
+ for( int i=temp_w; --i>=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; y<ptr->end_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; x<mask_w; ++x ) { \
- int m = mask_row[x], n = max-m; \
+ type a = msk_row[x], b = max-a; \
if( components == 4 ) { \
- output_row[x*4 + 3] = output_row[x*4 + 3]*a / max; \
+ out_row[x*4 + 3] = out_row[x*4 + 3]*b / max; \
} \
else { \
- output_row[x*3 + 0] = output_row[x*3 + 0]*a / max; \
- output_row[x*3 + 1] = output_row[x*3 + 1]*a / max; \
- output_row[x*3 + 2] = output_row[x*3 + 2]*a / max; \
+ out_row[x*3 + 0] = out_row[x*3 + 0]*b / max; \
+ out_row[x*3 + 1] = out_row[x*3 + 1]*b / max; \
+ out_row[x*3 + 2] = out_row[x*3 + 2]*b / max; \
if( do_yuv ) { \
- output_row[x*3 + 1] += chroma_offset*b / max; \
- output_row[x*3 + 2] += chroma_offset*b / max; \
+ out_row[x*3 + 1] += chroma_offset*a / max; \
+ out_row[x*3 + 2] += chroma_offset*a / max; \
} \
} \
} \
} break
-#define MASK_ALPHA(mode, a, b) \
-case mode: \
- switch( engine->output->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<MaskPoint*> *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();
}
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(); ++i ) {
+ MaskPoint *ap = points[i];
+ MaskPoint *bp = (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<n && !recalculate; ++i ) {
- ArrayList<MaskPoint*> 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; i<total_submasks && !recalculate; ++i ) {
+ float new_fader = keyframe_set->get_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<MaskPoint*> 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<MaskPoint*> *points = point_sets.values[i];
+ ArrayList<MaskPoint*> *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<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
- 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; i<total_submasks; ++i ) {
+ float fader = keyframe_set->get_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()
#include "mutex.inc"
#include "vframe.inc"
+typedef uint16_t temp_t; // temp is A16
class MaskEngine;
enum
{
DO_MASK,
- DO_X_FEATHER,
- DO_Y_FEATHER,
+ DO_FEATHER,
DO_APPLY
};
+
class MaskPackage : public LoadPackage
{
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,
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<ArrayList<MaskPoint*>*> point_sets;
- int mode;
- int step;
- double feather;
+ VFrame *mask, *temp;
+ MaskEdges edges;
+ MaskPointSets point_sets;
+ ArrayList<float> faders;
+ ArrayList<float> feathers;
+ int step, total_submasks;
int recalculate;
- int value;
+ temp_t fade[SUBMASKS+1];
};
" 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<len; ++i ) {\n"
+ " float dx = float(points[i].x) - gl_FragCoord.x;\n"
+ " float dy = float(points[i].y) - gl_FragCoord.y;\n"
+ " float dd = dx*dx + dy*dy;\n"
+ " if( dd >= 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 =
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()
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();
}
+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<Vertex>
+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> *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<double *> *invented = (ArrayList<double *> *)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)
{
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;
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<Vertex>;
-
-
+ 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<MaskPoint*> *points = new ArrayList<MaskPoint*>;
- 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<GLdouble*> 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
// 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);
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<double *> 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; i<edge.size(); ++i ) {
+ MaskCoord &a = edge[i];
+ MaskCoord &b = i<edge.size()-1 ? edge[i+1] : edge[0];
+ draw_spots(spots, a.x,a.y+h, b.x,b.y+h);
+ }
+ int sz = spots.size() * sizeof(MaskSpot);
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, points[0], 0, sz);
+ glBufferData(GL_SHADER_STORAGE_BUFFER, sz, &spots[0], GL_DYNAMIC_COPY);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+ glUseProgram(frag_shader);
+ float r = feathers[k], v = faders[k];
+ glUniform1f(glGetUniformLocation(frag_shader, "r"), r);
+ glUniform1f(glGetUniformLocation(frag_shader, "v"), v);
+ in->bind(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();
}
-
-
-
-
-
-
-
-
void Playback3D::convert_cmodel(Canvas *canvas,
VFrame *output,
int dst_cmodel)
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();
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();
#include "bcwindowbase.inc"
#include "canvas.inc"
#include "condition.inc"
-#include "maskauto.inc"
+#include "maskauto.h"
#include "maskautos.inc"
#include "mutex.inc"
#include "mwindow.inc"
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,
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 ||
output_temp->clear_frame();
return;
}
-
+*/
if(use_opengl) {
if( !((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->can_mask(
start_position_project, keyframe_set) )
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
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();
}
-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 && i<shader_ids.size(); ++i ) {
+ ShaderID &sp = *shader_ids[i];
+ if( sp.window_id == current_window->get_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();
}
{
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; i<shader_ids.size(); ++i ) {
+ if( shader_ids.values[i]->handle == 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)
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;
};
// 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);
BC_WindowBase::get_synchronous()->release_texture(
window_id,
texture_id);
- texture_id = -1;
- window_id = -1;
+ texture_id = -1;
+ window_id = -1;
}
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);
}
#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();
#endif
}
+void BC_Texture::write_tex(const char *fn)
+{
+#ifdef HAVE_GL
+ write_tex(fn, 31);
+#endif
+}
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();
#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()
//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);
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);
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; i<nb_frags; ++i ) frags[i] = va_arg(list, char*);
- va_end(list);
- fragments = frags;
- }
-
- while( (text = *fragments++) ) {
- char src[strlen(text) + BCSTRLEN + 1];
+ if( !segs || !n ) return 0;
+// concat source segs
+ int ids = 0;
+ char *ret = 0;
+ for( int i=0; i<n; ++i ) {
+ const char *text = *segs++;
+ char src[strlen(text) + BCSTRLEN + 1], *sp = src;
const char *tp = strstr(text, "main()");
if( tp ) {
// Replace main() with a mainxxx()
- char mainxxx[BCSTRLEN], *sp = src;
- sprintf(mainxxx, "main%03d()", nb_mains++);
int n = tp - text;
memcpy(sp, text, n); sp += n;
- n = strlen(mainxxx);
- memcpy(sp, mainxxx, n); sp += n;
- tp += strlen("main()");
- strcpy(sp, tp);
+ sp += sprintf(sp, "main%03d()", ids++);
+ strcpy(sp, tp+strlen("main()"));
text = src;
}
-
- char *new_program = !program ? cstrdup(text) :
- cstrcat(2, program, text);
- delete [] program; program = new_program;
+ char *cp = !ret ? cstrdup(text) : cstrcat(2, ret, text);
+ delete [] ret; ret = cp;
}
-// Add main() which calls mainxxx() in order
- char main_program[BCTEXTLEN], *cp = main_program;
+// add main() which calls mainxxx() in order
+ char main_prog[BCTEXTLEN];
+ char *cp = main_prog;
cp += sprintf(cp, "\nvoid main() {\n");
- for( int i=0; i < nb_mains; ++i )
+ for( int i=0; i < ids; ++i )
cp += sprintf(cp, "\tmain%03d();\n", i);
cp += sprintf(cp, "}\n");
- cp = !program ? cstrdup(main_program) :
- cstrcat(2, program, main_program);
- delete [] program; program = cp;
-
- int got_it = 0;
- result = BC_WindowBase::get_synchronous()->get_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; i<nb_segs; ++i )
+ segs[i] = va_arg(list, const char *);
+ va_end(list);
+ segments = segs;
+ }
+
+ const char *vert_shaders[nb_segs]; int vert_segs = 0;
+ const char *frag_shaders[nb_segs]; int frag_segs = 0;
+ for( int i=0; segments[i]!=0; ++i ) {
+ const char *seg = segments[i];
+ if( strstr(seg, "// vertex shader") )
+ vert_shaders[vert_segs++] = seg;
+ else
+ frag_shaders[frag_segs++] = seg;
}
-//printf("VFrame::make_shader\n%s\n", program);
- delete [] program;
+ char *vert = shader_segs(vert_shaders, vert_segs);
+ char *frag = shader_segs(frag_shaders, frag_segs);
+ if( !BC_WindowBase::get_synchronous()->get_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)