1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-02-25 07:24:00 +00:00

clean up interpolators; WIP towards bspline support in anim editor

This commit is contained in:
fgenesis 2022-09-13 18:38:44 +02:00
parent 55689228bf
commit 29fd4ec44e
9 changed files with 213 additions and 155 deletions

View file

@ -472,7 +472,7 @@ void AnimationEditor::applyState()
splinegrid->setTexture("mithalas-house-bg-0001"); splinegrid->setTexture("mithalas-house-bg-0001");
splinegrid->setWidthHeight(200, 200); splinegrid->setWidthHeight(200, 200);
splinegrid->position = Vector(400, 300); splinegrid->position = Vector(400, 300);
splinegrid->resize(3,3,10,10); splinegrid->resize(3,3,10,10,3);
splinegrid->resetControlPoints(); splinegrid->resetControlPoints();
addRenderObject(splinegrid, LR_PARTICLES_TOP); addRenderObject(splinegrid, LR_PARTICLES_TOP);
@ -647,12 +647,12 @@ void AnimationEditor::moveBoneStripPoint(const Vector &mov)
{ {
if (!sel->changeStrip.empty()) if (!sel->changeStrip.empty())
{ {
if (b->strip.size() < sel->changeStrip.size()) if (b->grid.size() < sel->changeStrip.size())
{ {
b->strip.resize(sel->changeStrip.size()); b->grid.resize(sel->changeStrip.size());
} }
b->strip[selectedStripPoint] = sel->changeStrip[selectedStripPoint] += mov*0.006f; b->grid[selectedStripPoint] = sel->changeStrip[selectedStripPoint] += mov*0.006f;
} }
} }
} }
@ -1266,7 +1266,7 @@ void AnimationEditor::cloneBoneAhead()
b2->x = b1->x; b2->x = b1->x;
b2->y = b1->y; b2->y = b1->y;
b2->rot = b1->rot; b2->rot = b1->rot;
b2->strip = b1->strip; b2->grid = b1->grid;
} }
} }
} }

View file

@ -1,5 +1,6 @@
#include "Interpolators.h" #include "Interpolators.h"
#include <math.h> #include <math.h>
#include "tbsp.hh"
CosineInterpolator::CosineInterpolator() CosineInterpolator::CosineInterpolator()
{ {
@ -66,3 +67,56 @@ tail:
for( ; k < n; ++k) for( ; k < n; ++k)
ys[k] = v; ys[k] = v;
} }
BSpline2D::BSpline2D()
: _cpx(0), _cpy(0), _degx(0), _degy(0), _tmin(0), _tmax(0)
{
}
void BSpline2D::resize(size_t cx, size_t cy, unsigned degx, unsigned degy, float tmin, float tmax)
{
controlpoints.resize(cx * cy);
knotsX.resize(tbsp__getNumKnots(cx, degx));
knotsY.resize(tbsp__getNumKnots(cy, degy));
tbsp::fillKnotVector<float>(&knotsX[0], cx, degx, tmin, tmax);
tbsp::fillKnotVector<float>(&knotsY[0], cy, degy, tmin, tmax);
_cpx = cx;
_cpy = cy;
_degx = degx;
_degy = degy;
_tmin = tmin;
_tmax = tmax;
}
void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres)
{
std::vector<Vector> tmpv;
size_t degn = std::max(_degx, _degy);
size_t tmpn = (yres * _cpx) + degn;
size_t tmpsz = tmpn * sizeof(Vector);
Vector *tmp;
if(tmpsz < 17*1024)
tmp = (Vector*)alloca(tmpsz);
else
{
tmpv.resize(tmpn);
tmp = &tmpv[0];
}
Vector *work = tmp + (tmpn - degn);
// Each column -> Y-axis interpolation
for(size_t x = 0; x < _cpx; ++x)
{
const Vector *srccol = &controlpoints[x];
Vector *dstcol = &tmp[x];
tbsp::evalRange(dstcol, yres, &work[0], &knotsY[0], srccol, _cpy, _degy, _tmin, _tmax, _cpx, _cpx);
}
// Each row -> X-axis interpolation
for(size_t y = 0; y < yres; ++y)
{
const Vector *srcrow = &tmp[y * _cpx];
tbsp::evalRange(dst, xres, &work[0], &knotsX[0], srcrow, _cpx, _degx, _tmin, _tmax);
dst += xres;
}
}

View file

@ -21,3 +21,32 @@ private:
#endif #endif
class BSpline2D
{
public:
BSpline2D();
// # of control points on each axis
void resize(size_t cx, size_t cy, unsigned degx, unsigned degy, float tmin, float tmax);
void recalc(Vector *dst, size_t xres, size_t yres);
std::vector<Vector> controlpoints;
inline Vector& controlpoint(size_t x, size_t y)
{
return controlpoints[y * _cpx + x];
}
inline size_t ctrlX() const { return _cpx; }
inline size_t ctrlY() const { return _cpy; }
inline unsigned degX() const { return _degx; }
inline unsigned degY() const { return _degy; }
private:
size_t _cpx, _cpy; // # of control points
unsigned _degx, _degy;
float _tmin, _tmax;
std::vector<float> knotsX, knotsY;
};

View file

@ -77,7 +77,8 @@ public:
enum GridType enum GridType
{ {
GRID_WAVY = 0, GRID_WAVY = 0,
GRID_SET = 1 GRID_STRIP = 1, // quad is in strip mode
GRID_INTERP = 2, // quad is in grid mode
}; };
unsigned char gridType; // unsigned char to save space unsigned char gridType; // unsigned char to save space

View file

@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "SimpleIStringStream.h" #include "SimpleIStringStream.h"
#include "ReadXML.h" #include "ReadXML.h"
#include "RenderBase.h" #include "RenderBase.h"
#include "SplineGrid.h"
#include <tinyxml2.h> #include <tinyxml2.h>
using namespace tinyxml2; using namespace tinyxml2;
@ -137,7 +138,7 @@ void Bone::createStrip(bool vert, int num)
createGrid(2, num); createGrid(2, num);
} }
stripVert = vert; stripVert = vert;
gridType = GRID_SET; gridType = GRID_STRIP;
changeStrip.resize(num); changeStrip.resize(num);
} }
@ -1083,10 +1084,10 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
{ {
BoneKeyframe *b = &a->keyframes[j].keyframes[k]; BoneKeyframe *b = &a->keyframes[j].keyframes[k];
os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " "; os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
os << b->strip.size() << " "; os << b->grid.size() << " ";
for (size_t i = 0; i < b->strip.size(); i++) for (size_t i = 0; i < b->grid.size(); i++)
{ {
os << b->strip[i].x << " " << b->strip[i].y << " "; os << b->grid[i].x << " " << b->grid[i].y << " ";
} }
if (b->doScale) if (b->doScale)
{ {
@ -1652,10 +1653,10 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
b.rot = rot; b.rot = rot;
if (strip>0) if (strip>0)
{ {
b.strip.resize(strip); b.grid.resize(strip);
for (size_t i = 0; i < b.strip.size(); i++) for (size_t i = 0; i < b.grid.size(); i++)
{ {
is >> b.strip[i].x >> b.strip[i].y; is >> b.grid[i].x >> b.grid[i].y;
} }
} }
@ -1746,9 +1747,38 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
XMLElement *interp = animation->FirstChildElement("Interpolator"); XMLElement *interp = animation->FirstChildElement("Interpolator");
while(interp) while(interp)
{ {
Bone *bi = NULL;
if(const char *sbone = interp->Attribute("bone"))
bi = getBoneByIdx(atoi(sbone));
if(!bi)
continue;
//SplineType spline = SPLINE_BSPLINE;
int cx = 3, cy = 3, degx = 3, degy = 3;
if(const char *stype = interp->Attribute("type"))
{
SimpleIStringStream is(stype);
std::string ty;
is >> ty;
BoneGridInterpolator bgip;
if(ty == "bspline")
{
//spline = SPLINE_BSPLINE;
is >> cx >> cy >> degx >> degy;
}
}
BoneGridInterpolator bgip;
//bgip.type = spline;
bgip.idx = bi->boneIdx;
bgip.pointsX = cx;
bgip.pointsY = cy;
bgip.degreeX = degx;
bgip.degreeY = degy;
// TODO
interp = interp->NextSiblingElement("Interpolator"); interp = interp->NextSiblingElement("Interpolator");
} }
animation = animation->NextSiblingElement("Animation"); animation = animation->NextSiblingElement("Animation");
@ -1885,13 +1915,13 @@ void AnimationLayer::updateBones()
} }
if (b->animated==Bone::ANIM_ALL && !b->changeStrip.empty()) if (b->animated==Bone::ANIM_ALL && !b->changeStrip.empty())
{ {
if (bkey2->strip.size() < b->changeStrip.size()) if (bkey2->grid.size() < b->changeStrip.size())
bkey2->strip.resize(b->changeStrip.size()); bkey2->grid.resize(b->changeStrip.size());
if (bkey1->strip.size() < b->changeStrip.size()) if (bkey1->grid.size() < b->changeStrip.size())
bkey1->strip.resize(b->changeStrip.size()); bkey1->grid.resize(b->changeStrip.size());
for (size_t i = 0; i < b->changeStrip.size(); i++) for (size_t i = 0; i < b->changeStrip.size(); i++)
{ {
b->changeStrip[i] = Vector(lerp(bkey1->strip[i].x, bkey2->strip[i].x, dt, lerpType), lerp(bkey1->strip[i].y, bkey2->strip[i].y, dt, lerpType)); b->changeStrip[i] = Vector(lerp(bkey1->grid[i].x, bkey2->grid[i].x, dt, lerpType), lerp(bkey1->grid[i].y, bkey2->grid[i].y, dt, lerpType));
} }
b->setGridPoints(b->stripVert, b->changeStrip); b->setGridPoints(b->stripVert, b->changeStrip);
} }

View file

@ -128,7 +128,8 @@ public:
int x, y, rot; int x, y, rot;
float sx, sy; float sx, sy;
bool doScale; bool doScale;
std::vector<Vector> strip; std::vector<Vector> grid;
std::vector<Vector> controlpoints;
}; };
class SkeletalKeyframe class SkeletalKeyframe
@ -150,6 +151,15 @@ public:
void copyAllButTime(SkeletalKeyframe *copy); void copyAllButTime(SkeletalKeyframe *copy);
}; };
class BoneGridInterpolator
{
public:
size_t idx;
unsigned pointsX, pointsY;
unsigned degreeX, degreeY;
void updateGrid(BoneKeyframe& bk);
};
class Animation class Animation
{ {
public: public:
@ -170,6 +180,9 @@ public:
size_t getNumKeyframes(); size_t getNumKeyframes();
void reverse(); void reverse();
bool resetPassOnEnd; bool resetPassOnEnd;
typedef std::vector <BoneGridInterpolator> Interpolators;
Interpolators interpolators;
}; };
class SkeletalSprite; class SkeletalSprite;

