-/* === S I N F G =========================================================== */
-/*! \file blur.cpp
+/* === S Y N F I G ========================================================= */
+/*! \file synfig/blur.cpp
** \brief Blur Implementation File
**
-** $Id: blur.cpp,v 1.1.1.1 2005/01/04 01:23:14 darco Exp $
+** $Id$
**
** \legal
-** Copyright (c) 2002 Robert B. Quattlebaum Jr.
+** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**
-** This software and associated documentation
-** are CONFIDENTIAL and PROPRIETARY property of
-** the above-mentioned copyright holder.
+** 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.
**
-** You may not copy, print, publish, or in any
-** other way distribute this software without
-** a prior written agreement with
-** the copyright holder.
+** 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
*/
/* ========================================================================= */
# include <config.h>
#endif
-#include <sinfg/general.h>
-#include <sinfg/surface.h>
+#include <synfig/general.h>
+#include <synfig/surface.h>
#include "blur.h"
using namespace std;
using namespace etl;
-using namespace sinfg;
+using namespace synfig;
/* === M A C R O S ========================================================= */
/* === M E T H O D S ======================================================= */
Point Blur::operator ()(const Point &pos) const
-{
+{
Point blurpos(pos);
-
+
switch(type)
{
case CROSS:
blurpos[1]+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) * size[1];
break;
}
-
+
return blurpos;
}
-Point Blur::operator ()(sinfg::Real x, sinfg::Real y) const
+Point Blur::operator ()(synfig::Real x, synfig::Real y) const
{
return (*this)(Point(x,y));
}
}
template <>
-static inline Color zero<Color>()
+inline Color zero<Color>()
{
return Color::alpha();
}
Tmp2=SR0+Tmp1;
SR0=Tmp1;
surface[y][x]=(SC0[x]+Tmp2)/4;
- SC0[x]=Tmp2;
+ SC0[x]=Tmp2;
}
}
delete [] SC0;
T *SC0=new T[w+1];
T *SC1=new T[w+1];
- // Setup the row bufers
+ // Setup the row buffers
for(x=0;x<w;x++)SC0[x]=surface[0][x]*4;
// memcpy(SC1,surface[0],w*sizeof(T));
SR0=Tmp1;
Tmp1=SR1+Tmp2;
SR1=Tmp2;
-
+
// Column Machine
Tmp2=SC0[x]+Tmp1;
SC0[x]=Tmp1;
if(y&&x)
surface[y-1][x-1]=(SC1[x]+Tmp2)/16;
SC1[x]=Tmp2;
- }
+ }
}
delete [] SC0;
w=surface.get_w();
h=surface.get_h();
- // Setup the row bufers
+ // Setup the row buffers
for(x=0;x<w;x++)SC0[x+2]=surface[0][x]*24;
// memset(SC0,0,(w+2)*sizeof(T));
memset(SC1,0,(w+2)*sizeof(T));
T SR[n-1];
T *SC[n-1];
-
+
for(i=0;i<n-1;i++)
{
SC[i]=new T[w+half_n];
}
//THE GOOD ONE!!!!!!!!!
-bool Blur::operator ()(const Surface &surface,
- const Vector &resolution,
+bool Blur::operator ()(const Surface &surface,
+ const Vector &resolution,
Surface &out) const
{
int w = surface.get_w(),
h = surface.get_h();
-
+
if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
-
+
const Real pw = resolution[0]/w,
ph = resolution[1]/h;
-
+
int halfsizex = (int) (abs(size[0]*.5/pw) + 1),
- halfsizey = (int) (abs(size[1]*.5/ph) + 1);
-
+ halfsizey = (int) (abs(size[1]*.5/ph) + 1);
+
int x,y;
-
+
SuperCallback blurcall(cb,0,5000,5000);
-
+
Surface worksurface(w,h);
-
- //sinfg::info("Blur: check surface = %s", surface_valid(surface)?"true":"false");
-
+
+ //synfig::info("Blur: check surface = %s", surface_valid(surface)?"true":"false");
+
// Premultiply the alpha
for(y=0;y<h;y++)
{
worksurface[y][x] = a;
}
}
-
+
switch(type)
{
case Blur::DISC: // D I S C ----------------------------------------------------------
- {
+ {
int bw = halfsizex;
int bh = halfsizey;
-
+
if(size[0] && size[1] && w*h>2)
{
int x2,y2;
Surface tmp_surface(worksurface);
-
+
for(y=0;y<h;y++)
{
for(x=0;x<w;x++)
//accumulate all the pixels in an ellipse of w,h about the current pixel
Color color=Color::alpha();
int total=0;
-
+
for(y2=-bh;y2<=bh;y2++)
{
for(x2=-bw;x2<=bw;x2++)
float tmp_y=(float)y2/bh;
tmp_x*=tmp_x;
tmp_y*=tmp_y;
-
+
//ignore if it's outside of the disc
if( tmp_x+tmp_y>1.0)
continue;
-
+
//cap the pixel indices to inside the surface
int u= x+x2,
v= y+y2;
-
+
if( u < 0 ) u = 0;
if( u >= w ) u = w-1;
-
+
if( v < 0 ) v = 0;
if( v >= h ) v = h-1;
-
+
//accumulate the color, and # of pixels added in
color += tmp_surface[v][u];
total++;
}
}
-
+
//blend the color with the original color
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
worksurface[y][x]=color/total;
}
break;
}
-
+
//if we don't qualify for disc blur just use box blur
}
case Blur::BOX: // B O X -------------------------------------------------------
{
//horizontal part
- //sinfg::info("Blur: Starting Box blur (surface valid %d)", (int)surface_valid(worksurface));
-
+ //synfig::info("Blur: Starting Box blur (surface valid %d)", (int)surface_valid(worksurface));
+
Surface temp_surface;
temp_surface.set_wh(w,h);
-
+
if(size[0])
{
int length = halfsizex;
length=std::max(1,length);
-
- //sinfg::info("Blur: hbox blur work -> temp %d", length);
+
+ //synfig::info("Blur: hbox blur work -> temp %d", length);
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
- //sinfg::info("Blur: hbox finished");
-
+ //synfig::info("Blur: hbox finished");
+
//vertical part
//Surface temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
if(size[1])
{
int length = halfsizey;
length = std::max(1,length);
-
- //sinfg::info("Blur: vbox blur temp -> work %d",length);
+
+ //synfig::info("Blur: vbox blur temp -> work %d",length);
etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
}
else worksurface = temp_surface;
- //sinfg::info("Blur: vbox finished");
-
+ //synfig::info("Blur: vbox finished");
+
//blend with the original surface
/*int x,y;
for(y=0;y<h;y++)
break;
case Blur::FASTGAUSSIAN: // F A S T G A U S S I A N ----------------------------------------------
- {
+ {
//fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
-
+
/* 1 2 1
2 4 2
1 2 1
*/
-
+
Surface temp_surface;
temp_surface.set_wh(w,h);
-
+
//Surface temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
//horizontal part
if(size[0])
{
- int length=(int)(abs((float)w/(resolution[0]))*size[0]*0.5+1);
- length=std::max(1,length);
-
+ Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
+ length=std::max(1.0,length);
+
//two box blurs produces: 1 2 1
- etl::hbox_blur(worksurface.begin(),w,h,length*3/4,temp_surface.begin());
- etl::hbox_blur(temp_surface.begin(),w,h,length*3/4,worksurface.begin());
+ etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
+ etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=worksurface;
-
+
//vertical part
if(size[1])
{
- int length=(int)(abs((float)h/(resolution[1]))*size[1]*0.5+1);
- length=std::max(1,length);
-
+ Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
+ length=std::max(1.0,length);
+
//two box blurs produces: 1 2 1 on the horizontal 1 2 1
- etl::vbox_blur(worksurface.begin(),w,h,length*3/4,temp_surface.begin());
- etl::vbox_blur(temp_surface.begin(),w,h,length*3/4,worksurface.begin());
+ etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
+ etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=temp_surface2;
-
+
/*int x,y;
for(y=0;y<h;y++)
{
//horizontal part
Surface temp_surface;
temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[0])
{
int length = halfsizex;
length = std::max(1,length);
-
+
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
-
+
//vertical part
Surface temp_surface2;
temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[1])
{
int length = halfsizey;
length = std::max(1,length);
-
+
etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
}
else temp_surface2 = worksurface;
-
+
//blend the two together
int x,y;
Real pw = (Real)w/(resolution[0]);
Real ph = (Real)h/(resolution[1]);
-
+
Surface temp_surface;
Surface *gauss_surface;
-
- //sinfg::warning("Didn't crash yet b1");
-
+
+ //synfig::warning("Didn't crash yet b1");
+
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
gauss_surface = &worksurface;
/*else
}*/
/* Squaring the pw and ph values
- is necessary to insure consistant
+ is necessary to insure consistent
results when rendered to different
resolutions.
- Unfortunately, this automaticly
+ Unfortunately, this automatically
squares our rendertime.
There has got to be a faster way...
*/
memset(SC0,0,(w+2)*sizeof(Color));
memset(SC0,0,(w+2)*sizeof(Color));
- //sinfg::warning("Didn't crash yet b2");
+ //synfig::warning("Didn't crash yet b2");
//int i = 0;
-
+
while(bw&&bh)
{
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
GuassianBlur_2x2(*gauss_surface);
bw--,bh--;
}
-
- //sinfg::warning("Didn't crash yet bi - %d",i++);
+
+ //synfig::warning("Didn't crash yet bi - %d",i++);
}
while(bw)
{
GuassianBlur_2x1(*gauss_surface);
bw--;
}
- //sinfg::warning("Didn't crash yet bi - %d",i++);
+ //synfig::warning("Didn't crash yet bi - %d",i++);
}
while(bh)
{
GuassianBlur_1x2(*gauss_surface);
bh--;
}
- //sinfg::warning("Didn't crash yet bi - %d",i++);
+ //synfig::warning("Didn't crash yet bi - %d",i++);
}
delete [] SC0;
for(x=0;x<renddesc.get_w();x++)
worksurface[y][x]=Color::blend(temp_surface[y][x],worksurface[y][x],get_amount(),get_blend_method());
}*/
- //sinfg::warning("Didn't crash yet b end",i++);
+ //synfig::warning("Didn't crash yet b end",i++);
}
break;
}
// Scale up the alpha
-
+
//be sure the surface is of the correct size
//surface->set_wh(renddesc.get_w(),renddesc.get_h());
out.set_wh(w,h);
-
+
//divide out the alpha
for(y=0;y<h;y++)
{
else out[y][x]=Color::alpha();
}
}
-
+
//we are FRIGGGIN done....
blurcall.amount_complete(100,100);
-
+
return true;
}
-bool Blur::operator ()(const surface<float> &surface,
- const Vector &resolution,
- surface<float> &out) const
+bool Blur::operator ()(const etl::surface<float> &surface,
+ const synfig::Vector &resolution,
+ etl::surface<float> &out) const
{
int w = surface.get_w(),
h = surface.get_h();
-
+
if(w == 0 || h == 0 || resolution[0] == 0 || resolution[1] == 0) return false;
-
+
const Real pw = resolution[0]/w,
ph = resolution[1]/h;
-
+
int halfsizex = (int) (abs(size[0]*.5/pw) + 1),
- halfsizey = (int) (abs(size[1]*.5/ph) + 1);
+ halfsizey = (int) (abs(size[1]*.5/ph) + 1);
int x,y;
-
+
SuperCallback blurcall(cb,0,5000,5000);
-
+
etl::surface<float> worksurface(surface);
-
+
//don't need to premultiply because we are dealing with ONLY alpha
-
+
switch(type)
{
case Blur::DISC: // D I S C ----------------------------------------------------------
- {
+ {
int bw = halfsizex;
int bh = halfsizey;
-
+
if(size[0] && size[1] && w*h>2)
{
int x2,y2;
etl::surface<float> tmp_surface(worksurface);
-
+
for(y=0;y<h;y++)
{
for(x=0;x<w;x++)
//accumulate all the pixels in an ellipse of w,h about the current pixel
float a = 0;
int total=0;
-
+
for(y2=-bh;y2<=bh;y2++)
{
for(x2=-bw;x2<=bw;x2++)
float tmp_y=(float)y2/bh;
tmp_x*=tmp_x;
tmp_y*=tmp_y;
-
+
//ignore if it's outside of the disc
if( tmp_x+tmp_y>1.0)
continue;
-
+
//cap the pixel indices to inside the surface
int u= x+x2,
v= y+y2;
-
+
if( u < 0 ) u = 0;
if( u >= w ) u = w-1;
-
+
if( v < 0 ) v = 0;
if( v >= h ) v = h-1;
-
+
//accumulate the color, and # of pixels added in
a += tmp_surface[v][u];
total++;
}
}
-
+
//blend the color with the original color
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
worksurface[y][x]=a/total;
}
break;
}
-
+
//if we don't qualify for disc blur just use box blur
}
//horizontal part
etl::surface<float> temp_surface;
temp_surface.set_wh(w,h);
-
+
if(size[0])
{
int length = halfsizex;
length=std::max(1,length);
-
+
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
-
+
//vertical part
//etl::surface<float> temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
if(size[1])
{
int length = halfsizey;
etl::vbox_blur(temp_surface.begin(),temp_surface.end(),length,worksurface.begin());
}
else worksurface = temp_surface;
-
+
//blend with the original surface
/*int x,y;
for(y=0;y<h;y++)
break;
case Blur::FASTGAUSSIAN: // F A S T G A U S S I A N ----------------------------------------------
- {
+ {
//fast gaussian is treated as a 3x3 type of thing, except expanded to work with the length
-
+
/* 1 2 1
2 4 2
1 2 1
*/
-
+
etl::surface<float> temp_surface;
temp_surface.set_wh(w,h);
-
+
//etl::surface<float> temp_surface2;
//temp_surface2.set_wh(w,h);
-
+
//horizontal part
if(size[0])
{
- int length=(int)(abs((float)w/(resolution[0]))*size[0]*0.5+1);
- length=std::max(1,length);
-
+ Real length=abs((float)w/(resolution[0]))*size[0]*0.5+1;
+ length=std::max(1.0,length);
+
//two box blurs produces: 1 2 1
- etl::hbox_blur(worksurface.begin(),w,h,length*3/4,temp_surface.begin());
- etl::hbox_blur(temp_surface.begin(),w,h,length*3/4,worksurface.begin());
+ etl::hbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
+ etl::hbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=worksurface;
-
+
//vertical part
if(size[1])
{
- int length=(int)(abs((float)h/(resolution[1]))*size[1]*0.5+1);
- length=std::max(1,length);
-
+ Real length=abs((float)h/(resolution[1]))*size[1]*0.5+1;
+ length=std::max(1.0,length);
+
//two box blurs produces: 1 2 1 on the horizontal 1 2 1
- etl::vbox_blur(worksurface.begin(),w,h,length*3/4,temp_surface.begin());
- etl::vbox_blur(temp_surface.begin(),w,h,length*3/4,worksurface.begin());
+ etl::vbox_blur(worksurface.begin(),w,h,(int)(length*3/4),temp_surface.begin());
+ etl::vbox_blur(temp_surface.begin(),w,h,(int)(length*3/4),worksurface.begin());
}
//else temp_surface2=temp_surface2;
-
+
/*int x,y;
for(y=0;y<h;y++)
{
//horizontal part
etl::surface<float> temp_surface;
temp_surface.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[0])
{
int length = halfsizex;
length = std::max(1,length);
-
+
etl::hbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface.begin());
}
else temp_surface = worksurface;
-
+
//vertical part
etl::surface<float> temp_surface2;
temp_surface2.set_wh(worksurface.get_w(),worksurface.get_h());
-
+
if(size[1])
{
int length = halfsizey;
length = std::max(1,length);
-
+
etl::vbox_blur(worksurface.begin(),worksurface.end(),length,temp_surface2.begin());
}
else temp_surface2 = worksurface;
-
+
//blend the two together
int x,y;
Real pw = (Real)w/(resolution[0]);
Real ph = (Real)h/(resolution[1]);
-
+
//etl::surface<float> temp_surface;
etl::surface<float> *gauss_surface;
-
+
//if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
gauss_surface = &worksurface;
/*else
}*/
/* Squaring the pw and ph values
- is necessary to insure consistant
+ is necessary to insure consistent
results when rendered to different
resolutions.
- Unfortunately, this automaticly
+ Unfortunately, this automatically
squares our rendertime.
There has got to be a faster way...
*/
float *SC1=new float[w+2];
float *SC2=new float[w+2];
float *SC3=new float[w+2];
-
+
memset(SC0,0,(w+2)*sizeof(float));
memset(SC0,0,(w+2)*sizeof(float));
memset(SC0,0,(w+2)*sizeof(float));
memset(SC0,0,(w+2)*sizeof(float));
//int i = 0;
-
+
while(bw&&bh)
- {
+ {
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
if(bw>=4 && bh>=4)
bw--,bh--;
}
}
-
+
while(bw)
{
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
bw--;
}
}
-
+
while(bh)
{
if(!blurcall.amount_complete(max-(bw+bh),max))return false;
default:
break;
}
-
+
//be sure the surface is of the correct size
//surface->set_wh(renddesc.get_w(),renddesc.get_h());
out.set_wh(w,h);
-
+
//divide out the alpha - don't need to cause we rock
out = worksurface;
-
+
//we are FRIGGGIN done....
blurcall.amount_complete(100,100);
-
+
return true;
}