1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-08-24 15:30:53 +00:00

Merge branch 'more-bspline' into tile-optimization

This commit is contained in:
fgenesis 2024-07-07 05:36:51 +02:00
commit d4b80525a9
8 changed files with 1187 additions and 128 deletions

View file

@ -240,6 +240,7 @@ void AnimationEditor::applyState()
editingBone = 0; editingBone = 0;
currentKey = 0; currentKey = 0;
splinegrid = 0; splinegrid = 0;
assistedSplineEdit = true;
editSprite = new SkeletalSprite(); editSprite = new SkeletalSprite();
editSprite->cull = false; editSprite->cull = false;
@ -302,6 +303,8 @@ void AnimationEditor::applyState()
addAction(MakeFunctionEvent(AnimationEditor, decrTimelineGrid), KEY_O, 0); addAction(MakeFunctionEvent(AnimationEditor, decrTimelineGrid), KEY_O, 0);
addAction(MakeFunctionEvent(AnimationEditor, incrTimelineGrid), KEY_P, 0); addAction(MakeFunctionEvent(AnimationEditor, incrTimelineGrid), KEY_P, 0);
addAction(MakeFunctionEvent(AnimationEditor, toggleSplineMode), KEY_W, 0);
addAction(ACTION_SWIMLEFT, KEY_J, -1); addAction(ACTION_SWIMLEFT, KEY_J, -1);
@ -462,6 +465,12 @@ void AnimationEditor::applyState()
reverseAnim->event.set(MakeFunctionEvent(AnimationEditor, reverseAnim)); reverseAnim->event.set(MakeFunctionEvent(AnimationEditor, reverseAnim));
addRenderObject(reverseAnim, LR_MENU); addRenderObject(reverseAnim, LR_MENU);
DebugButton *bAssist = new DebugButton(0, 0, 150);
bAssist->position = Vector(10, 510);
bAssist->event.set(MakeFunctionEvent(AnimationEditor, toggleSplineMode));
addRenderObject(bAssist, LR_MENU);
bSplineAssist = bAssist;
OutlineRect *rect = new OutlineRect; OutlineRect *rect = new OutlineRect;
rect->setWidthHeight(400,400); rect->setWidthHeight(400,400);
@ -494,6 +503,7 @@ void AnimationEditor::applyState()
updateTimelineGrid(); updateTimelineGrid();
updateTimelineUnit(); updateTimelineUnit();
updateButtonLabels();
} }
void AnimationEditor::clearUndoHistory() void AnimationEditor::clearUndoHistory()
@ -1005,18 +1015,24 @@ void AnimationEditor::editStripKey()
bgGrad->makeVertical(Vector(0.4f, 0.6f, 0.4f), Vector(0.8f, 1, 0.8f)); bgGrad->makeVertical(Vector(0.4f, 0.6f, 0.4f), Vector(0.8f, 1, 0.8f));
BoneKeyframe *bk = a->getKeyframe(currentKey)->getBoneKeyframe(editingBone->boneIdx); BoneKeyframe *bk = a->getKeyframe(currentKey)->getBoneKeyframe(editingBone->boneIdx);
assert(bk->controlpoints.size() == interp->bsp.ctrlX() * interp->bsp.ctrlY()); const size_t totalcp = interp->bsp.ctrlX() * interp->bsp.ctrlY();
const bool reset = bk->controlpoints.empty();
bk->controlpoints.resize(totalcp);
assert(!splinegrid);
splinegrid = new SplineGrid; splinegrid = new SplineGrid();
DynamicRenderGrid *rgrid = splinegrid->resize(interp->bsp.ctrlX(), interp->bsp.ctrlY(), grid->width(), grid->height(), interp->bsp.degX(), interp->bsp.degY()); DynamicRenderGrid *rgrid = splinegrid->resize(interp->bsp.ctrlX(), interp->bsp.ctrlY(), grid->width(), grid->height(), interp->bsp.degX(), interp->bsp.degY());
rgrid->setDrawOrder(grid->getDrawOrder()); rgrid->setDrawOrder(grid->getDrawOrder());
splinegrid->setTexture(editingBone->texture->name); splinegrid->setTexture(editingBone->texture->name);
splinegrid->setWidthHeight(editingBone->width, editingBone->height); splinegrid->setWidthHeight(editingBone->width, editingBone->height);
splinegrid->position = Vector(400, 300); splinegrid->position = Vector(400, 300);
//splinegrid->followCamera = 1; splinegrid->setAssist(assistedSplineEdit);
splinegrid->importControlPoints(&bk->controlpoints[0]);
//editSprite->addChild(splinegrid, PM_STATIC, RBP_OFF, CHILD_FRONT); if(reset)
//editSprite->alphaMod = 0.5f; splinegrid->resetControlPoints();
else
splinegrid->importKeyframe(bk);
addRenderObject(splinegrid, LR_PARTICLES_TOP); addRenderObject(splinegrid, LR_PARTICLES_TOP);
} }
else else
@ -1616,6 +1632,23 @@ void AnimationEditor::decrTimelineGrid()
updateTimelineGrid(); updateTimelineGrid();
} }
void AnimationEditor::toggleSplineMode()
{
assistedSplineEdit = !assistedSplineEdit;
updateButtonLabels();
if(splinegrid)
splinegrid->setAssist(assistedSplineEdit);
}
void AnimationEditor::updateButtonLabels()
{
{
std::ostringstream os;
os << "S.Assist (W)(" << (assistedSplineEdit ? "on" : "off") << ")";
bSplineAssist->label->setText(os.str());
}
}
void AnimationEditor::updateTimelineGrid() void AnimationEditor::updateTimelineGrid()
{ {
std::ostringstream os; std::ostringstream os;
@ -1636,9 +1669,9 @@ void AnimationEditor::applyBoneToSplineGrid()
{ {
Animation *a = editSprite->getCurrentAnimation(); Animation *a = editSprite->getCurrentAnimation();
BoneKeyframe *bk = a->getKeyframe(currentKey)->getBoneKeyframe(editingBone->boneIdx); 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()); assert(bk->grid.size() == editingBone->getGrid()->linearsize());
splinegrid->importControlPoints(&bk->controlpoints[0]); splinegrid->importKeyframe(bk);
} }
} }
@ -1648,10 +1681,10 @@ void AnimationEditor::applySplineGridToBone()
{ {
Animation *a = editSprite->getCurrentAnimation(); Animation *a = editSprite->getCurrentAnimation();
BoneKeyframe *bk = a->getKeyframe(currentKey)->getBoneKeyframe(editingBone->boneIdx); 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()); assert(bk->grid.size() == editingBone->getGrid()->linearsize());
splinegrid->exportControlPoints(&bk->controlpoints[0]); splinegrid->exportKeyframe(bk);
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx); BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
interp->updateGridAndBone(*bk, editingBone); interp->updateGridAndBone(*bk, editingBone);
} }
} }

