mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-05-09 10:34:05 +00:00
More work on tile rendering:
- Use indexed triangle rendering, no more GL_QUADS for tiles - Fix aquarian text on maps - Tile tex repeat mode works again Known broken: - Editor - Tile repeat with grid effects
This commit is contained in:
parent
395ff079e9
commit
368271c40e
25 changed files with 749 additions and 429 deletions
|
@ -961,7 +961,7 @@ void AnimationEditor::editStripKey()
|
|||
{
|
||||
if(editingBone && editingBone->getGrid())
|
||||
{
|
||||
RenderGrid *grid = editingBone->getGrid();
|
||||
DynamicRenderGrid *grid = editingBone->getGrid();
|
||||
Animation *a = editSprite->getCurrentAnimation();
|
||||
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
|
||||
|
||||
|
@ -975,8 +975,8 @@ void AnimationEditor::editStripKey()
|
|||
assert(bk->controlpoints.size() == interp->bsp.ctrlX() * interp->bsp.ctrlY());
|
||||
|
||||
splinegrid = new SplineGrid;
|
||||
RenderGrid *rgrid = splinegrid->resize(interp->bsp.ctrlX(), interp->bsp.ctrlY(), grid->width(), grid->height(), interp->bsp.degX(), interp->bsp.degY());
|
||||
rgrid->drawOrder = grid->drawOrder;
|
||||
DynamicRenderGrid *rgrid = splinegrid->resize(interp->bsp.ctrlX(), interp->bsp.ctrlY(), grid->width(), grid->height(), interp->bsp.degX(), interp->bsp.degY());
|
||||
rgrid->setDrawOrder(grid->getDrawOrder());
|
||||
splinegrid->setTexture(editingBone->texture->name);
|
||||
splinegrid->setWidthHeight(editingBone->width, editingBone->height);
|
||||
splinegrid->position = Vector(400, 300);
|
||||
|
@ -1604,7 +1604,7 @@ void AnimationEditor::applyBoneToSplineGrid()
|
|||
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());
|
||||
assert(bk->grid.size() == editingBone->getGrid()->linearsize());
|
||||
splinegrid->importControlPoints(&bk->controlpoints[0]);
|
||||
}
|
||||
}
|
||||
|
@ -1616,7 +1616,7 @@ void AnimationEditor::applySplineGridToBone()
|
|||
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());
|
||||
assert(bk->grid.size() == editingBone->getGrid()->linearsize());
|
||||
splinegrid->exportControlPoints(&bk->controlpoints[0]);
|
||||
BoneGridInterpolator *interp = a->getBoneGridInterpolator(editingBone->boneIdx);
|
||||
interp->updateGridAndBone(*bk, editingBone);
|
||||
|
|
|
@ -3522,14 +3522,14 @@ bool DSQ::loadTileset(std::string pack, const unsigned char *usedIdx, size_t use
|
|||
y++;
|
||||
}
|
||||
|
||||
et->tu1 = x*cell;
|
||||
et->tv1 = y*cell;
|
||||
et->tu2 = et->tu1 + cell;
|
||||
et->tv2 = et->tv1 + cell;
|
||||
et->tc.u1 = x*cell;
|
||||
et->tc.v1 = y*cell;
|
||||
et->tc.u2 = et->tc.u1 + cell;
|
||||
et->tc.v2 = et->tc.v1 + cell;
|
||||
|
||||
et->tv2 = 1 - et->tv2;
|
||||
et->tv1 = 1 - et->tv1;
|
||||
std::swap(et->tv1,et->tv2);
|
||||
/*et->tc.v2 = 1 - et->tc.v2;
|
||||
et->tc.v1 = 1 - et->tc.v1;
|
||||
std::swap(et->tc.v1,et->tc.v2);*/
|
||||
|
||||
et->w = 512*cell;
|
||||
et->h = 512*cell;
|
||||
|
|
|
@ -243,7 +243,7 @@ void Element::setElementEffectByIndex(int eidx)
|
|||
eff->wavyMin = bity;
|
||||
eff->wavyMax = bity*1.2f;
|
||||
|
||||
if(RenderGrid *g = createGrid(2, e.segsy))
|
||||
if(DynamicRenderGrid *g = createGrid(2, e.segsy))
|
||||
{
|
||||
g->gridType = GRID_UNDEFINED; // by default it's GRID_WAVY, but that would reset during update
|
||||
setGridFromWavy();
|
||||
|
|
|
@ -124,13 +124,15 @@ void TileMgr::createTiles(const TileDef* defs, size_t n)
|
|||
t->flags |= TILEFLAG_FH;
|
||||
if(d.fv)
|
||||
t->flags |= TILEFLAG_FV;
|
||||
if(d.repeat)
|
||||
t->setRepeatOn(d.rsx, d.rsy);
|
||||
|
||||
t->rotation = d.rot;
|
||||
t->tag = d.tag;
|
||||
t->scalex = d.sx;
|
||||
t->scaley = d.sy;
|
||||
|
||||
// must be done last
|
||||
if(d.repeat)
|
||||
t->setRepeatOn(d.rsx, d.rsy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,6 +190,7 @@ TileData* TileMgr::_createTile(unsigned tilesetID, unsigned layer, float x, flo
|
|||
//t.beforeScaleOffsetY = 0;
|
||||
t.flags = GetTileFlags(ef);
|
||||
t.tag = 0;
|
||||
t.rep = NULL;
|
||||
t.et = tileset.getByIdx(tilesetID);
|
||||
assert(t.et);
|
||||
/* t.eff = */ tileEffects.assignEffect(t, effidx);
|
||||
|
|
|
@ -563,11 +563,11 @@ void WorldMapRender::setVis(WorldMapTile *tile)
|
|||
|
||||
if (visMethod == VIS_VERTEX)
|
||||
{
|
||||
RenderGrid *g = tile->q->setSegs(MAPVIS_SUBDIV, MAPVIS_SUBDIV, 0, 0, 0, 0, 2.0, 1);
|
||||
DynamicRenderGrid *g = tile->q->setSegs(MAPVIS_SUBDIV, MAPVIS_SUBDIV, 0, 0, 0, 0, 2.0, 1);
|
||||
if(g)
|
||||
{
|
||||
g->gridType = GRID_UNDEFINED;
|
||||
g->drawOrder = GRID_DRAW_WORLDMAP;
|
||||
g->setDrawOrder(GRID_DRAW_WORLDMAP);
|
||||
tileDataToVis(tile, g->array2d());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
int screenWidth, screenHeight;
|
||||
int textureWidth, textureHeight;
|
||||
|
||||
Vector ** drawGrid; // TODO: make this + related code use RenderGrid
|
||||
Vector ** drawGrid; // TODO: make this + related code use DynamicRenderGrid
|
||||
|
||||
// returns handle > 0 on success
|
||||
int loadShaderFile(const char *vert, const char *frag);
|
||||
|
|
|
@ -155,7 +155,9 @@ void Core::setup_opengl()
|
|||
if(afterEffectManager)
|
||||
afterEffectManager->updateDevice();
|
||||
|
||||
defaultQuadVertexBuf.initQuadVertices(0, 0, 1, 1);
|
||||
TexCoordBox defaultTC;
|
||||
defaultTC.setStandard();
|
||||
defaultQuadGrid.init(2, 2, defaultTC);
|
||||
}
|
||||
|
||||
void Core::resizeWindow(int w, int h, int full, int bpp, int vsync, int display, int hz)
|
||||
|
@ -279,7 +281,7 @@ static bool checkWritable(const std::string& path, bool warn, bool critical)
|
|||
|
||||
|
||||
Core::Core(const std::string &filesystem, const std::string& extraDataDir, int numRenderLayers, const std::string &appName, int particleSize, std::string userDataSubFolder)
|
||||
: ActionMapper(), StateManager(), appName(appName), defaultQuadVertexBuf(GPUBUF_STATIC | GPUBUF_VERTEXBUF)
|
||||
: ActionMapper(), StateManager(), appName(appName)
|
||||
{
|
||||
window = NULL;
|
||||
sound = NULL;
|
||||
|
@ -731,6 +733,8 @@ void Core::initGraphicsLibrary(int width, int height, bool fullscreen, bool vsyn
|
|||
debugLog((const char*)glGetString(GL_RENDERER));
|
||||
debugLog((const char*)glGetString(GL_VERSION));
|
||||
|
||||
DynamicGPUBuffer::StaticInit();
|
||||
|
||||
enumerateScreenModes(window->getDisplayIndex());
|
||||
|
||||
window->updateSize();
|
||||
|
@ -1920,7 +1924,7 @@ void Core::shutdown()
|
|||
frameBuffer.unloadDevice();
|
||||
debugLog("OK");
|
||||
|
||||
defaultQuadVertexBuf.dropBuffer();
|
||||
defaultQuadGrid.dropBuffers();
|
||||
|
||||
debugLog("Shutdown Graphics Library...");
|
||||
shutdownGraphicsLibrary();
|
||||
|
|
|
@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "TextureMgr.h"
|
||||
#include "VertexBuffer.h"
|
||||
#include "DarkLayer.h"
|
||||
|
||||
#include "RenderGrid.h"
|
||||
#include "GameKeys.h"
|
||||
|
||||
class ParticleEffect;
|
||||
|
@ -413,7 +413,7 @@ public:
|
|||
|
||||
TextureMgr texmgr;
|
||||
|
||||
inline const DynamicGPUBuffer *getDefaultQuadVertexBuffer() const { return &defaultQuadVertexBuf; }
|
||||
inline const RenderGrid *getDefaultQuadGrid() const { return &defaultQuadGrid; }
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -492,7 +492,7 @@ protected:
|
|||
virtual void updateActionButtons();
|
||||
void clearActionButtons();
|
||||
|
||||
DynamicGPUBuffer defaultQuadVertexBuf;
|
||||
RenderGrid defaultQuadGrid;
|
||||
|
||||
public:
|
||||
// inclusive!
|
||||
|
|
|
@ -84,4 +84,35 @@ public:
|
|||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class Accessor2d
|
||||
{
|
||||
public:
|
||||
Accessor2d(T *p, size_t w, size_t h) : _p(p), _w(w), _h(h) {}
|
||||
|
||||
size_t width() const {return _w;}
|
||||
size_t height() const {return _h;}
|
||||
size_t linearsize() const {return _w * _h;}
|
||||
|
||||
inline T& operator()(size_t x, size_t y)
|
||||
{
|
||||
return _p[y * _w + x];
|
||||
}
|
||||
inline const T& operator()(size_t x, size_t y) const
|
||||
{
|
||||
return _p[y * _w + x];
|
||||
}
|
||||
|
||||
const T *data() const { return _p; }
|
||||
T *data() { return _p; }
|
||||
|
||||
const T *row(size_t y) const { return &_p[y * _w]; }
|
||||
T *row(size_t y) { return &_p[y * _w]; }
|
||||
|
||||
private:
|
||||
const T *_p;
|
||||
const size_t _w, _h;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -75,20 +75,29 @@ void Quad::destroy()
|
|||
|
||||
|
||||
|
||||
RenderGrid *Quad::setSegs(int x, int y, float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo)
|
||||
DynamicRenderGrid *Quad::setSegs(int x, int y, float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo)
|
||||
{
|
||||
RenderGrid *g = createGrid(x, y);
|
||||
DynamicRenderGrid *g = createGrid(x, y);
|
||||
if(g)
|
||||
g->setSegs(dgox, dgoy, dgmx, dgmy, dgtm, dgo);
|
||||
return g;
|
||||
}
|
||||
|
||||
RenderGrid *Quad::createGrid(int xd, int yd)
|
||||
DynamicRenderGrid *Quad::createGrid(int xd, int yd)
|
||||
{
|
||||
delete grid;
|
||||
return (grid = xd && yd
|
||||
? new RenderGrid(xd, yd)
|
||||
: NULL);
|
||||
grid = NULL;
|
||||
if(xd && yd)
|
||||
{
|
||||
TexCoordBox tc;
|
||||
tc.u1 = upperLeftTextureCoordinates.x;
|
||||
tc.v1 = upperLeftTextureCoordinates.y;
|
||||
tc.u2 = lowerRightTextureCoordinates.x;
|
||||
tc.v2 = lowerRightTextureCoordinates.y;
|
||||
grid = new DynamicRenderGrid();
|
||||
grid->init(xd, yd, tc);
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
|
||||
void Quad::setDrawGridAlpha(size_t x, size_t y, float alpha)
|
||||
|
@ -208,7 +217,7 @@ void Quad::renderGrid(const RenderState& rs) const
|
|||
glPushMatrix();
|
||||
glScalef(width, height, 1);
|
||||
|
||||
grid->render(rx, upperLeftTextureCoordinates, lowerRightTextureCoordinates);
|
||||
grid->render(rx);
|
||||
|
||||
// debug points
|
||||
if (RenderObject::renderCollisionShape)
|
||||
|
|
12
BBGE/Quad.h
12
BBGE/Quad.h
|
@ -39,7 +39,7 @@ protected:
|
|||
void onRender(const RenderState& rs) const OVERRIDE;
|
||||
};
|
||||
|
||||
class RenderGrid;
|
||||
class DynamicRenderGrid;
|
||||
|
||||
class Quad : public RenderObject
|
||||
{
|
||||
|
@ -47,7 +47,7 @@ public:
|
|||
Quad(const std::string &tex, const Vector &pos);
|
||||
Quad();
|
||||
virtual ~Quad();
|
||||
RenderGrid *createGrid(int x, int y);
|
||||
DynamicRenderGrid *createGrid(int x, int y);
|
||||
void destroy() OVERRIDE;
|
||||
bool isCoordinateInside(Vector coord, int minSize=0) const;
|
||||
bool isCoordinateInsideWorld(const Vector &coord, int minSize=0) const;
|
||||
|
@ -61,14 +61,14 @@ public:
|
|||
float getWidth() const {return width;}
|
||||
float getHeight() const {return height;}
|
||||
|
||||
RenderGrid *setSegs(int x, int y, float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo);
|
||||
DynamicRenderGrid *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 repeatTextureToFill(bool on);
|
||||
void refreshRepeatTextureToFill();
|
||||
bool isRepeatingTextureToFill() const { return repeatTexture; }
|
||||
void setStripPoints(bool vert, const Vector *points, size_t n);
|
||||
RenderGrid *getGrid() { return grid; }
|
||||
const RenderGrid *getGrid() const { return grid; }
|
||||
DynamicRenderGrid *getGrid() { return grid; }
|
||||
const DynamicRenderGrid *getGrid() const { return grid; }
|
||||
|
||||
void reloadDevice() OVERRIDE;
|
||||
|
||||
|
@ -88,7 +88,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
RenderGrid *grid;
|
||||
DynamicRenderGrid *grid;
|
||||
|
||||
|
||||
void resetGrid();
|
||||
|
|
|
@ -41,157 +41,87 @@ void RenderGrid::ResetWithAlpha(Vector* dst, size_t w, size_t h, float alpha)
|
|||
}
|
||||
|
||||
|
||||
|
||||
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)
|
||||
RenderGrid::RenderGrid()
|
||||
: indexbuf(GPUBUF_STATIC | GPUBUF_INDEXBUF), vbo(GPUBUF_DYNAMIC | GPUBUF_VERTEXBUF), trisToDraw(0)
|
||||
, needVBOUpdate(false), drawOrder(GRID_DRAW_DEFAULT)
|
||||
{
|
||||
init(w, h);
|
||||
tc.setStandard();
|
||||
}
|
||||
|
||||
RenderGrid::~RenderGrid()
|
||||
{
|
||||
}
|
||||
|
||||
void RenderGrid::init(size_t w, size_t h)
|
||||
void RenderGrid::dropBuffers()
|
||||
{
|
||||
vbo.dropBuffer();
|
||||
indexbuf.dropBuffer();
|
||||
}
|
||||
|
||||
void RenderGrid::init(size_t w, size_t h, const TexCoordBox& tc)
|
||||
{
|
||||
assert(w > 1 && h > 1);
|
||||
grid.init(w, h);
|
||||
setDrawOrder((GridDrawOrder)drawOrder, true);
|
||||
this->tc = tc;
|
||||
reset();
|
||||
Vector *dg = grid.data();
|
||||
for(size_t i = 0; i < grid.linearsize(); ++i)
|
||||
dg[i].z = 1.0f;
|
||||
|
||||
updateVBO();
|
||||
}
|
||||
|
||||
|
||||
void RenderGrid::reset()
|
||||
{
|
||||
ResetGrid(grid.data(), grid.width(), grid.height());
|
||||
needVBOUpdate = true;
|
||||
}
|
||||
|
||||
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();
|
||||
const size_t w = grid.width();
|
||||
const size_t h = grid.height();
|
||||
|
||||
size_t nx = w;
|
||||
if(drawGridOut)
|
||||
nx /= 2;
|
||||
|
||||
for (size_t y = 0; y < h; y++)
|
||||
{
|
||||
Vector * const row = grid.row(y);
|
||||
const float xoffset = y * drawGridOffsetX;
|
||||
const float addx = sinf(gridTimer+xoffset)*drawGridModX;
|
||||
|
||||
size_t x;
|
||||
for (x = 0; x < nx; x++)
|
||||
row[x].x -= addx;
|
||||
for (; x < w; x++)
|
||||
row[x].x += addx;
|
||||
|
||||
if(const float dgmy = drawGridModY)
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
float yoffset = x * drawGridOffsetY;
|
||||
row[x].y += cosf(gridTimer+yoffset)*dgmy;
|
||||
}
|
||||
}
|
||||
}
|
||||
needVBOUpdate = true;
|
||||
}
|
||||
|
||||
void RenderGrid::setAlpha(size_t x, size_t y, float a)
|
||||
{
|
||||
if (x < grid.width() && y < grid.height())
|
||||
grid(x, y).z = a;
|
||||
needVBOUpdate = true;
|
||||
}
|
||||
|
||||
void RenderGrid::setSegs(float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo)
|
||||
void RenderGrid::setDrawOrder(GridDrawOrder ord, bool force)
|
||||
{
|
||||
drawGridOffsetX = dgox;
|
||||
drawGridOffsetY = dgoy;
|
||||
drawGridModX = dgmx;
|
||||
drawGridModY = dgmy;
|
||||
drawGridTimeMultiplier = dgtm;
|
||||
drawGridOut = dgo;
|
||||
gridTimer = 0;
|
||||
gridType = GRID_WAVY;
|
||||
if(!force && drawOrder == ord)
|
||||
return;
|
||||
drawOrder = ord;
|
||||
trisToDraw = indexbuf.initGridIndices_Triangles(grid.width(), grid.height(), ord == GRID_DRAW_LRBT, GPUACCESS_HOSTCOPY);
|
||||
}
|
||||
|
||||
void RenderGrid::setStripPoints(bool vert, const Vector* points, size_t n)
|
||||
void RenderGrid::setTexCoords(const TexCoordBox& tc)
|
||||
{
|
||||
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 float* 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 y = 0; y < H; y++)
|
||||
{
|
||||
const size_t wavy_y = (H - y)-1;
|
||||
if (wavy_y < len)
|
||||
{
|
||||
const float tmp = wavy[wavy_y] * iw;
|
||||
Vector * const row = grid.row(y);
|
||||
for (size_t x = 0; x < NX; x++)
|
||||
{
|
||||
row[x].x = tmp - 0.5f;
|
||||
row[x+1].x = tmp + 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
this->tc = tc;
|
||||
needVBOUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
void RenderGrid::render(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
|
||||
void RenderGrid::render(const RenderState& rs) 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;
|
||||
if(rs.alpha != 1 || rs.color != Vector(1,1,1))
|
||||
{
|
||||
render_WithAlpha(rs);
|
||||
break;
|
||||
}
|
||||
// else fall through
|
||||
|
||||
default:
|
||||
render_Indexed(rs);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,133 +131,74 @@ void RenderGrid::renderDebugPoints(const RenderState& rs) const
|
|||
|
||||
glPointSize(2);
|
||||
glColor3f(1,0,0);
|
||||
glBegin(GL_POINTS);
|
||||
const size_t W = grid.width();
|
||||
const size_t H = grid.height();
|
||||
for (size_t y = 0; y < H; y++)
|
||||
{
|
||||
const Vector * const row = grid.row(y);
|
||||
for (size_t x = 0; x < W; x++)
|
||||
glVertex2f(row[x].x, row[x].y);
|
||||
}
|
||||
glEnd();
|
||||
vbo.apply();
|
||||
glDrawArrays(GL_POINTS, 0, grid.linearsize());
|
||||
}
|
||||
|
||||
void RenderGrid::render_LRTB(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
|
||||
void RenderGrid::updateVBO()
|
||||
{
|
||||
const float percentX = lowerRightTexCoords.x - upperLeftTexCoords.x;
|
||||
const float percentY = lowerRightTexCoords.y - upperLeftTexCoords.y;
|
||||
const float percentX = tc.u2 - tc.u1;
|
||||
const float percentY = tc.v2 - tc.v1;
|
||||
|
||||
const float baseX = upperLeftTexCoords.x;
|
||||
const float baseY = upperLeftTexCoords.y;
|
||||
const float baseX = tc.u1;
|
||||
const float baseY = tc.v1;
|
||||
|
||||
const size_t NX = grid.width()-1;
|
||||
const size_t NY = grid.height()-1;
|
||||
const size_t W = grid.width();
|
||||
const size_t H = grid.height();
|
||||
|
||||
// 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 incX = percentX / float(W-1);
|
||||
const float incY = percentY / float(H-1);
|
||||
|
||||
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)
|
||||
do
|
||||
{
|
||||
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)
|
||||
float *p = (float*)vbo.beginWrite(GPUBUFTYPE_VEC2_TC, W*H * (2*2) * sizeof(float), GPUACCESS_DEFAULT);
|
||||
|
||||
float v = baseY;
|
||||
for (size_t y = 0; y < H; y++, v += incY)
|
||||
//for (size_t y = H; y --> 0; v += incY)
|
||||
{
|
||||
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);
|
||||
float u = baseX;
|
||||
const Vector *row = grid.row(y);
|
||||
for (size_t x = 0; x < W; x++, u += incX)
|
||||
{
|
||||
*p++ = row->x;
|
||||
*p++ = row->y;
|
||||
++row;
|
||||
*p++ = u;
|
||||
*p++ = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
while(!vbo.commitWrite());
|
||||
|
||||
needVBOUpdate = false;
|
||||
}
|
||||
|
||||
void RenderGrid::render_LRBT(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
|
||||
void RenderGrid::render_Indexed(const RenderState& rs) 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)rs;
|
||||
// can't render this here when color/alpha is modulated AND we have colors as part of the vertex data;
|
||||
// old opengl simply doesn't support this
|
||||
assert(drawOrder != GRID_DRAW_WORLDMAP || (rs.color == Vector(1,1,1) && rs.alpha == 1));
|
||||
vbo.apply();
|
||||
indexbuf.drawElements(GL_TRIANGLES, trisToDraw);
|
||||
}
|
||||
|
||||
void RenderGrid::render_WithAlpha(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const
|
||||
void RenderGrid::render_WithAlpha(const RenderState& rs) const
|
||||
{
|
||||
const float percentX = fabsf(lowerRightTexCoords.x - upperLeftTexCoords.x);
|
||||
const float percentY = fabsf(upperLeftTexCoords.y - lowerRightTexCoords.y);
|
||||
const float percentX = fabsf(tc.u2 - tc.u1);
|
||||
const float percentY = fabsf(tc.v1 - tc.v2);
|
||||
|
||||
const float baseX =
|
||||
(lowerRightTexCoords.x < upperLeftTexCoords.x)
|
||||
? lowerRightTexCoords.x : upperLeftTexCoords.x;
|
||||
(tc.u2 < tc.u1)
|
||||
? tc.u2 : tc.u1;
|
||||
const float baseY =
|
||||
(lowerRightTexCoords.y < upperLeftTexCoords.y)
|
||||
? lowerRightTexCoords.y : upperLeftTexCoords.y;
|
||||
(tc.v2 < tc.v1)
|
||||
? tc.v2 : tc.v1;
|
||||
|
||||
const size_t NX = grid.width()-1;
|
||||
const size_t NY = grid.height()-1;
|
||||
|
@ -381,3 +252,120 @@ void RenderGrid::render_WithAlpha(const RenderState& rs, const Vector& upperLeft
|
|||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
|
||||
DynamicRenderGrid::DynamicRenderGrid()
|
||||
: RenderGrid()
|
||||
, gridTimer(0)
|
||||
, drawGridOffsetX(0), drawGridOffsetY(0), drawGridModX(0), drawGridModY(0), drawGridTimeMultiplier(0)
|
||||
, drawGridOut(false), gridType(GRID_WAVY)
|
||||
{
|
||||
}
|
||||
|
||||
DynamicRenderGrid::~DynamicRenderGrid()
|
||||
{
|
||||
}
|
||||
|
||||
void DynamicRenderGrid::update(float dt)
|
||||
{
|
||||
if (gridType == GRID_WAVY)
|
||||
{
|
||||
gridTimer += dt * drawGridTimeMultiplier;
|
||||
reset();
|
||||
const size_t w = grid.width();
|
||||
const size_t h = grid.height();
|
||||
|
||||
size_t nx = w;
|
||||
if(drawGridOut)
|
||||
nx /= 2;
|
||||
|
||||
for (size_t y = 0; y < h; y++)
|
||||
{
|
||||
Vector * const row = grid.row(y);
|
||||
const float xoffset = y * drawGridOffsetX;
|
||||
const float addx = sinf(gridTimer+xoffset)*drawGridModX;
|
||||
|
||||
size_t x;
|
||||
for (x = 0; x < nx; x++)
|
||||
row[x].x -= addx;
|
||||
for (; x < w; x++)
|
||||
row[x].x += addx;
|
||||
|
||||
if(const float dgmy = drawGridModY)
|
||||
for (x = 0; x < w; x++)
|
||||
{
|
||||
float yoffset = x * drawGridOffsetY;
|
||||
row[x].y += cosf(gridTimer+yoffset)*dgmy;
|
||||
}
|
||||
}
|
||||
// always update vbo now
|
||||
}
|
||||
else if(!needVBOUpdate)
|
||||
return;
|
||||
|
||||
updateVBO();
|
||||
}
|
||||
|
||||
void DynamicRenderGrid::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 DynamicRenderGrid::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;
|
||||
}
|
||||
|
||||
needVBOUpdate = true;
|
||||
}
|
||||
|
||||
void DynamicRenderGrid::setFromWavy(const float* 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 y = 0; y < H; y++)
|
||||
{
|
||||
const size_t wavy_y = (H - y)-1;
|
||||
if (wavy_y < len)
|
||||
{
|
||||
const float tmp = wavy[wavy_y] * iw;
|
||||
Vector * const row = grid.row(y);
|
||||
for (size_t x = 0; x < NX; x++)
|
||||
{
|
||||
row[x].x = tmp - 0.5f;
|
||||
row[x+1].x = tmp + 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
needVBOUpdate = true;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "Vector.h"
|
||||
#include "DataStructures.h"
|
||||
#include "VertexBuffer.h"
|
||||
#include "Texture.h" // TexCoordBox
|
||||
|
||||
struct RenderState;
|
||||
|
||||
|
@ -23,23 +25,26 @@ enum GridType
|
|||
GRID_INTERP = 3, // quad is in grid mode
|
||||
};
|
||||
|
||||
// simple render grid, must be manually uploaded to GPU if changed
|
||||
class RenderGrid
|
||||
{
|
||||
public:
|
||||
RenderGrid(size_t w, size_t h);
|
||||
RenderGrid();
|
||||
~RenderGrid();
|
||||
void dropBuffers();
|
||||
|
||||
void init(size_t w, size_t h);
|
||||
void init(size_t w, size_t h, const TexCoordBox& tc);
|
||||
void reset();
|
||||
void resetWithAlpha(float a);
|
||||
void update(float dt);
|
||||
void render(const RenderState& rs, const Vector& upperLeftTexCoords, const Vector& lowerRightTexCoords) const;
|
||||
void render(const RenderState& rs) 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 float *wavy, size_t len, float width);
|
||||
void setDrawOrder(GridDrawOrder ord, bool force = false);
|
||||
inline GridDrawOrder getDrawOrder() const { return GridDrawOrder(drawOrder); }
|
||||
void setTexCoords(const TexCoordBox& tc);
|
||||
const TexCoordBox& getTexCoords() const { return tc; }
|
||||
|
||||
bool empty() const { return !(width() | height()); }
|
||||
size_t width() const { return grid.width(); }
|
||||
size_t height() const { return grid.height(); }
|
||||
size_t linearsize() const { return grid.linearsize(); }
|
||||
|
@ -47,11 +52,39 @@ public:
|
|||
Vector *data() { return grid.data(); }
|
||||
Array2d<Vector>& array2d() { return grid; }
|
||||
const Array2d<Vector>& array2d() const { return grid; }
|
||||
const DynamicGPUBuffer& getVBO() const { return vbo; }
|
||||
void updateVBO();
|
||||
|
||||
static void ResetWithAlpha(Vector* dst, size_t w, size_t h, float alpha);
|
||||
|
||||
protected:
|
||||
DynamicGPUBuffer indexbuf, vbo;
|
||||
size_t trisToDraw;
|
||||
Array2d<Vector> grid;
|
||||
TexCoordBox tc;
|
||||
bool needVBOUpdate;
|
||||
|
||||
void render_Indexed(const RenderState& rs) const;
|
||||
void render_WithAlpha(const RenderState& rs) const;
|
||||
|
||||
public:
|
||||
GridDrawOrder drawOrder;
|
||||
};
|
||||
|
||||
// supports animation and automatic upload
|
||||
class DynamicRenderGrid : public RenderGrid
|
||||
{
|
||||
public:
|
||||
DynamicRenderGrid();
|
||||
~DynamicRenderGrid();
|
||||
|
||||
void update(float dt);
|
||||
|
||||
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 float *wavy, size_t len, float width);
|
||||
|
||||
protected:
|
||||
float gridTimer;
|
||||
float drawGridOffsetX;
|
||||
float drawGridOffsetY;
|
||||
|
@ -61,11 +94,6 @@ protected:
|
|||
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
|
||||
|
|
|
@ -130,7 +130,7 @@ void Bone::addSegment(Bone *b)
|
|||
|
||||
void Bone::createStrip(bool vert, int num)
|
||||
{
|
||||
RenderGrid *grid = vert ? createGrid(2, num) : createGrid(num, 2);
|
||||
DynamicRenderGrid *grid = vert ? createGrid(2, num) : createGrid(num, 2);
|
||||
stripVert = vert;
|
||||
grid->gridType = GRID_STRIP;
|
||||
changeStrip.resize(num);
|
||||
|
@ -974,7 +974,7 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
XMLElement *bones = xml->NewElement("Bones");
|
||||
for (i = 0; i < this->bones.size(); i++)
|
||||
{
|
||||
const RenderGrid * const grid = this->bones[i]->getGrid();
|
||||
const DynamicRenderGrid * const grid = this->bones[i]->getGrid();
|
||||
XMLElement *bone = xml->NewElement("Bone");
|
||||
bone->SetAttribute("idx", (unsigned int) this->bones[i]->boneIdx);
|
||||
bone->SetAttribute("gfx", this->bones[i]->gfx.c_str());
|
||||
|
@ -1033,9 +1033,9 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
bone->SetAttribute("sz", os.str().c_str());
|
||||
}
|
||||
|
||||
if(grid && grid->drawOrder != GRID_DRAW_DEFAULT)
|
||||
if(grid && grid->getDrawOrder() != GRID_DRAW_DEFAULT)
|
||||
{
|
||||
bone->SetAttribute("gridDrawOrder", (int)grid->drawOrder);
|
||||
bone->SetAttribute("gridDrawOrder", (int)grid->getDrawOrder());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1073,7 +1073,8 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
const BoneGridInterpolator& bgip = a->interpolators[j];
|
||||
XMLElement *interp = xml->NewElement("Interpolator");
|
||||
Bone *bone = this->getBoneByIdx(bgip.idx);
|
||||
assert(bone->gridType == Quad::GRID_INTERP);
|
||||
DynamicRenderGrid *grid = bone->getGrid();
|
||||
assert(grid && grid->gridType == GRID_INTERP);
|
||||
if(bgip.storeBoneByIdx)
|
||||
interp->SetAttribute("bone", (int)bone->boneIdx);
|
||||
else
|
||||
|
@ -1128,7 +1129,7 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
Bone *bone = this->getBoneByIdx(b->idx);
|
||||
if(bone)
|
||||
{
|
||||
const RenderGrid * const bgrid = bone->getGrid();
|
||||
const DynamicRenderGrid * const bgrid = bone->getGrid();
|
||||
os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
|
||||
// don't want to store grid points if they can be regenerated automatically
|
||||
size_t usedGridSize = (!bgrid || bgrid->gridType == GRID_INTERP) ? 0 : b->grid.size();
|
||||
|
@ -1601,7 +1602,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
}
|
||||
if (bone->Attribute("grid"))
|
||||
{
|
||||
RenderGrid *grid = newb->getGrid();
|
||||
DynamicRenderGrid *grid = newb->getGrid();
|
||||
if(!grid)
|
||||
{
|
||||
SimpleIStringStream is(bone->Attribute("grid"), SimpleIStringStream::REUSE);
|
||||
|
@ -1618,7 +1619,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
if(const char *gdo = bone->Attribute("gridDrawOrder"))
|
||||
{
|
||||
int ord = atoi(gdo);
|
||||
grid->drawOrder = (GridDrawOrder)ord;
|
||||
grid->setDrawOrder((GridDrawOrder)ord);
|
||||
}
|
||||
}
|
||||
bone = bone->NextSiblingElement("Bone");
|
||||
|
@ -1842,7 +1843,7 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
debugLog(os.str());
|
||||
continue;
|
||||
}
|
||||
RenderGrid *grid = bi->getGrid();
|
||||
DynamicRenderGrid *grid = bi->getGrid();
|
||||
if(!grid)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
@ -2060,7 +2061,7 @@ void AnimationLayer::updateBones()
|
|||
b->scale.x = lerp(bkey1->sx, bkey2->sx, dt, lerpType);
|
||||
b->scale.y = lerp(bkey1->sy, bkey2->sy, dt, lerpType);
|
||||
}
|
||||
RenderGrid *grid = b->getGrid();
|
||||
DynamicRenderGrid *grid = b->getGrid();
|
||||
if (grid && b->animated==Bone::ANIM_ALL && !b->changeStrip.empty() && grid->gridType == GRID_STRIP)
|
||||
{
|
||||
if (bkey2->grid.size() < b->changeStrip.size())
|
||||
|
@ -2079,12 +2080,12 @@ void AnimationLayer::updateBones()
|
|||
if(bkey1->grid.size() < N)
|
||||
{
|
||||
bkey1->grid.resize(N);
|
||||
RenderGrid::ResetWithAlpha(&bkey1->grid[0], grid->width(), grid->height(), 1.0f);
|
||||
DynamicRenderGrid::ResetWithAlpha(&bkey1->grid[0], grid->width(), grid->height(), 1.0f);
|
||||
}
|
||||
if(bkey2->grid.size() < N)
|
||||
{
|
||||
bkey2->grid.resize(N);
|
||||
RenderGrid::ResetWithAlpha(&bkey2->grid[0], grid->width(), grid->height(), 1.0f);
|
||||
DynamicRenderGrid::ResetWithAlpha(&bkey2->grid[0], grid->width(), grid->height(), 1.0f);
|
||||
}
|
||||
|
||||
Vector *dst = grid->data();
|
||||
|
@ -2217,7 +2218,7 @@ void SkeletalSprite::selectNextBone()
|
|||
|
||||
void BoneGridInterpolator::updateGridOnly(BoneKeyframe& bk, const Bone *bone)
|
||||
{
|
||||
const RenderGrid *grid = bone->getGrid();
|
||||
const DynamicRenderGrid *grid = bone->getGrid();
|
||||
assert(bone->boneIdx == bk.idx);
|
||||
assert(bk.grid.size() == grid->linearsize());
|
||||
bsp.recalc(&bk.grid[0], grid->width(), grid->height(), &bk.controlpoints[0]);
|
||||
|
|
|
@ -81,12 +81,12 @@ SplineGrid::~SplineGrid()
|
|||
{
|
||||
}
|
||||
|
||||
RenderGrid *SplineGrid::resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy)
|
||||
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();
|
||||
|
||||
RenderGrid *ret = this->createGrid(xres, yres);
|
||||
DynamicRenderGrid *ret = this->createGrid(xres, yres);
|
||||
|
||||
std::vector<SplineGridCtrlPoint*> oldp;
|
||||
ctrlp.swap(oldp);
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
~SplineGrid();
|
||||
|
||||
// # of control points on each axis
|
||||
RenderGrid *resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy);
|
||||
DynamicRenderGrid *resize(size_t w, size_t h, size_t xres, size_t yres, unsigned degx, unsigned degy);
|
||||
void recalc();
|
||||
void exportControlPoints(Vector *controlpoints);
|
||||
void importControlPoints(const Vector *controlpoints);
|
||||
|
|
|
@ -30,6 +30,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "GLLoad.h"
|
||||
#include "stb_image_resize.h"
|
||||
|
||||
bool TexCoordBox::isStandard() const
|
||||
{
|
||||
return u1 == 0 && v1 == 0 && u2 == 1 && v2 == 1;
|
||||
}
|
||||
|
||||
void TexCoordBox::setStandard()
|
||||
{
|
||||
u1 = 0;
|
||||
v1 = 0;
|
||||
u2 = 1;
|
||||
v2 = 1;
|
||||
}
|
||||
|
||||
|
||||
Texture::Texture()
|
||||
{
|
||||
|
@ -88,13 +101,13 @@ static const GLenum repeatLUT[] = { GL_CLAMP_TO_EDGE, GL_REPEAT };
|
|||
void Texture::apply(bool repeat) const
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, gltexid);
|
||||
if(repeat != _repeating)
|
||||
/*if(repeat != _repeating)
|
||||
{
|
||||
_repeating = repeat;
|
||||
GLenum rep = repeatLUT[repeat];
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, rep);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, rep);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
struct GlTexFormat
|
||||
|
@ -127,8 +140,8 @@ bool Texture::upload(const ImageData& img, bool mipmap)
|
|||
if(!gltexid)
|
||||
glGenTextures(1, &gltexid);
|
||||
glBindTexture(GL_TEXTURE_2D, gltexid);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
_repeating = false;
|
||||
|
||||
const GlTexFormat& f = formatLUT[img.channels - 1];
|
||||
|
|
|
@ -24,6 +24,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include <string>
|
||||
#include "Refcounted.h"
|
||||
|
||||
struct TexCoordBox
|
||||
{
|
||||
float u1, v1; // upper left (x,y)
|
||||
float u2, v2; // lower right (x,y)
|
||||
|
||||
bool isStandard() const;
|
||||
void setStandard();
|
||||
};
|
||||
|
||||
enum TextureLoadResult
|
||||
{
|
||||
|
|
204
BBGE/Tile.cpp
204
BBGE/Tile.cpp
|
@ -146,12 +146,11 @@ static void dropEffect(TileData& t)
|
|||
|
||||
static void dropRepeat(TileData& t)
|
||||
{
|
||||
if(t.flags & TILEFLAG_OWN_REPEAT)
|
||||
if(t.rep)
|
||||
{
|
||||
delete t.rep;
|
||||
t.flags &= ~TILEFLAG_OWN_REPEAT;
|
||||
t.rep = NULL;
|
||||
}
|
||||
t.rep = NULL;
|
||||
}
|
||||
|
||||
static void dropAll(TileData& t)
|
||||
|
@ -232,6 +231,10 @@ size_t TileStorage::cloneSome(const TileEffectStorage& effstore, const size_t* i
|
|||
for(size_t i = ret; i < N; ++i) // loop only over newly added tiles
|
||||
{
|
||||
TileData& t = tiles[i];
|
||||
if(t.rep)
|
||||
{
|
||||
t.rep = new TileRepeatData(*t.rep); // must be done BEFORE assigning eff
|
||||
}
|
||||
if((t.flags & TILEFLAG_OWN_EFFDATA) && t.eff)
|
||||
{
|
||||
int efx = t.eff->efxidx;
|
||||
|
@ -239,10 +242,6 @@ size_t TileStorage::cloneSome(const TileEffectStorage& effstore, const size_t* i
|
|||
t.flags &= TILEFLAG_OWN_EFFDATA;
|
||||
effstore.assignEffect(t, efx); // recreate effect properly
|
||||
}
|
||||
if((t.flags & TILEFLAG_OWN_REPEAT) && t.rep)
|
||||
{
|
||||
t.rep = new TileRepeatData(*t.rep);
|
||||
}
|
||||
}
|
||||
|
||||
refreshAll();
|
||||
|
@ -282,9 +281,11 @@ void TileStorage::clearSelection()
|
|||
tiles[i].flags &= ~TILEFLAG_SELECTED;
|
||||
}
|
||||
|
||||
TileEffectData::TileEffectData(const TileEffectConfig& cfg)
|
||||
TileEffectData::TileEffectData(const TileEffectConfig& cfg, const TileData *t)
|
||||
: efxtype(cfg.type), efxidx(cfg.index)
|
||||
, grid(NULL), alpha(1), blend(BLEND_DEFAULT)
|
||||
, ownGrid(false), shared(false)
|
||||
|
||||
{
|
||||
switch(cfg.type)
|
||||
{
|
||||
|
@ -294,14 +295,14 @@ TileEffectData::TileEffectData(const TileEffectConfig& cfg)
|
|||
|
||||
case EFX_WAVY:
|
||||
{
|
||||
float bity = 20; // FIXME
|
||||
assert(t);
|
||||
float bity = t->et->h/float(cfg.u.wavy.segsy);
|
||||
wavy.wavy.resize(cfg.u.wavy.segsy, 0.0f);
|
||||
wavy.flip = cfg.u.wavy.flip;
|
||||
wavy.min = bity;
|
||||
wavy.max = bity*1.2f;
|
||||
|
||||
RenderGrid *g = new RenderGrid(2, cfg.u.wavy.segsy);
|
||||
grid = g;
|
||||
DynamicRenderGrid *g = _ensureGrid(2, cfg.u.wavy.segsy, t);
|
||||
g->gridType = GRID_UNDEFINED; // we do the grid update manually
|
||||
|
||||
wavy.angleOffset = 0;
|
||||
|
@ -317,8 +318,7 @@ TileEffectData::TileEffectData(const TileEffectConfig& cfg)
|
|||
|
||||
case EFX_SEGS:
|
||||
{
|
||||
RenderGrid *g = new RenderGrid(cfg.u.segs.x, cfg.u.segs.y);
|
||||
grid = g;
|
||||
DynamicRenderGrid *g = _ensureGrid(cfg.u.segs.x, cfg.u.segs.y, t);
|
||||
g->setSegs(cfg.u.segs.dgox, cfg.u.segs.dgoy, cfg.u.segs.dgmx, cfg.u.segs.dgmy, cfg.u.segs.dgtm, cfg.u.segs.dgo);
|
||||
}
|
||||
break;
|
||||
|
@ -335,7 +335,43 @@ TileEffectData::TileEffectData(const TileEffectConfig& cfg)
|
|||
|
||||
TileEffectData::~TileEffectData()
|
||||
{
|
||||
delete grid;
|
||||
if(ownGrid)
|
||||
delete grid;
|
||||
}
|
||||
|
||||
DynamicRenderGrid *TileEffectData::_ensureGrid(size_t w, size_t h, const TileData *t)
|
||||
{
|
||||
DynamicRenderGrid *g = grid;
|
||||
if(ownGrid)
|
||||
{
|
||||
assert(g);
|
||||
return g;
|
||||
}
|
||||
|
||||
if(t && t->rep)
|
||||
{
|
||||
assert(!shared); // a shared instance MUST have its own grid and MUST NOT refer to the grid of any tile
|
||||
if(ownGrid)
|
||||
delete g;
|
||||
g = &t->rep->grid;
|
||||
ownGrid = false;
|
||||
}
|
||||
|
||||
if(!g)
|
||||
{
|
||||
g = new DynamicRenderGrid;
|
||||
ownGrid = true;
|
||||
}
|
||||
grid = g;
|
||||
TexCoordBox tc;
|
||||
if(t)
|
||||
tc = t->getTexcoords();
|
||||
else
|
||||
tc.setStandard();
|
||||
g->init(w, h, tc);
|
||||
if(t && t->rep)
|
||||
t->rep->refresh(*t);
|
||||
return g;
|
||||
}
|
||||
|
||||
void TileEffectData::Wavy::update(float dt)
|
||||
|
@ -463,19 +499,28 @@ void TileEffectStorage::assignEffect(TileData& t, int index) const
|
|||
return;
|
||||
|
||||
size_t idx = size_t(index);
|
||||
if(idx >= configs.size())
|
||||
return;
|
||||
|
||||
if(idx < prepared.size() && prepared[idx])
|
||||
|
||||
bool needinstance = false;
|
||||
if(idx < configs.size())
|
||||
{
|
||||
t.eff = prepared[idx];
|
||||
needinstance = configs[idx].needsOwnInstanceForTile(t);
|
||||
}
|
||||
else if(idx < configs.size())
|
||||
|
||||
if(needinstance)
|
||||
{
|
||||
if(configs[idx].type == EFX_NONE)
|
||||
return;
|
||||
|
||||
t.eff = new TileEffectData(configs[idx]);
|
||||
t.eff = new TileEffectData(configs[idx], &t);
|
||||
t.flags |= TILEFLAG_OWN_EFFDATA;
|
||||
}
|
||||
else if(idx < prepared.size() && prepared[idx])
|
||||
{
|
||||
t.eff = prepared[idx];
|
||||
}
|
||||
}
|
||||
|
||||
void TileEffectStorage::update(float dt)
|
||||
|
@ -513,7 +558,10 @@ void TileEffectStorage::finalize()
|
|||
// segs and alpha are independent of the tile they are applied to,
|
||||
// so we can create shared instances of the effect.
|
||||
if(c.type == EFX_SEGS || c.type == EFX_ALPHA)
|
||||
prepared[i] = new TileEffectData(c);
|
||||
{
|
||||
prepared[i] = new TileEffectData(c, NULL);
|
||||
prepared[i]->shared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -532,12 +580,21 @@ bool TileData::isCoordinateInside(float cx, float cy, float minsize) const
|
|||
}
|
||||
|
||||
TileRepeatData::TileRepeatData()
|
||||
: vertexbuf(GPUBUF_STATIC | GPUBUF_VERTEXBUF)
|
||||
: texscaleX(1), texscaleY(1)
|
||||
, texOffX(0), texOffY(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TileRepeatData::refresh(const ElementTemplate& et, float scalex, float scaley)
|
||||
TileRepeatData::TileRepeatData(const TileRepeatData& o)
|
||||
: texscaleX(o.texscaleX), texscaleY(o.texscaleY)
|
||||
, texOffX(o.texOffX), texOffY(o.texOffY)
|
||||
{
|
||||
}
|
||||
|
||||
TexCoordBox TileRepeatData::calcTexCoords(const TileData& t) const
|
||||
{
|
||||
const ElementTemplate& et = *t.et;
|
||||
|
||||
float tw, th;
|
||||
if(et.tex)
|
||||
{
|
||||
|
@ -550,43 +607,118 @@ void TileRepeatData::refresh(const ElementTemplate& et, float scalex, float scal
|
|||
th = et.h;
|
||||
}
|
||||
|
||||
const float tu1 = texOffX;
|
||||
const float tv1 = texOffY;
|
||||
const float tu2 = (et.w*scalex*texscaleX)/tw + texOffX;
|
||||
const float tv2 = (et.h*scaley*texscaleY)/th + texOffY;
|
||||
TexCoordBox tc;
|
||||
tc.u1 = texOffX;
|
||||
tc.v1 = texOffY;
|
||||
tc.u2 = (et.w*t.scalex*texscaleX)/tw + texOffX;
|
||||
tc.v2 = (et.h*t.scaley*texscaleY)/th + texOffY;
|
||||
|
||||
this->tu1 = tu1;
|
||||
this->tv1 = tv1;
|
||||
this->tu2 = tu2;
|
||||
this->tv2 = tv2;
|
||||
// HACK: partially repeated textures have a weird Y axis. assuming a repeat factor of 0.5,
|
||||
// instead of texcoords from 0 -> 0.4 everything is biased towards the opposite end, ie. 0.6 -> 1.
|
||||
// This is especially true for partial repeats, we always need to bias towards the other end.
|
||||
// I have no idea why this has to be like this for tiles, but this is NOT the case for fonts.
|
||||
// And NOTE: without this, maps may look deceivingly correct, but they really are not.
|
||||
const float percentY = tc.v2 - tc.v1;
|
||||
const float remainder = 1.0f - fmodf(percentY, 1.0f);
|
||||
tc.v1 += remainder; // bias towards next int
|
||||
tc.v2 += remainder;
|
||||
|
||||
vertexbuf.initQuadVertices(tu1, tv1, tu2, tv2);
|
||||
return tc;
|
||||
}
|
||||
|
||||
void TileRepeatData::refresh(const TileData& t)
|
||||
{
|
||||
TexCoordBox tc = calcTexCoords(t);
|
||||
|
||||
/*if(t.eff)
|
||||
if(const DynamicRenderGrid *g = t.eff->grid)
|
||||
{
|
||||
grid.init(g->width(), g->height(), grid.getTexCoords());
|
||||
grid.gridType = g->gridType;
|
||||
}*/
|
||||
|
||||
if(grid.empty())
|
||||
grid.init(2, 2, tc);
|
||||
else
|
||||
{
|
||||
grid.setTexCoords(tc);
|
||||
grid.reset();
|
||||
grid.updateVBO();
|
||||
}
|
||||
}
|
||||
|
||||
TileRepeatData* TileData::setRepeatOn(float texscalex, float texscaley, float offx, float offy)
|
||||
{
|
||||
if(rep && !(flags & TILEFLAG_OWN_REPEAT))
|
||||
rep = NULL;
|
||||
flags |= (TILEFLAG_OWN_REPEAT | TILEFLAG_REPEAT);
|
||||
flags |= TILEFLAG_REPEAT;
|
||||
if(!rep)
|
||||
rep = new TileRepeatData;
|
||||
rep->texscaleX = texscalex;
|
||||
rep->texscaleY = texscaley;
|
||||
rep->texOffX = offx;
|
||||
rep->texOffY = offy;
|
||||
rep->refresh(*et, scalex, scaley);
|
||||
rep->refresh(*this);
|
||||
|
||||
// FIXME: if eff, link eff->grid to rep->grid
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
void TileData::setRepeatOff()
|
||||
{
|
||||
flags &= ~TILEFLAG_REPEAT;
|
||||
// don't delete this->rep; if we're in editor mode we don't want to lose the repeat data just yet
|
||||
// also, a TileEffectData may point to rep->grid
|
||||
}
|
||||
|
||||
void TileData::refreshRepeat()
|
||||
{
|
||||
if((flags & TILEFLAG_OWN_REPEAT) && rep)
|
||||
if(rep)
|
||||
{
|
||||
rep->refresh(*et, scalex, scaley);
|
||||
rep->refresh(*this);
|
||||
}
|
||||
}
|
||||
|
||||
bool TileData::hasStandardTexcoords() const
|
||||
{
|
||||
// repeat applies per-tile texcoords, so if that's set it's non-standard
|
||||
return !rep && et->tc.isStandard();
|
||||
}
|
||||
|
||||
const TexCoordBox& TileData::getTexcoords() const
|
||||
{
|
||||
return !(flags & TILEFLAG_REPEAT)
|
||||
? et->tc
|
||||
: rep->grid.getTexCoords();
|
||||
}
|
||||
|
||||
const RenderGrid *TileData::getGrid() const
|
||||
{
|
||||
if(flags & TILEFLAG_REPEAT)
|
||||
return &rep->getGrid();
|
||||
|
||||
if(eff && eff->grid)
|
||||
return eff->grid;
|
||||
|
||||
return et->grid;
|
||||
}
|
||||
|
||||
bool TileEffectConfig::needsOwnInstanceForTile(const TileData& t) const
|
||||
{
|
||||
const bool rep = !!(t.flags & TILEFLAG_REPEAT);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case EFX_NONE:
|
||||
case EFX_ALPHA:
|
||||
return false;
|
||||
|
||||
case EFX_WAVY:
|
||||
return true;
|
||||
|
||||
case EFX_SEGS:
|
||||
return rep || !t.hasStandardTexcoords();
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return true; // uhhhh
|
||||
}
|
||||
|
|
51
BBGE/Tile.h
51
BBGE/Tile.h
|
@ -5,6 +5,9 @@
|
|||
#include "Vector.h"
|
||||
#include "EngineEnums.h"
|
||||
#include "VertexBuffer.h"
|
||||
#include "RenderGrid.h"
|
||||
#include "Texture.h" // TexCoordBox
|
||||
|
||||
|
||||
// A Tile is a very stripped down RenderObject that bypasses the default
|
||||
// rendering pipeline for efficiency reasons.
|
||||
|
@ -33,14 +36,17 @@ Assumptions:
|
|||
- Most tiles that exist are going to be rendered
|
||||
- Only few tiles have an effect attached
|
||||
|
||||
Gotaches:
|
||||
Gotchas:
|
||||
- Keeping a pointer to a TileData is not safe.
|
||||
- Tile indexes are not stable. Moving a tile changes the index it can be addressed with
|
||||
- Tile repeat causes a tile to have non-standard texcoords.
|
||||
Grid effect texcoords need to be synced with repeat tc, if repeat is toggled.
|
||||
Also mind non-standard texcoords in ElementTemplate (eg. aquarian glyphs)
|
||||
*/
|
||||
|
||||
class ElementTemplate;
|
||||
class Texture;
|
||||
class RenderGrid;
|
||||
class DynamicRenderGrid;
|
||||
class TileRender;
|
||||
|
||||
enum EFXType
|
||||
|
@ -51,6 +57,8 @@ enum EFXType
|
|||
EFX_WAVY
|
||||
};
|
||||
|
||||
struct TileData;
|
||||
|
||||
// static configuration for one effect type. POD.
|
||||
struct TileEffectConfig
|
||||
{
|
||||
|
@ -81,6 +89,9 @@ public:
|
|||
BlendType blend;
|
||||
} alpha;
|
||||
} u;
|
||||
|
||||
|
||||
bool needsOwnInstanceForTile(const TileData& t) const;
|
||||
};
|
||||
|
||||
enum TileFlags
|
||||
|
@ -96,24 +107,23 @@ enum TileFlags
|
|||
TILEFLAG_HIDDEN = 0x80, // don't render tile
|
||||
TILEFLAG_SELECTED = 0x100, // ephemeral: selected in editor
|
||||
TILEFLAG_EDITOR_HIDDEN = 0x200, // tile is hidden for editor reasons. temporarily set when multi-selecting and moving. doesn't count as hidden externally and is only for rendering.
|
||||
TILEFLAG_OWN_REPEAT = 0x400, // owns TileRepeatData, may update, must delete
|
||||
TILEFLAG_FV = 0x800, // flipped vertically
|
||||
TILEFLAG_FV = 0x400, // flipped vertically
|
||||
};
|
||||
|
||||
struct TileData;
|
||||
|
||||
struct TileEffectData
|
||||
{
|
||||
TileEffectData(const TileEffectConfig& cfg);
|
||||
TileEffectData(const TileEffectConfig& cfg, const TileData *t); // NULL is passed in during global prepare, when we don't have a tile
|
||||
~TileEffectData();
|
||||
void update(float dt, const TileData *t); // optional t needed for EFX_WAVY
|
||||
void doInteraction(const TileData& t, const Vector& pos, const Vector& vel, float mult, float touchWidth);
|
||||
|
||||
const EFXType efxtype;
|
||||
const unsigned efxidx; // index of TileEffect
|
||||
RenderGrid *grid;
|
||||
DynamicRenderGrid *grid; // may or may not own this. This possibly points to a tile's TileRepeatData::grid
|
||||
InterpolatedVector alpha;
|
||||
BlendType blend;
|
||||
bool ownGrid; // true if we own grid
|
||||
bool shared; // only used for assertions. set if this tile effect instance is pre-made and shared across many tiles
|
||||
|
||||
struct Wavy
|
||||
{
|
||||
|
@ -128,23 +138,29 @@ struct TileEffectData
|
|||
Wavy wavy;
|
||||
|
||||
private:
|
||||
DynamicRenderGrid *_ensureGrid(size_t w, size_t h, const TileData *t);
|
||||
TileEffectData(const TileEffectData&); // no-copy
|
||||
};
|
||||
|
||||
struct TileRepeatData
|
||||
{
|
||||
TileRepeatData();
|
||||
TileRepeatData(const TileRepeatData& o);
|
||||
const TexCoordBox& getTexCoords() const { return grid.getTexCoords(); }
|
||||
const DynamicRenderGrid& getGrid() const { return grid; }
|
||||
|
||||
// written via refresh()
|
||||
DynamicGPUBuffer vertexbuf;
|
||||
float tu1, tv1, tu2, tv2;
|
||||
DynamicRenderGrid grid; // need this here because a repeating tile WITH a grid-based tile effect is a special and annoying case to handle
|
||||
|
||||
// set by user
|
||||
float texscaleX, texscaleY;
|
||||
float texOffX, texOffY;
|
||||
|
||||
// pass ET & scale of owning tile
|
||||
void refresh(const ElementTemplate& et, float scalex, float scaley);
|
||||
// pass owning tile
|
||||
void refresh(const TileData& t);
|
||||
|
||||
private:
|
||||
TexCoordBox calcTexCoords(const TileData& t) const;
|
||||
};
|
||||
|
||||
// POD and as compact as possible. Intended for rendering as quickly as possible.
|
||||
|
@ -157,9 +173,9 @@ struct TileData
|
|||
float rotation;
|
||||
unsigned flags; // TileFlags
|
||||
unsigned tag; // FIXME: make this int
|
||||
const ElementTemplate *et; // never NULL. texture, texcoords, etc is here. // TODO: maybe replace with unsigned tilesetID? but that's an extra indirection or two during rendering...
|
||||
TileEffectData *eff; // mostly NULL
|
||||
TileRepeatData *rep;
|
||||
const ElementTemplate *et; // never NULL. texture, texcoords, etc is here.
|
||||
TileEffectData *eff; // mostly NULL. owned if flags & TILEFLAG_OWN_EFFDATA, otherwise shared
|
||||
TileRepeatData *rep; // NULL in most cases, set if repeating. Always owned.
|
||||
|
||||
// helpers for external access
|
||||
inline void setVisible(bool on) { if(on) flags &= ~TILEFLAG_HIDDEN; else flags |= TILEFLAG_HIDDEN; }
|
||||
|
@ -168,6 +184,11 @@ struct TileData
|
|||
TileRepeatData *setRepeatOn(float texscalex = 1, float texscaley = 1, float offx = 0, float offy = 0);
|
||||
void setRepeatOff();
|
||||
void refreshRepeat();
|
||||
|
||||
bool hasStandardTexcoords() const;
|
||||
|
||||
const TexCoordBox& getTexcoords() const;
|
||||
const RenderGrid *getGrid() const;
|
||||
};
|
||||
|
||||
class TileEffectStorage
|
||||
|
|
|
@ -64,8 +64,6 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
|
||||
const bool renderExtras = renderBorders || RenderObject::renderCollisionShape;
|
||||
const TileEffectData *prevEff = ((TileEffectData*)NULL)+1; // initial value is different from anything else
|
||||
const RenderGrid *grid = NULL;
|
||||
const DynamicGPUBuffer *lastVertexBuf = NULL;
|
||||
|
||||
for(size_t i = 0; i < storage.tiles.size(); ++i)
|
||||
{
|
||||
|
@ -114,12 +112,9 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
{
|
||||
prevEff = eff;
|
||||
BlendType blend = BLEND_DEFAULT;
|
||||
alpha = rs.alpha;
|
||||
grid = NULL;
|
||||
|
||||
if(eff)
|
||||
{
|
||||
grid = eff->grid;
|
||||
alpha *= eff->alpha.x;
|
||||
blend = eff->blend;
|
||||
}
|
||||
|
@ -136,7 +131,7 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
// Maps were designed with the bug present so we need to replicate it,
|
||||
// otherwise things won't look correct.
|
||||
unsigned effflag = tile.flags;
|
||||
if(grid)
|
||||
if(eff && eff->grid)
|
||||
effflag &= ~TILEFLAG_FV;
|
||||
|
||||
float effrot = tile.rotation;
|
||||
|
@ -166,37 +161,12 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
glScalef(sw, sh, 1);
|
||||
|
||||
|
||||
const RenderGrid *grid = tile.getGrid();
|
||||
if(!grid)
|
||||
{
|
||||
const DynamicGPUBuffer *vb = !(tile.flags & TILEFLAG_REPEAT)
|
||||
? tile.et->vertexbuf
|
||||
: &tile.rep->vertexbuf;
|
||||
assert(vb);
|
||||
if(vb != lastVertexBuf)
|
||||
{
|
||||
lastVertexBuf = vb;
|
||||
vb->apply();
|
||||
}
|
||||
vb->DrawArrays(GL_TRIANGLE_FAN, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
rx.alpha = alpha;
|
||||
grid = core->getDefaultQuadGrid();
|
||||
rx.alpha = alpha;
|
||||
grid->render(rx);
|
||||
|
||||
Vector upperLeftTextureCoordinates, lowerRightTextureCoordinates;
|
||||
if(tile.flags & TILEFLAG_REPEAT)
|
||||
{
|
||||
upperLeftTextureCoordinates = Vector(tile.rep->tu1, tile.rep->tv1);
|
||||
lowerRightTextureCoordinates = Vector(tile.rep->tu2, tile.rep->tv2);
|
||||
}
|
||||
else
|
||||
{
|
||||
upperLeftTextureCoordinates = Vector(et->tu1, et->tv1);
|
||||
lowerRightTextureCoordinates = Vector(et->tu2, et->tv2);
|
||||
}
|
||||
|
||||
grid->render(rx, upperLeftTextureCoordinates, lowerRightTextureCoordinates);
|
||||
}
|
||||
|
||||
if(renderExtras)
|
||||
{
|
||||
|
@ -221,6 +191,7 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
glVertex2f(0,0);
|
||||
glEnd();
|
||||
|
||||
// TODO: move this to the IBO
|
||||
glLineWidth(2);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex2f(0.5f, 0.5f);
|
||||
|
@ -235,7 +206,8 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
|
||||
|
||||
RenderObject::lastTextureApplied = lastTexId;
|
||||
RenderObject::lastTextureRepeat = !!lastTexRepeat;
|
||||
|
|
|
@ -172,8 +172,7 @@ const ElementTemplate* Tileset::getAdjacent(size_t idx, int direction, bool wrap
|
|||
|
||||
ElementTemplate::~ElementTemplate()
|
||||
{
|
||||
if(ownsVertexbuf)
|
||||
delete const_cast<DynamicGPUBuffer*>(vertexbuf);
|
||||
delete grid;
|
||||
}
|
||||
|
||||
void ElementTemplate::finalize()
|
||||
|
@ -195,20 +194,16 @@ void ElementTemplate::finalize()
|
|||
h = 64;
|
||||
}
|
||||
|
||||
if(tu1 == 0 && tv1 == 0 && tu2 == 1 && tv2 == 1)
|
||||
if(tc.isStandard())
|
||||
{
|
||||
// this avoids buffer switches later on
|
||||
vertexbuf = core->getDefaultQuadVertexBuffer();
|
||||
ownsVertexbuf = false;
|
||||
delete grid;
|
||||
grid = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
DynamicGPUBuffer *vb = ownsVertexbuf
|
||||
? const_cast<DynamicGPUBuffer*>(vertexbuf)
|
||||
: new DynamicGPUBuffer(GPUBUF_STATIC | GPUBUF_VERTEXBUF);
|
||||
vb->initQuadVertices(tu1, tv1, tu2, tv2);
|
||||
vertexbuf = vb;
|
||||
ownsVertexbuf = true;
|
||||
if(!grid)
|
||||
grid = new RenderGrid;
|
||||
grid->init(2, 2, tc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
#include "Vector.h"
|
||||
#include <vector>
|
||||
#include "Texture.h"
|
||||
#include "VertexBuffer.h"
|
||||
#include "RenderGrid.h"
|
||||
|
||||
class DynamicRenderGrid;
|
||||
|
||||
class ElementTemplate
|
||||
{
|
||||
public:
|
||||
ElementTemplate() { w=0; h=0; idx=-1; tu1=tv1=0; tu2=tv2=1; vertexbuf = NULL; ownsVertexbuf = false; }
|
||||
ElementTemplate() { w=0; h=0; idx=-1; tc.setStandard(); grid = NULL; }
|
||||
~ElementTemplate();
|
||||
inline bool operator<(const ElementTemplate& o) const { return idx < o.idx; }
|
||||
|
||||
|
@ -18,11 +20,10 @@ public:
|
|||
// lazily assigned when tex is loaded
|
||||
CountedPtr<Texture> tex; // NULL if failed to load or not yet loaded
|
||||
float w,h; // custom size if used, otherwise texture size
|
||||
const DynamicGPUBuffer * vertexbuf; // never NULL
|
||||
bool ownsVertexbuf;
|
||||
RenderGrid *grid; // NULL if default, otherwise we own this
|
||||
|
||||
// fixed
|
||||
float tu1, tu2, tv1, tv2; // texcoords
|
||||
TexCoordBox tc;
|
||||
size_t idx;
|
||||
std::string gfx;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "RenderBase.h"
|
||||
#include "Base.h"
|
||||
#include <assert.h>
|
||||
#include "Texture.h" // TexCoordBox
|
||||
|
||||
bool DynamicGPUBuffer::_HasARB = false;
|
||||
|
||||
|
@ -34,8 +35,9 @@ DynamicGPUBuffer::DynamicGPUBuffer(unsigned usage)
|
|||
: _bufid(0)
|
||||
, _binding((usage & GPUBUF_INDEXBUF) ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB)
|
||||
, _size(0)
|
||||
, _cap(0)
|
||||
, _h_cap(0)
|
||||
, _h_data(NULL)
|
||||
, _d_cap(0)
|
||||
, _d_map(NULL)
|
||||
, _usage(toGlUsage(usage))
|
||||
, _datatype(BufDataType(-1))
|
||||
|
@ -55,7 +57,7 @@ void* DynamicGPUBuffer::_allocBytes(size_t bytes)
|
|||
void *p = realloc(_h_data, bytes);
|
||||
if(p)
|
||||
{
|
||||
_cap = bytes;
|
||||
_h_cap = bytes;
|
||||
_h_data = p;
|
||||
}
|
||||
return p;
|
||||
|
@ -63,10 +65,10 @@ void* DynamicGPUBuffer::_allocBytes(size_t bytes)
|
|||
|
||||
void* DynamicGPUBuffer::_ensureBytes(size_t bytes)
|
||||
{
|
||||
if(bytes < _cap)
|
||||
if(bytes < _h_cap)
|
||||
return _h_data;
|
||||
|
||||
size_t newsize = 2 * _size;
|
||||
size_t newsize = 2 * _h_cap;
|
||||
if(newsize < bytes)
|
||||
newsize += bytes;
|
||||
|
||||
|
@ -81,9 +83,10 @@ void* DynamicGPUBuffer::beginWrite(BufDataType type, size_t newsize, unsigned ac
|
|||
if(_HasARB)
|
||||
{
|
||||
glBindBufferARB(_binding, _ensureDBuf());
|
||||
glBufferDataARB(_binding, newsize, NULL, _usage); // orphan buffer
|
||||
if(!(access & GPUACCESS_HOSTCOPY))
|
||||
{
|
||||
_d_cap = newsize;
|
||||
glBufferDataARB(_binding, newsize, NULL, _usage); // orphan buffer
|
||||
void *p = glMapBufferARB(_binding, GL_WRITE_ONLY_ARB);
|
||||
_d_map = p;
|
||||
if(p)
|
||||
|
@ -95,21 +98,41 @@ void* DynamicGPUBuffer::beginWrite(BufDataType type, size_t newsize, unsigned ac
|
|||
}
|
||||
|
||||
bool DynamicGPUBuffer::commitWrite()
|
||||
{
|
||||
return _commitWrite(_size);
|
||||
}
|
||||
|
||||
bool DynamicGPUBuffer::commitWrite(size_t used)
|
||||
{
|
||||
_size = used;
|
||||
return _commitWrite(used);
|
||||
}
|
||||
|
||||
bool DynamicGPUBuffer::_commitWrite(size_t used)
|
||||
{
|
||||
if(_HasARB)
|
||||
{
|
||||
if(_d_map)
|
||||
{
|
||||
assert(used <= _d_cap);
|
||||
_d_map = NULL;
|
||||
return glUnmapBufferARB(_binding); // can fail
|
||||
}
|
||||
// otherwise, the prev. call to glMapBufferARB failed (or GPUACCESS_NOMAP was set).
|
||||
// otherwise, the prev. call to glMapBufferARB failed (or GPUACCESS_HOSTCOPY was set).
|
||||
// -> didn't map, but wrote to host memory. upload it.
|
||||
assert(_h_data);
|
||||
glBufferSubDataARB(_binding, 0, _size, _h_data);
|
||||
assert(used <= _h_cap);
|
||||
if(used <= _d_cap)
|
||||
glBufferSubDataARB(_binding, 0, used, _h_data); // update existing buffer
|
||||
else
|
||||
{
|
||||
_d_cap = used;
|
||||
glBufferDataARB(_binding, used, _h_data, _usage); // alloc new buffer
|
||||
}
|
||||
}
|
||||
// else nothing to do
|
||||
|
||||
assert(used <= _h_cap);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -144,33 +167,40 @@ void DynamicGPUBuffer::apply(BufDataType usetype) const
|
|||
if(!usetype)
|
||||
usetype = _datatype;
|
||||
|
||||
const unsigned bufid = this->_bufid;
|
||||
|
||||
void *p;
|
||||
if(_HasARB)
|
||||
if(bufid)
|
||||
{
|
||||
unsigned bufid = this->_bufid;
|
||||
assert(bufid != s_lastVertexBuffer); // check that it's no redundant state change
|
||||
if(bufid == s_lastVertexBuffer && usetype == s_lastDataType)
|
||||
return;
|
||||
p = NULL;
|
||||
s_lastVertexBuffer = bufid;
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, bufid);
|
||||
//if(bufid != s_lastVertexBuffer)
|
||||
// glBindBufferARB(GL_ARRAY_BUFFER_ARB, bufid);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = (void*)this->_h_data;
|
||||
assert(p != s_lastHostPtr); // check that it's no redundant state change
|
||||
if(p == s_lastHostPtr && usetype == s_lastDataType) // don't need to check for datatype since that's const for the buffer with that ptr
|
||||
return;
|
||||
//assert(p != s_lastHostPtr); // check that it's no redundant state change
|
||||
//if(p == s_lastHostPtr && usetype == s_lastDataType) // don't need to check for datatype since that's const for the buffer with that ptr
|
||||
// return;
|
||||
}
|
||||
|
||||
s_lastDataType = usetype;
|
||||
assert(bufid || p);
|
||||
|
||||
assert((ty & 0xf) < Countof(s_gltype));
|
||||
const unsigned gltype = s_gltype[usetype & 0xf];
|
||||
const unsigned scalars = (usetype >> 4) & 0xf;
|
||||
const unsigned stride = (usetype >> 8) & 0xff;
|
||||
const unsigned tcoffset = (usetype >> 16) & 0xff;
|
||||
const unsigned coloroffset = usetype >> 24;
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, bufid);
|
||||
|
||||
//if(bufid == s_lastVertexBuffer && usetype == s_lastDataType && p == s_lastHostPtr)
|
||||
// return;
|
||||
|
||||
s_lastDataType = usetype;
|
||||
s_lastVertexBuffer = bufid;
|
||||
|
||||
unsigned u = usetype; // always want unsigned shifts
|
||||
assert((u & 0xf) < Countof(s_gltype));
|
||||
const unsigned gltype = s_gltype[u & 0xf];
|
||||
const unsigned scalars = (u >> 4u) & 0xf;
|
||||
const unsigned stride = (u >> 8u) & 0xff;
|
||||
const unsigned tcoffset = (u >> 16u) & 0xff;
|
||||
const unsigned coloroffset = u >> 24u;
|
||||
|
||||
// vertex and texcoords are always enabled
|
||||
glVertexPointer(scalars, gltype, stride, p);
|
||||
|
@ -225,38 +255,107 @@ void DynamicGPUBuffer::dropBuffer()
|
|||
_size = 0;
|
||||
}
|
||||
|
||||
void DynamicGPUBuffer::DrawArrays(unsigned glmode, size_t n, size_t first)
|
||||
static unsigned getBoundBuffer(unsigned target)
|
||||
{
|
||||
glDrawArrays(glmode, first, n);
|
||||
int id = 0;
|
||||
glGetIntegerv(target, &id);
|
||||
return id;
|
||||
}
|
||||
|
||||
void DynamicGPUBuffer::drawElements(unsigned glmode, size_t n, size_t first)
|
||||
void DynamicGPUBuffer::drawElements(unsigned glmode, size_t n, size_t first) const
|
||||
{
|
||||
assert(_binding == GL_ELEMENT_ARRAY_BUFFER_ARB);
|
||||
assert(s_gltype[_datatype & 0xf] == GL_SHORT);
|
||||
assert(getBoundBuffer(GL_ARRAY_BUFFER_BINDING)); // FIXME: this assert is wrong if indices are on the host
|
||||
|
||||
if(s_lastIndexBuffer != _bufid)
|
||||
{
|
||||
s_lastIndexBuffer = _bufid;
|
||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _bufid);
|
||||
}
|
||||
unsigned id = _bufid;
|
||||
|
||||
glDrawElements(glmode, n, GL_SHORT, NULL);
|
||||
//if(s_lastIndexBuffer != id)
|
||||
//{
|
||||
// s_lastIndexBuffer = id;
|
||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, id);
|
||||
//}
|
||||
|
||||
void *p = id ? NULL : _h_data;
|
||||
assert(p || id);
|
||||
|
||||
glDrawElements(glmode, n, GL_UNSIGNED_SHORT, p);
|
||||
}
|
||||
|
||||
void DynamicGPUBuffer::initQuadVertices(float tu1, float tv1, float tu2, float tv2)
|
||||
void DynamicGPUBuffer::initQuadVertices(const TexCoordBox& tc, unsigned access)
|
||||
{
|
||||
do
|
||||
{
|
||||
float *p = (float*)beginWrite(GPUBUFTYPE_VEC2_TC, (4*4) * sizeof(float), GPUACCESS_DEFAULT);
|
||||
float *p = (float*)beginWrite(GPUBUFTYPE_VEC2_TC, (4*4) * sizeof(float), access);
|
||||
*p++ = -0.5f; *p++ = +0.5f; // xy
|
||||
*p++ = tu1; *p++ = 1.0f-tv1; // uv
|
||||
*p++ = tc.u1; *p++ = tc.v1; // uv
|
||||
*p++ = +0.5f; *p++ = +0.5f; // xy
|
||||
*p++ = tu2; *p++ = 1.0f-tv1; // uv
|
||||
*p++ = tc.u2; *p++ = tc.v1; // uv
|
||||
*p++ = +0.5f; *p++ = -0.5f; // xy
|
||||
*p++ = tu2; *p++ = 1.0f-tv2; // uv
|
||||
*p++ = tc.u2; *p++ = tc.v2; // uv
|
||||
*p++ = -0.5f; *p++ = -0.5f; // xy
|
||||
*p++ = tu1; *p++ = 1.0f-tv2; // uv
|
||||
*p++ = tc.u1; *p++ = tc.v2; // uv
|
||||
}
|
||||
while(!commitWrite());
|
||||
}
|
||||
|
||||
// 0---1---2---3
|
||||
// | | | |
|
||||
// 4---5---6---7
|
||||
// | | | |
|
||||
// 8---9---10--11
|
||||
// This is a 4x3 grid
|
||||
// Which is 3*2 = 6 quads
|
||||
// That's 12 triangles
|
||||
// Each triangle is 3 indices, so we get 36 indices in total
|
||||
size_t DynamicGPUBuffer::initGridIndices_Triangles(size_t w, size_t h, bool invert, unsigned access)
|
||||
{
|
||||
assert(w * h < 0xffff);
|
||||
|
||||
const size_t quadsx = w - 1;
|
||||
const size_t quadsy = h - 1;
|
||||
const size_t quads = quadsx * quadsy;
|
||||
do
|
||||
{
|
||||
unsigned short *p = (unsigned short*)beginWrite(GPUBUFTYPE_U16, 6*quads * sizeof(short), access);
|
||||
|
||||
if(!invert)
|
||||
{
|
||||
// top to bottom
|
||||
for(size_t y = 0; y < quadsy; ++y)
|
||||
{
|
||||
size_t i = y * w;
|
||||
for(size_t x = 0; x < quadsx; ++x)
|
||||
{
|
||||
*p++ = (unsigned short)(i); // 0
|
||||
*p++ = (unsigned short)(i + 1); // 1
|
||||
*p++ = (unsigned short)(i + w); // 4
|
||||
|
||||
*p++ = (unsigned short)(i + 1); // 1
|
||||
*p++ = (unsigned short)(i + w + 1); // 5
|
||||
*p++ = (unsigned short)(i + w); // 4
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// bottom to top
|
||||
for(size_t y = quadsy; y --> 0; )
|
||||
{
|
||||
size_t i = y * w;
|
||||
for(size_t x = 0; x < quadsx; ++x)
|
||||
{
|
||||
*p++ = (unsigned short)(i); // 0
|
||||
*p++ = (unsigned short)(i + 1); // 1
|
||||
*p++ = (unsigned short)(i + w); // 4
|
||||
|
||||
*p++ = (unsigned short)(i + 1); // 1
|
||||
*p++ = (unsigned short)(i + w + 1); // 5
|
||||
*p++ = (unsigned short)(i + w); // 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while(!commitWrite());
|
||||
return quads * 6; // each quad is 2 triangles x 3 verts
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdlib.h> // size_t
|
||||
|
||||
struct TexCoordBox;
|
||||
|
||||
enum BufUsage
|
||||
{
|
||||
// usage
|
||||
|
@ -43,9 +45,8 @@ enum AccessFlags
|
|||
|
||||
class DynamicGPUBuffer
|
||||
{
|
||||
friend class BufMapW;
|
||||
public:
|
||||
void StaticInit();
|
||||
static void StaticInit();
|
||||
DynamicGPUBuffer(unsigned usage);
|
||||
~DynamicGPUBuffer();
|
||||
void dropBuffer();
|
||||
|
@ -54,37 +55,51 @@ public:
|
|||
|
||||
// beginWrite(), then write exactly newsize bytes, then commit
|
||||
void *beginWrite(BufDataType type, size_t newsize, unsigned access); // AccessFlags
|
||||
bool commitWrite();
|
||||
bool commitWrite(); // used same size as passed to beginWrite()
|
||||
bool commitWrite(size_t used); // explicitly specify used size (may be less than initially requested)
|
||||
|
||||
void upload(BufDataType type, const void *data, size_t size);
|
||||
|
||||
static void DrawArrays(unsigned glmode, size_t n, size_t first = 0); // uses last applied buffer for drawing
|
||||
|
||||
// uses own data for indexing and prev. applied buffer for the data to draw
|
||||
void drawElements(unsigned glmode, size_t n, size_t first = 0);
|
||||
void drawElements(unsigned glmode, size_t n, size_t first = 0) const;
|
||||
|
||||
|
||||
void apply(BufDataType usetype = GPUBUFTYPE_NONE) const;
|
||||
|
||||
// Inteded for use with DrawArrays(4) and GL_TRIANGLE_FAN or GL_QUADS (both work)
|
||||
void initQuadVertices(float tu1, float tu2, float tv1, float tv2);
|
||||
void initQuadVertices(const TexCoordBox& tc, unsigned access);
|
||||
|
||||
// Init indices for drawing a grid, like this 4x3 grid:
|
||||
// 0---1---2---3
|
||||
// | | | |
|
||||
// 4---5---6---7
|
||||
// | | | |
|
||||
// 8---9---10--11
|
||||
// Returns the number of triangles to use with GL_TRIANGLES.
|
||||
// Pass invert==true to draw from bottom to top.
|
||||
size_t initGridIndices_Triangles(size_t w, size_t h, bool invert, unsigned access);
|
||||
|
||||
private:
|
||||
|
||||
void* _allocBytes(size_t bytes);
|
||||
void* _ensureBytes(size_t bytes);
|
||||
unsigned _ensureDBuf();
|
||||
bool _commitWrite(size_t used);
|
||||
|
||||
unsigned _bufid;
|
||||
unsigned _binding;
|
||||
size_t _size;
|
||||
size_t _cap;
|
||||
size_t _h_cap;
|
||||
void *_h_data;
|
||||
size_t _d_cap;
|
||||
void *_d_map;
|
||||
const unsigned _usage;
|
||||
BufDataType _datatype;
|
||||
|
||||
static bool _HasARB;
|
||||
|
||||
DynamicGPUBuffer(const DynamicGPUBuffer&); // no copy
|
||||
DynamicGPUBuffer& operator=(const DynamicGPUBuffer&); // no assign
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue