Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: port layer to Cobra renderer: Curve Gradient #3307

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
272 changes: 217 additions & 55 deletions synfig-core/src/modules/mod_gradient/curvegradient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@
#include <synfig/bezier.h>
#include <synfig/context.h>
#include <synfig/paramdesc.h>
#include <synfig/renddesc.h>
#include <synfig/surface.h>
#include <synfig/rendering/software/task/taskpaintpixelsw.h>
#include <synfig/value.h>
#include <synfig/valuenode.h>

Expand Down Expand Up @@ -194,6 +193,208 @@ find_closest(bool fast, const std::vector<synfig::BLinePoint>& bline,const Point
return ret;
}

class TaskCurveGradient: public rendering::Task
{
public:
typedef etl::handle<TaskCurveGradient> Handle;
SYNFIG_EXPORT static Token token;
Token::Handle get_token() const override { return token.handle(); }

Point origin;
Real width;
std::vector<synfig::BLinePoint> bline;
bool loop;
bool perpendicular;
bool fast;
bool bline_loop;
Real curve_length;
CompiledGradient compiled_gradient;
};


class TaskCurveGradientSW: public TaskCurveGradient, public rendering::TaskPaintPixelSW
{
public:
typedef etl::handle<TaskCurveGradient> Handle;
SYNFIG_EXPORT static Token token;
Token::Handle get_token() const override { return token.handle(); }

Color get_color(const Vector& p) const override
{
Vector tangent;
Vector diff;
Point p1;
Real thickness;
Real dist;

Real perp_dist = 0;
bool edge_case = false;

if(bline.size()==0)
return Color::alpha();
else if(bline.size()==1)
{
tangent=bline.front().get_tangent1();
p1=bline.front().get_vertex();
thickness=bline.front().get_width();
}
else
{
Real t;
const Point point(p-origin);

std::vector<synfig::BLinePoint>::const_iterator iter,next;

// Figure out the BLinePoints we will be using,
// Taking into account looping.
if(perpendicular)
{
next=find_closest(fast,bline,point,t,bline_loop,&perp_dist);
perp_dist/=curve_length;
}
else // not perpendicular
{
next=find_closest(fast,bline,point,t,bline_loop);
}

iter=next++;
if(next==bline.end()) next=bline.begin();

// Setup the curve
hermite<Vector> curve(
iter->get_vertex(),
next->get_vertex(),
iter->get_tangent2(),
next->get_tangent1()
);

int search_iterations(7);

// Figure out the closest point on the curve
if (fast)
t = curve.find_closest(fast, point,search_iterations);

// Calculate our values
p1=curve(t); // the closest point on the curve
tangent=curve.derivative(t); // the tangent at that point

// if the point we're nearest to is at either end of the
// bline, our distance from the curve is the distance from the
// point on the curve. we need to know which side of the
// curve we're on, so find the average of the two tangents at
// this point
if (t<0.00001 || t>0.99999)
{
bool zero_tangent = (tangent[0] == 0 && tangent[1] == 0);

if (t<0.5)
{
if (iter->get_split_tangent_angle() || iter->get_split_tangent_radius() || zero_tangent)
{
// fake the current tangent if we need to
if (zero_tangent) tangent = curve(FAKE_TANGENT_STEP) - curve(0);

// calculate the other tangent
Vector other_tangent(iter->get_tangent1());
if (other_tangent[0] == 0 && other_tangent[1] == 0)
{
// find the previous blinepoint
std::vector<synfig::BLinePoint>::const_iterator prev;
if (iter != bline.begin()) (prev = iter)--;
else if (loop) (prev = bline.end())--;
else prev = iter;

hermite<Vector> other_curve(prev->get_vertex(), iter->get_vertex(), prev->get_tangent2(), iter->get_tangent1());
other_tangent = other_curve(1) - other_curve(1-FAKE_TANGENT_STEP);
}

// normalise and sum the two tangents
tangent=(other_tangent.norm()+tangent.norm());
edge_case=true;
}
}
else
{
if (next->get_split_tangent_angle() || next->get_split_tangent_radius() || zero_tangent)
{
// fake the current tangent if we need to
if (zero_tangent) tangent = curve(1) - curve(1-FAKE_TANGENT_STEP);

// calculate the other tangent
Vector other_tangent(next->get_tangent2());
if (other_tangent[0] == 0 && other_tangent[1] == 0)
{
// find the next blinepoint
std::vector<synfig::BLinePoint>::const_iterator next2(next);
if (++next2 == bline.end())
{
if (loop) next2 = bline.begin();
else next2 = next;
}

hermite<Vector> other_curve(next->get_vertex(), next2->get_vertex(), next->get_tangent2(), next2->get_tangent1());
other_tangent = other_curve(FAKE_TANGENT_STEP) - other_curve(0);
}

// normalise and sum the two tangents
tangent=(other_tangent.norm()+tangent.norm());
edge_case=true;
}
}
}
tangent = tangent.norm();

if(perpendicular)
{
tangent*=curve_length;
p1-=tangent*perp_dist;
tangent=-tangent.perp();
}
else // not perpendicular
// the width of the bline at the closest point on the curve
thickness=(next->get_width()-iter->get_width())*t+iter->get_width();
}

if (perpendicular && bline.size() > 1)
{
diff=tangent.perp();
//p1-=diff*0.5;
const Real mag(diff.inv_mag());
diff*=mag*mag;
dist=(p-origin - p1)*diff;
}
else // not perpendicular
{
if (edge_case)
{
diff=(p1-(p-origin));
if(diff*tangent.perp()<0) diff=-diff;
diff=diff.norm()*thickness*width;
}
else
diff=tangent.perp()*thickness*width;

p1-=diff*0.5;
const Real mag(diff.inv_mag());
diff*=mag*mag;
dist=(p-origin - p1)*diff;
}

Real supersample = 0;
return compiled_gradient.average(dist - supersample, dist + supersample);
}

bool run(RunParams&) const override {
return run_task();
}
};

SYNFIG_EXPORT rendering::Task::Token TaskCurveGradient::token(
DescAbstract<TaskCurveGradient>("CurveGradient") );
SYNFIG_EXPORT rendering::Task::Token TaskCurveGradientSW::token(
DescReal<TaskCurveGradientSW, TaskCurveGradient>("CurveGradientSW") );


/* === M E T H O D S ======================================================= */

inline void
Expand Down Expand Up @@ -450,12 +651,6 @@ CurveGradient::color_func(const Point &point_, int quality, Real supersample)con
return compiled_gradient.average(dist - supersample, dist + supersample);
}

Real
CurveGradient::calc_supersample(const synfig::Point &/*x*/, Real pw, Real /*ph*/)const
{
return pw;
}

synfig::Layer::Handle
CurveGradient::hit_check(synfig::Context context, const synfig::Point &point)const
{
Expand Down Expand Up @@ -571,52 +766,19 @@ CurveGradient::get_color(Context context, const Point &point)const
return Color::blend(color,context.get_color(point),get_amount(),get_blend_method());
}

bool
CurveGradient::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
rendering::Task::Handle
CurveGradient::build_composite_task_vfunc(ContextParams /*context_params*/) const
{
RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__)

SuperCallback supercb(cb,0,9500,10000);

if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
surface->set_wh(renddesc.get_w(),renddesc.get_h());
}
else
{
if(!context.accelerated_render(surface,quality,renddesc,&supercb))
return false;
if(get_amount()==0)
return true;
}


int x,y;

Surface::pen pen(surface->begin());
const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
Point pos;
Point tl(renddesc.get_tl());
const int w(surface->get_w());
const int h(surface->get_h());

if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
for(x=0,pos[0]=tl[0];x<w;x++,pen.inc_x(),pos[0]+=pw)
pen.put_value(color_func(pos,quality,calc_supersample(pos,pw,ph)));
}
else
{
for(y=0,pos[1]=tl[1];y<h;y++,pen.inc_y(),pen.dec_x(x),pos[1]+=ph)
for(x=0,pos[0]=tl[0];x<w;x++,pen.inc_x(),pos[0]+=pw)
pen.put_value(Color::blend(color_func(pos,quality,calc_supersample(pos,pw,ph)),pen.get_value(),get_amount(),get_blend_method()));
}

// Mark our progress as finished
if(cb && !cb->amount_complete(10000,10000))
return false;

return true;
TaskCurveGradient::Handle task(new TaskCurveGradient());
task->origin = param_origin.get(Point());
task->width = param_width.get(Real());
task->bline = param_bline.get_list_of(BLinePoint());
task->loop = param_loop.get(bool());
task->perpendicular = param_perpendicular.get(bool());
task->fast = param_fast.get(bool());
task->compiled_gradient = compiled_gradient;
task->curve_length = curve_length_;
task->bline_loop = bline_loop;

return task;
}

5 changes: 3 additions & 2 deletions synfig-core/src/modules/mod_gradient/curvegradient.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,19 @@ class CurveGradient : public Layer_Composite, public Layer_NoDeform
void compile();
void sync();
Color color_func(const Point &x, int quality=10, Real supersample=0)const;
Real calc_supersample(const Point &x, Real pw, Real ph)const;

public:
CurveGradient();

virtual bool set_param(const String &param, const ValueBase &value);
virtual ValueBase get_param(const String &param)const;
virtual Color get_color(Context context, const Point &pos)const;
virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const;
Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const;

virtual Vocab get_param_vocab()const;

protected:
virtual rendering::Task::Handle build_composite_task_vfunc(synfig::ContextParams context_params) const;
};

/* === E N D =============================================================== */
Expand Down
Loading