View file

@ -8,6 +8,7 @@
class DebugFont; class DebugFont;
class BitmapText; class BitmapText;
class SplineGrid; class SplineGrid;
class DebugButton;
class KeyframeWidget : public Quad class KeyframeWidget : public Quad
{ {
@ -133,6 +134,7 @@ public:
SkeletalKeyframe buffer; SkeletalKeyframe buffer;
bool editingStrip; bool editingStrip;
bool assistedSplineEdit;
size_t selectedStripPoint; size_t selectedStripPoint;
void reverseAnim(); void reverseAnim();
@ -162,6 +164,10 @@ public:
SplineGrid *splinegrid; SplineGrid *splinegrid;
void applySplineGridToBone(); void applySplineGridToBone();
void applyBoneToSplineGrid(); void applyBoneToSplineGrid();
void toggleSplineMode();
DebugButton *bSplineAssist;
void updateButtonLabels();
}; };

View file

@ -1,6 +1,5 @@
#include "Interpolators.h" #include "Interpolators.h"
#include <math.h> #include <math.h>
#include "tbsp.hh"
// usually one would expect that a bspline goes from t=0 to t=1. // usually one would expect that a bspline goes from t=0 to t=1.
// here, splines eval between these -0.5 .. +0.5. // here, splines eval between these -0.5 .. +0.5.
@ -101,9 +100,10 @@ void BSpline2D::resize(size_t cx, size_t cy, unsigned degx, unsigned degy)
void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres, const Vector *controlpoints) void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres, const Vector *controlpoints)
{ {
const unsigned maxDeg = std::max(_degx, _degy);
std::vector<Vector> tmpv; std::vector<Vector> tmpv;
size_t degn = std::max(_degx, _degy); size_t tmpn = (yres * _cpx) + maxDeg;
size_t tmpn = (yres * _cpx) + degn;
size_t tmpsz = tmpn * sizeof(Vector); size_t tmpsz = tmpn * sizeof(Vector);
Vector *tmp; Vector *tmp;
if(tmpsz < 17*1024) if(tmpsz < 17*1024)
@ -113,7 +113,9 @@ void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres, const Vector *cont
tmpv.resize(tmpn); tmpv.resize(tmpn);
tmp = &tmpv[0]; tmp = &tmpv[0];
} }
Vector *work = tmp + (tmpn - degn); // 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 // Each column -> Y-axis interpolation
for(size_t x = 0; x < _cpx; ++x) for(size_t x = 0; x < _cpx; ++x)
@ -162,3 +164,80 @@ void BSpline2DWithPoints::reset()
{ {
BSpline2D::reset(&controlpoints[0]); BSpline2D::reset(&controlpoints[0]);
} }
bool BSpline2DControlPointGenerator::resize(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);
cp2d.init(cx, cy);
const size_t maxcp = std::max(cx, cy);
vectmp.resize(maxcp);
return interp.x.init(&floats[0], cx, cx)
&& interp.y.init(&floats[interpStorageSizeX], cy, cy);
}
bool 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];
}
return 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.y.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();
}
bool BSpline2DControlPointGeneratorWithPoints::resize(size_t cx, size_t cy)
{
designpoints.resize(cx * cy);
return BSpline2DControlPointGenerator::resize(cx, cy);
}
Vector* BSpline2DControlPointGeneratorWithPoints::generateControlPoints()
{
return BSpline2DControlPointGenerator::generateControlPoints(&designpoints[0]);
}

