mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-05-09 10:34:05 +00:00
Initial implementation of bspline support in the animation editor
This commit is contained in:
parent
4c52a147b0
commit
575a83abd6
10 changed files with 515 additions and 120 deletions
|
@ -225,8 +225,8 @@ void AnimationEditor::applyState()
|
|||
StateObject::applyState();
|
||||
boneEdit = 0;
|
||||
editingBone = 0;
|
||||
|
||||
currentKey = 0;
|
||||
splinegrid = 0;
|
||||
|
||||
editSprite = new SkeletalSprite();
|
||||
editSprite->cull = false;
|
||||
|
@ -468,15 +468,6 @@ void AnimationEditor::applyState()
|
|||
tr->position = Vector(0, KEYFRAME_POS_Y);
|
||||
addRenderObject(tr, LR_BLACKGROUND);
|
||||
|
||||
splinegrid = new SplineGrid;
|
||||
splinegrid->setTexture("mithalas-house-bg-0001");
|
||||
splinegrid->setWidthHeight(200, 200);
|
||||
splinegrid->position = Vector(400, 300);
|
||||
splinegrid->resize(3,3,10,10,3);
|
||||
splinegrid->resetControlPoints();
|
||||
addRenderObject(splinegrid, LR_PARTICLES_TOP);
|
||||
|
||||
|
||||
editSprite->setSelectedBone(0);
|
||||
|
||||
dsq->overlay->alpha.interpolateTo(0, 0.5f);
|
||||
|
@ -720,12 +711,18 @@ void AnimationEditor::update(float dt)
|
|||
sprintf(t2buf, "Bone x: %.3f, y: %.3f, rot: %.3f strip: %u pass: %d (%d)", ebdata.x, ebdata.y, ebdata.z, (unsigned)selectedStripPoint, pass, origpass);
|
||||
text2->setText(t2buf);
|
||||
|
||||
RenderObject *ctrlSprite;
|
||||
if(splinegrid)
|
||||
ctrlSprite = splinegrid;
|
||||
else
|
||||
ctrlSprite = editSprite;
|
||||
|
||||
if (core->mouse.buttons.middle)
|
||||
{
|
||||
editSprite->position += core->mouse.change;
|
||||
ctrlSprite->position += core->mouse.change;
|
||||
}
|
||||
|
||||
if (editingStrip)
|
||||
if (editingStrip && !splinegrid)
|
||||
{
|
||||
if (isActing(ACTION_SWIMLEFT, -1))
|
||||
moveBoneStripPoint(Vector(-dt, 0));
|
||||
|
@ -740,23 +737,23 @@ void AnimationEditor::update(float dt)
|
|||
int spd = 1;
|
||||
if (core->mouse.scrollWheelChange < 0)
|
||||
{
|
||||
editSprite->scale -= Vector(spd*0.05f,spd*0.05f);
|
||||
ctrlSprite->scale -= Vector(spd*0.05f,spd*0.05f);
|
||||
}
|
||||
else if (core->mouse.scrollWheelChange > 0)
|
||||
{
|
||||
editSprite->scale += Vector(spd*0.05f,spd*0.05f);
|
||||
ctrlSprite->scale += Vector(spd*0.05f,spd*0.05f);
|
||||
}
|
||||
if (core->getKeyState(KEY_PGDN) && core->getShiftState())
|
||||
{
|
||||
editSprite->scale -= Vector(spd*0.05f,spd*0.05f);
|
||||
ctrlSprite->scale -= Vector(spd*0.05f,spd*0.05f);
|
||||
}
|
||||
if (core->getKeyState(KEY_PGUP) && core->getShiftState())
|
||||
{
|
||||
editSprite->scale += Vector(spd*0.05f,spd*0.05f);
|
||||
ctrlSprite->scale += Vector(spd*0.05f,spd*0.05f);
|
||||
}
|
||||
if (editSprite->scale.x < 0.05f)
|
||||
if (ctrlSprite->scale.x < 0.05f)
|
||||
{
|
||||
editSprite->scale = Vector(0.05f,0.05f);
|
||||
ctrlSprite->scale = Vector(0.05f,0.05f);
|
||||
}
|
||||
|
||||
if (boneEdit == 0)
|
||||
|
@ -768,7 +765,7 @@ void AnimationEditor::update(float dt)
|
|||
|
||||
}
|
||||
}
|
||||
if (editingBone && boneEdit == 1)
|
||||
if (editingBone && boneEdit == 1 && !splinegrid)
|
||||
{
|
||||
Vector add = core->mouse.change;
|
||||
// adjust relative mouse movement to absolute bone rotation
|
||||
|
@ -804,11 +801,17 @@ void AnimationEditor::update(float dt)
|
|||
editSprite->updateBones();
|
||||
}
|
||||
}
|
||||
|
||||
if(splinegrid && editingBone && editingStrip && splinegrid->wasModified)
|
||||
{
|
||||
applySplineGridToBone();
|
||||
splinegrid->wasModified = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationEditor::copy()
|
||||
{
|
||||
if (dsq->isNested()) return;
|
||||
if (dsq->isNested()) return;
|
||||
|
||||
if (core->getCtrlState())
|
||||
copyBuffer = *editSprite->getCurrentAnimation()->getKeyframe(currentKey);
|
||||
|
@ -831,7 +834,7 @@ void AnimationEditor::nextKey()
|
|||
{
|
||||
if (dsq->isNested()) return;
|
||||
|
||||
if (editingStrip)
|
||||
if (editingStrip && !splinegrid)
|
||||
{
|
||||
selectedStripPoint++;
|
||||
if (selectedStripPoint >= editSprite->getSelectedBone(false)->changeStrip.size()
|
||||
|
@ -857,13 +860,15 @@ void AnimationEditor::nextKey()
|
|||
currentKey --;
|
||||
}
|
||||
}
|
||||
|
||||
applyBoneToSplineGrid();
|
||||
}
|
||||
|
||||
void AnimationEditor::prevKey()
|
||||
{
|
||||
if (dsq->isNested()) return;
|
||||
|
||||
if (editingStrip)
|
||||
if (editingStrip && !splinegrid)
|
||||
{
|
||||
if(selectedStripPoint > 0) {
|
||||
selectedStripPoint--;
|
||||
|
@ -889,6 +894,8 @@ void AnimationEditor::prevKey()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyBoneToSplineGrid();
|
||||
}
|
||||
|
||||
|
||||
|
@ -938,11 +945,58 @@ void AnimationEditor::editStripKey()
|
|||
selectedStripPoint = 0;
|
||||
editingStrip = false;
|
||||
bgGrad->makeVertical(Vector(0.4f, 0.4f, 0.4f), Vector(0.8f, 0.8f, 0.8f));
|
||||
|
||||
if(splinegrid)
|
||||
{
|
||||
//editSprite->alphaMod = 1;
|
||||
//editSprite->removeChild(splinegrid);
|
||||
splinegrid->safeKill();
|
||||
splinegrid = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
editingStrip = true;
|
||||
bgGrad->makeVertical(Vector(0.4f, 0.4f, 0.6f), Vector(0.8f, 0.8f, 1));
|
||||
if(editingBone && !editingBone->getDrawGrid().empty())
|
||||
{
|
||||
Animation *a = editSprite->getCurrentAnimation();
|
||||
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
|
||||
|
||||
editingStrip = true;
|
||||
|
||||
if(interp)
|
||||
{
|
||||
bgGrad->makeVertical(Vector(0.4f, 0.6f, 0.4f), Vector(0.8f, 1, 0.8f));
|
||||
|
||||
BoneKeyframe *bk = a->getKeyframe(currentKey)->getBoneKeyframe(editingBone->boneIdx);
|
||||
assert(bk->controlpoints.size() == interp->bsp.ctrlX() * interp->bsp.ctrlY());
|
||||
|
||||
splinegrid = new SplineGrid;
|
||||
splinegrid->setTexture(editingBone->texture->name);
|
||||
splinegrid->setWidthHeight(editingBone->width, editingBone->height);
|
||||
splinegrid->position = Vector(400, 300);
|
||||
//splinegrid->followCamera = 1;
|
||||
splinegrid->resize(interp->bsp.ctrlX(), interp->bsp.ctrlY(), editingBone->getDrawGrid().width(), editingBone->getDrawGrid().height(), interp->bsp.degX(), interp->bsp.degY());
|
||||
splinegrid->importControlPoints(&bk->controlpoints[0]);
|
||||
//editSprite->addChild(splinegrid, PM_STATIC, RBP_OFF, CHILD_FRONT);
|
||||
//editSprite->alphaMod = 0.5f;
|
||||
addRenderObject(splinegrid, LR_PARTICLES_TOP);
|
||||
}
|
||||
else
|
||||
{
|
||||
bgGrad->makeVertical(Vector(0.4f, 0.4f, 0.6f), Vector(0.8f, 0.8f, 1));
|
||||
}
|
||||
|
||||
}
|
||||
else if(editingBone)
|
||||
{
|
||||
debugLog("Bone has no grid, cannot edit grid");
|
||||
dsq->sound->playSfx("denied");
|
||||
}
|
||||
else
|
||||
{
|
||||
debugLog("No bone selected for grid edit mode");
|
||||
dsq->sound->playSfx("denied");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1097,6 +1151,8 @@ void AnimationEditor::clearRot()
|
|||
{
|
||||
if(core->getCtrlState())
|
||||
editingBone->texture->reload();
|
||||
else if(splinegrid)
|
||||
splinegrid->resetControlPoints();
|
||||
else
|
||||
applyRotation();
|
||||
}
|
||||
|
@ -1293,6 +1349,8 @@ void AnimationEditor::loadFile()
|
|||
// disable strip edit mode if still active
|
||||
if (editingStrip)
|
||||
editStripKey();
|
||||
|
||||
applyBoneToSplineGrid();
|
||||
}
|
||||
|
||||
void AnimationEditor::goToTitle()
|
||||
|
@ -1325,6 +1383,7 @@ void AnimationEditor::nextAnim()
|
|||
void AnimationEditor::prevAnim()
|
||||
{
|
||||
if (dsq->isNested()) return;
|
||||
if (editingStrip) return;
|
||||
|
||||
if (!core->getShiftState())
|
||||
{
|
||||
|
@ -1475,3 +1534,29 @@ void AnimationEditor::updateTimelineGrid()
|
|||
os << "Grid: " << TIMELINE_GRIDSIZE;
|
||||
gridsize->setText(os.str());
|
||||
}
|
||||
|
||||
void AnimationEditor::applyBoneToSplineGrid()
|
||||
{
|
||||
if(splinegrid && editingBone)
|
||||
{
|
||||
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->getDrawGrid().linearsize());
|
||||
splinegrid->importControlPoints(&bk->controlpoints[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationEditor::applySplineGridToBone()
|
||||
{
|
||||
if(splinegrid && editingBone)
|
||||
{
|
||||
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->getDrawGrid().linearsize());
|
||||
splinegrid->exportControlPoints(&bk->controlpoints[0]);
|
||||
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
|
||||
interp->updateGridAndBone(*bk, editingBone);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,6 +150,8 @@ public:
|
|||
DebugFont *gridsize, *unitsize;
|
||||
|
||||
SplineGrid *splinegrid;
|
||||
void applySplineGridToBone();
|
||||
void applyBoneToSplineGrid();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
#include <math.h>
|
||||
#include "tbsp.hh"
|
||||
|
||||
// usually one would expect that a bspline goes from t=0 to t=1.
|
||||
// here, splines eval between these -0.5 .. +0.5.
|
||||
// this way 0 is perfectly in the center (which is a nice property to have)
|
||||
// but more importantly the Quad::drawGrid in its default state
|
||||
// has values in -0.5..+0.5 in its initial state.
|
||||
// So we follow the same here, that the spline produces values
|
||||
// in -0.5..+0.5 in its initial state.
|
||||
static const float TMIN = -0.5f;
|
||||
static const float TMAX = 0.5f;
|
||||
|
||||
CosineInterpolator::CosineInterpolator()
|
||||
{
|
||||
}
|
||||
|
@ -73,9 +83,10 @@ BSpline2D::BSpline2D()
|
|||
{
|
||||
}
|
||||
|
||||
void BSpline2D::resize(size_t cx, size_t cy, unsigned degx, unsigned degy, float tmin, float tmax)
|
||||
void BSpline2D::resize(size_t cx, size_t cy, unsigned degx, unsigned degy)
|
||||
{
|
||||
controlpoints.resize(cx * cy);
|
||||
const float tmin = TMIN;
|
||||
const float tmax = TMAX;
|
||||
knotsX.resize(tbsp__getNumKnots(cx, degx));
|
||||
knotsY.resize(tbsp__getNumKnots(cy, degy));
|
||||
tbsp::fillKnotVector<float>(&knotsX[0], cx, degx, tmin, tmax);
|
||||
|
@ -88,7 +99,7 @@ void BSpline2D::resize(size_t cx, size_t cy, unsigned degx, unsigned degy, float
|
|||
_tmax = tmax;
|
||||
}
|
||||
|
||||
void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres)
|
||||
void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres, const Vector *controlpoints)
|
||||
{
|
||||
std::vector<Vector> tmpv;
|
||||
size_t degn = std::max(_degx, _degy);
|
||||
|
@ -120,3 +131,34 @@ void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres)
|
|||
dst += xres;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add minx/y, maxx/y params?
|
||||
// this should NOT be tmin?! probably?
|
||||
void BSpline2D::reset(Vector* controlpoints)
|
||||
{
|
||||
const float dx = (_tmax - _tmin) / float(_cpx - 1);
|
||||
const float dy = (_tmax - _tmin) / float(_cpy - 1);
|
||||
float yy = _tmin;
|
||||
for(size_t y = 0; y < _cpy; ++y, yy += dy)
|
||||
{
|
||||
float xx = _tmin;
|
||||
for(size_t x = 0; x < _cpx; ++x, xx += dx)
|
||||
*controlpoints++ = Vector(xx, yy);
|
||||
}
|
||||
}
|
||||
|
||||
void BSpline2DWithPoints::resize(size_t cx, size_t cy, unsigned degx, unsigned degy)
|
||||
{
|
||||
controlpoints.resize(cx * cy);
|
||||
BSpline2D::resize(cx, cy, degx, degy);
|
||||
}
|
||||
|
||||
void BSpline2DWithPoints::recalc(Vector* dst, size_t xres, size_t yres)
|
||||
{
|
||||
BSpline2D::recalc(dst, xres, yres, &controlpoints[0]);
|
||||
}
|
||||
|
||||
void BSpline2DWithPoints::reset()
|
||||
{
|
||||
BSpline2D::reset(&controlpoints[0]);
|
||||
}
|
||||
|
|
|
@ -19,24 +19,16 @@ private:
|
|||
std::vector<std::pair<float, float> > pxy;
|
||||
};
|
||||
|
||||
#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];
|
||||
}
|
||||
void resize(size_t cx, size_t cy, unsigned degx, unsigned degy);
|
||||
void recalc(Vector *dst, size_t xres, size_t yres, const Vector *controlpoints);
|
||||
|
||||
void reset(Vector *controlpoints);
|
||||
|
||||
inline size_t ctrlX() const { return _cpx; }
|
||||
inline size_t ctrlY() const { return _cpy; }
|
||||
|
@ -50,3 +42,23 @@ private:
|
|||
float _tmin, _tmax;
|
||||
std::vector<float> knotsX, knotsY;
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
|
||||
void reset();
|
||||
|
||||
std::vector<Vector> controlpoints;
|
||||
|
||||
inline Vector& controlpoint(size_t x, size_t y)
|
||||
{
|
||||
return controlpoints[y * ctrlX() + x];
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -100,23 +100,50 @@ void Quad::setStripPoints(bool vert, const Vector *points, size_t n)
|
|||
}
|
||||
}
|
||||
|
||||
void Quad::resetGrid()
|
||||
void Quad::ResetGrid(Vector* dst, size_t w, size_t h)
|
||||
{
|
||||
const float yMulF = 1.0f / (float)(drawGrid.height()-1);
|
||||
const float xMulF = 1.0f / (float)(drawGrid.width()-1);
|
||||
assert(w > 1 && h > 1);
|
||||
const float xMulF = 1.0f / (float)(w-1);
|
||||
const float yMulF = 1.0f / (float)(h-1);
|
||||
|
||||
for (size_t y = 0; y < drawGrid.height(); y++)
|
||||
for (size_t y = 0; y < h; y++)
|
||||
{
|
||||
Vector *row = drawGrid.row(y);
|
||||
const float yval = float(y)*yMulF-0.5f;
|
||||
for (size_t x = 0; x < drawGrid.width(); x++)
|
||||
for (size_t x = 0; x < w; x++)
|
||||
{
|
||||
row[x].x = float(x)*xMulF-0.5f;
|
||||
row[x].y = yval;
|
||||
dst->x = float(x)*xMulF-0.5f;
|
||||
dst->y = yval;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Quad::ResetGridAndAlpha(Vector* dst, size_t w, size_t h, float alpha)
|
||||
{
|
||||
assert(w > 1 && h > 1);
|
||||
const float xMulF = 1.0f / (float)(w-1);
|
||||
const float yMulF = 1.0f / (float)(h-1);
|
||||
|
||||
for (size_t y = 0; y < h; y++)
|
||||
{
|
||||
const float yval = float(y)*yMulF-0.5f;
|
||||
for (size_t x = 0; x < w; x++)
|
||||
{
|
||||
dst->x = float(x)*xMulF-0.5f;
|
||||
dst->y = yval;
|
||||
dst->z = alpha;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Quad::resetGrid()
|
||||
{
|
||||
if (drawGrid.empty()) return;
|
||||
|
||||
ResetGrid(drawGrid.data(), drawGrid.width(), drawGrid.height());
|
||||
}
|
||||
|
||||
void Quad::initQuad()
|
||||
{
|
||||
repeatToFillScale = Vector(1,1);
|
||||
|
|
|
@ -93,6 +93,10 @@ public:
|
|||
float borderAlpha;
|
||||
Vector repeatToFillScale;
|
||||
|
||||
static void ResetGrid(Vector *dst, size_t w, size_t h);
|
||||
static void ResetGridAndAlpha(Vector *dst, size_t w, size_t h, float alpha = 1.0f);
|
||||
|
||||
|
||||
protected:
|
||||
float gridTimer;
|
||||
Array2d<Vector> drawGrid;
|
||||
|
|
|
@ -748,6 +748,19 @@ size_t Animation::getSkeletalKeyframeIndex(SkeletalKeyframe *skey)
|
|||
return -1;
|
||||
}
|
||||
|
||||
BoneGridInterpolator * Animation::getBoneGridInterpolator(size_t boneIdx)
|
||||
{
|
||||
for(size_t i = 0; i < interpolators.size(); ++i)
|
||||
{
|
||||
BoneGridInterpolator& bgip = interpolators[i];
|
||||
if(bgip.idx == boneIdx)
|
||||
{
|
||||
return &bgip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BoneKeyframe *SkeletalKeyframe::getBoneKeyframe(size_t idx)
|
||||
{
|
||||
for (size_t i = 0; i < keyframes.size(); i++)
|
||||
|
@ -1012,7 +1025,13 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
bone->SetAttribute("offy", this->bones[i]->offset.y);
|
||||
if (!this->bones[i]->prt.empty())
|
||||
bone->SetAttribute("prt", this->bones[i]->prt.c_str());
|
||||
if (!this->bones[i]->changeStrip.empty())
|
||||
if(!this->bones[i]->getDrawGrid().empty() && this->bones[i]->gridType != Quad::GRID_STRIP)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << this->bones[i]->getDrawGrid().width() << " " << this->bones[i]->getDrawGrid().height();
|
||||
bone->SetAttribute("grid", os.str().c_str());
|
||||
}
|
||||
else if (!this->bones[i]->changeStrip.empty())
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << this->bones[i]->stripVert << " " << this->bones[i]->changeStrip.size();
|
||||
|
@ -1064,6 +1083,45 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
animation->SetAttribute("name", a->name.c_str());
|
||||
if(a->resetPassOnEnd)
|
||||
animation->SetAttribute("resetPassOnEnd", a->resetPassOnEnd);
|
||||
|
||||
for (size_t j = 0; j < a->interpolators.size(); ++j)
|
||||
{
|
||||
const BoneGridInterpolator& bgip = a->interpolators[j];
|
||||
XMLElement *interp = xml->NewElement("Interpolator");
|
||||
Bone *bone = this->getBoneByIdx(bgip.idx);
|
||||
assert(bone->gridType == Quad::GRID_INTERP);
|
||||
if(bgip.storeBoneByIdx)
|
||||
interp->SetAttribute("bone", (int)bone->boneIdx);
|
||||
else
|
||||
interp->SetAttribute("bone", bone->name.c_str());
|
||||
|
||||
{
|
||||
std::ostringstream osty;
|
||||
osty << "bspline"
|
||||
<< " " <<bgip.bsp.ctrlX()
|
||||
<< " " <<bgip.bsp.ctrlY()
|
||||
<< " " <<bgip.bsp.degX()
|
||||
<< " " <<bgip.bsp.degY();
|
||||
interp->SetAttribute("type", osty.str().c_str());
|
||||
}
|
||||
{
|
||||
std::ostringstream osd;
|
||||
for (size_t k = 0; k < a->keyframes.size(); k++)
|
||||
{
|
||||
SkeletalKeyframe& sk = a->keyframes[k];
|
||||
BoneKeyframe *bk = sk.getBoneKeyframe(bgip.idx);
|
||||
|
||||
assert(bk->controlpoints.size() == bgip.bsp.ctrlX() * bgip.bsp.ctrlY());
|
||||
osd << bgip.bsp.ctrlX() << " " << bgip.bsp.ctrlY();
|
||||
for(size_t p = 0; p < bk->controlpoints.size(); ++p)
|
||||
osd << " " << bk->controlpoints[p].x << " " << bk->controlpoints[p].y;
|
||||
osd << " ";
|
||||
}
|
||||
interp->SetAttribute("data", osd.str().c_str());
|
||||
}
|
||||
animation->InsertEndChild(interp);
|
||||
|
||||
}
|
||||
for (size_t j = 0; j < a->keyframes.size(); j++)
|
||||
{
|
||||
XMLElement *key = xml->NewElement("Key");
|
||||
|
@ -1083,16 +1141,16 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
for (size_t k = 0; k < a->keyframes[j].keyframes.size(); k++)
|
||||
{
|
||||
BoneKeyframe *b = &a->keyframes[j].keyframes[k];
|
||||
Bone *bone = this->getBoneByIdx(b->idx);
|
||||
os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
|
||||
os << b->grid.size() << " ";
|
||||
for (size_t i = 0; i < b->grid.size(); i++)
|
||||
{
|
||||
os << b->grid[i].x << " " << b->grid[i].y << " ";
|
||||
}
|
||||
// don't want to store grid points if they can be regenerated automatically
|
||||
size_t usedGridSize = bone->gridType == Quad::GRID_INTERP ? 0 : b->grid.size();
|
||||
os << usedGridSize << " ";
|
||||
if(usedGridSize)
|
||||
for (size_t i = 0; i < usedGridSize; i++)
|
||||
os << b->grid[i].x << " " << b->grid[i].y << " ";
|
||||
if (b->doScale)
|
||||
{
|
||||
szos << b->idx << " " << b->sx << " " << b->sy << " ";
|
||||
}
|
||||
}
|
||||
std::string szoss = szos.str();
|
||||
if (!szoss.empty())
|
||||
|
@ -1104,6 +1162,7 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
}
|
||||
animations->InsertEndChild(animation);
|
||||
}
|
||||
|
||||
xml->InsertEndChild(animations);
|
||||
return xml->SaveFile(file.c_str()) == XML_SUCCESS;
|
||||
}
|
||||
|
@ -1376,7 +1435,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
{
|
||||
if (bones->Attribute("scale"))
|
||||
{
|
||||
SimpleIStringStream is(bones->Attribute("scale"));
|
||||
SimpleIStringStream is(bones->Attribute("scale"), SimpleIStringStream::REUSE);
|
||||
is >> scale.x >> scale.y;
|
||||
}
|
||||
|
||||
|
@ -1411,7 +1470,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if (bone->Attribute("prt"))
|
||||
{
|
||||
newb->prt = bone->Attribute("prt");
|
||||
SimpleIStringStream is(newb->prt);
|
||||
SimpleIStringStream is(newb->prt.c_str(), SimpleIStringStream::REUSE);
|
||||
int slot;
|
||||
std::string pfile;
|
||||
while (is >> slot)
|
||||
|
@ -1477,13 +1536,13 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
}
|
||||
if (bone->Attribute("io"))
|
||||
{
|
||||
SimpleIStringStream is(bone->Attribute("io"));
|
||||
SimpleIStringStream is(bone->Attribute("io"), SimpleIStringStream::REUSE);
|
||||
is >> newb->internalOffset.x >> newb->internalOffset.y;
|
||||
}
|
||||
|
||||
if (bone->Attribute("strip"))
|
||||
{
|
||||
SimpleIStringStream is(bone->Attribute("strip"));
|
||||
SimpleIStringStream is(bone->Attribute("strip"), SimpleIStringStream::REUSE);
|
||||
bool vert;
|
||||
int num;
|
||||
is >> vert >> num;
|
||||
|
@ -1492,7 +1551,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if (bone->Attribute("sz"))
|
||||
{
|
||||
float sx, sy;
|
||||
SimpleIStringStream is(bone->Attribute("sz"));
|
||||
SimpleIStringStream is(bone->Attribute("sz"), SimpleIStringStream::REUSE);
|
||||
is >> sx >> sy;
|
||||
|
||||
newb->scale = newb->originalScale = Vector(sx,sy);
|
||||
|
@ -1512,7 +1571,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if (bone->Attribute("alpha"))
|
||||
{
|
||||
float a=1.0;
|
||||
SimpleIStringStream is(bone->Attribute("alpha"));
|
||||
SimpleIStringStream is(bone->Attribute("alpha"), SimpleIStringStream::REUSE);
|
||||
is >> a;
|
||||
newb->alpha = a;
|
||||
}
|
||||
|
@ -1520,7 +1579,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if (bone->Attribute("alphaMod"))
|
||||
{
|
||||
float a=1.0;
|
||||
SimpleIStringStream is(bone->Attribute("alphaMod"));
|
||||
SimpleIStringStream is(bone->Attribute("alphaMod"), SimpleIStringStream::REUSE);
|
||||
is >> a;
|
||||
newb->alphaMod = a;
|
||||
}
|
||||
|
@ -1530,14 +1589,14 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
int x, y;
|
||||
float dgox, dgoy, dgmx, dgmy, dgtm;
|
||||
bool dgo;
|
||||
SimpleIStringStream is(bone->Attribute("segs"));
|
||||
SimpleIStringStream is(bone->Attribute("segs"), SimpleIStringStream::REUSE);
|
||||
is >> x >> y >> dgox >> dgoy >> dgmx >> dgmy >> dgtm >> dgo;
|
||||
newb->setSegs(x, y, dgox, dgoy, dgmx, dgmy, dgtm, dgo);
|
||||
}
|
||||
|
||||
if (bone->Attribute("color"))
|
||||
{
|
||||
SimpleIStringStream in(bone->Attribute("color"));
|
||||
SimpleIStringStream in(bone->Attribute("color"), SimpleIStringStream::REUSE);
|
||||
in >> newb->color.x >> newb->color.y >> newb->color.z;
|
||||
}
|
||||
if (bone->Attribute("sel"))
|
||||
|
@ -1546,10 +1605,19 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
}
|
||||
if (bone->Attribute("grid"))
|
||||
{
|
||||
SimpleIStringStream is(bone->Attribute("grid"));
|
||||
int x, y;
|
||||
is >> x >> y;
|
||||
newb->createGrid(x, y);
|
||||
if(newb->getDrawGrid().empty())
|
||||
{
|
||||
SimpleIStringStream is(bone->Attribute("grid"), SimpleIStringStream::REUSE);
|
||||
int x, y;
|
||||
is >> x >> y;
|
||||
newb->createGrid(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Bone idx " << newb->idx << " already has a DrawGrid, ignoring \"grid\" attribute";
|
||||
errorLog(os.str());
|
||||
}
|
||||
}
|
||||
bone = bone->NextSiblingElement("Bone");
|
||||
}
|
||||
|
@ -1566,6 +1634,12 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
os << "Parent bone not found, index: " << b->pidx << " from bone idx: " << b->getIdx();
|
||||
debugLog(os.str());
|
||||
}
|
||||
else if(b == pb) // self-loop would crash
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Bone index " << b->pidx << " has itself as parent, this is bad, ignoring";
|
||||
errorLog(os.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
pb->addChild(b, PM_POINTER);
|
||||
|
@ -1586,7 +1660,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
AnimationLayer newAnimationLayer;
|
||||
if (animationLayer->Attribute("ignore"))
|
||||
{
|
||||
SimpleIStringStream is(animationLayer->Attribute("ignore"));
|
||||
SimpleIStringStream is(animationLayer->Attribute("ignore"), SimpleIStringStream::REUSE);
|
||||
int t;
|
||||
while (is >> t)
|
||||
{
|
||||
|
@ -1595,7 +1669,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
}
|
||||
if (animationLayer->Attribute("include"))
|
||||
{
|
||||
SimpleIStringStream is(animationLayer->Attribute("include"));
|
||||
SimpleIStringStream is(animationLayer->Attribute("include"), SimpleIStringStream::REUSE);
|
||||
int t;
|
||||
while (is >> t)
|
||||
{
|
||||
|
@ -1631,7 +1705,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if (key->Attribute("e"))
|
||||
{
|
||||
float time;
|
||||
SimpleIStringStream is(key->Attribute("e"));
|
||||
SimpleIStringStream is(key->Attribute("e"), SimpleIStringStream::REUSE);
|
||||
is >> time;
|
||||
int idx, x, y, rot, strip;
|
||||
newSkeletalKeyframe.t = time;
|
||||
|
@ -1662,7 +1736,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
}
|
||||
if (key->Attribute("sz"))
|
||||
{
|
||||
SimpleIStringStream is2(key->Attribute("sz"));
|
||||
SimpleIStringStream is2(key->Attribute("sz"), SimpleIStringStream::REUSE);
|
||||
int midx;
|
||||
float bsx, bsy;
|
||||
while (is2 >> midx)
|
||||
|
@ -1684,7 +1758,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if (key->Attribute("d"))
|
||||
{
|
||||
float time;
|
||||
SimpleIStringStream is(key->Attribute("d"));
|
||||
SimpleIStringStream is(key->Attribute("d"), SimpleIStringStream::REUSE);
|
||||
is >> time;
|
||||
int idx, x, y, rot;
|
||||
|
||||
|
@ -1707,7 +1781,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if (key->Attribute("cmd"))
|
||||
{
|
||||
newSkeletalKeyframe.cmd = key->Attribute("cmd");
|
||||
SimpleIStringStream is(newSkeletalKeyframe.cmd);
|
||||
SimpleIStringStream is(newSkeletalKeyframe.cmd.c_str(), SimpleIStringStream::REUSE);
|
||||
int bidx;
|
||||
while (is >> bidx)
|
||||
{
|
||||
|
@ -1730,55 +1804,125 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
// generate empty bone keys
|
||||
for (size_t i = 0; i < this->bones.size(); i++)
|
||||
{
|
||||
if (newSkeletalKeyframe.getBoneKeyframe(this->bones[i]->boneIdx))
|
||||
{
|
||||
}
|
||||
else
|
||||
Bone *bone = this->bones[i];
|
||||
const Array2d<Vector>& dg = bone->getDrawGrid();
|
||||
BoneKeyframe *bk = newSkeletalKeyframe.getBoneKeyframe(bone->boneIdx);
|
||||
if(!bk)
|
||||
{
|
||||
BoneKeyframe b;
|
||||
b.idx = this->bones[i]->boneIdx;
|
||||
newSkeletalKeyframe.keyframes.push_back(b);
|
||||
}
|
||||
}
|
||||
newAnimation.keyframes.push_back(newSkeletalKeyframe);
|
||||
key = key->NextSiblingElement("Key");
|
||||
}
|
||||
|
||||
// <Interpolator bone="name or idx" type="TYPE config and params" data="controlpoints; aded by editor" />
|
||||
XMLElement *interp = animation->FirstChildElement("Interpolator");
|
||||
while(interp)
|
||||
for( ; interp; interp = interp->NextSiblingElement("Interpolator"))
|
||||
{
|
||||
Bone *bi = NULL;
|
||||
if(const char *sbone = interp->Attribute("bone"))
|
||||
bi = getBoneByIdx(atoi(sbone));
|
||||
const char *sbone = interp->Attribute("bone");
|
||||
bool boneByIdx = false;
|
||||
if(sbone)
|
||||
{
|
||||
bi = getBoneByName(sbone);
|
||||
if(!bi)
|
||||
{
|
||||
bi = getBoneByIdx(atoi(sbone));
|
||||
boneByIdx = true;
|
||||
}
|
||||
}
|
||||
if(!bi)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Interpolator specifies non-existing bone [" << (sbone ? sbone : "(null)") << "]";
|
||||
debugLog(os.str());
|
||||
continue;
|
||||
//SplineType spline = SPLINE_BSPLINE;
|
||||
}
|
||||
if(bi->getDrawGrid().empty())
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Interpolator specifies bone [" << bi->boneIdx << "] that has no grid";
|
||||
debugLog(os.str());
|
||||
continue;
|
||||
}
|
||||
|
||||
SplineType spline = SPLINE_BSPLINE;
|
||||
int cx = 3, cy = 3, degx = 3, degy = 3;
|
||||
if(const char *stype = interp->Attribute("type"))
|
||||
{
|
||||
SimpleIStringStream is(stype);
|
||||
SimpleIStringStream is(stype, SimpleIStringStream::REUSE);
|
||||
std::string ty;
|
||||
is >> ty;
|
||||
BoneGridInterpolator bgip;
|
||||
if(ty == "bspline")
|
||||
{
|
||||
//spline = SPLINE_BSPLINE;
|
||||
is >> cx >> cy >> degx >> degy;
|
||||
spline = SPLINE_BSPLINE;
|
||||
if(!(is >> cx >> cy >> degx >> degy))
|
||||
{
|
||||
if(!degx)
|
||||
degx = 1;
|
||||
if(!degy)
|
||||
degy = 1;
|
||||
}
|
||||
if(cx < 2)
|
||||
cx = 2;
|
||||
if(cy < 2)
|
||||
cy = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorLog("Unknown interpolator spline type [" + ty + "]");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
BoneGridInterpolator bgip;
|
||||
bi->gridType = Quad::GRID_INTERP;
|
||||
// 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.back();
|
||||
//bgip.type = spline;
|
||||
bgip.idx = bi->boneIdx;
|
||||
bgip.pointsX = cx;
|
||||
bgip.pointsY = cy;
|
||||
bgip.degreeX = degx;
|
||||
bgip.degreeY = degy;
|
||||
bgip.storeBoneByIdx = boneByIdx;
|
||||
|
||||
// TODO
|
||||
|
||||
interp = interp->NextSiblingElement("Interpolator");
|
||||
// ---- bspline -----
|
||||
bgip.bsp.resize(cx, cy, degx, degy);
|
||||
|
||||
const size_t numcp = size_t(cx) * size_t(cy);
|
||||
const size_t numgridp = bi->getDrawGrid().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)
|
||||
{
|
||||
SkeletalKeyframe& kf = newAnimation.keyframes[k];
|
||||
BoneKeyframe *bk = kf.getBoneKeyframe(bgip.idx);
|
||||
|
||||
bk->controlpoints.resize(numcp);
|
||||
bgip.bsp.reset(&bk->controlpoints[0]);
|
||||
|
||||
unsigned w = 0, h = 0;
|
||||
Vector cp;
|
||||
cp.z = 1; // we want all grid points at full alpha
|
||||
|
||||
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 -----
|
||||
}
|
||||
|
||||
animation = animation->NextSiblingElement("Animation");
|
||||
|
@ -1913,7 +2057,7 @@ void AnimationLayer::updateBones()
|
|||
b->scale.x = lerp(bkey1->sx, bkey2->sx, dt, lerpType);
|
||||
b->scale.y = lerp(bkey1->sy, bkey2->sy, dt, lerpType);
|
||||
}
|
||||
if (b->animated==Bone::ANIM_ALL && !b->changeStrip.empty())
|
||||
if (b->animated==Bone::ANIM_ALL && !b->changeStrip.empty() && b->gridType == Quad::GRID_STRIP)
|
||||
{
|
||||
if (bkey2->grid.size() < b->changeStrip.size())
|
||||
bkey2->grid.resize(b->changeStrip.size());
|
||||
|
@ -1925,6 +2069,28 @@ void AnimationLayer::updateBones()
|
|||
}
|
||||
b->setStripPoints(b->stripVert, &b->changeStrip[0], b->changeStrip.size());
|
||||
}
|
||||
if (b->animated==Bone::ANIM_ALL && b->gridType == Quad::GRID_INTERP)
|
||||
{
|
||||
Array2d<Vector>& dg = b->getDrawGrid();
|
||||
const size_t N = dg.linearsize();
|
||||
if(bkey1->grid.size() < N)
|
||||
{
|
||||
bkey1->grid.resize(N);
|
||||
Quad::ResetGridAndAlpha(&bkey1->grid[0], dg.width(), dg.height(), 1.0f);
|
||||
}
|
||||
if(bkey2->grid.size() < N)
|
||||
{
|
||||
bkey2->grid.resize(N);
|
||||
Quad::ResetGridAndAlpha(&bkey2->grid[0], dg.width(), dg.height(), 1.0f);
|
||||
}
|
||||
|
||||
Vector *dst = dg.data();
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
{
|
||||
dst[i].x = lerp(bkey1->grid[i].x, bkey2->grid[i].x, dt, lerpType);
|
||||
dst[i].y = lerp(bkey1->grid[i].y, bkey2->grid[i].y, dt, lerpType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2046,4 +2212,18 @@ void SkeletalSprite::selectNextBone()
|
|||
updateSelectedBoneColor();
|
||||
}
|
||||
|
||||
void BoneGridInterpolator::updateGridOnly(BoneKeyframe& bk, const Bone *bone)
|
||||
{
|
||||
const Array2d<Vector>& dg = bone->getDrawGrid();
|
||||
assert(bone->boneIdx == bk.idx);
|
||||
assert(bk.grid.size() == dg.linearsize());
|
||||
bsp.recalc(&bk.grid[0], dg.width(), dg.height(), &bk.controlpoints[0]);
|
||||
|
||||
}
|
||||
|
||||
void BoneGridInterpolator::updateGridAndBone(BoneKeyframe& bk, Bone *bone)
|
||||
{
|
||||
updateGridOnly(bk, bone);
|
||||
Vector *dst = bone->getDrawGrid().data();
|
||||
std::copy(bk.grid.begin(), bk.grid.end(), dst);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "Quad.h"
|
||||
#include "SimpleIStringStream.h"
|
||||
#include <map>
|
||||
#include "Interpolators.h"
|
||||
// for 2d system only
|
||||
|
||||
enum AnimationCommand
|
||||
|
@ -155,9 +156,10 @@ class BoneGridInterpolator
|
|||
{
|
||||
public:
|
||||
size_t idx;
|
||||
unsigned pointsX, pointsY;
|
||||
unsigned degreeX, degreeY;
|
||||
void updateGrid(BoneKeyframe& bk);
|
||||
BSpline2D bsp;
|
||||
bool storeBoneByIdx;
|
||||
void updateGridOnly(BoneKeyframe& bk, const Bone *bone);
|
||||
void updateGridAndBone(BoneKeyframe& bk, Bone *bone);
|
||||
};
|
||||
|
||||
class Animation
|
||||
|
@ -181,6 +183,7 @@ public:
|
|||
void reverse();
|
||||
bool resetPassOnEnd;
|
||||
|
||||
BoneGridInterpolator *getBoneGridInterpolator(size_t boneIdx);
|
||||
typedef std::vector <BoneGridInterpolator> Interpolators;
|
||||
Interpolators interpolators;
|
||||
};
|
||||
|
|
|
@ -14,27 +14,57 @@ Vector SplineGridCtrlPoint::getSplinePosition() const
|
|||
{
|
||||
SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent();
|
||||
// always return alpha == 1
|
||||
// points within the quad result in in -0.5 .. +0.5 on both axes
|
||||
return Vector(position.x / p->width, position.y / p->height, 1.0f);
|
||||
}
|
||||
|
||||
void SplineGridCtrlPoint::setSplinePosition(Vector pos)
|
||||
{
|
||||
SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent();
|
||||
position.x = pos.x * p->width;
|
||||
position.y = pos.y * p->height;
|
||||
}
|
||||
|
||||
void SplineGridCtrlPoint::onUpdate(float dt)
|
||||
{
|
||||
const bool lmb = core->mouse.buttons.left;
|
||||
|
||||
// FIXME: selected point tracking should be done by the parent
|
||||
|
||||
Vector cur = core->mouse.position;
|
||||
// bool wouldpick = isCoordinateInside(cur); // doesn't work
|
||||
Vector wp = getWorldPosition();
|
||||
const bool wouldpick = (cur - wp).isLength2DIn(10);
|
||||
|
||||
if(wouldpick)
|
||||
color = Vector(1,0,0);
|
||||
else
|
||||
color = Vector(1,1,1);
|
||||
|
||||
if(lmb)
|
||||
{
|
||||
if(!movingPoint && isCoordinateInside(core->mouse.position))
|
||||
if(!movingPoint && wouldpick)
|
||||
{
|
||||
movingPoint = this;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(movingPoint)
|
||||
{
|
||||
movingPoint->color = Vector(1,1,1);
|
||||
movingPoint = NULL;
|
||||
}
|
||||
|
||||
if(movingPoint == this)
|
||||
{
|
||||
SplineGrid *p = (SplineGrid*)getParent();
|
||||
const Vector parentPos = p->getWorldPosition();
|
||||
position = core->mouse.position - parentPos;
|
||||
p->recalc();
|
||||
const Vector invscale = Vector(1.0f / p->scale.x, 1.0f / p->scale.y);
|
||||
Vector newpos = (cur - parentPos) * invscale;
|
||||
if(position != newpos)
|
||||
{
|
||||
position = newpos;
|
||||
p->recalc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +80,7 @@ SplineGrid::~SplineGrid()
|
|||
{
|
||||
}
|
||||
|
||||
void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned deg)
|
||||
void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy)
|
||||
{
|
||||
size_t oldcpx = bsp.ctrlX();
|
||||
size_t oldcpy = bsp.ctrlY();
|
||||
|
@ -74,7 +104,7 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned d
|
|||
}
|
||||
}
|
||||
|
||||
bsp.resize(w, h, deg, deg, -1.0f, 1.0f);
|
||||
bsp.resize(w, h, degx, degy);
|
||||
|
||||
// kill any excess points
|
||||
for(size_t i = 0; i < oldp.size(); ++i)
|
||||
|
@ -95,27 +125,29 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned d
|
|||
|
||||
void SplineGrid::recalc()
|
||||
{
|
||||
for(size_t i = 0; i < ctrlp.size(); ++i)
|
||||
bsp.controlpoints[i] = ctrlp[i]->getSplinePosition();
|
||||
exportControlPoints(&bsp.controlpoints[0]);
|
||||
bsp.recalc(drawGrid.data(), drawGrid.width(), drawGrid.height());
|
||||
wasModified = true;
|
||||
}
|
||||
|
||||
void SplineGrid::exportControlPoints(Vector* controlpoints)
|
||||
{
|
||||
for(size_t i = 0; i < ctrlp.size(); ++i)
|
||||
controlpoints[i] = ctrlp[i]->getSplinePosition();
|
||||
}
|
||||
|
||||
void SplineGrid::importControlPoints(const Vector* controlpoints)
|
||||
{
|
||||
for(size_t i = 0; i < ctrlp.size(); ++i)
|
||||
ctrlp[i]->setSplinePosition(controlpoints[i]);
|
||||
recalc();
|
||||
}
|
||||
|
||||
|
||||
void SplineGrid::resetControlPoints()
|
||||
{
|
||||
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)
|
||||
{
|
||||
float xx = width * -0.5f;
|
||||
SplineGridCtrlPoint **row = &ctrlp[y * cpx];
|
||||
for(size_t x = 0; x < cpx; ++x, xx += dx)
|
||||
row[x]->position = Vector(xx, yy);
|
||||
}
|
||||
bsp.reset();
|
||||
importControlPoints(&bsp.controlpoints[0]);
|
||||
}
|
||||
|
||||
SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y)
|
||||
|
@ -145,7 +177,7 @@ void SplineGrid::onRender(const RenderState& rs) const
|
|||
const Vector wh2(width * 0.5f, height * 0.5f);
|
||||
|
||||
glLineWidth(2);
|
||||
glColor4f(0.0f, 1.0f, 0.3f, 0.3f);
|
||||
glColor4f(0.0f, 0.3f, 1.0f, 0.3f);
|
||||
|
||||
const size_t cpx = bsp.ctrlX();
|
||||
const size_t cpy = bsp.ctrlY();
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
SplineGridCtrlPoint();
|
||||
virtual void onUpdate(float dt) OVERRIDE;
|
||||
Vector getSplinePosition() const;
|
||||
void setSplinePosition(Vector pos);
|
||||
|
||||
static SplineGridCtrlPoint *movingPoint;
|
||||
};
|
||||
|
@ -32,21 +33,28 @@ public:
|
|||
~SplineGrid();
|
||||
|
||||
// # of control points on each axis
|
||||
void resize(size_t w, size_t h, size_t xres, size_t yres, unsigned deg);
|
||||
void 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);
|
||||
void resetControlPoints();
|
||||
|
||||
|
||||
virtual void onRender(const RenderState& rs) const OVERRIDE;
|
||||
virtual void onUpdate(float dt) OVERRIDE;
|
||||
|
||||
BSpline2D& getSpline() { return bsp; }
|
||||
const BSpline2D& getSpline() const { return bsp; }
|
||||
|
||||
bool wasModified; // to be checked/reset by external code
|
||||
|
||||
private:
|
||||
|
||||
SplineGridCtrlPoint *createControlPoint(size_t x, size_t y);
|
||||
|
||||
std::vector<SplineGridCtrlPoint*> ctrlp;
|
||||
unsigned deg;
|
||||
BSpline2D bsp;
|
||||
BSpline2DWithPoints bsp;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue