1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-07-03 22:44:32 +00:00

split grid rendering off from Quad, to a new RenderGrid class

This commit is contained in:
fgenesis 2023-07-10 17:23:19 +02:00
parent 0f0f3e9023
commit 976ce8ff3e
12 changed files with 603 additions and 505 deletions

View file

@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "RenderBase.h" #include "RenderBase.h"
#include "Game.h" #include "Game.h"
#include "SplineGrid.h" #include "SplineGrid.h"
#include "RenderGrid.h"
int TIMELINE_GRIDSIZE = 10; int TIMELINE_GRIDSIZE = 10;
@ -958,8 +959,9 @@ void AnimationEditor::editStripKey()
} }
else else
{ {
if(editingBone && !editingBone->getDrawGrid().empty()) if(editingBone && editingBone->getGrid())
{ {
RenderGrid *grid = editingBone->getGrid();
Animation *a = editSprite->getCurrentAnimation(); Animation *a = editSprite->getCurrentAnimation();
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx); BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
@ -973,12 +975,12 @@ void AnimationEditor::editStripKey()
assert(bk->controlpoints.size() == interp->bsp.ctrlX() * interp->bsp.ctrlY()); assert(bk->controlpoints.size() == interp->bsp.ctrlX() * interp->bsp.ctrlY());
splinegrid = new SplineGrid; splinegrid = new SplineGrid;
splinegrid->drawOrder = editingBone->drawOrder; RenderGrid *rgrid = splinegrid->resize(interp->bsp.ctrlX(), interp->bsp.ctrlY(), grid->width(), grid->height(), interp->bsp.degX(), interp->bsp.degY());
rgrid->drawOrder = grid->drawOrder;
splinegrid->setTexture(editingBone->texture->name); splinegrid->setTexture(editingBone->texture->name);
splinegrid->setWidthHeight(editingBone->width, editingBone->height); splinegrid->setWidthHeight(editingBone->width, editingBone->height);
splinegrid->position = Vector(400, 300); splinegrid->position = Vector(400, 300);
//splinegrid->followCamera = 1; //splinegrid->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]); splinegrid->importControlPoints(&bk->controlpoints[0]);
//editSprite->addChild(splinegrid, PM_STATIC, RBP_OFF, CHILD_FRONT); //editSprite->addChild(splinegrid, PM_STATIC, RBP_OFF, CHILD_FRONT);
//editSprite->alphaMod = 0.5f; //editSprite->alphaMod = 0.5f;

View file

@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "Element.h" #include "Element.h"
#include "Game.h" #include "Game.h"
#include "RenderGrid.h"
ElementEffectData::ElementEffectData() ElementEffectData::ElementEffectData()
: elementEffectType(EFX_NONE) : elementEffectType(EFX_NONE)
@ -182,8 +183,8 @@ void Element::update(float dt)
updateLife(dt); updateLife(dt);
if (eff) if (eff)
updateEffects(dt); updateEffects(dt);
if (!drawGrid.empty()) if(grid)
updateGrid(dt); grid->update(dt);
} }
} }
@ -204,26 +205,8 @@ int Element::getElementEffectIndex()
void Element::setGridFromWavy() void Element::setGridFromWavy()
{ {
if (!drawGrid.empty()) if(grid && eff->wavy.size())
{ grid->setFromWavy(&eff->wavy[0], eff->wavy.size(), width);
const size_t NX = drawGrid.width() - 1;
const size_t H = drawGrid.height();
const float iw = 1.0f / float(getWidth());
for (size_t x = 0; x < NX; x++)
{
for (size_t y = 0; y < H; y++)
{
const size_t wavy_y = (H - y)-1;
if (wavy_y < 0 || wavy_y < eff->wavy.size())
{
const float tmp = eff->wavy[wavy_y].x * iw;
drawGrid(x,y).x = tmp - 0.5f;
drawGrid(x+1,y).x = tmp + 0.5f;
}
}
}
}
} }
void Element::setElementEffectByIndex(int eidx) void Element::setElementEffectByIndex(int eidx)

View file