View file

@ -4,6 +4,15 @@
#include <algorithm> // std::pair #include <algorithm> // std::pair
#include <vector> #include <vector>
#include "Vector.h" #include "Vector.h"
#include "tbsp.hh"
#include "DataStructures.h"
enum SplineType
{
INTERPOLATOR_BSPLINE,
INTERPOLATOR_COSINE,
INTERPOLATOR_BSPLINE_EXT
};
class CosineInterpolator class CosineInterpolator
{ {
@ -36,18 +45,20 @@ public:
inline unsigned degX() const { return _degx; } inline unsigned degX() const { return _degx; }
inline unsigned degY() const { return _degy; } inline unsigned degY() const { return _degy; }
inline const float *getKnotsX() const { return &knotsX[0]; }
inline const float *getKnotsY() const { return &knotsY[0]; }
private: private:
size_t _cpx, _cpy; // # of control points size_t _cpx, _cpy; // # of control points
unsigned _degx, _degy; unsigned _degx, _degy;
float _tmin, _tmax; float _tmin, _tmax;
std::vector<float> knotsX, knotsY; std::vector<float> knotsX, knotsY;
}; };
class BSpline2DWithPoints : public BSpline2D class BSpline2DWithPoints : public BSpline2D
{ {
public: public:
void resize(size_t cx, size_t cy, unsigned degx, unsigned degy); void resize(size_t cx, size_t cy, unsigned degx, unsigned degy);
void recalc(Vector *dst, size_t xres, size_t yres); void recalc(Vector *dst, size_t xres, size_t yres);
@ -61,4 +72,31 @@ public:
} }
}; };
class BSpline2DControlPointGenerator
{
public:
bool resize(size_t cx, size_t cy);
bool 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:
bool resize(size_t cx, size_t cy);
Vector *generateControlPoints();
std::vector<Vector> designpoints;
};
#endif #endif

