diff --git a/Aquaria/AnimationEditor.cpp b/Aquaria/AnimationEditor.cpp index 1404525..514e7a5 100644 --- a/Aquaria/AnimationEditor.cpp +++ b/Aquaria/AnimationEditor.cpp @@ -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; } } } diff --git a/BBGE/Interpolators.cpp b/BBGE/Interpolators.cpp index ed89a83..a071607 100644 --- a/BBGE/Interpolators.cpp +++ b/BBGE/Interpolators.cpp @@ -1,5 +1,6 @@ #include "Interpolators.h" #include +#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(&knotsX[0], cx, degx, tmin, tmax); + tbsp::fillKnotVector(&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 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; + } +} diff --git a/BBGE/Interpolators.h b/BBGE/Interpolators.h index 5d47d80..7d6d34c 100644 --- a/BBGE/Interpolators.h +++ b/BBGE/Interpolators.h @@ -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 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 knotsX, knotsY; +}; diff --git a/BBGE/Quad.h b/BBGE/Quad.h index 49771b4..9baf55e 100644 --- a/BBGE/Quad.h +++ b/BBGE/Quad.h @@ -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 diff --git a/BBGE/SkeletalSprite.cpp b/BBGE/SkeletalSprite.cpp index b07e27c..ad56016 100644 --- a/BBGE/SkeletalSprite.cpp +++ b/BBGE/SkeletalSprite.cpp @@ -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 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); } diff --git a/BBGE/SkeletalSprite.h b/BBGE/SkeletalSprite.h index fe21e6f..d99c635 100644 --- a/BBGE/SkeletalSprite.h +++ b/BBGE/SkeletalSprite.h @@ -128,7 +128,8 @@ public: int x, y, rot; float sx, sy; bool doScale; - std::vector strip; + std::vector grid; + std::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 Interpolators; + Interpolators interpolators; }; class SkeletalSprite; diff --git a/BBGE/SplineGrid.cpp b/BBGE/SplineGrid.cpp index af08848..a0538ae 100644 --- a/BBGE/SplineGrid.cpp +++ b/BBGE/SplineGrid.cpp @@ -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(&knotsX[0], w, degreeX, -1.0f, 1.0f); - tbsp::fillKnotVector(&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 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 px(std::max(_cpx, _xres)); - std::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 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 y = 0; y < _yres; ++y) + for(size_t x = 0; x < _xres; ++x) + dg[x][y] = *gp++; } -void SplineGrid::recalcCosine() -{ - // TODO - /*std::vector px(std::max(_cpx, _xres)); - std::vector 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(); - } - */ } diff --git a/BBGE/SplineGrid.h b/BBGE/SplineGrid.h index 5a3a671..d2a8e82 100644 --- a/BBGE/SplineGrid.h +++ b/BBGE/SplineGrid.h @@ -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 knotsX, knotsY; - std::vector 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 ctrlp; - SplineType splinetype; + std::vector gridpoints; + size_t _xres, _yres; + unsigned deg; + BSpline2D bsp; }; diff --git a/ExternalLibs/tbsp.hh b/ExternalLibs/tbsp.hh index 8855389..bacec09 100644 --- a/ExternalLibs/tbsp.hh +++ b/ExternalLibs/tbsp.hh @@ -95,14 +95,14 @@ static void genKnotsUniform(K *knots, size_t nn, K mink, K maxk) } template -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 -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 - for( ; i < numdst; ++i) - dst[i] = points[numpoints - 1]; + if(i < numdst) + { + T last = points[(numpoints - 1) * inputStride]; + for( ; i < numdst; ++i) + { + *dst = last; + dst += outputStride; + } + } }