@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "Gradient.h" #include "Gradient.h"
#include "TTFFont.h" #include "TTFFont.h"
#include "RoundedRect.h" #include "RoundedRect.h"
#include "RenderGrid.h"
#define GEM_GRAB 10 #define GEM_GRAB 10
@ -561,8 +562,12 @@ void WorldMapRender::setVis(WorldMapTile *tile)
if (visMethod == VIS_VERTEX) if (visMethod == VIS_VERTEX)
{ {
tile->q->setSegs(MAPVIS_SUBDIV, MAPVIS_SUBDIV, 0, 0, 0, 0, 2.0, 1); RenderGrid *g = tile->q->setSegs(MAPVIS_SUBDIV, MAPVIS_SUBDIV, 0, 0, 0, 0, 2.0, 1);
tileDataToVis(tile, tile->q->getDrawGrid()); if(g)
{
g->drawOrder = GRID_DRAW_WORLDMAP;
tileDataToVis(tile, g->array2d());
}
} }
else if (visMethod == VIS_WRITE) else if (visMethod == VIS_WRITE)
{ {
@ -662,7 +667,6 @@ WorldMapRender::WorldMapRender() : RenderObject(), ActionMapper()
q->setTexturePointer(texs[i]); q->setTexturePointer(texs[i]);
q->position = pos; q->position = pos;
q->alphaMod = 0; q->alphaMod = 0;
q->drawOrder = Quad::GRID_DRAW_WORLDMAP;
tile->q = q; tile->q = q;

View file

@ -112,7 +112,7 @@ public:
int screenWidth, screenHeight; int screenWidth, screenHeight;
int textureWidth, textureHeight; int textureWidth, textureHeight;
Vector ** drawGrid; Vector ** drawGrid; // TODO: make this + related code use RenderGrid
// returns handle > 0 on success // returns handle > 0 on success
int loadShaderFile(const char *vert, const char *frag); int loadShaderFile(const char *vert, const char *frag);

View file

@ -72,6 +72,8 @@ set(BBGE_SRCS
Refcounted.h Refcounted.h
RenderBase.cpp RenderBase.cpp
RenderBase.h RenderBase.h
RenderGrid.cpp
RenderGrid.h
RenderObject.cpp RenderObject.cpp
RenderObject.h RenderObject.h
RenderObject_inline.h RenderObject_inline.h

View file

@ -21,135 +21,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "Quad.h" #include "Quad.h"
#include "Core.h" #include "Core.h"
#include "RenderBase.h" #include "RenderBase.h"
#include "RenderGrid.h"
#include <assert.h> #include <assert.h>
Quad::Quad(const std::string &tex, const Vector &pos) Quad::Quad(const std::string &tex, const Vector &pos)
: RenderObject() : RenderObject()
{ {
renderBorderColor = Vector(1,1,1);
initQuad(); initQuad();
renderBorderColor = Vector(1,1,1);
position = pos; position = pos;
setTexture(tex); setTexture(tex);
} }
Quad::Quad() : RenderObject()
{
initQuad();
}
Quad::~Quad()
void Quad::setSegs(int x, int y, float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo)
{ {
deleteGrid(); deleteGrid();
if (x == 0 || y == 0)
{
doUpdateGrid = false;
}
else
{
doUpdateGrid = true;
this->drawGridOffsetX = dgox;
this->drawGridOffsetY = dgoy;
this->drawGridModX = dgmx;
this->drawGridModY = dgmy;
this->drawGridTimeMultiplier = dgtm;
drawGridOut = dgo;
createGrid(x, y);
}
gridTimer = 0;
}
void Quad::createGrid(int xd, int yd)
{
drawGrid.init(xd, yd);
resetGrid();
Vector *dg = drawGrid.data();
for(size_t i = 0; i < drawGrid.linearsize(); ++i)
dg[i].z = 1.0f;
}
void Quad::setDrawGridAlpha(size_t x, size_t y, float alpha)
{
if (x < drawGrid.width() && y < drawGrid.height())
{
drawGrid(x, y).z = alpha;
}
}
void Quad::setStripPoints(bool vert, const Vector *points, size_t n)
{
if (drawGrid.empty()) return;
resetGrid();
const float mul = float(n);
if (!vert) // horz
{
const size_t xmax = std::min(drawGrid.width(), n);
for (size_t y = 0; y < drawGrid.height(); y++)
{
Vector *row = drawGrid.row(y);
for (size_t x = 0; x < xmax; x++)
row[x] += points[x] * mul;
}
}
else
{
const size_t ymax = std::min(drawGrid.height(), n);
for (size_t x = 0; x < drawGrid.width(); x++)
for (size_t y = 0; y < ymax; y++)
drawGrid(x, y) += points[y] * mul;
}
}
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()
{
if (drawGrid.empty()) return;
ResetGrid(drawGrid.data(), drawGrid.width(), drawGrid.height());
} }
void Quad::initQuad() void Quad::initQuad()
{ {
addType(SCO_QUAD);
borderAlpha = 0.5;
repeatToFillScale = Vector(1,1); repeatToFillScale = Vector(1,1);
gridType = GRID_WAVY;
gridTimer = 0;
doUpdateGrid = false;
autoWidth = autoHeight = 0; autoWidth = autoHeight = 0;
@ -157,12 +55,58 @@ void Quad::initQuad()
renderCenter = true; renderCenter = true;
width = 2; height = 2; width = 2; height = 2;
upperLeftTextureCoordinates = Vector(0,0); upperLeftTextureCoordinates = Vector(0,0);
lowerRightTextureCoordinates = Vector(1,1); lowerRightTextureCoordinates = Vector(1,1);
renderQuad = true; renderQuad = true;
grid = NULL;
}
void Quad::deleteGrid()
{
delete grid;
grid = NULL;
}
void Quad::destroy()
{
deleteGrid();
RenderObject::destroy();
}
RenderGrid *Quad::setSegs(int x, int y, float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo)
{
RenderGrid *g = createGrid(x, y);
if(g)
g->setSegs(dgox, dgoy, dgmx, dgmy, dgtm, dgo);
return g;
}
RenderGrid *Quad::createGrid(int xd, int yd)
{
delete grid;
return (grid = xd && yd
? new RenderGrid(xd, yd)
: NULL);
}
void Quad::setDrawGridAlpha(size_t x, size_t y, float alpha)
{
if(grid)
grid->setAlpha(x, y, alpha);
}
void Quad::setStripPoints(bool vert, const Vector *points, size_t n)
{
if(grid)
grid->setStripPoints(vert, points, n);
}
void Quad::resetGrid()
{
if(grid)
grid->reset();
} }
void Quad::_renderBorder(const RenderState& rs, Vector color, float borderalpha) const void Quad::_renderBorder(const RenderState& rs, Vector color, float borderalpha) const
@ -195,27 +139,7 @@ void Quad::_renderBorder(const RenderState& rs, Vector color, float borderalpha)
RenderObject::lastTextureApplied = 0; RenderObject::lastTextureApplied = 0;
} }
Quad::Quad() : RenderObject()
{
addType(SCO_QUAD);
borderAlpha = 0.5;
drawOrder = GRID_DRAW_DEFAULT;
initQuad();
}
void Quad::deleteGrid()
{
drawGrid.clear();
}
void Quad::destroy()
{
deleteGrid();
RenderObject::destroy();
}
bool Quad::isCoordinateInside(Vector coord, int minSize) const bool Quad::isCoordinateInside(Vector coord, int minSize) const
{ {
@ -275,272 +199,28 @@ bool Quad::isCoordinateInsideWorldRect(const Vector &coord, int w, int h) const
return false; return false;
} }
void Quad::updateGrid(float dt)
{
if (!doUpdateGrid) return;
if (gridType == GRID_WAVY)
{
gridTimer += dt * drawGridTimeMultiplier;
resetGrid();
size_t hx = drawGrid.width()/2;
for (size_t x = 0; x < drawGrid.width(); x++)
{
float yoffset = x * drawGridOffsetY;
float addY = 0;
if (drawGridModY != 0)
addY = cosf(gridTimer+yoffset)*drawGridModY;
for (size_t y = 0; y < drawGrid.height(); y++)
{
float xoffset = y * drawGridOffsetX;
if (drawGridModX != 0)
{
float addX = (sinf(gridTimer+xoffset)*drawGridModX);
if (drawGridOut && x < hx)
drawGrid(x,y).x += addX;
else
drawGrid(x,y).x -= addX;
}
drawGrid(x,y).y += addY;
}
}
}
}
void Quad::renderGrid(const RenderState& rs) const void Quad::renderGrid(const RenderState& rs) const
{ {
if (drawGrid.width() < 2 || drawGrid.height() < 2) RenderState rx(rs);
return; rx.color = rs.color * this->color;
rx.alpha = rs.alpha * this->alpha.x * this->alphaMod;
switch(drawOrder) glPushMatrix();
{ glScalef(width, height, 1);
case GRID_DRAW_LRTB:
renderGrid_LRTB(rs);
break;
case GRID_DRAW_LRBT: grid->render(rx, upperLeftTextureCoordinates, lowerRightTextureCoordinates);
renderGrid_LRBT(rs);
break;
case GRID_DRAW_WORLDMAP:
renderGridWithAlpha(rs);
break;
}
// debug points // debug points
if (RenderObject::renderCollisionShape) if (RenderObject::renderCollisionShape)
{ {
const size_t NX = drawGrid.width()-1;
const size_t NY = drawGrid.height()-1;
const float w = this->getWidth();
const float h = this->getHeight();
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glPointSize(2); grid->renderDebugPoints(rx);
glColor3f(1,0,0);
glBegin(GL_POINTS);
for (size_t y = 0; y < NY; y++)
{
for (size_t x = 0; x < NX; x++)
{
glVertex2f(w*drawGrid(x,y).x, h*drawGrid(x,y).y);
glVertex2f(w*drawGrid(x,y+1).x, h*drawGrid(x,y+1).y);
glVertex2f(w*drawGrid(x+1,y+1).x, h*drawGrid(x+1,y+1).y);
glVertex2f(w*drawGrid(x+1,y).x, h*drawGrid(x+1,y).y);
}
}
glEnd();
RenderObject::lastTextureApplied = 0; RenderObject::lastTextureApplied = 0;
} }
glPopMatrix();
} }
void Quad::renderGrid_LRTB(const RenderState& rs) const
{
const float percentX = lowerRightTextureCoordinates.x - upperLeftTextureCoordinates.x;
const float percentY = lowerRightTextureCoordinates.y - upperLeftTextureCoordinates.y;
const float baseX = upperLeftTextureCoordinates.x;
const float baseY = upperLeftTextureCoordinates.y;
const size_t NX = drawGrid.width()-1;
const size_t NY = drawGrid.height()-1;
// NOTE: These are used to avoid repeated expensive divide operations,
// but they may cause rounding error of around 1 part per million,
// which could in theory cause minor graphical glitches with broken
// OpenGL implementations. --achurch
const float incX = percentX / float(NX);
const float incY = percentY / float(NY);
const float w = this->getWidth();
const float h = this->getHeight();
const float red = rs.color.x * this->color.x;
const float green = rs.color.y * this->color.y;
const float blue = rs.color.z * this->color.z;
const float alpha = rs.alpha * this->alpha.x * this->alphaMod;
glColor4f(red, green, blue, alpha);
glBegin(GL_QUADS);
float v0 = baseY;
float v1 = v0 + incY;
for (size_t y = 0; y < NY; y++, v0 = v1, v1 += incY)
{
float u0 = baseX;
float u1 = u0 + incX;
const Vector *row0 = drawGrid.row(y);
const Vector *row1 = drawGrid.row(y+1);
for (size_t x = 0; x < NX; x++, u0 = u1, u1 += incX)
{
const Vector dg00 = row0[x];
const Vector dg01 = row1[x];
const Vector dg10 = row0[x+1];
const Vector dg11 = row1[x+1];
glTexCoord2f(u0, v0);
glVertex2f(w*dg00.x, h*dg00.y);
glTexCoord2f(u0, v1);
glVertex2f(w*dg01.x, h*dg01.y);
glTexCoord2f(u1, v1);
glVertex2f(w*dg11.x, h*dg11.y);
glTexCoord2f(u1, v0);
glVertex2f(w*dg10.x, h*dg10.y);
}
}
glEnd();
}
void Quad::renderGrid_LRBT(const RenderState& rs) const
{
const float percentX = lowerRightTextureCoordinates.x - upperLeftTextureCoordinates.x;
const float percentY = upperLeftTextureCoordinates.y - lowerRightTextureCoordinates.y;
const float baseX = upperLeftTextureCoordinates.x;
const float baseY = lowerRightTextureCoordinates.y;
const size_t NX = drawGrid.width()-1;
const size_t NY = drawGrid.height()-1;
// NOTE: These are used to avoid repeated expensive divide operations,
// but they may cause rounding error of around 1 part per million,
// which could in theory cause minor graphical glitches with broken
// OpenGL implementations. --achurch
const float incX = percentX / float(NX);
const float incY = percentY / float(NY);
const float w = this->getWidth();
const float h = this->getHeight();
const float red = rs.color.x * this->color.x;
const float green = rs.color.y * this->color.y;
const float blue = rs.color.z * this->color.z;
const float alpha = rs.alpha * this->alpha.x * this->alphaMod;
glColor4f(red, green, blue, alpha);
glBegin(GL_QUADS);
float v0 = baseY;
float v1 = v0 + incY;
for (size_t y = NY; y --> 0; v0 = v1, v1 += incY)
{
float u0 = baseX;
float u1 = u0 + incX;
const Vector *row0 = drawGrid.row(y+1);
const Vector *row1 = drawGrid.row(y);
for (size_t x = 0; x < NX; x++, u0 = u1, u1 += incX)
{
const Vector dg00 = row0[x];
const Vector dg01 = row1[x];
const Vector dg10 = row0[x+1];
const Vector dg11 = row1[x+1];
glTexCoord2f(u0, v0);
glVertex2f(w*dg00.x, h*dg00.y);
glTexCoord2f(u0, v1);
glVertex2f(w*dg01.x, h*dg01.y);
glTexCoord2f(u1, v1);
glVertex2f(w*dg11.x, h*dg11.y);
glTexCoord2f(u1, v0);
glVertex2f(w*dg10.x, h*dg10.y);
}
}
glEnd();
}
void Quad::renderGridWithAlpha(const RenderState& rs) const
{
const float percentX = fabsf(this->lowerRightTextureCoordinates.x - this->upperLeftTextureCoordinates.x);
const float percentY = fabsf(this->upperLeftTextureCoordinates.y - this->lowerRightTextureCoordinates.y);
const float baseX =
(lowerRightTextureCoordinates.x < upperLeftTextureCoordinates.x)
? lowerRightTextureCoordinates.x : upperLeftTextureCoordinates.x;
const float baseY =
(lowerRightTextureCoordinates.y < upperLeftTextureCoordinates.y)
? lowerRightTextureCoordinates.y : upperLeftTextureCoordinates.y;
const size_t NX = drawGrid.width()-1;
const size_t NY = drawGrid.height()-1;
// NOTE: These are used to avoid repeated expensive divide operations,
// but they may cause rounding error of around 1 part per million,
// which could in theory cause minor graphical glitches with broken
// OpenGL implementations. --achurch
const float incX = percentX / float(NX);
const float incY = percentY / float(NY);
const float w = this->getWidth();
const float h = this->getHeight();
const float red = rs.color.x * this->color.x;
const float green = rs.color.y * this->color.y;
const float blue = rs.color.z * this->color.z;
const float alpha = rs.alpha * this->alpha.x * this->alphaMod;
glBegin(GL_QUADS);
float v0 = 1 - percentY + baseY;
float v1 = v0 + incY;
for (size_t y = 0; y < NY; y++, v0 = v1, v1 += incY)
{
float u0 = baseX;
float u1 = u0 + incX;
const Vector *row0 = drawGrid.row(y);
const Vector *row1 = drawGrid.row(y+1);
for (size_t x = 0; x < NX; x++, u0 = u1, u1 += incX)
{
const Vector dg00 = row0[x];
const Vector dg01 = row1[x];
const Vector dg10 = row0[x+1];
const Vector dg11 = row1[x+1];
if (dg00.z != 0 || dg01.z != 0 || dg10.z != 0 || dg11.z != 0)
{
glColor4f(red, green, blue, alpha*dg00.z);
glTexCoord2f(u0, v0);
glVertex2f(w*dg00.x, h*dg00.y);
glColor4f(red, green, blue, alpha*dg01.z);
glTexCoord2f(u0, v1);
glVertex2f(w*dg01.x, h*dg01.y);
glColor4f(red, green, blue, alpha*dg11.z);
glTexCoord2f(u1, v1);
glVertex2f(w*dg11.x, h*dg11.y);
glColor4f(red, green, blue, alpha*dg10.z);
glTexCoord2f(u1, v0);
glVertex2f(w*dg10.x, h*dg10.y);
}
}
}
glEnd();
}
void Quad::repeatTextureToFill(bool on) void Quad::repeatTextureToFill(bool on)
{ {
@ -556,7 +236,7 @@ void Quad::onRender(const RenderState& rs) const
const float _w2 = width*0.5f; const float _w2 = width*0.5f;
const float _h2 = height*0.5f; const float _h2 = height*0.5f;
if (drawGrid.empty()) if (!grid)
{ {
glBegin(GL_QUADS); glBegin(GL_QUADS);
{ {
@ -643,9 +323,9 @@ void Quad::onUpdate(float dt)
else if (autoHeight == AUTO_VIRTUALHEIGHT) else if (autoHeight == AUTO_VIRTUALHEIGHT)
height = core->getVirtualHeight(); height = core->getVirtualHeight();
if (!drawGrid.empty() && alpha.x > 0 && alphaMod > 0) if (grid && alpha.x > 0 && alphaMod > 0)
{ {
updateGrid(dt); grid->update(dt);
} }
} }

View file

@ -39,12 +39,15 @@ protected:
void onRender(const RenderState& rs) const OVERRIDE; void onRender(const RenderState& rs) const OVERRIDE;
}; };
class RenderGrid;
class Quad : public RenderObject class Quad : public RenderObject
{ {
public: public:
Quad(const std::string &tex, const Vector &pos); Quad(const std::string &tex, const Vector &pos);
Quad(); Quad();
void createGrid(int x, int y); virtual ~Quad();
RenderGrid *createGrid(int x, int y);
void destroy() OVERRIDE; void destroy() OVERRIDE;
bool isCoordinateInside(Vector coord, int minSize=0) const; bool isCoordinateInside(Vector coord, int minSize=0) const;
bool isCoordinateInsideWorld(const Vector &coord, int minSize=0) const; bool isCoordinateInsideWorld(const Vector &coord, int minSize=0) const;
@ -58,78 +61,44 @@ public:
float getWidth() const {return width;} float getWidth() const {return width;}
float getHeight() const {return height;} float getHeight() const {return height;}
void setSegs(int x, int y, float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo); RenderGrid *setSegs(int x, int y, float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo);
void setDrawGridAlpha(size_t x, size_t y, float alpha); void setDrawGridAlpha(size_t x, size_t y, float alpha);
void repeatTextureToFill(bool on); void repeatTextureToFill(bool on);
void refreshRepeatTextureToFill(); void refreshRepeatTextureToFill();
bool isRepeatingTextureToFill() const { return repeatTexture; } bool isRepeatingTextureToFill() const { return repeatTexture; }
void setStripPoints(bool vert, const Vector *points, size_t n); void setStripPoints(bool vert, const Vector *points, size_t n);
Array2d<Vector>& getDrawGrid() { return drawGrid; } RenderGrid *getGrid() { return grid; }
const Array2d<Vector>& getDrawGrid() const { return drawGrid; } const RenderGrid *getGrid() const { return grid; }
void reloadDevice() OVERRIDE; void reloadDevice() OVERRIDE;
void deleteGrid(); void deleteGrid();
Vector upperLeftTextureCoordinates, lowerRightTextureCoordinates; Vector upperLeftTextureCoordinates, lowerRightTextureCoordinates;
enum GridDrawOrder // TODO: this should be a bitmask
{ char autoWidth, autoHeight;
GRID_DRAW_WORLDMAP = -1, // LRTB order, uses grid.z as alpha
GRID_DRAW_LRTB = 0, // the default. ignores grid.z
GRID_DRAW_LRBT = 1, // Y axis inverted
GRID_DRAW_DEFAULT = GRID_DRAW_LRTB
};
enum GridType
{
GRID_WAVY = 0,
GRID_STRIP = 1, // quad is in strip mode
GRID_INTERP = 2, // quad is in grid mode
};
unsigned char gridType; // unsigned char to save space
char autoWidth, autoHeight; // char to save space
bool renderQuad, renderCenter, renderBorder; bool renderQuad, renderCenter, renderBorder;
Vector texOff; Vector texOff;
float borderAlpha; float borderAlpha;
Vector renderBorderColor; Vector renderBorderColor;
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;
Array2d<Vector> drawGrid; RenderGrid *grid;
void resetGrid(); void resetGrid();
void updateGrid(float dt);
void renderGrid(const RenderState& rs) const; void renderGrid(const RenderState& rs) const;
void renderGrid_LRTB(const RenderState& rs) const;
void renderGrid_LRBT(const RenderState& rs) const;
void renderGridWithAlpha(const RenderState& rs) const;
float drawGridOffsetX;
float drawGridOffsetY;
float drawGridModX;
float drawGridModY;
float drawGridTimeMultiplier;
bool drawGridOut;
void onSetTexture() OVERRIDE; void onSetTexture() OVERRIDE;
void onRender(const RenderState& rs) const OVERRIDE; void onRender(const RenderState& rs) const OVERRIDE;
void onUpdate(float dt) OVERRIDE; void onUpdate(float dt) OVERRIDE;
public:
GridDrawOrder drawOrder;
private: private:
bool doUpdateGrid;
void initQuad(); void initQuad();
void _renderBorder(const RenderState& rs, Vector color, float borderalpha) const; void _renderBorder(const RenderState& rs, Vector color, float borderalpha) const;
}; };

381
BBGE/RenderGrid.cpp Normal file
View file

@ -0,0 +1,381 @@
#include "RenderGrid.h"
#include "RenderBase.h"
#include "RenderState.h"
static void 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 RenderGrid::ResetWithAlpha(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;
}
}
}
RenderGrid::RenderGrid(size_t w, size_t h)
: gridTimer(0)
, drawGridOffsetX(0), drawGridOffsetY(0), drawGridModX(0), drawGridModY(0), drawGridTimeMultiplier(0)
, drawGridOut(false), gridType(GRID_WAVY), drawOrder(GRID_DRAW_DEFAULT)
{
init(w, h);
}
RenderGrid::~RenderGrid()
{
}
void RenderGrid::init(size_t w, size_t h)
{
assert(w > 1 && h > 1);
grid.init(w, h);
reset();
Vector *dg = grid.data();
for(size_t i = 0; i < grid.linearsize(); ++i)
dg[i].z = 1.0f;
}
void RenderGrid::reset()
{
ResetGrid(grid.data(), grid.width(), grid.height());
}
void RenderGrid::resetWithAlpha(float a)
{
ResetWithAlpha(grid.data(), grid.width(), grid.height(), a);
}
void RenderGrid::update(float dt)
{
if (gridType == GRID_WAVY)
{
gridTimer += dt * drawGridTimeMultiplier;
reset();
size_t hx = grid.width()/2;
for (size_t x = 0; x < grid.width(); x++)
{
float yoffset = x * drawGridOffsetY;
float addY = 0;
if (drawGridModY != 0)
addY = cosf(gridTimer+yoffset)*drawGridModY;
for (size_t y = 0; y < grid.height(); y++)
{
float xoffset = y * drawGridOffsetX;
if (drawGridModX != 0)
{
float addX = (sinf(gridTimer+xoffset)*drawGridModX);
if (drawGridOut && x < hx)
grid(x,y).x += addX;
else
grid(x,y).x -= addX;
}
grid(x,y).y += addY;
}
}
}
}
void RenderGrid::setAlpha(size_t x, size_t y, float a)
{
if (x < grid.width() && y < grid.height())
grid(x, y).z = a;
}
void RenderGrid::setSegs(float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo)
{
drawGridOffsetX = dgox;
drawGridOffsetY = dgoy;
drawGridModX = dgmx;
drawGridModY = dgmy;
drawGridTimeMultiplier = dgtm;
drawGridOut = dgo;
gridTimer = 0;
gridType = GRID_WAVY;
}
void RenderGrid::setStripPoints(bool vert, const Vector* points, size_t n)
{
reset();
const float mul = float(n);
if (!vert) // horz
{
const size_t xmax = std::min(grid.width(), n);
for (size_t y = 0; y < grid.height(); y++)
{
Vector *row = grid.row(y);
for (size_t x = 0; x < xmax; x++)
row[x] += points[x] * mul;
}
}
else
{
const size_t ymax = std::min(grid.height(), n);
for (size_t x = 0; x < grid.width(); x++)
for (size_t y = 0; y < ymax; y++)
grid(x, y) += points[y] * mul;
}
}
void RenderGrid::setFromWavy(const Vector* wavy, size_t len, float width)
{
const size_t NX = grid.width() - 1;
const size_t H = grid.height();
const float iw = 1.0f / width;
for (size_t x = 0; x < NX; x++) // TODO invert loop
{
for (size_t y = 0; y < H; y++)
{
const size_t wavy_y = (H - y)-1;
if (wavy_y < len)
{
const float tmp = wavy[wavy_y].x * iw;
grid(x,y).x = tmp - 0.5f;
grid(x+1,y).x = tmp + 0.5f;
}
}
}
}
void RenderGrid::render(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
{
switch(drawOrder)
{
case GRID_DRAW_LRTB:
render_LRTB(rs, upperLeftTexCoords, lowerRightTexCoords);
break;
case GRID_DRAW_LRBT:
render_LRBT(rs, upperLeftTexCoords, lowerRightTexCoords);
break;
case GRID_DRAW_WORLDMAP:
render_WithAlpha(rs, upperLeftTexCoords, lowerRightTexCoords);
break;
}
}
void RenderGrid::renderDebugPoints(const RenderState& rs) const
{
(void)rs; // unused
glPointSize(2);
glColor3f(1,0,0);
glBegin(GL_POINTS);
const size_t NX = grid.width()-1;
const size_t NY = grid.height()-1;
for (size_t y = 0; y < NY; y++)
{
for (size_t x = 0; x < NX; x++)
{
glVertex2f(grid(x,y).x, grid(x,y).y);
glVertex2f(grid(x,y+1).x, grid(x,y+1).y);
glVertex2f(grid(x+1,y+1).x, grid(x+1,y+1).y);
glVertex2f(grid(x+1,y).x, grid(x+1,y).y);
}
}
glEnd();
}
void RenderGrid::render_LRTB(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
{
const float percentX = lowerRightTexCoords.x - upperLeftTexCoords.x;
const float percentY = lowerRightTexCoords.y - upperLeftTexCoords.y;
const float baseX = upperLeftTexCoords.x;
const float baseY = upperLeftTexCoords.y;
const size_t NX = grid.width()-1;
const size_t NY = grid.height()-1;
// NOTE: These are used to avoid repeated expensive divide operations,
// but they may cause rounding error of around 1 part per million,
// which could in theory cause minor graphical glitches with broken
// OpenGL implementations. --achurch
const float incX = percentX / float(NX);
const float incY = percentY / float(NY);
glColor4f(rs.color.x, rs.color.y, rs.color.z, rs.alpha);
glBegin(GL_QUADS);
float v0 = baseY;
float v1 = v0 + incY;
for (size_t y = 0; y < NY; y++, v0 = v1, v1 += incY)
{
float u0 = baseX;
float u1 = u0 + incX;
const Vector *row0 = grid.row(y);
const Vector *row1 = grid.row(y+1);
for (size_t x = 0; x < NX; x++, u0 = u1, u1 += incX)
{
const Vector dg00 = row0[x];
const Vector dg01 = row1[x];
const Vector dg10 = row0[x+1];
const Vector dg11 = row1[x+1];
glTexCoord2f(u0, v0);
glVertex2f(dg00.x, dg00.y);
glTexCoord2f(u0, v1);
glVertex2f(dg01.x, dg01.y);
glTexCoord2f(u1, v1);
glVertex2f(dg11.x, dg11.y);
glTexCoord2f(u1, v0);
glVertex2f(dg10.x, dg10.y);
}
}
glEnd();
}
void RenderGrid::render_LRBT(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
{
const float percentX = lowerRightTexCoords.x - upperLeftTexCoords.x;
const float percentY = upperLeftTexCoords.y - lowerRightTexCoords.y;
const float baseX = upperLeftTexCoords.x;
const float baseY = lowerRightTexCoords.y;
const size_t NX = grid.width()-1;
const size_t NY = grid.height()-1;
// NOTE: These are used to avoid repeated expensive divide operations,
// but they may cause rounding error of around 1 part per million,
// which could in theory cause minor graphical glitches with broken
// OpenGL implementations. --achurch
const float incX = percentX / float(NX);
const float incY = percentY / float(NY);
glColor4f(rs.color.x, rs.color.y, rs.color.z, rs.alpha);
glBegin(GL_QUADS);
float v0 = baseY;
float v1 = v0 + incY;
for (size_t y = NY; y --> 0; v0 = v1, v1 += incY)
{
float u0 = baseX;
float u1 = u0 + incX;
const Vector *row0 = grid.row(y+1);
const Vector *row1 = grid.row(y);
for (size_t x = 0; x < NX; x++, u0 = u1, u1 += incX)
{
const Vector dg00 = row0[x];
const Vector dg01 = row1[x];
const Vector dg10 = row0[x+1];
const Vector dg11 = row1[x+1];
glTexCoord2f(u0, v0);
glVertex2f(dg00.x, dg00.y);
glTexCoord2f(u0, v1);
glVertex2f(dg01.x, dg01.y);
glTexCoord2f(u1, v1);
glVertex2f(dg11.x, dg11.y);
glTexCoord2f(u1, v0);
glVertex2f(dg10.x, dg10.y);
}
}
glEnd();
}
void RenderGrid::render_WithAlpha(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
{
const float percentX = fabsf(lowerRightTexCoords.x - upperLeftTexCoords.x);
const float percentY = fabsf(upperLeftTexCoords.y - lowerRightTexCoords.y);
const float baseX =
(lowerRightTexCoords.x < upperLeftTexCoords.x)
? lowerRightTexCoords.x : upperLeftTexCoords.x;
const float baseY =
(lowerRightTexCoords.y < upperLeftTexCoords.y)
? lowerRightTexCoords.y : upperLeftTexCoords.y;
const size_t NX = grid.width()-1;
const size_t NY = grid.height()-1;
// NOTE: These are used to avoid repeated expensive divide operations,
// but they may cause rounding error of around 1 part per million,
// which could in theory cause minor graphical glitches with broken
// OpenGL implementations. --achurch
const float incX = percentX / float(NX);
const float incY = percentY / float(NY);
const Vector c = rs.color;
const float alpha = rs.alpha;
glBegin(GL_QUADS);
float v0 = 1 - percentY + baseY;
float v1 = v0 + incY;
for (size_t y = 0; y < NY; y++, v0 = v1, v1 += incY)
{
float u0 = baseX;
float u1 = u0 + incX;
const Vector *row0 = grid.row(y);
const Vector *row1 = grid.row(y+1);
for (size_t x = 0; x < NX; x++, u0 = u1, u1 += incX)
{
const Vector dg00 = row0[x];
const Vector dg01 = row1[x];
const Vector dg10 = row0[x+1];
const Vector dg11 = row1[x+1];
if (dg00.z != 0 || dg01.z != 0 || dg10.z != 0 || dg11.z != 0)
{
glColor4f(c.x, c.y, c.z, alpha*dg00.z);
glTexCoord2f(u0, v0);
glVertex2f(dg00.x, dg00.y);
glColor4f(c.x, c.y, c.z, alpha*dg01.z);
glTexCoord2f(u0, v1);
glVertex2f(dg01.x, dg01.y);
glColor4f(c.x, c.y, c.z, alpha*dg11.z);
glTexCoord2f(u1, v1);
glVertex2f(dg11.x, dg11.y);
glColor4f(c.x, c.y, c.z, alpha*dg10.z);
glTexCoord2f(u1, v0);
glVertex2f(dg10.x, dg10.y);
}
}
}
glEnd();
}

73
BBGE/RenderGrid.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef BBGE_RENDERGRID_H
#define BBGE_RENDERGRID_H
#include "Vector.h"
#include "DataStructures.h"
struct RenderState;
enum GridDrawOrder
{
GRID_DRAW_WORLDMAP = -1, // LRTB order, uses grid.z as alpha
GRID_DRAW_LRTB = 0, // the default. ignores grid.z
GRID_DRAW_LRBT = 1, // Y axis inverted
GRID_DRAW_DEFAULT = GRID_DRAW_LRTB
};
enum GridType
{
GRID_UNDEFINED = -1,
GRID_WAVY = 0,
GRID_STRIP = 1, // quad is in strip mode
GRID_INTERP = 2, // quad is in grid mode
};
class RenderGrid
{
public:
RenderGrid(size_t w, size_t h);
~RenderGrid();
void init(size_t w, size_t h);
void reset();
void resetWithAlpha(float a);
void update(float dt);
void render(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const;
void renderDebugPoints(const RenderState& rs) const;
void setAlpha(size_t x, size_t y, float a);
void setSegs(float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo);
void setStripPoints(bool vert, const Vector *points, size_t n);
void setFromWavy(const Vector *wavy, size_t len, float width);
size_t width() const { return grid.width(); }
size_t height() const { return grid.height(); }
size_t linearsize() const { return grid.linearsize(); }
const Vector *data() const { return grid.data(); }
Vector *data() { return grid.data(); }
Array2d<Vector>& array2d() { return grid; }
const Array2d<Vector>& array2d() const { return grid; }
static void ResetWithAlpha(Vector* dst, size_t w, size_t h, float alpha);
protected:
Array2d<Vector> grid;
float gridTimer;
float drawGridOffsetX;
float drawGridOffsetY;
float drawGridModX;
float drawGridModY;
float drawGridTimeMultiplier;
bool drawGridOut;
public:
unsigned char gridType; // unsigned char to save space
unsigned char drawOrder;
void render_LRTB(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const;
void render_LRBT(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const;
void render_WithAlpha(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const;
};
#endif

View file

@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "ReadXML.h" #include "ReadXML.h"
#include "RenderBase.h" #include "RenderBase.h"
#include "SplineGrid.h" #include "SplineGrid.h"
#include "RenderGrid.h"
#include <tinyxml2.h> #include <tinyxml2.h>
using namespace tinyxml2; using namespace tinyxml2;
@ -129,16 +130,9 @@ void Bone::addSegment(Bone *b)
void Bone::createStrip(bool vert, int num) void Bone::createStrip(bool vert, int num)
{ {
if (!vert) RenderGrid *grid = vert ? createGrid(2, num) : createGrid(num, 2);
{
createGrid(num, 2);
}
else
{
createGrid(2, num);
}
stripVert = vert; stripVert = vert;
gridType = GRID_STRIP; grid->gridType = GRID_STRIP;
changeStrip.resize(num); changeStrip.resize(num);
} }
@ -980,6 +974,7 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
XMLElement *bones = xml->NewElement("Bones"); XMLElement *bones = xml->NewElement("Bones");
for (i = 0; i < this->bones.size(); i++) for (i = 0; i < this->bones.size(); i++)
{ {
const RenderGrid * const grid = this->bones[i]->getGrid();
XMLElement *bone = xml->NewElement("Bone"); XMLElement *bone = xml->NewElement("Bone");
bone->SetAttribute("idx", (unsigned int) this->bones[i]->boneIdx); bone->SetAttribute("idx", (unsigned int) this->bones[i]->boneIdx);
bone->SetAttribute("gfx", this->bones[i]->gfx.c_str()); bone->SetAttribute("gfx", this->bones[i]->gfx.c_str());
@ -1009,10 +1004,10 @@ 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]->getDrawGrid().empty() && this->bones[i]->gridType != Quad::GRID_STRIP) if(grid && grid->gridType != GRID_STRIP)
{ {
std::ostringstream os; std::ostringstream os;
os << this->bones[i]->getDrawGrid().width() << " " << this->bones[i]->getDrawGrid().height(); os << grid->width() << " " << grid->height();
bone->SetAttribute("grid", os.str().c_str()); bone->SetAttribute("grid", os.str().c_str());
} }
else if (!this->bones[i]->changeStrip.empty()) else if (!this->bones[i]->changeStrip.empty())
@ -1037,9 +1032,10 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
os << this->bones[i]->originalScale.x << " " << this->bones[i]->originalScale.y; os << this->bones[i]->originalScale.x << " " << this->bones[i]->originalScale.y;
bone->SetAttribute("sz", os.str().c_str()); bone->SetAttribute("sz", os.str().c_str());
} }
if(this->bones[i]->drawOrder != Quad::GRID_DRAW_DEFAULT)
if(grid && grid->drawOrder != GRID_DRAW_DEFAULT)
{ {
bone->SetAttribute("gridDrawOrder", (int)this->bones[i]->drawOrder); bone->SetAttribute("gridDrawOrder", (int)grid->drawOrder);
} }
@ -1132,9 +1128,10 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
Bone *bone = this->getBoneByIdx(b->idx); Bone *bone = this->getBoneByIdx(b->idx);
if(bone) if(bone)
{ {
const RenderGrid * const bgrid = bone->getGrid();
os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " "; os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
// don't want to store grid points if they can be regenerated automatically // 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(); size_t usedGridSize = (!bgrid || bgrid->gridType == GRID_INTERP) ? 0 : b->grid.size();
os << usedGridSize << " "; os << usedGridSize << " ";
if(usedGridSize) if(usedGridSize)
for (size_t i = 0; i < usedGridSize; i++) for (size_t i = 0; i < usedGridSize; i++)
@ -1604,12 +1601,13 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
} }
if (bone->Attribute("grid")) if (bone->Attribute("grid"))
{ {
if(newb->getDrawGrid().empty()) RenderGrid *grid = newb->getGrid();
if(!grid)
{ {
SimpleIStringStream is(bone->Attribute("grid"), SimpleIStringStream::REUSE); SimpleIStringStream is(bone->Attribute("grid"), SimpleIStringStream::REUSE);
int x, y; int x, y;
is >> x >> y; is >> x >> y;
newb->createGrid(x, y); grid = newb->createGrid(x, y);
} }
else else
{ {
@ -1617,11 +1615,11 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
os << "Bone idx " << newb->idx << " already has a DrawGrid, ignoring \"grid\" attribute"; os << "Bone idx " << newb->idx << " already has a DrawGrid, ignoring \"grid\" attribute";
errorLog(os.str()); errorLog(os.str());
} }
} if(const char *gdo = bone->Attribute("gridDrawOrder"))
if(const char *gdo = bone->Attribute("gridDrawOrder")) {
{ int ord = atoi(gdo);
int ord = atoi(gdo); grid->drawOrder = (GridDrawOrder)ord;
newb->drawOrder = (Quad::GridDrawOrder)ord; }
} }
bone = bone->NextSiblingElement("Bone"); bone = bone->NextSiblingElement("Bone");
} }
@ -1809,7 +1807,6 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
for (size_t i = 0; i < this->bones.size(); i++) for (size_t i = 0; i < this->bones.size(); i++)
{ {
Bone *bone = this->bones[i]; Bone *bone = this->bones[i];
const Array2d<Vector>& dg = bone->getDrawGrid();
BoneKeyframe *bk = newSkeletalKeyframe.getBoneKeyframe(bone->boneIdx); BoneKeyframe *bk = newSkeletalKeyframe.getBoneKeyframe(bone->boneIdx);
if(!bk) if(!bk)
{ {
@ -1845,7 +1842,8 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
debugLog(os.str()); debugLog(os.str());
continue; continue;
} }
if(bi->getDrawGrid().empty()) RenderGrid *grid = bi->getGrid();
if(!grid)
{ {
std::ostringstream os; std::ostringstream os;
os << "Interpolator specifies bone [" << bi->boneIdx << "] that has no grid"; os << "Interpolator specifies bone [" << bi->boneIdx << "] that has no grid";
@ -1854,7 +1852,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
} }
SplineType spline = SPLINE_BSPLINE; SplineType spline = SPLINE_BSPLINE;
int cx = 3, cy = 3, degx = 3, degy = 3; unsigned cx = 3, cy = 3, degx = 3, degy = 3;
if(const char *stype = interp->Attribute("type")) if(const char *stype = interp->Attribute("type"))
{ {
SimpleIStringStream is(stype, SimpleIStringStream::REUSE); SimpleIStringStream is(stype, SimpleIStringStream::REUSE);
@ -1883,7 +1881,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
} }
} }
bi->gridType = Quad::GRID_INTERP; grid->gridType = GRID_INTERP;
// bone grid should have been created via <Bone grid=... /> earlier // bone grid should have been created via <Bone grid=... /> earlier
const char *idata = interp->Attribute("data"); const char *idata = interp->Attribute("data");
@ -1898,7 +1896,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
bgip.bsp.resize(cx, cy, degx, degy); bgip.bsp.resize(cx, cy, degx, degy);
const size_t numcp = size_t(cx) * size_t(cy); const size_t numcp = size_t(cx) * size_t(cy);
const size_t numgridp = bi->getDrawGrid().linearsize(); const size_t numgridp = grid->linearsize();
// data format: "W H [x y x y ... (W*H times)] W H x y x y ..." // data format: "W H [x y x y ... (W*H times)] W H x y x y ..."
// ^- start of 1st keyframe ^- 2nd keyframe // ^- start of 1st keyframe ^- 2nd keyframe
@ -2062,7 +2060,8 @@ 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() && b->gridType == Quad::GRID_STRIP) RenderGrid *grid = b->getGrid();
if (grid && b->animated==Bone::ANIM_ALL && !b->changeStrip.empty() && grid->gridType == 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());
@ -2074,22 +2073,21 @@ 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) if (grid && b->animated==Bone::ANIM_ALL && grid->gridType == GRID_INTERP)
{ {
Array2d<Vector>& dg = b->getDrawGrid(); const size_t N = grid->linearsize();
const size_t N = dg.linearsize();
if(bkey1->grid.size() < N) if(bkey1->grid.size() < N)
{ {
bkey1->grid.resize(N); bkey1->grid.resize(N);
Quad::ResetGridAndAlpha(&bkey1->grid[0], dg.width(), dg.height(), 1.0f); RenderGrid::ResetWithAlpha(&bkey1->grid[0], grid->width(), grid->height(), 1.0f);
} }
if(bkey2->grid.size() < N) if(bkey2->grid.size() < N)
{ {
bkey2->grid.resize(N); bkey2->grid.resize(N);
Quad::ResetGridAndAlpha(&bkey2->grid[0], dg.width(), dg.height(), 1.0f); RenderGrid::ResetWithAlpha(&bkey2->grid[0], grid->width(), grid->height(), 1.0f);
} }
Vector *dst = dg.data(); Vector *dst = grid->data();
for(size_t i = 0; i < N; ++i) for(size_t i = 0; i < N; ++i)
{ {
dst[i].x = lerp(bkey1->grid[i].x, bkey2->grid[i].x, dt, lerpType); dst[i].x = lerp(bkey1->grid[i].x, bkey2->grid[i].x, dt, lerpType);
@ -2219,16 +2217,16 @@ void SkeletalSprite::selectNextBone()
void BoneGridInterpolator::updateGridOnly(BoneKeyframe& bk, const Bone *bone) void BoneGridInterpolator::updateGridOnly(BoneKeyframe& bk, const Bone *bone)
{ {
const Array2d<Vector>& dg = bone->getDrawGrid(); const RenderGrid *grid = bone->getGrid();
assert(bone->boneIdx == bk.idx); assert(bone->boneIdx == bk.idx);
assert(bk.grid.size() == dg.linearsize()); assert(bk.grid.size() == grid->linearsize());
bsp.recalc(&bk.grid[0], dg.width(), dg.height(), &bk.controlpoints[0]); bsp.recalc(&bk.grid[0], grid->width(), grid->height(), &bk.controlpoints[0]);
} }
void BoneGridInterpolator::updateGridAndBone(BoneKeyframe& bk, Bone *bone) void BoneGridInterpolator::updateGridAndBone(BoneKeyframe& bk, Bone *bone)
{ {
updateGridOnly(bk, bone); updateGridOnly(bk, bone);
Vector *dst = bone->getDrawGrid().data(); Vector *dst = bone->getGrid()->data();
std::copy(bk.grid.begin(), bk.grid.end(), dst); std::copy(bk.grid.begin(), bk.grid.end(), dst);
} }

View file

@ -1,6 +1,7 @@
#include "SplineGrid.h" #include "SplineGrid.h"
#include "RenderBase.h" #include "RenderBase.h"
#include "Core.h" #include "Core.h"
#include "RenderGrid.h"
SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint; SplineGridCtrlPoint *SplineGridCtrlPoint::movingPoint;
@ -69,7 +70,7 @@ void SplineGridCtrlPoint::onUpdate(float dt)
} }
SplineGrid::SplineGrid() SplineGrid::SplineGrid()
: deg(0) : wasModified(false), deg(0)
{ {
setWidthHeight(128, 128); setWidthHeight(128, 128);
renderQuad = true; renderQuad = true;
@ -80,12 +81,12 @@ SplineGrid::~SplineGrid()
{ {
} }
void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy) RenderGrid *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();
this->createGrid(xres, yres); RenderGrid *ret = this->createGrid(xres, yres);
std::vector<SplineGridCtrlPoint*> oldp; std::vector<SplineGridCtrlPoint*> oldp;
ctrlp.swap(oldp); ctrlp.swap(oldp);
@ -121,13 +122,18 @@ void SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned d
} }
recalc(); recalc();
return ret;
} }
void SplineGrid::recalc() void SplineGrid::recalc()
{ {
exportControlPoints(&bsp.controlpoints[0]); exportControlPoints(&bsp.controlpoints[0]);
bsp.recalc(drawGrid.data(), drawGrid.width(), drawGrid.height()); if(grid)
wasModified = true; {
bsp.recalc(grid->data(), grid->width(), grid->height());
wasModified = true;
}
} }
void SplineGrid::exportControlPoints(Vector* controlpoints) void SplineGrid::exportControlPoints(Vector* controlpoints)

View file

@ -33,7 +33,7 @@ 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 degx, unsigned degy); RenderGrid *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 exportControlPoints(Vector *controlpoints);
void importControlPoints(const Vector *controlpoints); void importControlPoints(const Vector *controlpoints);