View file

@ -1660,7 +1660,9 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
XMLElement *animation = animations->FirstChildElement("Animation"); XMLElement *animation = animations->FirstChildElement("Animation");
while(animation) while(animation)
{ {
Animation newAnimation; this->animations.push_back(Animation());
Animation& newAnimation = this->animations.back();
newAnimation.name = animation->Attribute("name"); newAnimation.name = animation->Attribute("name");
if(animation->Attribute("resetOnEnd")) if(animation->Attribute("resetOnEnd"))
newAnimation.resetOnEnd = animation->BoolAttribute("resetOnEnd"); newAnimation.resetOnEnd = animation->BoolAttribute("resetOnEnd");
@ -1786,8 +1788,15 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
} }
// <Interpolator bone="name or idx" type="TYPE config and params" data="controlpoints; aded by editor" /> // <Interpolator bone="name or idx" type="TYPE config and params" data="controlpoints; aded by editor" />
size_t numInterp = 0;
XMLElement *interp = animation->FirstChildElement("Interpolator"); XMLElement *interp = animation->FirstChildElement("Interpolator");
for( ; interp; interp = interp->NextSiblingElement("Interpolator")) for( ; interp; interp = interp->NextSiblingElement("Interpolator"))
++numInterp;
newAnimation.interpolators.resize(numInterp);
interp = animation->FirstChildElement("Interpolator");
for(numInterp = 0 ; interp; interp = interp->NextSiblingElement("Interpolator"), ++numInterp)
{ {
Bone *bi = NULL; Bone *bi = NULL;
const char *sbone = interp->Attribute("bone"); const char *sbone = interp->Attribute("bone");
@ -1817,17 +1826,16 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
continue; continue;
} }
SplineType spline = SPLINE_BSPLINE; SplineType spline = INTERPOLATOR_BSPLINE;
unsigned cx = 3, cy = 3, degx = 3, degy = 3; unsigned cx = 3, cy = 3, degx = 3, degy = 3;
if(const char *stype = interp->Attribute("type")) if(const char *stype = interp->Attribute("type"))
{ {
SimpleIStringStream is(stype, SimpleIStringStream::REUSE); SimpleIStringStream is(stype, SimpleIStringStream::REUSE);
std::string ty; std::string ty;
is >> ty; is >> ty;
BoneGridInterpolator bgip;
if(ty == "bspline") if(ty == "bspline")
{ {
spline = SPLINE_BSPLINE; spline = INTERPOLATOR_BSPLINE;
if(!(is >> cx >> cy >> degx >> degy)) if(!(is >> cx >> cy >> degx >> degy))
{ {
if(!degx) if(!degx)
@ -1850,10 +1858,8 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
grid->gridType = GRID_INTERP; grid->gridType = GRID_INTERP;
// bone grid should have been created via <Bone grid=... /> earlier // bone grid should have been created via <Bone grid=... /> earlier
const char *idata = interp->Attribute("data");
newAnimation.interpolators.push_back(BoneGridInterpolator()); BoneGridInterpolator& bgip = newAnimation.interpolators[numInterp];
BoneGridInterpolator& bgip = newAnimation.interpolators.back();
//bgip.type = spline;
bgip.idx = bi->boneIdx; bgip.idx = bi->boneIdx;
bgip.storeBoneByIdx = boneByIdx; bgip.storeBoneByIdx = boneByIdx;
@ -1864,38 +1870,40 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
const size_t numcp = size_t(cx) * size_t(cy); const size_t numcp = size_t(cx) * size_t(cy);
const size_t numgridp = grid->linearsize(); const size_t numgridp = grid->linearsize();
// data format: "W H [x y x y ... (W*H times)] W H x y x y ..." if(const char *idata = interp->Attribute("data"))
// ^- 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)
{ {
SkeletalKeyframe& kf = newAnimation.keyframes[k]; // data format: "W H [x y x y ... (W*H times)] W H x y x y ..."
BoneKeyframe *bk = kf.getBoneKeyframe(bgip.idx); // ^- start of 1st keyframe ^- 2nd keyframe
SimpleIStringStream is(idata, SimpleIStringStream::REUSE);
bk->controlpoints.resize(numcp); // fixup keyframes and recalc spline points
bgip.bsp.reset(&bk->controlpoints[0]); 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; bk->controlpoints.resize(numcp);
Vector cp; bgip.bsp.reset(&bk->controlpoints[0]);
cp.z = 1; // we want all grid points at full alpha
if((is >> w >> h)) unsigned w = 0, h = 0;
for(unsigned y = 0; y < h; ++y) Vector cp;
for(unsigned x = 0; x < w; ++x) cp.z = 1; // we want all grid points at full alpha
if((is >> cp.x >> cp.y))
if(x < cx && y < cy)
bk->controlpoints[y*size_t(cx) + x] = cp;
bk->grid.resize(numgridp); if((is >> w >> h))
bgip.updateGridOnly(*bk, bi); 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 ----- // ---- end bspline -----
} }
animation = animation->NextSiblingElement("Animation"); animation = animation->NextSiblingElement("Animation");
this->animations.push_back(newAnimation);
} }
} }
} }

View file

@ -1,7 +1,12 @@
#include "SplineGrid.h" #include "SplineGrid.h"
#include <assert.h>
#include "RenderBase.h" #include "RenderBase.h"
#include "Core.h" #include "Core.h"
#include "RenderGrid.h" #include "RenderGrid.h"
#include "SkeletalSprite.h"
SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint; SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint;
@ -74,11 +79,12 @@ void SplineGridCtrlPoint::onUpdate(float dt)
} }
SplineGrid::SplineGrid() SplineGrid::SplineGrid()
: wasModified(false), deg(0), pointscale(1) : wasModified(false), deg(0), pointscale(1), _assistMode(true)
{ {
setWidthHeight(128, 128); setWidthHeight(128, 128);
renderQuad = true; renderQuad = true;
renderBorder = true; renderBorder = true;
renderBorderColor = Vector(0.5f, 0.5f, 0.5f);
} }
SplineGrid::~SplineGrid() SplineGrid::~SplineGrid()
@ -87,6 +93,9 @@ SplineGrid::~SplineGrid()
DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy) DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy)
{ {
if(!cpgen.resize(w, h))
return NULL;
size_t oldcpx = bsp.ctrlX(); size_t oldcpx = bsp.ctrlX();
size_t oldcpy = bsp.ctrlY(); size_t oldcpy = bsp.ctrlY();
@ -126,6 +135,9 @@ DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yr
ref = createControlPoint(x, y); ref = createControlPoint(x, y);
} }
if(!cpgen.refresh(bsp.getKnotsX(), bsp.getKnotsY(), bsp.degX(), bsp.degY()))
return NULL;
recalc(); recalc();
return ret; return ret;
@ -133,7 +145,17 @@ DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yr
void SplineGrid::recalc() void SplineGrid::recalc()
{ {
exportControlPoints(&bsp.controlpoints[0]); if(_assistMode)
{
exportGridPoints(&cpgen.designpoints[0]);
_generateControlPointsFromDesignPoints();
}
else
{
exportGridPoints(&bsp.controlpoints[0]);
bsp.recalc(&cpgen.designpoints[0], bsp.ctrlX(), bsp.ctrlY());
}
if(grid) if(grid)
{ {
bsp.recalc(grid->dataRW(), grid->width(), grid->height()); bsp.recalc(grid->dataRW(), grid->width(), grid->height());
@ -141,24 +163,67 @@ void SplineGrid::recalc()
} }
} }
void SplineGrid::exportControlPoints(Vector* controlpoints) void SplineGrid::exportGridPoints(Vector* pdst) const
{ {
for(size_t i = 0; i < ctrlp.size(); ++i) 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) 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(_assistMode)
{
// 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(); 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() void SplineGrid::resetControlPoints()
{ {
bsp.reset(); 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(_assistMode) // ALWAYS DO THIS!!
{
cpgen.designpoints = bsp.controlpoints;
_generateControlPointsFromDesignPoints();
}
recalc();
}
void SplineGrid::_generateControlPointsFromDesignPoints()
{
const Vector *cp = cpgen.generateControlPoints();
memcpy(&bsp.controlpoints[0], cp, bsp.controlpoints.size() * sizeof(*cp));
} }
SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y) SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y)
@ -190,7 +255,10 @@ void SplineGrid::onRender(const RenderState& rs) const
const Vector wh2(width * 0.5f, height * 0.5f); const Vector wh2(width * 0.5f, height * 0.5f);
glLineWidth(2); glLineWidth(2);
glColor4f(0.0f, 0.3f, 1.0f, 0.3f); if(_assistMode)
glColor4f(0.0f, 0.3f, 1.0f, 0.4f);
else
glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
const size_t cpx = bsp.ctrlX(); const size_t cpx = bsp.ctrlX();
const size_t cpy = bsp.ctrlY(); const size_t cpy = bsp.ctrlY();
@ -219,6 +287,45 @@ void SplineGrid::onRender(const RenderState& rs) const
} }
glEnd(); glEnd();
} }
const Vector *psrc = _assistMode
? &bsp.controlpoints[0]
: &cpgen.designpoints[0];
if(RenderObject::renderCollisionShape)
{
glLineWidth(1);
glColor4f(1.0f, 0.3f, 0.3f, 0.7f);
glPushMatrix();
glScalef(width, height, 1);
// X axis
for(size_t y = 0; y < cpy; ++y)
{
glBegin(GL_LINE_STRIP);
const Vector *row = &psrc[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 = psrc[y * cpx + x];
glVertex2f(p.x, p.y);
}
glEnd();
}
glPopMatrix();
}
} }
void SplineGrid::setPointScale(const float scale) void SplineGrid::setPointScale(const float scale)
@ -230,3 +337,17 @@ void SplineGrid::setPointScale(const float scale)
ctrlp[i]->scale.y = scale; ctrlp[i]->scale.y = scale;
} }
} }
void SplineGrid::setAssist(bool on)
{
if(on == _assistMode)
return;
if(on)
importGridPoints(&cpgen.designpoints[0]);
else
importGridPoints(&bsp.controlpoints[0]);
_assistMode = on;
recalc();
}

