1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-11-29 12:03:51 +00:00
Aquaria/BBGE/SplineGrid.cpp
fgenesis 36aaa77436 bspline point gen is now properly integrated and only called while in the editor.
the remaining code uses the same old basic control points as it previously did.
2024-07-07 03:30:54 +02:00

339 lines
8.2 KiB
C++

#include "SplineGrid.h"
#include <assert.h>
#include "RenderBase.h"
#include "Core.h"
#include "RenderGrid.h"
#include "SkeletalSprite.h"
SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint;
SplineGridCtrlPoint::SplineGridCtrlPoint()
{
setTexture("gui/open-menu");
setWidthHeight(8, 8);
}
SplineGridCtrlPoint::~SplineGridCtrlPoint()
{
}
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 && wouldpick)
{
movingPoint = this;
}
}
else if(movingPoint)
{
movingPoint->color = Vector(1,1,1);
movingPoint = NULL;
}
if(movingPoint == this)
{
SplineGrid *p = (SplineGrid*)getParent();
const Vector parentPos = p->getWorldPosition();
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();
}
}
}
SplineGrid::SplineGrid()
: wasModified(false), deg(0), pointscale(1), cpgen(NULL)
{
setWidthHeight(128, 128);
renderQuad = true;
renderBorder = true;
}
SplineGrid::~SplineGrid()
{
delete cpgen;
}
DynamicRenderGrid *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();
if(cpgen && (oldcpx != w || oldcpy != h))
{
delete cpgen;
cpgen = NULL;
}
DynamicRenderGrid *ret = this->createGrid(xres, yres);
ret->gridType = GRID_INTERP;
std::vector<SplineGridCtrlPoint*> oldp;
ctrlp.swap(oldp);
ctrlp.resize(w * h);
// move any old points over that fit within the new size
{
const size_t cw = std::min(oldcpx, w);
const size_t ch = std::min(oldcpy, h);
for(size_t y = 0; y < ch; ++y)
for(size_t x = 0; x < cw; ++x)
{
SplineGridCtrlPoint *& ref = oldp[y * oldcpx + x];
ctrlp[y * w + x] = ref;
ref = NULL;
}
}
bsp.resize(w, h, degx, degy);
// 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);
}
_initCpgen();
recalc();
return ret;
}
void SplineGrid::recalc()
{
if(cpgen)
{
exportGridPoints(&cpgen->designpoints[0]);
_generateControlPointsFromDesignPoints();
}
else
{
exportGridPoints(&bsp.controlpoints[0]);
}
if(grid)
{
bsp.recalc(grid->dataRW(), grid->width(), grid->height());
wasModified = true;
}
}
void SplineGrid::exportGridPoints(Vector* pdst) const
{
for(size_t i = 0; i < ctrlp.size(); ++i)
pdst[i] = ctrlp[i]->getSplinePosition();
}
void SplineGrid::importGridPoints(const Vector* psrc)
{
for(size_t i = 0; i < ctrlp.size(); ++i)
ctrlp[i]->setSplinePosition(psrc[i]);
}
void SplineGrid::importKeyframe(const BoneKeyframe* bk)
{
const size_t numcp = bsp.ctrlX() * bsp.ctrlY();
assert(bk->controlpoints.size() == numcp);
bsp.controlpoints = bk->controlpoints;
if(cpgen)
{
// given control points, generate spline points (which are later caculated back into control points)
bsp.recalc(&cpgen->designpoints[0], bsp.ctrlX(), bsp.ctrlY());
importGridPoints(&cpgen->designpoints[0]);
}
else
importGridPoints(&bk->controlpoints[0]);
recalc();
}
void SplineGrid::exportKeyframe(BoneKeyframe* bk) const
{
const size_t numcp = bsp.ctrlX() * bsp.ctrlY();
assert(bk->controlpoints.size() == numcp);
bk->controlpoints = bsp.controlpoints;
}
void SplineGrid::resetControlPoints()
{
bsp.reset();
importGridPoints(&bsp.controlpoints[0]);
// This pushes the bspline controlpoints outwards so that all spline points line up as one would expect.
// If this weren't done, the tile's texture would be pulled inwards (more with increasing dimension);
// as if the tile was a piece of plastic foil that's seen too much heat.
if(cpgen)
{
cpgen->designpoints = bsp.controlpoints;
_generateControlPointsFromDesignPoints();
}
recalc();
}
void SplineGrid::_generateControlPointsFromDesignPoints()
{
const Vector *cp = cpgen->generateControlPoints();
memcpy(&bsp.controlpoints[0], cp, bsp.controlpoints.size() * sizeof(*cp));
}
void SplineGrid::_initCpgen()
{
assert(!cpgen);
cpgen = new BSpline2DControlPointGeneratorWithPoints(bsp.ctrlX(), bsp.ctrlY());
cpgen->refresh(bsp.getKnotsX(), bsp.getKnotsY(), bsp.degX(), bsp.degY());
}
SplineGridCtrlPoint* SplineGrid::createControlPoint(size_t x, size_t y)
{
const size_t cpx = bsp.ctrlX();
const size_t cpy = bsp.ctrlY();
assert(x < cpx && y < cpy);
const Vector wh(width, height);
const Vector pos01(float(x) / float(cpx-1), float(y) / float(cpy-1));
SplineGridCtrlPoint *cp = new SplineGridCtrlPoint();
cp->position = (pos01 - Vector(0.5f, 0.5f)) * wh;
cp->scale.x = pointscale;
cp->scale.y = pointscale;
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);
const Vector wh2(width * 0.5f, height * 0.5f);
glLineWidth(2);
glColor4f(0.0f, 0.3f, 1.0f, 0.3f);
const size_t cpx = bsp.ctrlX();
const size_t cpy = bsp.ctrlY();
// X axis
for(size_t y = 0; y < cpy; ++y)
{
glBegin(GL_LINE_STRIP);
const SplineGridCtrlPoint * const *row = &ctrlp[y * cpx];
for(size_t x = 0; x < cpx; ++x)
{
const Vector p = row[x]->position;
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 = ctrlp[y * cpx + x]->position;
glVertex2f(p.x, p.y);
}
glEnd();
}
if(RenderObject::renderCollisionShape && cpgen)
{
glColor4f(1.0f, 0.4f, 0.4f, 0.7f);
glPushMatrix();
glScalef(width, height, 1);
// X axis
for(size_t y = 0; y < cpy; ++y)
{
glBegin(GL_LINE_STRIP);
const Vector *row = &bsp.controlpoints[y * cpx];
for(size_t x = 0; x < cpx; ++x)
{
const Vector p = row[x];
glVertex2f(p.x, p.y);
}
glEnd();
}
// Y axis
for(size_t x = 0; x < cpx; ++x)
{
glBegin(GL_LINE_STRIP);
for(size_t y = 0; y < cpy; ++y)
{
const Vector p = bsp.controlpoints[y * cpx + x];
glVertex2f(p.x, p.y);
}
glEnd();
}
glPopMatrix();
}
}
void SplineGrid::setPointScale(const float scale)
{
pointscale = scale;
for(size_t i = 0; i < ctrlp.size(); ++i)
{
ctrlp[i]->scale.x = scale;
ctrlp[i]->scale.y = scale;
}
}