mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-07-04 15:04:36 +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();
|
StateObject::applyState();
|
||||||
boneEdit = 0;
|
boneEdit = 0;
|
||||||
editingBone = 0;
|
editingBone = 0;
|
||||||
|
|
||||||
currentKey = 0;
|
currentKey = 0;
|
||||||
|
splinegrid = 0;
|
||||||
|
|
||||||
editSprite = new SkeletalSprite();
|
editSprite = new SkeletalSprite();
|
||||||
editSprite->cull = false;
|
editSprite->cull = false;
|
||||||
|
@ -468,15 +468,6 @@ void AnimationEditor::applyState()
|
||||||
tr->position = Vector(0, KEYFRAME_POS_Y);
|
tr->position = Vector(0, KEYFRAME_POS_Y);
|
||||||
addRenderObject(tr, LR_BLACKGROUND);
|
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);
|
editSprite->setSelectedBone(0);
|
||||||
|
|
||||||
dsq->overlay->alpha.interpolateTo(0, 0.5f);
|
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);
|
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);
|
text2->setText(t2buf);
|
||||||
|
|
||||||
|
RenderObject *ctrlSprite;
|
||||||
|
if(splinegrid)
|
||||||
|
ctrlSprite = splinegrid;
|
||||||
|
else
|
||||||
|
ctrlSprite = editSprite;
|
||||||
|
|
||||||
if (core->mouse.buttons.middle)
|
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))
|
if (isActing(ACTION_SWIMLEFT, -1))
|
||||||
moveBoneStripPoint(Vector(-dt, 0));
|
moveBoneStripPoint(Vector(-dt, 0));
|
||||||
|
@ -740,23 +737,23 @@ void AnimationEditor::update(float dt)
|
||||||
int spd = 1;
|
int spd = 1;
|
||||||
if (core->mouse.scrollWheelChange < 0)
|
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)
|
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())
|
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())
|
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)
|
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;
|
Vector add = core->mouse.change;
|
||||||
// adjust relative mouse movement to absolute bone rotation
|
// adjust relative mouse movement to absolute bone rotation
|
||||||
|
@ -804,6 +801,12 @@ void AnimationEditor::update(float dt)
|
||||||
editSprite->updateBones();
|
editSprite->updateBones();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(splinegrid && editingBone && editingStrip && splinegrid->wasModified)
|
||||||
|
{
|
||||||
|
applySplineGridToBone();
|
||||||
|
splinegrid->wasModified = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationEditor::copy()
|
void AnimationEditor::copy()
|
||||||
|
@ -831,7 +834,7 @@ void AnimationEditor::nextKey()
|
||||||
{
|
{
|
||||||
if (dsq->isNested()) return;
|
if (dsq->isNested()) return;
|
||||||
|
|
||||||
if (editingStrip)
|
if (editingStrip && !splinegrid)
|
||||||
{
|
{
|
||||||
selectedStripPoint++;
|
selectedStripPoint++;
|
||||||
if (selectedStripPoint >= editSprite->getSelectedBone(false)->changeStrip.size()
|
if (selectedStripPoint >= editSprite->getSelectedBone(false)->changeStrip.size()
|
||||||
|
@ -857,13 +860,15 @@ void AnimationEditor::nextKey()
|
||||||
currentKey --;
|
currentKey --;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyBoneToSplineGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationEditor::prevKey()
|
void AnimationEditor::prevKey()
|
||||||
{
|
{
|
||||||
if (dsq->isNested()) return;
|
if (dsq->isNested()) return;
|
||||||
|
|
||||||
if (editingStrip)
|
if (editingStrip && !splinegrid)
|
||||||
{
|
{
|
||||||
if(selectedStripPoint > 0) {
|
if(selectedStripPoint > 0) {
|
||||||
selectedStripPoint--;
|
selectedStripPoint--;
|
||||||
|
@ -889,6 +894,8 @@ void AnimationEditor::prevKey()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyBoneToSplineGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -938,12 +945,59 @@ void AnimationEditor::editStripKey()
|
||||||
selectedStripPoint = 0;
|
selectedStripPoint = 0;
|
||||||
editingStrip = false;
|
editingStrip = false;
|
||||||
bgGrad->makeVertical(Vector(0.4f, 0.4f, 0.4f), Vector(0.8f, 0.8f, 0.8f));
|
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
|
else
|
||||||
{
|
{
|
||||||
|
if(editingBone && !editingBone->getDrawGrid().empty())
|
||||||
|
{
|
||||||
|
Animation *a = editSprite->getCurrentAnimation();
|
||||||
|
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
|
||||||
|
|
||||||
editingStrip = true;
|
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));
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationEditor::deleteKey()
|
void AnimationEditor::deleteKey()
|
||||||
|
@ -1097,6 +1151,8 @@ void AnimationEditor::clearRot()
|
||||||
{
|
{
|
||||||
if(core->getCtrlState())
|
if(core->getCtrlState())
|
||||||
editingBone->texture->reload();
|
editingBone->texture->reload();
|
||||||
|
else if(splinegrid)
|
||||||
|
splinegrid->resetControlPoints();
|
||||||
else
|
else
|
||||||
applyRotation();
|
applyRotation();
|
||||||
}
|
}
|
||||||
|
@ -1293,6 +1349,8 @@ void AnimationEditor::loadFile()
|
||||||
// disable strip edit mode if still active
|
// disable strip edit mode if still active
|
||||||
if (editingStrip)
|
if (editingStrip)
|
||||||
editStripKey();
|
editStripKey();
|
||||||
|
|
||||||
|
applyBoneToSplineGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationEditor::goToTitle()
|
void AnimationEditor::goToTitle()
|
||||||
|
@ -1325,6 +1383,7 @@ void AnimationEditor::nextAnim()
|
||||||
void AnimationEditor::prevAnim()
|
void AnimationEditor::prevAnim()
|
||||||
{
|
{
|
||||||
if (dsq->isNested()) return;
|
if (dsq->isNested()) return;
|
||||||
|
if (editingStrip) return;
|
||||||
|
|
||||||
if (!core->getShiftState())
|
if (!core->getShiftState())
|
||||||
{
|
{
|
||||||
|
@ -1475,3 +1534,29 @@ void AnimationEditor::updateTimelineGrid()
|
||||||
os << "Grid: " << TIMELINE_GRIDSIZE;
|
os << "Grid: " << TIMELINE_GRIDSIZE;
|
||||||
gridsize->setText(os.str());
|
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;
|
DebugFont *gridsize, *unitsize;
|
||||||
|
|
||||||
SplineGrid *splinegrid;
|
SplineGrid *splinegrid;
|
||||||
|
void applySplineGridToBone();
|
||||||
|
void applyBoneToSplineGrid();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,16 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "tbsp.hh"
|
#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()
|
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));
|
knotsX.resize(tbsp__getNumKnots(cx, degx));
|
||||||
knotsY.resize(tbsp__getNumKnots(cy, degy));
|
knotsY.resize(tbsp__getNumKnots(cy, degy));
|
||||||
tbsp::fillKnotVector<float>(&knotsX[0], cx, degx, tmin, tmax);
|
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;
|
_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;
|
std::vector<Vector> tmpv;
|
||||||
size_t degn = std::max(_degx, _degy);
|
size_t degn = std::max(_degx, _degy);
|
||||||
|
@ -120,3 +131,34 @@ void BSpline2D::recalc(Vector* dst, size_t xres, size_t yres)
|
||||||
dst += xres;
|
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;
|
std::vector<std::pair<float, float> > pxy;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class BSpline2D
|
class BSpline2D
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BSpline2D();
|
BSpline2D();
|
||||||
|
|
||||||
// # of control points on each axis
|
// # of control points on each axis
|
||||||
void resize(size_t cx, size_t cy, unsigned degx, unsigned degy, float tmin, float tmax);
|
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, const Vector *controlpoints);
|
||||||
|
|
||||||
std::vector<Vector> controlpoints;
|
|
||||||
|
|
||||||
inline Vector& controlpoint(size_t x, size_t y)
|
|
||||||
{
|
|
||||||
return controlpoints[y * _cpx + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void reset(Vector *controlpoints);
|
||||||
|
|
||||||
inline size_t ctrlX() const { return _cpx; }
|
inline size_t ctrlX() const { return _cpx; }
|
||||||
inline size_t ctrlY() const { return _cpy; }
|
inline size_t ctrlY() const { return _cpy; }
|
||||||
|
@ -50,3 +42,23 @@ private:
|
||||||
float _tmin, _tmax;
|
float _tmin, _tmax;
|
||||||
std::vector<float> knotsX, knotsY;
|
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,21 +100,48 @@ void Quad::setStripPoints(bool vert, const Vector *points, size_t n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Quad::ResetGrid(Vector* dst, size_t w, size_t h)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
void Quad::resetGrid()
|
||||||
{
|
{
|
||||||
const float yMulF = 1.0f / (float)(drawGrid.height()-1);
|
if (drawGrid.empty()) return;
|
||||||
const float xMulF = 1.0f / (float)(drawGrid.width()-1);
|
|
||||||
|
|
||||||
for (size_t y = 0; y < drawGrid.height(); y++)
|
ResetGrid(drawGrid.data(), drawGrid.width(), drawGrid.height());
|
||||||
{
|
|
||||||
Vector *row = drawGrid.row(y);
|
|
||||||
const float yval = float(y)*yMulF-0.5f;
|
|
||||||
for (size_t x = 0; x < drawGrid.width(); x++)
|
|
||||||
{
|
|
||||||
row[x].x = float(x)*xMulF-0.5f;
|
|
||||||
row[x].y = yval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Quad::initQuad()
|
void Quad::initQuad()
|
||||||
|
|
|
@ -93,6 +93,10 @@ public:
|
||||||
float borderAlpha;
|
float borderAlpha;
|
||||||
Vector repeatToFillScale;
|
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:
|
protected:
|
||||||
float gridTimer;
|
float gridTimer;
|
||||||
Array2d<Vector> drawGrid;
|
Array2d<Vector> drawGrid;
|
||||||
|
|
|
@ -748,6 +748,19 @@ size_t Animation::getSkeletalKeyframeIndex(SkeletalKeyframe *skey)
|
||||||
return -1;
|
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)
|
BoneKeyframe *SkeletalKeyframe::getBoneKeyframe(size_t idx)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < keyframes.size(); i++)
|
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);
|
bone->SetAttribute("offy", this->bones[i]->offset.y);
|
||||||
if (!this->bones[i]->prt.empty())
|
if (!this->bones[i]->prt.empty())
|
||||||
bone->SetAttribute("prt", this->bones[i]->prt.c_str());
|
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;
|
std::ostringstream os;
|
||||||
os << this->bones[i]->stripVert << " " << this->bones[i]->changeStrip.size();
|
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());
|
animation->SetAttribute("name", a->name.c_str());
|
||||||
if(a->resetPassOnEnd)
|
if(a->resetPassOnEnd)
|
||||||
animation->SetAttribute("resetPassOnEnd", 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++)
|
for (size_t j = 0; j < a->keyframes.size(); j++)
|
||||||
{
|
{
|
||||||
XMLElement *key = xml->NewElement("Key");
|
XMLElement *key = xml->NewElement("Key");
|
||||||
|
@ -1083,17 +1141,17 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
||||||
for (size_t k = 0; k < a->keyframes[j].keyframes.size(); k++)
|
for (size_t k = 0; k < a->keyframes[j].keyframes.size(); k++)
|
||||||
{
|
{
|
||||||
BoneKeyframe *b = &a->keyframes[j].keyframes[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->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
|
||||||
os << b->grid.size() << " ";
|
// don't want to store grid points if they can be regenerated automatically
|
||||||
for (size_t i = 0; i < b->grid.size(); i++)
|
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 << " ";
|
os << b->grid[i].x << " " << b->grid[i].y << " ";
|
||||||
}
|
|
||||||
if (b->doScale)
|
if (b->doScale)
|
||||||
{
|
|
||||||
szos << b->idx << " " << b->sx << " " << b->sy << " ";
|
szos << b->idx << " " << b->sx << " " << b->sy << " ";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
std::string szoss = szos.str();
|
std::string szoss = szos.str();
|
||||||
if (!szoss.empty())
|
if (!szoss.empty())
|
||||||
key->SetAttribute("sz", szoss.c_str());
|
key->SetAttribute("sz", szoss.c_str());
|
||||||
|
@ -1104,6 +1162,7 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
||||||
}
|
}
|
||||||
animations->InsertEndChild(animation);
|
animations->InsertEndChild(animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
xml->InsertEndChild(animations);
|
xml->InsertEndChild(animations);
|
||||||
return xml->SaveFile(file.c_str()) == XML_SUCCESS;
|
return xml->SaveFile(file.c_str()) == XML_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1376,7 +1435,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
{
|
{
|
||||||
if (bones->Attribute("scale"))
|
if (bones->Attribute("scale"))
|
||||||
{
|
{
|
||||||
SimpleIStringStream is(bones->Attribute("scale"));
|
SimpleIStringStream is(bones->Attribute("scale"), SimpleIStringStream::REUSE);
|
||||||
is >> scale.x >> scale.y;
|
is >> scale.x >> scale.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1411,7 +1470,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
if (bone->Attribute("prt"))
|
if (bone->Attribute("prt"))
|
||||||
{
|
{
|
||||||
newb->prt = bone->Attribute("prt");
|
newb->prt = bone->Attribute("prt");
|
||||||
SimpleIStringStream is(newb->prt);
|
SimpleIStringStream is(newb->prt.c_str(), SimpleIStringStream::REUSE);
|
||||||
int slot;
|
int slot;
|
||||||
std::string pfile;
|
std::string pfile;
|
||||||
while (is >> slot)
|
while (is >> slot)
|
||||||
|
@ -1477,13 +1536,13 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
}
|
}
|
||||||
if (bone->Attribute("io"))
|
if (bone->Attribute("io"))
|
||||||
{
|
{
|
||||||
SimpleIStringStream is(bone->Attribute("io"));
|
SimpleIStringStream is(bone->Attribute("io"), SimpleIStringStream::REUSE);
|
||||||
is >> newb->internalOffset.x >> newb->internalOffset.y;
|
is >> newb->internalOffset.x >> newb->internalOffset.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bone->Attribute("strip"))
|
if (bone->Attribute("strip"))
|
||||||
{
|
{
|
||||||
SimpleIStringStream is(bone->Attribute("strip"));
|
SimpleIStringStream is(bone->Attribute("strip"), SimpleIStringStream::REUSE);
|
||||||
bool vert;
|
bool vert;
|
||||||
int num;
|
int num;
|
||||||
is >> vert >> num;
|
is >> vert >> num;
|
||||||
|
@ -1492,7 +1551,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
if (bone->Attribute("sz"))
|
if (bone->Attribute("sz"))
|
||||||
{
|
{
|
||||||
float sx, sy;
|
float sx, sy;
|
||||||
SimpleIStringStream is(bone->Attribute("sz"));
|
SimpleIStringStream is(bone->Attribute("sz"), SimpleIStringStream::REUSE);
|
||||||
is >> sx >> sy;
|
is >> sx >> sy;
|
||||||
|
|
||||||
newb->scale = newb->originalScale = Vector(sx,sy);
|
newb->scale = newb->originalScale = Vector(sx,sy);
|
||||||
|
@ -1512,7 +1571,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
if (bone->Attribute("alpha"))
|
if (bone->Attribute("alpha"))
|
||||||
{
|
{
|
||||||
float a=1.0;
|
float a=1.0;
|
||||||
SimpleIStringStream is(bone->Attribute("alpha"));
|
SimpleIStringStream is(bone->Attribute("alpha"), SimpleIStringStream::REUSE);
|
||||||
is >> a;
|
is >> a;
|
||||||
newb->alpha = a;
|
newb->alpha = a;
|
||||||
}
|
}
|
||||||
|
@ -1520,7 +1579,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
if (bone->Attribute("alphaMod"))
|
if (bone->Attribute("alphaMod"))
|
||||||
{
|
{
|
||||||
float a=1.0;
|
float a=1.0;
|
||||||
SimpleIStringStream is(bone->Attribute("alphaMod"));
|
SimpleIStringStream is(bone->Attribute("alphaMod"), SimpleIStringStream::REUSE);
|
||||||
is >> a;
|
is >> a;
|
||||||
newb->alphaMod = a;
|
newb->alphaMod = a;
|
||||||
}
|
}
|
||||||
|
@ -1530,14 +1589,14 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
int x, y;
|
int x, y;
|
||||||
float dgox, dgoy, dgmx, dgmy, dgtm;
|
float dgox, dgoy, dgmx, dgmy, dgtm;
|
||||||
bool dgo;
|
bool dgo;
|
||||||
SimpleIStringStream is(bone->Attribute("segs"));
|
SimpleIStringStream is(bone->Attribute("segs"), SimpleIStringStream::REUSE);
|
||||||
is >> x >> y >> dgox >> dgoy >> dgmx >> dgmy >> dgtm >> dgo;
|
is >> x >> y >> dgox >> dgoy >> dgmx >> dgmy >> dgtm >> dgo;
|
||||||
newb->setSegs(x, y, dgox, dgoy, dgmx, dgmy, dgtm, dgo);
|
newb->setSegs(x, y, dgox, dgoy, dgmx, dgmy, dgtm, dgo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bone->Attribute("color"))
|
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;
|
in >> newb->color.x >> newb->color.y >> newb->color.z;
|
||||||
}
|
}
|
||||||
if (bone->Attribute("sel"))
|
if (bone->Attribute("sel"))
|
||||||
|
@ -1546,11 +1605,20 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
}
|
}
|
||||||
if (bone->Attribute("grid"))
|
if (bone->Attribute("grid"))
|
||||||
{
|
{
|
||||||
SimpleIStringStream is(bone->Attribute("grid"));
|
if(newb->getDrawGrid().empty())
|
||||||
|
{
|
||||||
|
SimpleIStringStream is(bone->Attribute("grid"), SimpleIStringStream::REUSE);
|
||||||
int x, y;
|
int x, y;
|
||||||
is >> x >> y;
|
is >> x >> y;
|
||||||
newb->createGrid(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");
|
bone = bone->NextSiblingElement("Bone");
|
||||||
}
|
}
|
||||||
// attach bones
|
// attach bones
|
||||||
|
@ -1566,6 +1634,12 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
os << "Parent bone not found, index: " << b->pidx << " from bone idx: " << b->getIdx();
|
os << "Parent bone not found, index: " << b->pidx << " from bone idx: " << b->getIdx();
|
||||||
debugLog(os.str());
|
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
|
else
|
||||||
{
|
{
|
||||||
pb->addChild(b, PM_POINTER);
|
pb->addChild(b, PM_POINTER);
|
||||||
|
@ -1586,7 +1660,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
AnimationLayer newAnimationLayer;
|
AnimationLayer newAnimationLayer;
|
||||||
if (animationLayer->Attribute("ignore"))
|
if (animationLayer->Attribute("ignore"))
|
||||||
{
|
{
|
||||||
SimpleIStringStream is(animationLayer->Attribute("ignore"));
|
SimpleIStringStream is(animationLayer->Attribute("ignore"), SimpleIStringStream::REUSE);
|
||||||
int t;
|
int t;
|
||||||
while (is >> t)
|
while (is >> t)
|
||||||
{
|
{
|
||||||
|
@ -1595,7 +1669,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
}
|
}
|
||||||
if (animationLayer->Attribute("include"))
|
if (animationLayer->Attribute("include"))
|
||||||
{
|
{
|
||||||
SimpleIStringStream is(animationLayer->Attribute("include"));
|
SimpleIStringStream is(animationLayer->Attribute("include"), SimpleIStringStream::REUSE);
|
||||||
int t;
|
int t;
|
||||||
while (is >> t)
|
while (is >> t)
|
||||||
{
|
{
|
||||||
|
@ -1631,7 +1705,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
if (key->Attribute("e"))
|
if (key->Attribute("e"))
|
||||||
{
|
{
|
||||||
float time;
|
float time;
|
||||||
SimpleIStringStream is(key->Attribute("e"));
|
SimpleIStringStream is(key->Attribute("e"), SimpleIStringStream::REUSE);
|
||||||
is >> time;
|
is >> time;
|
||||||
int idx, x, y, rot, strip;
|
int idx, x, y, rot, strip;
|
||||||
newSkeletalKeyframe.t = time;
|
newSkeletalKeyframe.t = time;
|
||||||
|
@ -1662,7 +1736,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
}
|
}
|
||||||
if (key->Attribute("sz"))
|
if (key->Attribute("sz"))
|
||||||
{
|
{
|
||||||
SimpleIStringStream is2(key->Attribute("sz"));
|
SimpleIStringStream is2(key->Attribute("sz"), SimpleIStringStream::REUSE);
|
||||||
int midx;
|
int midx;
|
||||||
float bsx, bsy;
|
float bsx, bsy;
|
||||||
while (is2 >> midx)
|
while (is2 >> midx)
|
||||||
|
@ -1684,7 +1758,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
if (key->Attribute("d"))
|
if (key->Attribute("d"))
|
||||||
{
|
{
|
||||||
float time;
|
float time;
|
||||||
SimpleIStringStream is(key->Attribute("d"));
|
SimpleIStringStream is(key->Attribute("d"), SimpleIStringStream::REUSE);
|
||||||
is >> time;
|
is >> time;
|
||||||
int idx, x, y, rot;
|
int idx, x, y, rot;
|
||||||
|
|
||||||
|
@ -1707,7 +1781,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
if (key->Attribute("cmd"))
|
if (key->Attribute("cmd"))
|
||||||
{
|
{
|
||||||
newSkeletalKeyframe.cmd = key->Attribute("cmd");
|
newSkeletalKeyframe.cmd = key->Attribute("cmd");
|
||||||
SimpleIStringStream is(newSkeletalKeyframe.cmd);
|
SimpleIStringStream is(newSkeletalKeyframe.cmd.c_str(), SimpleIStringStream::REUSE);
|
||||||
int bidx;
|
int bidx;
|
||||||
while (is >> bidx)
|
while (is >> bidx)
|
||||||
{
|
{
|
||||||
|
@ -1730,55 +1804,125 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
||||||
// generate empty bone keys
|
// generate empty bone keys
|
||||||
for (size_t i = 0; i < this->bones.size(); i++)
|
for (size_t i = 0; i < this->bones.size(); i++)
|
||||||
{
|
{
|
||||||
if (newSkeletalKeyframe.getBoneKeyframe(this->bones[i]->boneIdx))
|
Bone *bone = this->bones[i];
|
||||||
{
|
const Array2d<Vector>& dg = bone->getDrawGrid();
|
||||||
}
|
BoneKeyframe *bk = newSkeletalKeyframe.getBoneKeyframe(bone->boneIdx);
|
||||||
else
|
if(!bk)
|
||||||
{
|
{
|
||||||
BoneKeyframe b;
|
BoneKeyframe b;
|
||||||
b.idx = this->bones[i]->boneIdx;
|
b.idx = this->bones[i]->boneIdx;
|
||||||
newSkeletalKeyframe.keyframes.push_back(b);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newAnimation.keyframes.push_back(newSkeletalKeyframe);
|
newAnimation.keyframes.push_back(newSkeletalKeyframe);
|
||||||
key = key->NextSiblingElement("Key");
|
key = key->NextSiblingElement("Key");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// <Interpolator bone="name or idx" type="TYPE config and params" data="controlpoints; aded by editor" />
|
||||||
XMLElement *interp = animation->FirstChildElement("Interpolator");
|
XMLElement *interp = animation->FirstChildElement("Interpolator");
|
||||||
while(interp)
|
for( ; interp; interp = interp->NextSiblingElement("Interpolator"))
|
||||||
{
|
{
|
||||||
Bone *bi = NULL;
|
Bone *bi = NULL;
|
||||||
if(const char *sbone = interp->Attribute("bone"))
|
const char *sbone = interp->Attribute("bone");
|
||||||
bi = getBoneByIdx(atoi(sbone));
|
bool boneByIdx = false;
|
||||||
|
if(sbone)
|
||||||
|
{
|
||||||
|
bi = getBoneByName(sbone);
|
||||||
if(!bi)
|
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;
|
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;
|
int 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 is(stype, SimpleIStringStream::REUSE);
|
||||||
std::string ty;
|
std::string ty;
|
||||||
is >> ty;
|
is >> ty;
|
||||||
BoneGridInterpolator bgip;
|
BoneGridInterpolator bgip;
|
||||||
if(ty == "bspline")
|
if(ty == "bspline")
|
||||||
{
|
{
|
||||||
//spline = SPLINE_BSPLINE;
|
spline = SPLINE_BSPLINE;
|
||||||
is >> cx >> cy >> degx >> degy;
|
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.type = spline;
|
||||||
bgip.idx = bi->boneIdx;
|
bgip.idx = bi->boneIdx;
|
||||||
bgip.pointsX = cx;
|
bgip.storeBoneByIdx = boneByIdx;
|
||||||
bgip.pointsY = cy;
|
|
||||||
bgip.degreeX = degx;
|
|
||||||
bgip.degreeY = degy;
|
|
||||||
|
|
||||||
// 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");
|
animation = animation->NextSiblingElement("Animation");
|
||||||
|
@ -1913,7 +2057,7 @@ void AnimationLayer::updateBones()
|
||||||
b->scale.x = lerp(bkey1->sx, bkey2->sx, dt, lerpType);
|
b->scale.x = lerp(bkey1->sx, bkey2->sx, dt, lerpType);
|
||||||
b->scale.y = lerp(bkey1->sy, bkey2->sy, 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())
|
if (bkey2->grid.size() < b->changeStrip.size())
|
||||||
bkey2->grid.resize(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());
|
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();
|
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 "Quad.h"
|
||||||
#include "SimpleIStringStream.h"
|
#include "SimpleIStringStream.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include "Interpolators.h"
|
||||||
// for 2d system only
|
// for 2d system only
|
||||||
|
|
||||||
enum AnimationCommand
|
enum AnimationCommand
|
||||||
|
@ -155,9 +156,10 @@ class BoneGridInterpolator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
size_t idx;
|
size_t idx;
|
||||||
unsigned pointsX, pointsY;
|
BSpline2D bsp;
|
||||||
unsigned degreeX, degreeY;
|
bool storeBoneByIdx;
|
||||||
void updateGrid(BoneKeyframe& bk);
|
void updateGridOnly(BoneKeyframe& bk, const Bone *bone);
|
||||||
|
void updateGridAndBone(BoneKeyframe& bk, Bone *bone);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Animation
|
class Animation
|
||||||
|
@ -181,6 +183,7 @@ public:
|
||||||
void reverse();
|
void reverse();
|
||||||
bool resetPassOnEnd;
|
bool resetPassOnEnd;
|
||||||
|
|
||||||
|
BoneGridInterpolator *getBoneGridInterpolator(size_t boneIdx);
|
||||||
typedef std::vector <BoneGridInterpolator> Interpolators;
|
typedef std::vector <BoneGridInterpolator> Interpolators;
|
||||||
Interpolators interpolators;
|
Interpolators interpolators;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,28 +14,58 @@ Vector SplineGridCtrlPoint::getSplinePosition() const
|
||||||
{
|
{
|
||||||
SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent();
|
SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent();
|
||||||
// always return alpha == 1
|
// 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);
|
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)
|
void SplineGridCtrlPoint::onUpdate(float dt)
|
||||||
{
|
{
|
||||||
const bool lmb = core->mouse.buttons.left;
|
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(lmb)
|
||||||
{
|
{
|
||||||
if(!movingPoint && isCoordinateInside(core->mouse.position))
|
if(!movingPoint && wouldpick)
|
||||||
|
{
|
||||||
movingPoint = this;
|
movingPoint = this;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else if(movingPoint)
|
||||||
|
{
|
||||||
|
movingPoint->color = Vector(1,1,1);
|
||||||
movingPoint = NULL;
|
movingPoint = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(movingPoint == this)
|
if(movingPoint == this)
|
||||||
{
|
{
|
||||||
SplineGrid *p = (SplineGrid*)getParent();
|
SplineGrid *p = (SplineGrid*)getParent();
|
||||||
const Vector parentPos = p->getWorldPosition();
|
const Vector parentPos = p->getWorldPosition();
|
||||||
position = core->mouse.position - parentPos;
|
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();
|
p->recalc();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SplineGrid::SplineGrid()
|
SplineGrid::SplineGrid()
|
||||||
|
@ -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 oldcpx = bsp.ctrlX();
|
||||||
size_t oldcpy = bsp.ctrlY();
|
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
|
// kill any excess points
|
||||||
for(size_t i = 0; i < oldp.size(); ++i)
|
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()
|
void SplineGrid::recalc()
|
||||||
{
|
{
|
||||||
for(size_t i = 0; i < ctrlp.size(); ++i)
|
exportControlPoints(&bsp.controlpoints[0]);
|
||||||
bsp.controlpoints[i] = ctrlp[i]->getSplinePosition();
|
|
||||||
bsp.recalc(drawGrid.data(), drawGrid.width(), drawGrid.height());
|
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()
|
void SplineGrid::resetControlPoints()
|
||||||
{
|
{
|
||||||
const size_t cpx = bsp.ctrlX();
|
bsp.reset();
|
||||||
const size_t cpy = bsp.ctrlY();
|
importControlPoints(&bsp.controlpoints[0]);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y)
|
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);
|
const Vector wh2(width * 0.5f, height * 0.5f);
|
||||||
|
|
||||||
glLineWidth(2);
|
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 cpx = bsp.ctrlX();
|
||||||
const size_t cpy = bsp.ctrlY();
|
const size_t cpy = bsp.ctrlY();
|
||||||
|
|
|
@ -19,6 +19,7 @@ public:
|
||||||
SplineGridCtrlPoint();
|
SplineGridCtrlPoint();
|
||||||
virtual void onUpdate(float dt) OVERRIDE;
|
virtual void onUpdate(float dt) OVERRIDE;
|
||||||
Vector getSplinePosition() const;
|
Vector getSplinePosition() const;
|
||||||
|
void setSplinePosition(Vector pos);
|
||||||
|
|
||||||
static SplineGridCtrlPoint *movingPoint;
|
static SplineGridCtrlPoint *movingPoint;
|
||||||
};
|
};
|
||||||
|
@ -32,21 +33,28 @@ public:
|
||||||
~SplineGrid();
|
~SplineGrid();
|
||||||
|
|
||||||
// # of control points on each axis
|
// # 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 recalc();
|
||||||
|
void exportControlPoints(Vector *controlpoints);
|
||||||
|
void importControlPoints(const Vector *controlpoints);
|
||||||
void resetControlPoints();
|
void resetControlPoints();
|
||||||
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
BSpline2D& getSpline() { return bsp; }
|
||||||
|
const BSpline2D& getSpline() const { return bsp; }
|
||||||
|
|
||||||
|
bool wasModified; // to be checked/reset by external code
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SplineGridCtrlPoint *createControlPoint(size_t x, size_t y);
|
SplineGridCtrlPoint *createControlPoint(size_t x, size_t y);
|
||||||
|
|
||||||
std::vector<SplineGridCtrlPoint*> ctrlp;
|
std::vector<SplineGridCtrlPoint*> ctrlp;
|
||||||
unsigned deg;
|
unsigned deg;
|
||||||
BSpline2D bsp;
|
BSpline2DWithPoints bsp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue