1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-11-29 03:33:48 +00:00

bspline point gen is now properly integrated and only called while in the editor.

the remaining code uses the same old basic control points as it previously did.
This commit is contained in:
fgenesis 2024-07-07 03:30:54 +02:00
parent 7d2f961573
commit 36aaa77436
6 changed files with 267 additions and 148 deletions

View file

@ -1015,7 +1015,7 @@ void AnimationEditor::editStripKey()
splinegrid->setWidthHeight(editingBone->width, editingBone->height);
splinegrid->position = Vector(400, 300);
//splinegrid->followCamera = 1;
splinegrid->importControlPoints(&bk->controlpoints[0]);
splinegrid->importKeyframe(bk);
//editSprite->addChild(splinegrid, PM_STATIC, RBP_OFF, CHILD_FRONT);
//editSprite->alphaMod = 0.5f;
addRenderObject(splinegrid, LR_PARTICLES_TOP);
@ -1637,9 +1637,9 @@ void AnimationEditor::applyBoneToSplineGrid()
{
Animation *a = editSprite->getCurrentAnimation();
BoneKeyframe *bk = a->getKeyframe(currentKey)->getBoneKeyframe(editingBone->boneIdx);
assert(bk->controlpoints.size() == splinegrid->getSpline().ctrlX() * splinegrid->getSpline().ctrlY());
assert(bk->grid.size() == editingBone->getGrid()->linearsize());
splinegrid->importControlPoints(&bk->controlpoints[0]);
splinegrid->importKeyframe(bk);
}
}
@ -1649,9 +1649,8 @@ void AnimationEditor::applySplineGridToBone()
{
Animation *a = editSprite->getCurrentAnimation();
BoneKeyframe *bk = a->getKeyframe(currentKey)->getBoneKeyframe(editingBone->boneIdx);
assert(bk->controlpoints.size() == splinegrid->getSpline().ctrlX() * splinegrid->getSpline().ctrlY());
assert(bk->grid.size() == editingBone->getGrid()->linearsize());
splinegrid->exportControlPoints(&bk->controlpoints[0]);
splinegrid->exportKeyframe(bk);
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
interp->updateGridAndBone(*bk, editingBone);
}

View file

@ -78,24 +78,7 @@ tail:
}
BSpline2D::BSpline2D()
: _cpx(0), _cpy(0), _degx(0), _degy(0), _tmin(0), _tmax(0), _ext(NULL)
{
}
BSpline2D::~BSpline2D()
{
if(_ext)
{
_ext->~Extended();
free(_ext);
}
}
BSpline2D::BSpline2D(const BSpline2D& o)
: _cpx(o._cpx), _cpy(o._cpy), _degx(o._degx), _degy(o._degy)
, _tmin(o._tmin), _tmax(o._tmax)
, knotsX(o.knotsX), knotsY(o.knotsY)
, _ext(NULL) // VERY important
: _cpx(0), _cpy(0), _degx(0), _degy(0), _tmin(0), _tmax(0)
{
}
@ -113,84 +96,10 @@ void BSpline2D::resize(size_t cx, size_t cy, unsigned degx, unsigned degy)
_degy = degy;
_tmin = tmin;
_tmax = tmax;
const size_t maxCp = std::max(cx, cy);
const size_t interpStorageSizeX = tbsp__getInterpolatorStorageSize(cx, cx);
const size_t interpStorageSizeY = tbsp__getInterpolatorStorageSize(cy, cy);
const size_t interpRefreshTempSize = tbsp__getInterpolatorRefreshTempSize(maxCp, maxCp);
const size_t interpStorageNeeded = interpStorageSizeX + interpStorageSizeY;
if(_ext && _ext->capacity < interpStorageNeeded)
{
_ext->~Extended();
free(_ext);
_ext = NULL;
}
if(!_ext)
{
void *extmem = malloc(sizeof(Extended) + sizeof(float) * interpStorageNeeded);
Extended *ext = new (extmem) Extended;
ext->capacity = interpStorageNeeded;
_ext = ext;
}
if(_ext)
{
// Some extra temp memory is required during init, but can be discarded right afterward
std::vector<float> interptmp(interpRefreshTempSize);
float *mx = _ext->floats();
float *my = mx + interpStorageSizeX;
_ext->interp.x.init(mx, cx, cx);
_ext->interp.x.refresh(&interptmp[0], &knotsX[0], degx);
_ext->interp.y.init(my, cy, cy);
_ext->interp.y.refresh(&interptmp[0], &knotsY[0], degy);
_ext->tmp2d.init(cx, cy);
}
}
void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres, const Vector *controlpoints)
{
if(_ext)
{
const size_t maxCp = std::max(_cpx, _cpy);
Array2d<Vector>& tmp2d = _ext->tmp2d;
std::vector<Vector> tmpcp(maxCp), tmpin(maxCp);
// FIXME: should have in/out stride in the generator function
// y direction first
for(size_t x = 0; x < _cpx; ++x)
{
const Vector *src = &controlpoints[x];
for(size_t i = 0; i < _cpy; ++i, src += _cpx)
tmpin[i] = *src;
_ext->interp.y.generateControlPoints<Vector>(&tmpcp[0], NULL, &tmpin[0]);
for(size_t y = 0; y < _cpy; ++y)
tmp2d(x, y) = tmpcp[y];
}
// x direction
for(size_t y = 0; y < _cpy; ++y)
{
Vector *row = tmp2d.row(y);
memcpy(&tmpin[0], row, sizeof(Vector) * _cpx);
_ext->interp.x.generateControlPoints<Vector>(row, NULL, &tmpin[0]);
}
controlpoints = tmp2d.data();
}
const unsigned maxDeg = std::max(_degx, _degy);
std::vector<Vector> tmpv;
@ -204,6 +113,8 @@ void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres, const Vector *cont
tmpv.resize(tmpn);
tmp = &tmpv[0];
}
// tmp[] layout: leftmost part: entries to hold the matrix as it's being built;
// rightmost part: maxDeg entries as workmem for the deBoor eval
Vector *work = tmp + (tmpn - maxDeg);
// Each column -> Y-axis interpolation
@ -253,3 +164,79 @@ void BSpline2DWithPoints::reset()
{
BSpline2D::reset(&controlpoints[0]);
}
BSpline2DControlPointGenerator::BSpline2DControlPointGenerator(size_t cx, size_t cy)
{
const size_t interpStorageSizeX = tbsp__getInterpolatorStorageSize(cx, cx);
const size_t interpStorageSizeY = tbsp__getInterpolatorStorageSize(cy, cy);
const size_t interpStorageNeeded = interpStorageSizeX + interpStorageSizeY;
floats.resize(interpStorageNeeded);
interp.x.init(&floats[0], cx, cx);
interp.y.init(&floats[interpStorageSizeX], cy, cy);
cp2d.init(cx, cy);
const size_t maxcp = std::max(cx, cy);
vectmp.resize(maxcp);
}
void BSpline2DControlPointGenerator::refresh(const float* knotsx, const float* knotsy, unsigned degx, unsigned degy)
{
const size_t maxcp = vectmp.size();
const size_t tmpn = tbsp__getInterpolatorRefreshTempSize(maxcp, maxcp);
const size_t tmpsz = tmpn * sizeof(float);
float *tmp;
std::vector<float> tmpv;
if(tmpsz < 17*1024)
tmp = (float*)alloca(tmpsz);
else
{
tmpv.resize(tmpn);
tmp = &tmpv[0];
}
interp.x.refresh(tmp, knotsx, degx);
interp.y.refresh(tmp, knotsy, degy);
}
Vector* BSpline2DControlPointGenerator::generateControlPoints(const Vector *points2d)
{
const size_t cpx = interp.x.getNumInputPoints();
const size_t cpy = interp.x.getNumInputPoints();
// y direction first
for(size_t x = 0; x < cpx; ++x)
{
const Vector *src = &points2d[x];
for(size_t y = 0; y < cpy; ++y, src += cpx)
vectmp[y] = *src;
// solve in-place
interp.y.generateControlPoints<Vector>(&vectmp[0], NULL, &vectmp[0]);
for(size_t y = 0; y < cpy; ++y)
cp2d(x, y) = vectmp[y];
}
// x direction
for(size_t y = 0; y < cpy; ++y)
{
Vector *row = cp2d.row(y);
// solve in-place
interp.x.generateControlPoints<Vector>(row, NULL, row);
}
return cp2d.data();
}
BSpline2DControlPointGeneratorWithPoints::BSpline2DControlPointGeneratorWithPoints(size_t cx, size_t cy)
: BSpline2DControlPointGenerator(cx, cy)
, designpoints(cx * cy)
{
}
Vector* BSpline2DControlPointGeneratorWithPoints::generateControlPoints()
{
return BSpline2DControlPointGenerator::generateControlPoints(&designpoints[0]);
}

View file

@ -32,9 +32,6 @@ class BSpline2D
{
public:
BSpline2D();
BSpline2D(const BSpline2D&);
~BSpline2D();
// # of control points on each axis
void resize(size_t cx, size_t cy, unsigned degx, unsigned degy);
@ -48,34 +45,20 @@ public:
inline unsigned degX() const { return _degx; }
inline unsigned degY() const { return _degy; }
inline const float *getKnotsX() const { return &knotsX[0]; }
inline const float *getKnotsY() const { return &knotsY[0]; }
private:
size_t _cpx, _cpy; // # of control points
unsigned _degx, _degy;
float _tmin, _tmax;
std::vector<float> knotsX, knotsY;
// always allocated on heap, with extra space at the end
struct Extended
{
Array2d<Vector> tmp2d;
struct
{
tbsp::Interpolator<float> x, y;
} interp;
size_t capacity;
float *floats() { return reinterpret_cast<float*>(this + 1); }
// space for n floats follows
};
Extended *_ext;
};
class BSpline2DWithPoints : public BSpline2D
{
public:
void resize(size_t cx, size_t cy, unsigned degx, unsigned degy);
void recalc(Vector *dst, size_t xres, size_t yres);
@ -89,4 +72,31 @@ public:
}
};
class BSpline2DControlPointGenerator
{
public:
BSpline2DControlPointGenerator(size_t cx, size_t cy);
void refresh(const float *knotsx, const float *knotsy, unsigned degx, unsigned degy);
Vector *generateControlPoints(const Vector *points2d);
private:
Array2d<Vector> cp2d;
struct
{
tbsp::Interpolator<float> x, y;
} interp;
std::vector<float> floats;
std::vector<Vector> vectmp;
};
class BSpline2DControlPointGeneratorWithPoints : public BSpline2DControlPointGenerator
{
public:
BSpline2DControlPointGeneratorWithPoints(size_t cx, size_t cy);
Vector *generateControlPoints();
std::vector<Vector> designpoints;
};
#endif

View file

@ -1858,7 +1858,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
grid->gridType = GRID_INTERP;
// bone grid should have been created via <Bone grid=... /> earlier
const char *idata = interp->Attribute("data");
BoneGridInterpolator& bgip = newAnimation.interpolators[numInterp];
bgip.idx = bi->boneIdx;
bgip.storeBoneByIdx = boneByIdx;
@ -1870,32 +1870,35 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
const size_t numcp = size_t(cx) * size_t(cy);
const size_t numgridp = grid->linearsize();
// data format: "W H [x y x y ... (W*H times)] W H x y x y ..."
// ^- start of 1st keyframe ^- 2nd keyframe
SimpleIStringStream is(idata ? idata : "", SimpleIStringStream::REUSE);
// fixup keyframes and recalc spline points
for(size_t k = 0; k < newAnimation.keyframes.size(); ++k)
if(const char *idata = interp->Attribute("data"))
{
SkeletalKeyframe& kf = newAnimation.keyframes[k];
BoneKeyframe *bk = kf.getBoneKeyframe(bgip.idx);
// data format: "W H [x y x y ... (W*H times)] W H x y x y ..."
// ^- start of 1st keyframe ^- 2nd keyframe
SimpleIStringStream is(idata, SimpleIStringStream::REUSE);
bk->controlpoints.resize(numcp);
bgip.bsp.reset(&bk->controlpoints[0]);
// fixup keyframes and recalc spline points
for(size_t k = 0; k < newAnimation.keyframes.size(); ++k)
{
SkeletalKeyframe& kf = newAnimation.keyframes[k];
BoneKeyframe *bk = kf.getBoneKeyframe(bgip.idx);
unsigned w = 0, h = 0;
Vector cp;
cp.z = 1; // we want all grid points at full alpha
bk->controlpoints.resize(numcp);
bgip.bsp.reset(&bk->controlpoints[0]);
if((is >> w >> h))
for(unsigned y = 0; y < h; ++y)
for(unsigned x = 0; x < w; ++x)
if((is >> cp.x >> cp.y))
if(x < cx && y < cy)
bk->controlpoints[y*size_t(cx) + x] = cp;
unsigned w = 0, h = 0;
Vector cp;
cp.z = 1; // we want all grid points at full alpha
bk->grid.resize(numgridp);
bgip.updateGridOnly(*bk, bi);
if((is >> w >> h))
for(unsigned y = 0; y < h; ++y)
for(unsigned x = 0; x < w; ++x)
if((is >> cp.x >> cp.y))
if(x < cx && y < cy)
bk->controlpoints[y*size_t(cx) + x] = cp;
bk->grid.resize(numgridp);
bgip.updateGridOnly(*bk, bi);
}
}
// ---- end bspline -----
}

View file

