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->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;
}
}
}

View file

@ -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;
}
}

View file

@ -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;
};

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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();
}
*/
}

View file

@ -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;
};

View file

@ -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;
}
}
}