From 0afd09dc75cb25b38154248bda819f46bfc049c1 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Mon, 5 Sep 2022 17:19:34 +0200 Subject: [PATCH] bspline wip more --- Aquaria/AnimationEditor.cpp | 4 +- BBGE/CMakeLists.txt | 2 + BBGE/Interpolators.cpp | 68 +++++++++++++++++++++ BBGE/Interpolators.h | 23 +++++++ BBGE/SkeletalSprite.cpp | 16 +++++ BBGE/SplineGrid.cpp | 119 ++++++++++++++++++++++++++---------- BBGE/SplineGrid.h | 11 ++++ 7 files changed, 210 insertions(+), 33 deletions(-) create mode 100644 BBGE/Interpolators.cpp create mode 100644 BBGE/Interpolators.h diff --git a/Aquaria/AnimationEditor.cpp b/Aquaria/AnimationEditor.cpp index 5eea4d6..1404525 100644 --- a/Aquaria/AnimationEditor.cpp +++ b/Aquaria/AnimationEditor.cpp @@ -469,11 +469,11 @@ void AnimationEditor::applyState() addRenderObject(tr, LR_BLACKGROUND); splinegrid = new SplineGrid; - splinegrid->resize(5,5,30,30); + splinegrid->setTexture("mithalas-house-bg-0001"); splinegrid->setWidthHeight(200, 200); splinegrid->position = Vector(400, 300); + splinegrid->resize(3,3,10,10); splinegrid->resetControlPoints(); - splinegrid->setTexture("mithalas-house-bg-0001"); addRenderObject(splinegrid, LR_PARTICLES_TOP); diff --git a/BBGE/CMakeLists.txt b/BBGE/CMakeLists.txt index 41100e5..3d51a3b 100644 --- a/BBGE/CMakeLists.txt +++ b/BBGE/CMakeLists.txt @@ -19,6 +19,8 @@ set(BBGE_SRCS CMakeLists.txt Core.cpp Core.h + Interpolators.cpp + Interpolators.h DarkLayer.cpp DarkLayer.h DataStructures.cpp diff --git a/BBGE/Interpolators.cpp b/BBGE/Interpolators.cpp new file mode 100644 index 0000000..ed89a83 --- /dev/null +++ b/BBGE/Interpolators.cpp @@ -0,0 +1,68 @@ +#include "Interpolators.h" +#include + +CosineInterpolator::CosineInterpolator() +{ +} + +void CosineInterpolator::clear() +{ + pxy.clear(); +} + +void CosineInterpolator::setPoints(const Vector* p, size_t n) +{ + pxy.resize(n); + for(size_t i = 0; i < n; ++i) + { + pxy[i].first = p[i].x; + pxy[i].second = p[i].y; + } + + + std::sort(pxy.begin(), pxy.end()); +} + +float CosineInterpolator::operator()(float x) const +{ + if (x < pxy[0].first) + return pxy[0].second; + + size_t N = pxy.size() - 1; + for (size_t i = 0; i < N; ++i) + { + // TODO: binary search + if (pxy[i + 1].first > x) + { + float xfactor = (x - pxy[i].first) / (pxy[i + 1].first - pxy[i].first); + float yfactor = (1.0f - cos(xfactor * 3.141596f)) * 0.5f; + return yfactor * pxy[i + 1].second + (1 - yfactor) * pxy[i].second; + } + } + + return pxy[N].second; +} + +void CosineInterpolator::interpolateRange(float *ys, const float* xs, size_t n) +{ + size_t i = 0, k = 0; + for( ; k < n; ++k) + { + const float x = xs[k]; + + while(x < pxy[i].first) + { + ++i; + if(i >= pxy.size()) + goto tail; + } + + ys[k] = pxy[i].second; + } + return; + +tail: + const float v = pxy.back().second; + for( ; k < n; ++k) + ys[k] = v; +} diff --git a/BBGE/Interpolators.h b/BBGE/Interpolators.h new file mode 100644 index 0000000..5d47d80 --- /dev/null +++ b/BBGE/Interpolators.h @@ -0,0 +1,23 @@ +#ifndef BBGE_INTERPOLATORS_H +#define BBGE_INTERPOLATORS_H + +#include // std::pair +#include +#include "Vector.h" + +class CosineInterpolator +{ +public: + CosineInterpolator(); + void clear(); + void setPoints(const Vector *p, size_t n); + float operator()(float x) const; + void interpolateRange(float *ys, const float *xs, size_t n); + +private: + + std::vector > pxy; +}; + +#endif + diff --git a/BBGE/SkeletalSprite.cpp b/BBGE/SkeletalSprite.cpp index c6d5dda..b07e27c 100644 --- a/BBGE/SkeletalSprite.cpp +++ b/BBGE/SkeletalSprite.cpp @@ -1543,6 +1543,13 @@ void SkeletalSprite::loadSkeletal(const std::string &fn) { newb->selectable = bone->BoolAttribute("sel"); } + if (bone->Attribute("grid")) + { + SimpleIStringStream is(bone->Attribute("grid")); + int x, y; + is >> x >> y; + newb->createGrid(x, y); + } bone = bone->NextSiblingElement("Bone"); } // attach bones @@ -1735,6 +1742,15 @@ void SkeletalSprite::loadSkeletal(const std::string &fn) newAnimation.keyframes.push_back(newSkeletalKeyframe); key = key->NextSiblingElement("Key"); } + + XMLElement *interp = animation->FirstChildElement("Interpolator"); + while(interp) + { + + + interp = interp->NextSiblingElement("Interpolator"); + } + animation = animation->NextSiblingElement("Animation"); this->animations.push_back(newAnimation); } diff --git a/BBGE/SplineGrid.cpp b/BBGE/SplineGrid.cpp index 896b710..af08848 100644 --- a/BBGE/SplineGrid.cpp +++ b/BBGE/SplineGrid.cpp @@ -2,6 +2,7 @@ #include "tbsp.hh" #include "RenderBase.h" #include "Core.h" +#include "Interpolators.h" SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint; @@ -14,8 +15,7 @@ SplineGridCtrlPoint::SplineGridCtrlPoint() Vector SplineGridCtrlPoint::getSplinePosition() const { SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent(); - Vector pos = position; - return Vector(pos.x / p->width, pos.y / p->height); + return Vector(2 * position.x / p->width, 2 * position.y / p->height); } void SplineGridCtrlPoint::onUpdate(float dt) @@ -32,17 +32,19 @@ void SplineGridCtrlPoint::onUpdate(float dt) if(movingPoint == this) { - SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent(); + SplineGrid *p = (SplineGrid*)getParent(); const Vector parentPos = p->getWorldPosition(); position = core->mouse.position - parentPos; + p->recalc(); } } SplineGrid::SplineGrid() - : degreeX(3), degreeY(3), _cpx(0), _cpy(0), _xres(0), _yres(0) + : degreeX(3), degreeY(3), _cpx(0), _cpy(0), _xres(0), _yres(0), splinetype(SPLINE_BSPLINE) { setWidthHeight(128, 128); - //renderQuad = false; + renderQuad = true; + renderBorder = true; } SplineGrid::~SplineGrid() @@ -55,8 +57,8 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres) knotsX.resize(tbsp__getNumKnots(w, degreeX)); knotsY.resize(tbsp__getNumKnots(h, degreeY)); tmp.resize(xres * h); - tbsp::fillKnotVector(&knotsX[0], w, degreeX, 0.0f, 1.0f); - tbsp::fillKnotVector(&knotsY[0], h, degreeY, 0.0f, 1.0f); + tbsp::fillKnotVector(&knotsX[0], w, degreeX, -1.0f, 1.0f); + tbsp::fillKnotVector(&knotsY[0], h, degreeY, -1.0f, 1.0f); this->createGrid(xres, yres); @@ -77,6 +79,11 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres) } } + _cpx = w; + _cpy = h; + _xres = xres; + _yres = yres; + // kill any excess points for(size_t i = 0; i < oldp.size(); ++i) if(oldp[i]) @@ -90,31 +97,87 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres) if(!ref) ref = createControlPoint(x, y); } - - _cpx = w; - _cpy = h; - _xres = xres; - _yres = yres; } void SplineGrid::recalc() { - std::vector px(_cpx); + 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], px.size(), degreeX, 0.0f, 1.0f); + tbsp::evalRange(dst, _xres, &work[0], &knotsX[0], &px[0], _cpx, degreeX, -1.0f, 1.0f); } + + this->resetGrid(); + 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; + } + } + +} + +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 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) { @@ -128,11 +191,10 @@ void SplineGrid::resetControlPoints() SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y) { assert(x < _cpx && y < _cpy); - const float w2 = width * -0.5f; - const float h2 = height * -0.5f; + const Vector wh(width, height); + const Vector pos01(float(x) / float(_cpx-1), float(y) / float(_cpy-1)); SplineGridCtrlPoint *cp = new SplineGridCtrlPoint(); - cp->position.x = w2 + float(x) / float(_cpx + 1); - cp->position.y = h2 + float(y) / float(_cpy + 1); + cp->position = (pos01 - Vector(0.5f, 0.5f)) * wh; this->addChild(cp, PM_POINTER); return cp; } @@ -140,8 +202,6 @@ SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y) void SplineGrid::onUpdate(float dt) { Quad::onUpdate(dt); - - recalc(); // HACK } void SplineGrid::onRender(const RenderState& rs) const @@ -150,7 +210,7 @@ void SplineGrid::onRender(const RenderState& rs) const glBindTexture(GL_TEXTURE_2D, 0); - const Vector wh(width, height); + const Vector wh2(width * 0.5f, height * 0.5f); glLineWidth(2); glColor4f(0.0f, 1.0f, 0.3f, 0.3f); @@ -180,23 +240,20 @@ void SplineGrid::onRender(const RenderState& rs) const glEnd(); } - - - + /* glColor4f(0.0f, 0.2f, 1.0f, 1.0f); - glPointSize(3); - glBegin(GL_POINTS); - 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] * wh; + Vector pos = line[x] * wh2; glVertex2f(pos.x, pos.y); } + glEnd(); } - glEnd(); + */ } diff --git a/BBGE/SplineGrid.h b/BBGE/SplineGrid.h index 49288c7..5a3a671 100644 --- a/BBGE/SplineGrid.h +++ b/BBGE/SplineGrid.h @@ -6,6 +6,12 @@ #include "glm/glm.hpp" #include "Quad.h" +enum SplineType +{ + SPLINE_BSPLINE, + SPLINE_COSINE, +}; + class SplineGridCtrlPoint : public Quad { public: @@ -27,6 +33,7 @@ public: // # of control points on each axis void resize(size_t w, size_t h, size_t xres, size_t yres); void recalc(); + void resetControlPoints(); virtual void onRender(const RenderState& rs) const OVERRIDE; @@ -34,6 +41,9 @@ public: private: + void recalcBSpline(); + void recalcCosine(); + SplineGridCtrlPoint *createControlPoint(size_t x, size_t y); unsigned degreeX, degreeY; @@ -46,6 +56,7 @@ private: size_t _yres; std::vector ctrlp; + SplineType splinetype; };