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:
parent
55689228bf
commit
29fd4ec44e
9 changed files with 213 additions and 155 deletions
|
@ -472,7 +472,7 @@ void AnimationEditor::applyState()
|
|||
splinegrid->setTexture("mithalas-house-bg-0001");
|
||||
splinegrid->setWidthHeight(200, 200);
|
||||
splinegrid->position = Vector(400, 300);
|
||||
splinegrid->resize(3,3,10,10);
|
||||
splinegrid->resize(3,3,10,10,3);
|
||||
splinegrid->resetControlPoints();
|
||||
addRenderObject(splinegrid, LR_PARTICLES_TOP);
|
||||
|
||||
|
@ -647,12 +647,12 @@ void AnimationEditor::moveBoneStripPoint(const Vector &mov)
|
|||
{
|
||||
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->y = b1->y;
|
||||
b2->rot = b1->rot;
|
||||
b2->strip = b1->strip;
|
||||
b2->grid = b1->grid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "Interpolators.h"
|
||||
#include <math.h>
|
||||
#include "tbsp.hh"
|
||||
|
||||
CosineInterpolator::CosineInterpolator()
|
||||
{
|
||||
|
@ -66,3 +67,56 @@ tail:
|
|||
for( ; k < n; ++k)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,3 +21,32 @@ private:
|
|||
|
||||
#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;
|
||||
};
|
||||
|
|
|
@ -77,7 +77,8 @@ public:
|
|||
enum GridType
|
||||
{
|
||||
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
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "SimpleIStringStream.h"
|
||||
#include "ReadXML.h"
|
||||
#include "RenderBase.h"
|
||||
#include "SplineGrid.h"
|
||||
|
||||
#include <tinyxml2.h>
|
||||
using namespace tinyxml2;
|
||||
|
@ -137,7 +138,7 @@ void Bone::createStrip(bool vert, int num)
|
|||
createGrid(2, num);
|
||||
}
|
||||
stripVert = vert;
|
||||
gridType = GRID_SET;
|
||||
gridType = GRID_STRIP;
|
||||
changeStrip.resize(num);
|
||||
}
|
||||
|
||||
|
@ -1083,10 +1084,10 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
{
|
||||
BoneKeyframe *b = &a->keyframes[j].keyframes[k];
|
||||
os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
|
||||
os << b->strip.size() << " ";
|
||||
for (size_t i = 0; i < b->strip.size(); i++)
|
||||
os << b->grid.size() << " ";
|
||||
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)
|
||||
{
|
||||
|
@ -1652,10 +1653,10 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
b.rot = rot;
|
||||
if (strip>0)
|
||||
{
|
||||
b.strip.resize(strip);
|
||||
for (size_t i = 0; i < b.strip.size(); i++)
|
||||
b.grid.resize(strip);
|
||||
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");
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
animation = animation->NextSiblingElement("Animation");
|
||||
|
@ -1885,13 +1915,13 @@ void AnimationLayer::updateBones()
|
|||
}
|
||||
if (b->animated==Bone::ANIM_ALL && !b->changeStrip.empty())
|
||||
{
|
||||
if (bkey2->strip.size() < b->changeStrip.size())
|
||||
bkey2->strip.resize(b->changeStrip.size());
|
||||
if (bkey1->strip.size() < b->changeStrip.size())
|
||||
bkey1->strip.resize(b->changeStrip.size());
|
||||
if (bkey2->grid.size() < b->changeStrip.size())
|
||||
bkey2->grid.resize(b->changeStrip.size());
|
||||
if (bkey1->grid.size() < b->changeStrip.size())
|
||||
bkey1->grid.resize(b->changeStrip.size());
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -128,7 +128,8 @@ public:
|
|||
int x, y, rot;
|
||||
float sx, sy;
|
||||
bool doScale;
|
||||
std::vector<Vector> strip;
|
||||
std::vector<Vector> grid;
|
||||
std::vector<Vector> controlpoints;
|
||||
};
|
||||
|
||||
class SkeletalKeyframe
|
||||
|
@ -150,6 +151,15 @@ public:
|
|||
void copyAllButTime(SkeletalKeyframe *copy);
|
||||
};
|
||||
|
||||
class BoneGridInterpolator
|
||||
{
|
||||
public:
|
||||
size_t idx;
|
||||
unsigned pointsX, pointsY;
|
||||
unsigned degreeX, degreeY;
|
||||
void updateGrid(BoneKeyframe& bk);
|
||||
};
|
||||
|
||||
class Animation
|
||||
{
|
||||
public:
|
||||
|
@ -170,6 +180,9 @@ public:
|
|||
size_t getNumKeyframes();
|
||||
void reverse();
|
||||
bool resetPassOnEnd;
|
||||
|
||||
typedef std::vector <BoneGridInterpolator> Interpolators;
|
||||
Interpolators interpolators;
|
||||
};
|
||||
|
||||
class SkeletalSprite;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#include "SplineGrid.h"
|
||||
#include "tbsp.hh"
|
||||
#include "RenderBase.h"
|
||||
#include "Core.h"
|
||||
#include "Interpolators.h"
|
||||
|
||||
SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint;
|
||||
|
||||
|
@ -15,7 +13,8 @@ SplineGridCtrlPoint::SplineGridCtrlPoint()
|
|||
Vector SplineGridCtrlPoint::getSplinePosition() const
|
||||
{
|
||||
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)
|
||||
|
@ -40,7 +39,7 @@ void SplineGridCtrlPoint::onUpdate(float dt)
|
|||
}
|
||||
|
||||
SplineGrid::SplineGrid()
|
||||
: degreeX(3), degreeY(3), _cpx(0), _cpy(0), _xres(0), _yres(0), splinetype(SPLINE_BSPLINE)
|
||||
: _xres(0), _yres(0)
|
||||
{
|
||||
setWidthHeight(128, 128);
|
||||
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)
|
||||
{
|
||||
|
||||
knotsX.resize(tbsp__getNumKnots(w, degreeX));
|
||||
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);
|
||||
size_t oldcpx = bsp.ctrlX();
|
||||
size_t oldcpy = bsp.ctrlY();
|
||||
|
||||
this->createGrid(xres, yres);
|
||||
gridpoints.resize(xres * yres);
|
||||
|
||||
std::vector<SplineGridCtrlPoint*> 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
|
||||
{
|
||||
const size_t cw = std::min(_cpx, w);
|
||||
const size_t ch = std::min(_cpy, h);
|
||||
const size_t cw = std::min(oldcpx, w);
|
||||
const size_t ch = std::min(oldcpy, h);
|
||||
for(size_t y = 0; y < ch; ++y)
|
||||
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;
|
||||
ref = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_cpx = w;
|
||||
_cpy = h;
|
||||
_xres = xres;
|
||||
_yres = yres;
|
||||
bsp.resize(w, h, deg, deg, -1.0f, 1.0f);
|
||||
|
||||
// kill any excess points
|
||||
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)
|
||||
ref = createControlPoint(x, y);
|
||||
}
|
||||
|
||||
recalc();
|
||||
}
|
||||
|
||||
void SplineGrid::recalc()
|
||||
{
|
||||
switch(splinetype)
|
||||
{
|
||||
case SPLINE_BSPLINE:
|
||||
recalcBSpline();
|
||||
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();
|
||||
for(size_t i = 0; i < ctrlp.size(); ++i)
|
||||
bsp.controlpoints[i] = ctrlp[i]->getSplinePosition();
|
||||
Vector *gp = &gridpoints[0];
|
||||
bsp.recalc(gp, _xres, _yres);
|
||||
Vector **dg = this->getDrawGrid();
|
||||
|
||||
// Each column -> Y-axis interpolation
|
||||
std::vector<Vector> out(_yres);
|
||||
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;
|
||||
}
|
||||
for(size_t x = 0; x < _xres; ++x)
|
||||
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()
|
||||
{
|
||||
const float dx = width / float(_cpx - 1);
|
||||
const float dy = height / float(_cpy - 1);
|
||||
const size_t cpx = bsp.ctrlX();
|
||||
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;
|
||||
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;
|
||||
SplineGridCtrlPoint **row = &ctrlp[y * _cpx];
|
||||
for(size_t x = 0; x < _cpx; ++x, xx += dx)
|
||||
SplineGridCtrlPoint **row = &ctrlp[y * cpx];
|
||||
for(size_t x = 0; x < cpx; ++x, xx += dx)
|
||||
row[x]->position = Vector(xx, yy);
|
||||
}
|
||||
}
|
||||
|
||||
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 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();
|
||||
cp->position = (pos01 - Vector(0.5f, 0.5f)) * wh;
|
||||
this->addChild(cp, PM_POINTER);
|
||||
|
@ -215,12 +154,15 @@ void SplineGrid::onRender(const RenderState& rs) const
|
|||
glLineWidth(2);
|
||||
glColor4f(0.0f, 1.0f, 0.3f, 0.3f);
|
||||
|
||||
const size_t cpx = bsp.ctrlX();
|
||||
const size_t cpy = bsp.ctrlY();
|
||||
|
||||
// X axis
|
||||
for(size_t y = 0; y < _cpy; ++y)
|
||||
for(size_t y = 0; y < cpy; ++y)
|
||||
{
|
||||
glBegin(GL_LINE_STRIP);
|
||||
const SplineGridCtrlPoint * const *row = &ctrlp[y * _cpx];
|
||||
for(size_t x = 0; x < _cpx; ++x)
|
||||
const SplineGridCtrlPoint * const *row = &ctrlp[y * cpx];
|
||||
for(size_t x = 0; x < cpx; ++x)
|
||||
{
|
||||
const Vector p = row[x]->position;
|
||||
glVertex2f(p.x, p.y);
|
||||
|
@ -229,31 +171,16 @@ void SplineGrid::onRender(const RenderState& rs) const
|
|||
}
|
||||
|
||||
// Y axis
|
||||
for(size_t x = 0; x < _cpx; ++x)
|
||||
for(size_t x = 0; x < cpx; ++x)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Vector.h"
|
||||
#include "glm/glm.hpp"
|
||||
#include "Quad.h"
|
||||
#include "Interpolators.h"
|
||||
|
||||
enum SplineType
|
||||
{
|
||||
|
@ -31,7 +32,7 @@ public:
|
|||
~SplineGrid();
|
||||
|
||||
// # 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 resetControlPoints();
|
||||
|
@ -41,22 +42,13 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void recalcBSpline();
|
||||
void recalcCosine();
|
||||
|
||||
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;
|
||||
SplineType splinetype;
|
||||
std::vector<Vector> gridpoints;
|
||||
size_t _xres, _yres;
|
||||
unsigned deg;
|
||||
BSpline2D bsp;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -95,14 +95,14 @@ static void genKnotsUniform(K *knots, size_t nn, K mink, K maxk)
|
|||
}
|
||||
|
||||
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
|
||||
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 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 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);
|
||||
const K a = (t - ki) / div;
|
||||
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
|
||||
inputStride = 1;
|
||||
}
|
||||
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
|
||||
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);
|
||||
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
|
||||
for( ; i < numdst && t < knots[0]; ++i, t += step)
|
||||
dst[i] = points[0];
|
||||
{
|
||||
*dst = points[0];
|
||||
dst += outputStride;
|
||||
}
|
||||
|
||||
// actually interpolated points
|
||||
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
|
||||
++r;
|
||||
|
||||
const T* const src = &points[r - degree];
|
||||
dst[i] = detail::deBoor(work, src, knots, r, k, t);
|
||||
const T* const src = &points[(r - degree) * inputStride];
|
||||
*dst = detail::deBoor(work, src, knots, r, k, t, inputStride);
|
||||
dst += outputStride;
|
||||
}
|
||||
|
||||
// right out-of-bounds
|
||||
if(i < numdst)
|
||||
{
|
||||
T last = points[(numpoints - 1) * inputStride];
|
||||
for( ; i < numdst; ++i)
|
||||
dst[i] = points[numpoints - 1];
|
||||
{
|
||||
*dst = last;
|
||||
dst += outputStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue