From 5ae346e017651b10ea2b2b6e1391db5d4bc4243f Mon Sep 17 00:00:00 2001 From: dooglus Date: Fri, 7 Nov 2008 16:53:52 +0000 Subject: [PATCH] First stab at adding genete's suggested 'Curve Warp' layer. It's pretty slow at the moment, because it uses get_color() to render the context pixel by pixel rather than using accelerated_render() to render a block at once. git-svn-id: https://synfig.svn.sourceforge.net/svnroot/synfig@2164 1f10aa63-cdf2-0310-b900-c93c546f37ac --- synfig-core/trunk/src/modules/lyr_std/Makefile.am | 2 +- .../trunk/src/modules/lyr_std/curvewarp.cpp | 471 +++++++++++++++++++++ synfig-core/trunk/src/modules/lyr_std/curvewarp.h | 84 ++++ synfig-core/trunk/src/modules/lyr_std/main.cpp | 2 + 4 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp create mode 100644 synfig-core/trunk/src/modules/lyr_std/curvewarp.h diff --git a/synfig-core/trunk/src/modules/lyr_std/Makefile.am b/synfig-core/trunk/src/modules/lyr_std/Makefile.am index dc507d3..2cfbb76 100644 --- a/synfig-core/trunk/src/modules/lyr_std/Makefile.am +++ b/synfig-core/trunk/src/modules/lyr_std/Makefile.am @@ -7,7 +7,7 @@ INCLUDES = -I$(top_builddir) -I$(top_srcdir)/src moduledir=@MODULE_DIR@ module_LTLIBRARIES = liblyr_std.la -liblyr_std_la_SOURCES = main.cpp timeloop.cpp timeloop.h warp.cpp warp.h xorpattern.cpp booleancurve.h booleancurve.cpp bevel.cpp bevel.h shade.cpp shade.h twirl.cpp twirl.h stretch.cpp stretch.h xorpattern.h clamp.cpp clamp.h supersample.cpp supersample.h insideout.cpp insideout.h julia.cpp julia.h rotate.cpp rotate.h mandelbrot.cpp mandelbrot.h zoom.h zoom.cpp import.cpp import.h translate.h translate.cpp sphere_distort.h sphere_distort.cpp +liblyr_std_la_SOURCES = main.cpp timeloop.cpp timeloop.h warp.cpp warp.h xorpattern.cpp booleancurve.h booleancurve.cpp bevel.cpp bevel.h shade.cpp shade.h twirl.cpp twirl.h stretch.cpp stretch.h xorpattern.h clamp.cpp clamp.h supersample.cpp supersample.h insideout.cpp insideout.h julia.cpp julia.h rotate.cpp rotate.h mandelbrot.cpp mandelbrot.h zoom.h zoom.cpp import.cpp import.h translate.h translate.cpp sphere_distort.h sphere_distort.cpp curvewarp.cpp liblyr_std_la_CXXFLAGS = @SYNFIG_CFLAGS@ liblyr_std_la_LIBADD = ../../synfig/libsynfig.la @SYNFIG_LIBS@ liblyr_std_la_LDFLAGS = -module -no-undefined -avoid-version diff --git a/synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp b/synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp new file mode 100644 index 0000000..6b544e6 --- /dev/null +++ b/synfig-core/trunk/src/modules/lyr_std/curvewarp.cpp @@ -0,0 +1,471 @@ +/* === S Y N F I G ========================================================= */ +/*! \file curvewarp.cpp +** \brief Implementation of the "Curve Warp" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007-2008 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 "curvewarp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +/* === M A C R O S ========================================================= */ + +#define FAKE_TANGENT_STEP 0.000001 + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(CurveWarp); +SYNFIG_LAYER_SET_NAME(CurveWarp,"curve_warp"); +SYNFIG_LAYER_SET_LOCAL_NAME(CurveWarp,N_("Curve Warp")); +SYNFIG_LAYER_SET_CATEGORY(CurveWarp,N_("Distortions")); +SYNFIG_LAYER_SET_VERSION(CurveWarp,"0.0"); +SYNFIG_LAYER_SET_CVS_ID(CurveWarp,"$Id$"); + +/* === P R O C E D U R E S ================================================= */ + +inline float calculate_distance(const std::vector& bline) +{ + 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(); + 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+=curve.length(); + } + + return dist; +} + +std::vector::const_iterator +find_closest_to_bline(bool fast, const std::vector& bline,const Point& p,float& t, float& len, bool& extreme) +{ + 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_pos(0), best_len(0); + etl::hermite best_curve; + iter=next++; + Point bp; + float total_len(0); + bool first = true, last = false; + extreme = false; + + // printf(" loop\n"); + for(;next!=end;iter=next++) + { + // printf(" top\n"); + // Setup the curve + etl::hermite curve(iter->get_vertex(), next->get_vertex(), iter->get_tangent2(), next->get_tangent1()); + float thisdist(0); + last = false; + + if (fast) + { +#define POINT_CHECK(x) bp=curve(x); thisdist=(bp-p).mag_squared(); if(thisdist .99) extreme = true; + } + else + { + len = best_len + best_curve.find_distance(0,best_pos); + // printf("slow set len = %f + %f = %f\n", best_len, best_curve.find_distance(0,best_pos), len); + // printf("find_distance from 0 to %f is %f\n", best_pos, best_curve.find_distance(0,best_pos)); + // if (last) printf("last\n"); + + if (last && t > .999) + { + extreme = true; + // printf("extreme end\n"); + } + } + return ret; +} + +/* === M E T H O D S ======================================================= */ + +inline void +CurveWarp::sync() +{ + curve_length_=calculate_distance(bline); + perp_ = (end_point - start_point).perp().norm(); + // printf("curve_length_ = %f\n", curve_length_); +} + +CurveWarp::CurveWarp(): + origin(0,0), + width(1), + start_point(-3,-1), + end_point(3,1), + fast(true) +{ + bline.push_back(BLinePoint()); + bline.push_back(BLinePoint()); + bline[0].set_vertex(Point(-2.5,0)); + bline[1].set_vertex(Point(2.5,0)); + bline[0].set_tangent(Point(1, 1)); + bline[1].set_tangent(Point(1, -1)); + bline[0].set_width(1.0f); + bline[1].set_width(1.0f); + + sync(); +} + +inline Point +CurveWarp::transform(const Point &point_, int quality, float supersample)const +{ + Vector tangent; + Vector diff; + Point p1; + Real thickness; + Real dist; + bool edge_case = false; + float len(0); + bool extreme; + float t; + + if(bline.size()==0) + return Point(); + else if(bline.size()==1) + { + tangent=bline.front().get_tangent1(); + p1=bline.front().get_vertex(); + thickness=bline.front().get_width(); + t = 0.5; + extreme = false; + } + else + { + Point point(point_-origin); + + std::vector::const_iterator iter,next; + + // Figure out the BLinePoint we will be using, + next=find_closest_to_bline(fast,bline,point,t,len,extreme); + + 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<=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); // 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_flag() || 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::const_iterator prev; + if (iter != bline.begin()) (prev = iter)--; + else prev = iter; + + etl::hermite 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_flag() || 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::const_iterator next2(next); + if (++next2 == bline.end()) + next2 = next; + + etl::hermite 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(); + + // the width of the bline at the closest point on the curve + thickness=(next->get_width()-iter->get_width())*t+iter->get_width(); + } + + if (extreme) + { + Vector tangent, perp; + + if (t < 0.5) + { + synfig::BLinePoint start(bline[0]); + // Point a(start.get_vertex()); + tangent = start.get_tangent1().norm(); + diff = tangent.perp()*thickness*width; + len = (point_-origin - p1)*tangent; + } + else + { + std::vector::const_iterator iter; + iter=bline.end(); + iter--; + tangent = iter->get_tangent2().norm(); + diff = tangent.perp()*thickness*width; + len = (point_-origin - p1)*tangent + curve_length_; + } + } + else if (edge_case) + { + diff=(p1-(point_-origin)); + if(diff*tangent.perp()<0) diff=-diff; + diff=diff.norm()*thickness*width; + } + else + diff=tangent.perp()*thickness*width; + + const Real mag(diff.inv_mag()); + supersample=supersample*mag; + diff*=mag*mag; + dist=(point_-origin - p1)*diff; + + len /= curve_length_; + + // printf("len %6.2f dist %6.2f\n", len, dist); + return ((start_point + (end_point - start_point) * len) + + perp_ * dist); +} + +float +CurveWarp::calc_supersample(const synfig::Point &/*x*/, float pw,float /*ph*/)const +{ + return pw; +} + +synfig::Layer::Handle +CurveWarp::hit_check(synfig::Context context, const synfig::Point &point)const +{ + return context.hit_check(transform(point)); +} + +bool +CurveWarp::set_param(const String & param, const ValueBase &value) +{ + IMPORT(origin); + IMPORT(start_point); + IMPORT(end_point); + IMPORT(fast); + IMPORT(width); + + if(param=="bline" && value.get_type()==ValueBase::TYPE_LIST) + { + bline=value; + sync(); + + return true; + } + + IMPORT_AS(origin,"offset"); + + return false; +} + +ValueBase +CurveWarp::get_param(const String & param)const +{ + EXPORT(origin); + EXPORT(start_point); + EXPORT(end_point); + EXPORT(bline); + EXPORT(fast); + EXPORT(width); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return ValueBase(); +} + +Layer::Vocab +CurveWarp::get_param_vocab()const +{ + Layer::Vocab ret; + + ret.push_back(ParamDesc("origin") + .set_local_name(_("Origin"))); + + ret.push_back(ParamDesc("width") + .set_local_name(_("Width"))); + + ret.push_back(ParamDesc("start_point") + .set_local_name(_("Start Point"))); + + ret.push_back(ParamDesc("end_point") + .set_local_name(_("End Point"))); + + ret.push_back(ParamDesc("bline") + .set_local_name(_("Vertices")) + .set_origin("origin") + .set_hint("width") + .set_description(_("A list of BLine Points"))); + + ret.push_back(ParamDesc("fast") + .set_local_name(_("Fast"))); + + return ret; +} + +Color +CurveWarp::get_color(Context context, const Point &point)const +{ + return context.get_color(transform(point)); +} + +bool +CurveWarp::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + SuperCallback supercb(cb,0,9500,10000); + + if(!context.accelerated_render(surface,quality,renddesc,&supercb)) + return false; + + int x,y; + + 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()); + + for(y=0,pos[1]=tl[1];yamount_complete(10000,10000)) + return false; + + return true; +} diff --git a/synfig-core/trunk/src/modules/lyr_std/curvewarp.h b/synfig-core/trunk/src/modules/lyr_std/curvewarp.h new file mode 100644 index 0000000..da9c1b7 --- /dev/null +++ b/synfig-core/trunk/src/modules/lyr_std/curvewarp.h @@ -0,0 +1,84 @@ +/* === S Y N F I G ========================================================= */ +/*! \file curvewarp.h +** \brief Header file for implementation of the "Curve Warp" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007-2008 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 =========================================================== +** +** ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_CURVEWARP_H +#define __SYNFIG_CURVEWARP_H + +/* === H E A D E R S ======================================================= */ + +#include +#include +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +using namespace synfig; +using namespace std; +using namespace etl; + +class CurveWarp : public Layer +{ + SYNFIG_LAYER_MODULE_EXT + +private: + std::vector bline; + + Point origin; + Real width; + Point start_point; + Point end_point; + Real curve_length_; + Vector perp_; + bool fast; + + void sync(); + + synfig::Color color_func(const synfig::Point &x, int quality=10, float supersample=0)const; + + float calc_supersample(const synfig::Point &x, float pw,float ph)const; + +public: + CurveWarp(); + + virtual bool set_param(const String ¶m, const ValueBase &value); + virtual ValueBase get_param(const String ¶m)const; + virtual Point transform(const Point &point_, int quality=10, float supersample=0)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; + synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; + + virtual Vocab get_param_vocab()const; +}; + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/trunk/src/modules/lyr_std/main.cpp b/synfig-core/trunk/src/modules/lyr_std/main.cpp index cd793a9..faa0d7a 100644 --- a/synfig-core/trunk/src/modules/lyr_std/main.cpp +++ b/synfig-core/trunk/src/modules/lyr_std/main.cpp @@ -66,6 +66,7 @@ #include "warp.h" #include "timeloop.h" +#include "curvewarp.h" #endif @@ -98,5 +99,6 @@ MODULE_INVENTORY_BEGIN(liblyr_std) LAYER(Layer_Bevel) LAYER(Layer_TimeLoop) LAYER(Layer_SphereDistort) + LAYER(CurveWarp) END_LAYERS MODULE_INVENTORY_END -- 2.7.4