View file

@ -1,8 +1,6 @@
#include "SplineGrid.h" #include "SplineGrid.h"
#include "tbsp.hh"
#include "RenderBase.h" #include "RenderBase.h"
#include "Core.h" #include "Core.h"
#include "Interpolators.h"
SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint; SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint;
@ -15,7 +13,8 @@ SplineGridCtrlPoint::SplineGridCtrlPoint()
Vector SplineGridCtrlPoint::getSplinePosition() const Vector SplineGridCtrlPoint::getSplinePosition() const
{ {
SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent(); SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent();
return Vector(2 * position.x / p->width, 2 * position.y / p->height); // always return alpha == 1
return Vector(position.x / p->width, position.y / p->height, 1.0f);
} }
void SplineGridCtrlPoint::onUpdate(float dt) void SplineGridCtrlPoint::onUpdate(float dt)
@ -40,7 +39,7 @@ void SplineGridCtrlPoint::onUpdate(float dt)
} }
SplineGrid::SplineGrid() SplineGrid::SplineGrid()
: degreeX(3), degreeY(3), _cpx(0), _cpy(0), _xres(0), _yres(0), splinetype(SPLINE_BSPLINE) : _xres(0), _yres(0)
{ {
setWidthHeight(128, 128); setWidthHeight(128, 128);
renderQuad = true; renderQuad = true;
@ -51,16 +50,13 @@ SplineGrid::~SplineGrid()
{ {
} }
void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres) void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned deg)
{ {
size_t oldcpx = bsp.ctrlX();
knotsX.resize(tbsp__getNumKnots(w, degreeX)); size_t oldcpy = bsp.ctrlY();
knotsY.resize(tbsp__getNumKnots(h, degreeY));
tmp.resize(xres * h);
tbsp::fillKnotVector<float>(&knotsX[0], w, degreeX, -1.0f, 1.0f);
tbsp::fillKnotVector<float>(&knotsY[0], h, degreeY, -1.0f, 1.0f);
this->createGrid(xres, yres); this->createGrid(xres, yres);
gridpoints.resize(xres * yres);
std::vector<SplineGridCtrlPoint*> oldp; std::vector<SplineGridCtrlPoint*> oldp;
ctrlp.swap(oldp); ctrlp.swap(oldp);
@ -68,21 +64,20 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres)
// move any old points over that fit within the new size // move any old points over that fit within the new size
{ {
const size_t cw = std::min(_cpx, w); const size_t cw = std::min(oldcpx, w);
const size_t ch = std::min(_cpy, h); const size_t ch = std::min(oldcpy, h);
for(size_t y = 0; y < ch; ++y) for(size_t y = 0; y < ch; ++y)
for(size_t x = 0; x < cw; ++x) for(size_t x = 0; x < cw; ++x)
{ {
SplineGridCtrlPoint *& ref = oldp[y * _cpx + x]; SplineGridCtrlPoint *& ref = oldp[y * oldcpx + x];
ctrlp[y * w + x] = ref; ctrlp[y * w + x] = ref;
ref = NULL; ref = NULL;
} }
} }
_cpx = w;
_cpy = h;
_xres = xres; _xres = xres;
_yres = yres; _yres = yres;
bsp.resize(w, h, deg, deg, -1.0f, 1.0f);
// kill any excess points // kill any excess points
for(size_t i = 0; i < oldp.size(); ++i) for(size_t i = 0; i < oldp.size(); ++i)
@ -97,102 +92,46 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres)
if(!ref) if(!ref)
ref = createControlPoint(x, y); ref = createControlPoint(x, y);
} }
recalc();
} }
void SplineGrid::recalc() void SplineGrid::recalc()
{ {
switch(splinetype) for(size_t i = 0; i < ctrlp.size(); ++i)
{ bsp.controlpoints[i] = ctrlp[i]->getSplinePosition();
case SPLINE_BSPLINE: Vector *gp = &gridpoints[0];
recalcBSpline(); bsp.recalc(gp, _xres, _yres);
break;
case SPLINE_COSINE:
recalcCosine();
break;
}
}
void SplineGrid::recalcBSpline()
{
std::vector<Vector> px(std::max(_cpx, _xres));
std::vector<Vector> work(std::max(degreeX, degreeY));
// Each row -> X-axis interpolation
for(size_t y = 0; y < _cpy; ++y)
{
for(size_t x = 0; x < _cpx; ++x)
px[x] = ctrlp[y * _cpx + x]->getSplinePosition();
Vector *dst = &tmp[y * _xres];
tbsp::evalRange(dst, _xres, &work[0], &knotsX[0], &px[0], _cpx, degreeX, -1.0f, 1.0f);
}
this->resetGrid();
Vector **dg = this->getDrawGrid(); Vector **dg = this->getDrawGrid();
for(size_t y = 0; y < _yres; ++y)
// Each column -> Y-axis interpolation for(size_t x = 0; x < _xres; ++x)
std::vector<Vector> out(_yres); dg[x][y] = *gp++;
for(size_t x = 0; x < _xres; ++x)
{
for(size_t y = 0; y < _cpy; ++y)
px[y] = tmp[y * _xres + x];
tbsp::evalRange(&out[0], _yres, &work[0], &knotsY[0], &px[0], _cpy, degreeY, -1.0f, 1.0f);
for(size_t y = 0; y < _yres; ++y)
{
// output values are in [-1,+1] while drawgrid normally goes from [-0.5,+0.5]
Vector gp = out[y] * 0.5f;
gp.z = 1; // used as alpha
dg[x][y] = gp;
}
}
} }
void SplineGrid::recalcCosine()
{
// TODO
/*std::vector<Vector> px(std::max(_cpx, _xres));
std::vector<float> out(std::max(_xres, _yres));
CosineInterpolator top;
// Each row -> X-axis interpolation
for(size_t y = 0; y < _cpy; ++y)
{
for(size_t x = 0; x < _cpx; ++x)
px[x] = ctrlp[y * _cpx + x]->getSplinePosition();
std::sort(px.begin(), px.end());
top.setPoints(&px[0], _cpx);
Vector *dst = &tmp[y * _xres];
top.interpolateRange(&out[0,
*/
}
void SplineGrid::resetControlPoints() void SplineGrid::resetControlPoints()
{ {
const float dx = width / float(_cpx - 1); const size_t cpx = bsp.ctrlX();
const float dy = height / float(_cpy - 1); const size_t cpy = bsp.ctrlY();
const float dx = width / float(cpx - 1);
const float dy = height / float(cpy - 1);
float yy = height * -0.5f; float yy = height * -0.5f;
for(size_t y = 0; y < _cpy; ++y, yy += dy) for(size_t y = 0; y < cpy; ++y, yy += dy)
{ {
float xx = width * -0.5f; float xx = width * -0.5f;
SplineGridCtrlPoint **row = &ctrlp[y * _cpx]; SplineGridCtrlPoint **row = &ctrlp[y * cpx];
for(size_t x = 0; x < _cpx; ++x, xx += dx) for(size_t x = 0; x < cpx; ++x, xx += dx)
row[x]->position = Vector(xx, yy); row[x]->position = Vector(xx, yy);
} }
} }
SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y) SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y)
{ {
assert(x < _cpx && y < _cpy); const size_t cpx = bsp.ctrlX();
const size_t cpy = bsp.ctrlY();
assert(x < cpx && y < cpy);
const Vector wh(width, height); const Vector wh(width, height);
const Vector pos01(float(x) / float(_cpx-1), float(y) / float(_cpy-1)); const Vector pos01(float(x) / float(cpx-1), float(y) / float(cpy-1));
SplineGridCtrlPoint *cp = new SplineGridCtrlPoint(); SplineGridCtrlPoint *cp = new SplineGridCtrlPoint();
cp->position = (pos01 - Vector(0.5f, 0.5f)) * wh; cp->position = (pos01 - Vector(0.5f, 0.5f)) * wh;
this->addChild(cp, PM_POINTER); this->addChild(cp, PM_POINTER);
@ -215,12 +154,15 @@ void SplineGrid::onRender(const RenderState& rs) const
glLineWidth(2); glLineWidth(2);
glColor4f(0.0f, 1.0f, 0.3f, 0.3f); glColor4f(0.0f, 1.0f, 0.3f, 0.3f);
const size_t cpx = bsp.ctrlX();
const size_t cpy = bsp.ctrlY();
// X axis // X axis
for(size_t y = 0; y < _cpy; ++y) for(size_t y = 0; y < cpy; ++y)
{ {
glBegin(GL_LINE_STRIP); glBegin(GL_LINE_STRIP);
const SplineGridCtrlPoint * const *row = &ctrlp[y * _cpx]; const SplineGridCtrlPoint * const *row = &ctrlp[y * cpx];
for(size_t x = 0; x < _cpx; ++x) for(size_t x = 0; x < cpx; ++x)
{ {
const Vector p = row[x]->position; const Vector p = row[x]->position;
glVertex2f(p.x, p.y); glVertex2f(p.x, p.y);
@ -229,31 +171,16 @@ void SplineGrid::onRender(const RenderState& rs) const
} }
// Y axis // Y axis
for(size_t x = 0; x < _cpx; ++x) for(size_t x = 0; x < cpx; ++x)
{ {
glBegin(GL_LINE_STRIP); glBegin(GL_LINE_STRIP);
for(size_t y = 0; y < _cpy; ++y) for(size_t y = 0; y < cpy; ++y)
{ {
const Vector p = ctrlp[y * _cpx + x]->position; const Vector p = ctrlp[y * cpx + x]->position;
glVertex2f(p.x, p.y); glVertex2f(p.x, p.y);
} }
glEnd(); glEnd();
} }
/*
glColor4f(0.0f, 0.2f, 1.0f, 1.0f);
for(size_t y = 0; y < _cpy; ++y)
{
glBegin(GL_LINE_STRIP);
const value_type *line = &tmp[y * _xres];
for(size_t x = 0; x < _xres; ++x)
{
Vector pos = line[x] * wh2;
glVertex2f(pos.x, pos.y);
}
glEnd();
}
*/
} }

View file

@ -5,6 +5,7 @@
#include "Vector.h" #include "Vector.h"
#include "glm/glm.hpp" #include "glm/glm.hpp"
#include "Quad.h" #include "Quad.h"
#include "Interpolators.h"
enum SplineType enum SplineType
{ {
@ -31,7 +32,7 @@ public:
~SplineGrid(); ~SplineGrid();
// # of control points on each axis // # of control points on each axis
void resize(size_t w, size_t h, size_t xres, size_t yres); void resize(size_t w, size_t h, size_t xres, size_t yres, unsigned deg);
void recalc(); void recalc();
void resetControlPoints(); void resetControlPoints();
@ -41,22 +42,13 @@ public:
private: private:
void recalcBSpline();
void recalcCosine();
SplineGridCtrlPoint *createControlPoint(size_t x, size_t y); SplineGridCtrlPoint *createControlPoint(size_t x, size_t y);
unsigned degreeX, degreeY;
std::vector<float> knotsX, knotsY;
std::vector<value_type> tmp; // X-axis temporary values
size_t _cpx, _cpy; // # of control points
size_t _xres; // resolution for x-axis eval before doing 2D expansion
size_t _yres;
std::vector<SplineGridCtrlPoint*> ctrlp; std::vector<SplineGridCtrlPoint*> ctrlp;
SplineType splinetype; std::vector<Vector> gridpoints;
size_t _xres, _yres;
unsigned deg;
BSpline2D bsp;
}; };

View file

@ -95,14 +95,14 @@ static void genKnotsUniform(K *knots, size_t nn, K mink, K maxk)
} }
template<typename K, typename T> template<typename K, typename T>
static T deBoor(T *work, const T *src, const K *knots, const size_t r, const size_t k, const K t) static T deBoor(T *work, const T *src, const K *knots, const size_t r, const size_t k, const K t, size_t inputStride)
{ {
T last = src[0]; // init so that it works correctly even with degree == 0 T last = src[0]; // init so that it works correctly even with degree == 0
for(size_t worksize = k; worksize > 1; --worksize) for(size_t worksize = k; worksize > 1; --worksize)
{ {
const size_t j = k - worksize + 1; // iteration number, starting with 1, going up to k const size_t j = k - worksize + 1; // iteration number, starting with 1, going up to k
const size_t tmp = r - k + 1 + j; const size_t tmp = r - k + 1 + j;
for(size_t w = 0; w < worksize - 1; ++w) for(size_t w = 0, wr = 0; w < worksize - 1; ++w, wr += inputStride)
{ {
const size_t i = w + tmp; const size_t i = w + tmp;
const K ki = knots[i]; const K ki = knots[i];
@ -111,9 +111,10 @@ static T deBoor(T *work, const T *src, const K *knots, const size_t r, const siz
TBSP_ASSERT(div > 0); TBSP_ASSERT(div > 0);
const K a = (t - ki) / div; const K a = (t - ki) / div;
const K a1 = K(1) - a; const K a1 = K(1) - a;
work[w] = last = (src[w] * a1) + (src[w+1] * a); // lerp work[w] = last = (src[wr] * a1) + (src[wr + inputStride] * a); // lerp
} }
src = work; // done writing the initial data to work, now use that as input for further iterations src = work; // done writing the initial data to work, now use that as input for further iterations
inputStride = 1;
} }
return last; return last;
} }
@ -175,7 +176,7 @@ static T evalOne(T *work, const K *knots, const T *points, size_t numpoints, siz
// evaluate numdst points in range [tmin..tmax], equally spaced // evaluate numdst points in range [tmin..tmax], equally spaced
template<typename K, typename T> template<typename K, typename T>
static void evalRange(T *dst, size_t numdst, T *work, const K *knots, const T *points, size_t numpoints, size_t degree, K tmin, K tmax) static void evalRange(T *dst, size_t numdst, T *work, const K *knots, const T *points, size_t numpoints, size_t degree, K tmin, K tmax, size_t inputStride = 1, size_t outputStride = 1)
{ {
TBSP_ASSERT(tmin <= tmax); TBSP_ASSERT(tmin <= tmax);
if(numpoints - 1 < degree) if(numpoints - 1 < degree)
@ -196,7 +197,10 @@ static void evalRange(T *dst, size_t numdst, T *work, const K *knots, const T *p
// left out-of-bounds // left out-of-bounds
for( ; i < numdst && t < knots[0]; ++i, t += step) for( ; i < numdst && t < knots[0]; ++i, t += step)
dst[i] = points[0]; {
*dst = points[0];
dst += outputStride;
}
// actually interpolated points // actually interpolated points
const K maxknot = knots[numknots - 1]; const K maxknot = knots[numknots - 1];
@ -205,13 +209,21 @@ static void evalRange(T *dst, size_t numdst, T *work, const K *knots, const T *p
while(r < maxidx && knots[r+1] < t) // find new index; don't need to do binary search again while(r < maxidx && knots[r+1] < t) // find new index; don't need to do binary search again
++r; ++r;
const T* const src = &points[r - degree]; const T* const src = &points[(r - degree) * inputStride];
dst[i] = detail::deBoor(work, src, knots, r, k, t); *dst = detail::deBoor(work, src, knots, r, k, t, inputStride);
dst += outputStride;
} }
// right out-of-bounds // right out-of-bounds
for( ; i < numdst; ++i) if(i < numdst)
dst[i] = points[numpoints - 1]; {
T last = points[(numpoints - 1) * inputStride];
for( ; i < numdst; ++i)
{
*dst = last;
dst += outputStride;
}
}
} }