X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-core%2Ftags%2Fsynfig_0_61_07_rc3%2Fsrc%2Fmodules%2Fmod_gradient%2Fcurvegradient.cpp;fp=synfig-core%2Ftags%2Fsynfig_0_61_07_rc3%2Fsrc%2Fmodules%2Fmod_gradient%2Fcurvegradient.cpp;h=2fb682fcdab2017cf5837800cdc68aaccb7f3a21;hb=0e729dddd753ed872265ba82c0089bc55e64bf55;hp=0000000000000000000000000000000000000000;hpb=7a4d1b9ab079cc84ccfb4cf46f074c84b8caef2e;p=synfig.git diff --git a/synfig-core/tags/synfig_0_61_07_rc3/src/modules/mod_gradient/curvegradient.cpp b/synfig-core/tags/synfig_0_61_07_rc3/src/modules/mod_gradient/curvegradient.cpp new file mode 100644 index 0000000..2fb682f --- /dev/null +++ b/synfig-core/tags/synfig_0_61_07_rc3/src/modules/mod_gradient/curvegradient.cpp @@ -0,0 +1,569 @@ +/* === S Y N F I G ========================================================= */ +/*! \file curvegradient.cpp +** \brief Template Header +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007 Chris Moore +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +** +** === N O T E S =========================================================== +** +** ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "curvegradient.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +/* === M A C R O S ========================================================= */ + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(CurveGradient); +SYNFIG_LAYER_SET_NAME(CurveGradient,"curve_gradient"); +SYNFIG_LAYER_SET_LOCAL_NAME(CurveGradient,_("Curve Gradient")); +SYNFIG_LAYER_SET_CATEGORY(CurveGradient,_("Gradients")); +SYNFIG_LAYER_SET_VERSION(CurveGradient,"0.0"); +SYNFIG_LAYER_SET_CVS_ID(CurveGradient,"$Id$"); + +/* === P R O C E D U R E S ================================================= */ + +inline float calculate_distance(const synfig::BLinePoint& a,const synfig::BLinePoint& b) +{ +#if 1 + const Point& c1(a.get_vertex()); + const Point c2(a.get_vertex()+a.get_tangent2()/3); + const Point c3(b.get_vertex()-b.get_tangent1()/3); + const Point& c4(b.get_vertex()); + return (c1-c2).mag()+(c2-c3).mag()+(c3-c4).mag(); +#else +#endif +} + +inline float calculate_distance(const std::vector& bline, bool bline_loop) +{ + std::vector::const_iterator iter,next,ret; + std::vector::const_iterator end(bline.end()); + + float dist(0); + + if (bline.empty()) return dist; + + next=bline.begin(); + + if(bline_loop) + iter=--bline.end(); + else + iter=next++; + + for(;next!=end;iter=next++) + { + // Setup the curve + etl::hermite curve( + iter->get_vertex(), + next->get_vertex(), + iter->get_tangent2(), + next->get_tangent1()); + +// dist+=calculate_distance(*iter,*next); + dist+=curve.length(); + } + + return dist; +} + +std::vector::const_iterator +find_closest(bool fast, const std::vector& bline,const Point& p,float& t,bool loop=false,float *bline_dist_ret=0) +{ + std::vector::const_iterator iter,next,ret; + std::vector::const_iterator end(bline.end()); + + ret=bline.end(); + float dist(100000000000.0); + + next=bline.begin(); + + float best_bline_dist(0); + float best_bline_len(0); + float total_bline_dist(0); + float best_pos(0); + etl::hermite best_curve; + + if(loop) + iter=--bline.end(); + else + iter=next++; + + Point bp; + + for(;next!=end;iter=next++) + { + // Setup the curve + etl::hermite curve( + iter->get_vertex(), + next->get_vertex(), + iter->get_tangent2(), + next->get_tangent1()); + + /* + const float t(curve.find_closest(p,6,0.01,0.99)); + bp=curve(t);if((bp-p).mag_squared()::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 + etl::hermite curve( + iter->get_vertex(), + next->get_vertex(), + iter->get_tangent2(), + next->get_tangent1() + ); + + // Setup the derivative function + etl::derivative > deriv(curve); + + int search_iterations(7); + + /*if(quality==0)search_iterations=8; + else if(quality<=2)search_iterations=10; + else if(quality<=4)search_iterations=8; + */ + if(perpendicular) + { + if(quality>7) + search_iterations=4; + } + else // not perpendicular + { + if(quality<=6)search_iterations=7; + else if(quality<=7)search_iterations=6; + else if(quality<=8)search_iterations=5; + else search_iterations=4; + } + + // 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=deriv(t).norm(); // the unit 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) + { + if (t<0.5) + { + if (iter->get_split_tangent_flag()) + { + tangent=(iter->get_tangent1().norm()+tangent).norm(); + edge_case=true; + } + } + else + { + if (next->get_split_tangent_flag()) + { + tangent=(next->get_tangent2().norm()+tangent).norm(); + edge_case=true; + } + } + } + + 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) + { + if(quality>7) + { + dist=perp_dist; +/* diff=tangent.perp(); + const Real mag(diff.inv_mag()); + supersample=supersample*mag; +*/ + supersample=0; + } + else + { + diff=tangent.perp(); + //p1-=diff*0.5; + const Real mag(diff.inv_mag()); + supersample=supersample*mag; + diff*=mag*mag; + dist=((point_-offset)*diff-p1*diff); + } + } + else // not perpendicular + { + if (edge_case) + { + diff=(p1-(point_-offset)); + 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()); + supersample=supersample*mag; + diff*=mag*mag; + dist=((point_-offset)*diff-p1*diff); + } + + if(loop) + dist-=floor(dist); + + if(zigzag) + { + dist*=2.0; + supersample*=2.0; + if(dist>1)dist=2.0-dist; + } + + if(loop) + { + if(dist+supersample*0.5>1.0) + { + float left(supersample*0.5-(dist-1.0)); + float right(supersample*0.5+(dist-1.0)); + Color pool(gradient(1.0-(left*0.5),left).premult_alpha()*left/supersample); + if (zigzag) pool+=gradient(1.0-right*0.5,right).premult_alpha()*right/supersample; + else pool+=gradient(right*0.5,right).premult_alpha()*right/supersample; + return pool.demult_alpha(); + } + if(dist-supersample*0.5<0.0) + { + float left(supersample*0.5-dist); + float right(supersample*0.5+dist); + Color pool(gradient(right*0.5,right).premult_alpha()*right/supersample); + if (zigzag) pool+=gradient(left*0.5,left).premult_alpha()*left/supersample; + else pool+=gradient(1.0-left*0.5,left).premult_alpha()*left/supersample; + return pool.demult_alpha(); + } + } + return gradient(dist,supersample); +} + +float +CurveGradient::calc_supersample(const synfig::Point &/*x*/, float pw,float /*ph*/)const +{ + return pw; +} + +synfig::Layer::Handle +CurveGradient::hit_check(synfig::Context context, const synfig::Point &point)const +{ + if(get_blend_method()==Color::BLEND_STRAIGHT && get_amount()>=0.5) + return const_cast(this); + if(get_amount()==0.0) + return context.hit_check(point); + if((get_blend_method()==Color::BLEND_STRAIGHT || get_blend_method()==Color::BLEND_COMPOSITE|| get_blend_method()==Color::BLEND_ONTO) && color_func(point).get_a()>0.5) + return const_cast(this); + return context.hit_check(point); +} + +bool +CurveGradient::set_param(const String & param, const ValueBase &value) +{ + + + IMPORT(offset); + IMPORT(perpendicular); + IMPORT(fast); + + if(param=="bline" && value.get_type()==ValueBase::TYPE_LIST) + { + bline=value; + bline_loop=value.get_loop(); + sync(); + + return true; + } + + IMPORT(width); + IMPORT(gradient); + IMPORT(loop); + IMPORT(zigzag); + return Layer_Composite::set_param(param,value); +} + +ValueBase +CurveGradient::get_param(const String & param)const +{ + EXPORT(offset); + EXPORT(bline); + EXPORT(gradient); + EXPORT(loop); + EXPORT(zigzag); + EXPORT(width); + EXPORT(perpendicular); + EXPORT(fast); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_Composite::get_param(param); +} + +Layer::Vocab +CurveGradient::get_param_vocab()const +{ + Layer::Vocab ret(Layer_Composite::get_param_vocab()); + + ret.push_back(ParamDesc("offset") + .set_local_name(_("Offset"))); + + ret.push_back(ParamDesc("width") + .set_is_distance() + .set_local_name(_("Width"))); + + ret.push_back(ParamDesc("bline") + .set_local_name(_("Vertices")) + .set_origin("offset") + .set_scalar("width") + .set_description(_("A list of BLine Points"))); + + ret.push_back(ParamDesc("gradient") + .set_local_name(_("Gradient"))); + ret.push_back(ParamDesc("loop") + .set_local_name(_("Loop"))); + ret.push_back(ParamDesc("zigzag") + .set_local_name(_("ZigZag"))); + ret.push_back(ParamDesc("perpendicular") + .set_local_name(_("Perpendicular"))); + ret.push_back(ParamDesc("fast") + .set_local_name(_("Fast"))); + + return ret; +} + +Color +CurveGradient::get_color(Context context, const Point &point)const +{ + const Color color(color_func(point,0)); + + if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT) + return color; + else + 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 +{ + 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];yamount_complete(10000,10000)) + return false; + + return true; +}