2022-09-04 15:16:35 +00:00
|
|
|
#include "SplineGrid.h"
|
2024-07-07 01:30:54 +00:00
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
2022-09-04 15:16:35 +00:00
|
|
|
#include "RenderBase.h"
|
|
|
|
#include "Core.h"
|
2023-07-10 15:23:19 +00:00
|
|
|
#include "RenderGrid.h"
|
2024-07-07 01:30:54 +00:00
|
|
|
#include "SkeletalSprite.h"
|
|
|
|
|
2022-09-04 15:16:35 +00:00
|
|
|
|
|
|
|
SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint;
|
|
|
|
|
|
|
|
SplineGridCtrlPoint::SplineGridCtrlPoint()
|
|
|
|
{
|
|
|
|
setTexture("gui/open-menu");
|
2023-08-22 19:28:05 +00:00
|
|
|
setWidthHeight(8, 8);
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-25 18:13:56 +00:00
|
|
|
SplineGridCtrlPoint::~SplineGridCtrlPoint()
|
|
|
|
{
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector SplineGridCtrlPoint::getSplinePosition() const
|
|
|
|
{
|
|
|
|
SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent();
|
2022-09-13 16:38:44 +00:00
|
|
|
// always return alpha == 1
|
2022-09-23 16:10:44 +00:00
|
|
|
// points within the quad result in in -0.5 .. +0.5 on both axes
|
2022-09-13 16:38:44 +00:00
|
|
|
return Vector(position.x / p->width, position.y / p->height, 1.0f);
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
2022-09-23 16:10:44 +00:00
|
|
|
void SplineGridCtrlPoint::setSplinePosition(Vector pos)
|
|
|
|
{
|
|
|
|
SplineGridCtrlPoint *p = (SplineGridCtrlPoint*)getParent();
|
|
|
|
position.x = pos.x * p->width;
|
|
|
|
position.y = pos.y * p->height;
|
|
|
|
}
|
|
|
|
|
2022-09-04 15:16:35 +00:00
|
|
|
void SplineGridCtrlPoint::onUpdate(float dt)
|
|
|
|
{
|
|
|
|
const bool lmb = core->mouse.buttons.left;
|
|
|
|
|
2022-09-23 16:10:44 +00:00
|
|
|
// 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);
|
|
|
|
|
2022-09-04 15:16:35 +00:00
|
|
|
if(lmb)
|
|
|
|
{
|
2022-09-23 16:10:44 +00:00
|
|
|
if(!movingPoint && wouldpick)
|
|
|
|
{
|
2022-09-04 15:16:35 +00:00
|
|
|
movingPoint = this;
|
2022-09-23 16:10:44 +00:00
|
|
|
}
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
2022-09-23 16:10:44 +00:00
|
|
|
else if(movingPoint)
|
|
|
|
{
|
|
|
|
movingPoint->color = Vector(1,1,1);
|
2022-09-04 15:16:35 +00:00
|
|
|
movingPoint = NULL;
|
2022-09-23 16:10:44 +00:00
|
|
|
}
|
2022-09-04 15:16:35 +00:00
|
|
|
|
|
|
|
if(movingPoint == this)
|
|
|
|
{
|
2022-09-05 15:19:34 +00:00
|
|
|
SplineGrid *p = (SplineGrid*)getParent();
|
2022-09-04 15:16:35 +00:00
|
|
|
const Vector parentPos = p->getWorldPosition();
|
2022-09-23 16:10:44 +00:00
|
|
|
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();
|
|
|
|
}
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SplineGrid::SplineGrid()
|
2024-07-07 01:30:54 +00:00
|
|
|
: wasModified(false), deg(0), pointscale(1), cpgen(NULL)
|
2022-09-04 15:16:35 +00:00
|
|
|
{
|
|
|
|
setWidthHeight(128, 128);
|
2022-09-05 15:19:34 +00:00
|
|
|
renderQuad = true;
|
|
|
|
renderBorder = true;
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SplineGrid::~SplineGrid()
|
|
|
|
{
|
2024-07-07 01:30:54 +00:00
|
|
|
delete cpgen;
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-09 00:41:04 +00:00
|
|
|
DynamicRenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy)
|
2022-09-04 15:16:35 +00:00
|
|
|
{
|
2022-09-13 16:38:44 +00:00
|
|
|
size_t oldcpx = bsp.ctrlX();
|
|
|
|
size_t oldcpy = bsp.ctrlY();
|
2022-09-04 15:16:35 +00:00
|
|
|
|
2024-07-07 01:30:54 +00:00
|
|
|
if(cpgen && (oldcpx != w || oldcpy != h))
|
|
|
|
{
|
|
|
|
delete cpgen;
|
|
|
|
cpgen = NULL;
|
|
|
|
}
|
|
|
|
|
2023-08-09 00:41:04 +00:00
|
|
|
DynamicRenderGrid *ret = this->createGrid(xres, yres);
|
2024-02-06 00:36:38 +00:00
|
|
|
ret->gridType = GRID_INTERP;
|
2022-09-04 15:16:35 +00:00
|
|
|
|
|
|
|
std::vector<SplineGridCtrlPoint*> oldp;
|
|
|
|
ctrlp.swap(oldp);
|
|
|
|
ctrlp.resize(w * h);
|
|
|
|
|
|
|
|
// move any old points over that fit within the new size
|
|
|
|
{
|
2022-09-13 16:38:44 +00:00
|
|
|
const size_t cw = std::min(oldcpx, w);
|
|
|
|
const size_t ch = std::min(oldcpy, h);
|
2022-09-04 15:16:35 +00:00
|
|
|
for(size_t y = 0; y < ch; ++y)
|
|
|
|
for(size_t x = 0; x < cw; ++x)
|
|
|
|
{
|
2022-09-13 16:38:44 +00:00
|
|
|
SplineGridCtrlPoint *& ref = oldp[y * oldcpx + x];
|
2022-09-04 15:16:35 +00:00
|
|
|
ctrlp[y * w + x] = ref;
|
|
|
|
ref = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-23 16:10:44 +00:00
|
|
|
bsp.resize(w, h, degx, degy);
|
2022-09-05 15:19:34 +00:00
|
|
|
|
2022-09-04 15:16:35 +00:00
|
|
|
// kill any excess points
|
|
|
|
for(size_t i = 0; i < oldp.size(); ++i)
|
|
|
|
if(oldp[i])
|
|
|
|
oldp[i]->safeKill();
|
|
|
|
|
|
|
|
// extend until all points are there
|
|
|
|
for(size_t y = 0; y < h; ++y)
|
|
|
|
for(size_t x = 0; x < w; ++x)
|
|
|
|
{
|
|
|
|
SplineGridCtrlPoint *& ref = ctrlp[y * w + x];
|
|
|
|
if(!ref)
|
|
|
|
ref = createControlPoint(x, y);
|
|
|
|
}
|
2022-09-05 15:19:34 +00:00
|
|
|
|
2024-07-07 01:30:54 +00:00
|
|
|
_initCpgen();
|
|
|
|
|
2022-09-13 16:38:44 +00:00
|
|
|
recalc();
|
2023-07-10 15:23:19 +00:00
|
|
|
|
|
|
|
return ret;
|
2022-09-05 15:19:34 +00:00
|
|
|
}
|
|
|
|
|
2022-09-13 16:38:44 +00:00
|
|
|
void SplineGrid::recalc()
|
2022-09-05 15:19:34 +00:00
|
|
|
{
|
2024-07-07 01:30:54 +00:00
|
|
|
if(cpgen)
|
|
|
|
{
|
|
|
|
exportGridPoints(&cpgen->designpoints[0]);
|
|
|
|
_generateControlPointsFromDesignPoints();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
exportGridPoints(&bsp.controlpoints[0]);
|
|
|
|
}
|
|
|
|
|
2023-07-10 15:23:19 +00:00
|
|
|
if(grid)
|
|
|
|
{
|
2024-02-06 00:36:38 +00:00
|
|
|
bsp.recalc(grid->dataRW(), grid->width(), grid->height());
|
2023-07-10 15:23:19 +00:00
|
|
|
wasModified = true;
|
|
|
|
}
|
2022-09-23 16:10:44 +00:00
|
|
|
}
|
|
|
|
|
2024-07-07 01:30:54 +00:00
|
|
|
void SplineGrid::exportGridPoints(Vector* pdst) const
|
2022-09-23 16:10:44 +00:00
|
|
|
{
|
|
|
|
for(size_t i = 0; i < ctrlp.size(); ++i)
|
2024-07-07 01:30:54 +00:00
|
|
|
pdst[i] = ctrlp[i]->getSplinePosition();
|
2022-09-23 16:10:44 +00:00
|
|
|
}
|
2022-09-14 03:11:56 +00:00
|
|
|
|
2024-07-07 01:30:54 +00:00
|
|
|
void SplineGrid::importGridPoints(const Vector* psrc)
|
2022-09-23 16:10:44 +00:00
|
|
|
{
|
|
|
|
for(size_t i = 0; i < ctrlp.size(); ++i)
|
2024-07-07 01:30:54 +00:00
|
|
|
ctrlp[i]->setSplinePosition(psrc[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SplineGrid::importKeyframe(const BoneKeyframe* bk)
|
|
|
|
{
|
|
|
|
const size_t numcp = bsp.ctrlX() * bsp.ctrlY();
|
|
|
|
assert(bk->controlpoints.size() == numcp);
|
|
|
|
|
|
|
|
bsp.controlpoints = bk->controlpoints;
|
|
|
|
|
|
|
|
if(cpgen)
|
|
|
|
{
|
|
|
|
// given control points, generate spline points (which are later caculated back into control points)
|
|
|
|
bsp.recalc(&cpgen->designpoints[0], bsp.ctrlX(), bsp.ctrlY());
|
|
|
|
importGridPoints(&cpgen->designpoints[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
importGridPoints(&bk->controlpoints[0]);
|
|
|
|
|
2022-09-23 16:10:44 +00:00
|
|
|
recalc();
|
2022-09-05 15:19:34 +00:00
|
|
|
}
|
|
|
|
|
2024-07-07 01:30:54 +00:00
|
|
|
void SplineGrid::exportKeyframe(BoneKeyframe* bk) const
|
|
|
|
{
|
|
|
|
const size_t numcp = bsp.ctrlX() * bsp.ctrlY();
|
|
|
|
assert(bk->controlpoints.size() == numcp);
|
|
|
|
|
|
|
|
bk->controlpoints = bsp.controlpoints;
|
|
|
|
}
|
2022-09-04 15:16:35 +00:00
|
|
|
|
|
|
|
void SplineGrid::resetControlPoints()
|
|
|
|
{
|
2022-09-23 16:10:44 +00:00
|
|
|
bsp.reset();
|
2024-07-07 01:30:54 +00:00
|
|
|
|
|
|
|
importGridPoints(&bsp.controlpoints[0]);
|
|
|
|
|
|
|
|
// This pushes the bspline controlpoints outwards so that all spline points line up as one would expect.
|
|
|
|
// If this weren't done, the tile's texture would be pulled inwards (more with increasing dimension);
|
|
|
|
// as if the tile was a piece of plastic foil that's seen too much heat.
|
|
|
|
if(cpgen)
|
|
|
|
{
|
|
|
|
cpgen->designpoints = bsp.controlpoints;
|
|
|
|
_generateControlPointsFromDesignPoints();
|
|
|
|
}
|
|
|
|
|
|
|
|
recalc();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SplineGrid::_generateControlPointsFromDesignPoints()
|
|
|
|
{
|
|
|
|
const Vector *cp = cpgen->generateControlPoints();
|
|
|
|
memcpy(&bsp.controlpoints[0], cp, bsp.controlpoints.size() * sizeof(*cp));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SplineGrid::_initCpgen()
|
|
|
|
{
|
|
|
|
assert(!cpgen);
|
|
|
|
cpgen = new BSpline2DControlPointGeneratorWithPoints(bsp.ctrlX(), bsp.ctrlY());
|
|
|
|
cpgen->refresh(bsp.getKnotsX(), bsp.getKnotsY(), bsp.degX(), bsp.degY());
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y)
|
|
|
|
{
|
2022-09-13 16:38:44 +00:00
|
|
|
const size_t cpx = bsp.ctrlX();
|
|
|
|
const size_t cpy = bsp.ctrlY();
|
|
|
|
assert(x < cpx && y < cpy);
|
2022-09-05 15:19:34 +00:00
|
|
|
const Vector wh(width, height);
|
2022-09-13 16:38:44 +00:00
|
|
|
const Vector pos01(float(x) / float(cpx-1), float(y) / float(cpy-1));
|
2022-09-04 15:16:35 +00:00
|
|
|
SplineGridCtrlPoint *cp = new SplineGridCtrlPoint();
|
2022-09-05 15:19:34 +00:00
|
|
|
cp->position = (pos01 - Vector(0.5f, 0.5f)) * wh;
|
2023-08-22 19:28:05 +00:00
|
|
|
cp->scale.x = pointscale;
|
|
|
|
cp->scale.y = pointscale;
|
2022-09-04 15:16:35 +00:00
|
|
|
this->addChild(cp, PM_POINTER);
|
|
|
|
return cp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SplineGrid::onUpdate(float dt)
|
|
|
|
{
|
|
|
|
Quad::onUpdate(dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SplineGrid::onRender(const RenderState& rs) const
|
|
|
|
{
|
|
|
|
Quad::onRender(rs);
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
2022-09-05 15:19:34 +00:00
|
|
|
const Vector wh2(width * 0.5f, height * 0.5f);
|
2022-09-04 15:16:35 +00:00
|
|
|
|
|
|
|
glLineWidth(2);
|
2022-09-23 16:10:44 +00:00
|
|
|
glColor4f(0.0f, 0.3f, 1.0f, 0.3f);
|
2022-09-04 15:16:35 +00:00
|
|
|
|
2022-09-13 16:38:44 +00:00
|
|
|
const size_t cpx = bsp.ctrlX();
|
|
|
|
const size_t cpy = bsp.ctrlY();
|
|
|
|
|
2022-09-04 15:16:35 +00:00
|
|
|
// X axis
|
2022-09-13 16:38:44 +00:00
|
|
|
for(size_t y = 0; y < cpy; ++y)
|
2022-09-04 15:16:35 +00:00
|
|
|
{
|
|
|
|
glBegin(GL_LINE_STRIP);
|
2022-09-13 16:38:44 +00:00
|
|
|
const SplineGridCtrlPoint * const *row = &ctrlp[y * cpx];
|
|
|
|
for(size_t x = 0; x < cpx; ++x)
|
2022-09-04 15:16:35 +00:00
|
|
|
{
|
|
|
|
const Vector p = row[x]->position;
|
|
|
|
glVertex2f(p.x, p.y);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Y axis
|
2022-09-13 16:38:44 +00:00
|
|
|
for(size_t x = 0; x < cpx; ++x)
|
2022-09-04 15:16:35 +00:00
|
|
|
{
|
|
|
|
glBegin(GL_LINE_STRIP);
|
2022-09-13 16:38:44 +00:00
|
|
|
for(size_t y = 0; y < cpy; ++y)
|
2022-09-04 15:16:35 +00:00
|
|
|
{
|
2022-09-13 16:38:44 +00:00
|
|
|
const Vector p = ctrlp[y * cpx + x]->position;
|
2022-09-04 15:16:35 +00:00
|
|
|
glVertex2f(p.x, p.y);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
2024-07-07 01:30:54 +00:00
|
|
|
|
|
|
|
if(RenderObject::renderCollisionShape && cpgen)
|
|
|
|
{
|
|
|
|
glColor4f(1.0f, 0.4f, 0.4f, 0.7f);
|
|
|
|
glPushMatrix();
|
|
|
|
glScalef(width, height, 1);
|
|
|
|
|
|
|
|
// X axis
|
|
|
|
for(size_t y = 0; y < cpy; ++y)
|
|
|
|
{
|
|
|
|
glBegin(GL_LINE_STRIP);
|
|
|
|
const Vector *row = &bsp.controlpoints[y * cpx];
|
|
|
|
for(size_t x = 0; x < cpx; ++x)
|
|
|
|
{
|
|
|
|
const Vector p = row[x];
|
|
|
|
glVertex2f(p.x, p.y);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Y axis
|
|
|
|
for(size_t x = 0; x < cpx; ++x)
|
|
|
|
{
|
|
|
|
glBegin(GL_LINE_STRIP);
|
|
|
|
for(size_t y = 0; y < cpy; ++y)
|
|
|
|
{
|
|
|
|
const Vector p = bsp.controlpoints[y * cpx + x];
|
|
|
|
glVertex2f(p.x, p.y);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
2022-09-04 15:16:35 +00:00
|
|
|
}
|
|
|
|
|
2023-08-22 19:28:05 +00:00
|
|
|
void SplineGrid::setPointScale(const float scale)
|
|
|
|
{
|
|
|
|
pointscale = scale;
|
|
|
|
for(size_t i = 0; i < ctrlp.size(); ++i)
|
|
|
|
{
|
|
|
|
ctrlp[i]->scale.x = scale;
|
|
|
|
ctrlp[i]->scale.y = scale;
|
|
|
|
}
|
|
|
|
}
|