View file

@ -7,11 +7,8 @@
#include "Quad.h" #include "Quad.h"
#include "Interpolators.h" #include "Interpolators.h"
enum SplineType
{ class BoneKeyframe;
SPLINE_BSPLINE,
SPLINE_COSINE,
};
class SplineGridCtrlPoint : public Quad class SplineGridCtrlPoint : public Quad
{ {
@ -36,13 +33,22 @@ public:
// # of control points on each axis // # of control points on each axis
DynamicRenderGrid *resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy); DynamicRenderGrid *resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy);
void recalc(); 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 resetControlPoints();
void setPointScale(const float scale); void setPointScale(const float scale);
float getPointScale() const { return pointscale; } float getPointScale() const { return pointscale; }
void setAssist(bool on);
virtual void onRender(const RenderState& rs) const OVERRIDE; virtual void onRender(const RenderState& rs) const OVERRIDE;
virtual void onUpdate(float dt) OVERRIDE; virtual void onUpdate(float dt) OVERRIDE;
@ -53,6 +59,7 @@ public:
bool wasModified; // to be checked/reset by external code bool wasModified; // to be checked/reset by external code
private: private:
void _generateControlPointsFromDesignPoints();
SplineGridCtrlPoint *createControlPoint(size_t x, size_t y); SplineGridCtrlPoint *createControlPoint(size_t x, size_t y);
@ -60,6 +67,9 @@ private:
unsigned deg; unsigned deg;
BSpline2DWithPoints bsp; BSpline2DWithPoints bsp;
float pointscale; float pointscale;
BSpline2DControlPointGeneratorWithPoints cpgen;
bool _assistMode;
}; };

File diff suppressed because it is too large Load diff