@ -1,7 +1,12 @@
#include "SplineGrid.h"
#include <assert.h>
#include "RenderBase.h"
#include "Core.h"
#include "RenderGrid.h"
#include "SkeletalSprite.h"
SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint;
@ -74,7 +79,7 @@ void SplineGridCtrlPoint::onUpdate(float dt)
}
SplineGrid::SplineGrid()
: wasModified(false), deg(0), pointscale(1)
: wasModified(false), deg(0), pointscale(1), cpgen(NULL)
{
setWidthHeight(128, 128);
renderQuad = true;
@ -83,6 +88,7 @@ SplineGrid::SplineGrid()
SplineGrid::~SplineGrid()
{
delete cpgen;
}
DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy)
@ -90,6 +96,12 @@ DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yr
size_t oldcpx = bsp.ctrlX();
size_t oldcpy = bsp.ctrlY();
if(cpgen && (oldcpx != w || oldcpy != h))
{
delete cpgen;
cpgen = NULL;
}
DynamicRenderGrid *ret = this->createGrid(xres, yres);
ret->gridType = GRID_INTERP;
@ -126,6 +138,8 @@ DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yr
ref = createControlPoint(x, y);
}
_initCpgen();
recalc();
return ret;
@ -133,7 +147,16 @@ DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yr
void SplineGrid::recalc()
{
exportControlPoints(&bsp.controlpoints[0]);
if(cpgen)
{
exportGridPoints(&cpgen->designpoints[0]);
_generateControlPointsFromDesignPoints();
}
else
{
exportGridPoints(&bsp.controlpoints[0]);
}
if(grid)
{
bsp.recalc(grid->dataRW(), grid->width(), grid->height());
@ -141,24 +164,74 @@ void SplineGrid::recalc()
}
}
void SplineGrid::exportControlPoints(Vector* controlpoints)
void SplineGrid::exportGridPoints(Vector* pdst) const
{
for(size_t i = 0; i < ctrlp.size(); ++i)
controlpoints[i] = ctrlp[i]->getSplinePosition();
pdst[i] = ctrlp[i]->getSplinePosition();
}
void SplineGrid::importControlPoints(const Vector* controlpoints)
void SplineGrid::importGridPoints(const Vector* psrc)
{
for(size_t i = 0; i < ctrlp.size(); ++i)
ctrlp[i]->setSplinePosition(controlpoints[i]);
ctrlp[i]->setSplinePosition(psrc[i]);
}
void SplineGrid::importKeyframe(const BoneKeyframe* bk)
{
const size_t numcp = bsp.ctrlX() * bsp.ctrlY();
assert(bk->controlpoints.size() == numcp);
bsp.controlpoints = bk->controlpoints;
if(cpgen)
{
// given control points, generate spline points (which are later caculated back into control points)
bsp.recalc(&cpgen->designpoints[0], bsp.ctrlX(), bsp.ctrlY());
importGridPoints(&cpgen->designpoints[0]);
}
else
importGridPoints(&bk->controlpoints[0]);
recalc();
}
void SplineGrid::exportKeyframe(BoneKeyframe* bk) const
{
const size_t numcp = bsp.ctrlX() * bsp.ctrlY();
assert(bk->controlpoints.size() == numcp);
bk->controlpoints = bsp.controlpoints;
}
void SplineGrid::resetControlPoints()
{
bsp.reset();
importControlPoints(&bsp.controlpoints[0]);
importGridPoints(&bsp.controlpoints[0]);
// This pushes the bspline controlpoints outwards so that all spline points line up as one would expect.
// If this weren't done, the tile's texture would be pulled inwards (more with increasing dimension);
// as if the tile was a piece of plastic foil that's seen too much heat.
if(cpgen)
{
cpgen->designpoints = bsp.controlpoints;
_generateControlPointsFromDesignPoints();
}
recalc();
}
void SplineGrid::_generateControlPointsFromDesignPoints()
{
const Vector *cp = cpgen->generateControlPoints();
memcpy(&bsp.controlpoints[0], cp, bsp.controlpoints.size() * sizeof(*cp));
}
void SplineGrid::_initCpgen()
{
assert(!cpgen);
cpgen = new BSpline2DControlPointGeneratorWithPoints(bsp.ctrlX(), bsp.ctrlY());
cpgen->refresh(bsp.getKnotsX(), bsp.getKnotsY(), bsp.degX(), bsp.degY());
}
SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y)
@ -219,6 +292,40 @@ void SplineGrid::onRender(const RenderState& rs) const
}
glEnd();
}
if(RenderObject::renderCollisionShape && cpgen)
{
glColor4f(1.0f, 0.4f, 0.4f, 0.7f);
glPushMatrix();
glScalef(width, height, 1);
// X axis
for(size_t y = 0; y < cpy; ++y)
{
glBegin(GL_LINE_STRIP);
const Vector *row = &bsp.controlpoints[y * cpx];
for(size_t x = 0; x < cpx; ++x)
{
const Vector p = row[x];
glVertex2f(p.x, p.y);
}
glEnd();
}
// Y axis
for(size_t x = 0; x < cpx; ++x)
{
glBegin(GL_LINE_STRIP);
for(size_t y = 0; y < cpy; ++y)
{
const Vector p = bsp.controlpoints[y * cpx + x];
glVertex2f(p.x, p.y);
}
glEnd();
}
glPopMatrix();
}
}
void SplineGrid::setPointScale(const float scale)

View file

@ -8,6 +8,8 @@
#include "Interpolators.h"
class BoneKeyframe;
class SplineGridCtrlPoint : public Quad
{
public:
@ -31,8 +33,15 @@ public:
// # of control points on each axis
DynamicRenderGrid *resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy);
void recalc();
void exportControlPoints(Vector *controlpoints);
void importControlPoints(const Vector *controlpoints);
// Export/import grid points; depending on the mode these either correspond directly to control points
// or to spline points from which the control points need to be calculated first (using cpgen)
void exportGridPoints(Vector *pdst) const;
void importGridPoints(const Vector *psrc);
void importKeyframe(const BoneKeyframe *bk);
void exportKeyframe(BoneKeyframe *bk) const;
void resetControlPoints();
void setPointScale(const float scale);
@ -48,6 +57,8 @@ public:
bool wasModified; // to be checked/reset by external code
private:
void _generateControlPointsFromDesignPoints();
void _initCpgen();
SplineGridCtrlPoint *createControlPoint(size_t x, size_t y);
@ -55,6 +66,8 @@ private:
unsigned deg;
BSpline2DWithPoints bsp;
float pointscale;
BSpline2DControlPointGeneratorWithPoints *cpgen;
};