1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-11-28 19:23:53 +00:00

more drafting for tile redering optimization

This is the last commit before the old Element class gets ripped
This commit is contained in:
fgenesis 2023-07-11 22:30:28 +02:00
parent 0818fbcdb4
commit e8c405cd9e
11 changed files with 591 additions and 65 deletions

View file

@ -133,11 +133,11 @@ void Element::updateEffects(float dt)
weight = 1.0f-weight;
if (weight < 0.125f)
weight *= 0.5f;
eff->wavy[i].x = sinf(eff->wavyAngleOffset + (float(i)/wavySz)*PI)*float(eff->wavyMagnitude*eff->effectMult)*weight;
eff->wavy[i] = sinf(eff->wavyAngleOffset + (float(i)/wavySz)*PI)*float(eff->wavyMagnitude*eff->effectMult)*weight;
if (!eff->wavySave.empty())
{
if (eff->wavyLerpIn < 1)
eff->wavy[i].x = eff->wavy[i].x*eff->wavyLerpIn + (eff->wavySave[i].x*(1.0f-eff->wavyLerpIn));
eff->wavy[i] = eff->wavy[i]*eff->wavyLerpIn + (eff->wavySave[i]*(1.0f-eff->wavyLerpIn));
}
}
@ -237,12 +237,8 @@ void Element::setElementEffectByIndex(int eidx)
case EFX_WAVY:
{
eff->wavy.resize(e.segsy);
eff->wavy.resize(e.segsy, 0.0f);
float bity = float(getHeight())/float(e.segsy);
for (size_t i = 0; i < eff->wavy.size(); i++)
{
eff->wavy[i] = Vector(0, -(i*bity));
}
eff->wavyFlip = e.wavy_flip;
eff->wavyMin = bity;
eff->wavyMax = bity*1.2f;

View file

@ -25,6 +25,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
class Entity;
enum EFXType
{
EFX_NONE =-1,
EFX_SEGS =0,
EFX_ALPHA ,
EFX_WAVY ,
EFX_MAX
};
enum ElementFlag
{
@ -52,7 +60,7 @@ struct ElementEffectData
float hitPerc, effectMult;
bool wavyWaving, wavyFlip, touching;
Vector touchVel;
std::vector<Vector> wavy, wavySave;
std::vector<float> wavy, wavySave;
int elementEffectIndex; // used by editor only
};

View file

@ -202,15 +202,6 @@ enum FormUpgradeType
FORMUPGRADE_MAX
};
enum EFXType
{
EFX_NONE =-1,
EFX_SEGS =0,
EFX_ALPHA ,
EFX_WAVY ,
EFX_MAX
};
enum EmoteType
{
EMOTE_NAIJAEVILLAUGH = 0,

View file

@ -154,7 +154,7 @@ void RenderGrid::setStripPoints(bool vert, const Vector* points, size_t n)
}
}
void RenderGrid::setFromWavy(const Vector* wavy, size_t len, float width)
void RenderGrid::setFromWavy(const float* wavy, size_t len, float width)
{
const size_t NX = grid.width() - 1;
const size_t H = grid.height();
@ -165,7 +165,7 @@ void RenderGrid::setFromWavy(const Vector* wavy, size_t len, float width)
const size_t wavy_y = (H - y)-1;
if (wavy_y < len)
{
const float tmp = wavy[wavy_y].x * iw;
const float tmp = wavy[wavy_y] * iw;
Vector * const row = grid.row(y);
for (size_t x = 0; x < NX; x++)
{

View file

@ -38,7 +38,7 @@ public:
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);
void setFromWavy(const float *wavy, size_t len, float width);
size_t width() const { return grid.width(); }
size_t height() const { return grid.height(); }

View file

@ -32,6 +32,7 @@ class Core;
class StateData;
class Texture;
// TODO: move all the other bools from RenderObject here
enum RenderObjectFlags
{
RO_CLEAR = 0x00,

View file

@ -1,2 +1,356 @@
#include "Tile.h"
#include "RenderGrid.h"
#include "Tileset.h"
#include "Base.h"
TileStorage::TileStorage(const TileEffectStorage& eff)
: effstore(eff)
{
}
TileStorage::~TileStorage()
{
destroyAll();
}
void TileStorage::moveToFront(size_t idx)
{
_moveToFront(idx);
refreshAll();
}
void TileStorage::moveToBack(size_t idx)
{
_moveToBack(idx);
refreshAll();
}
void TileStorage::update(float dt)
{
for(size_t i = 0; i < indicesToUpdate.size(); ++i)
{
TileData& t = tiles[indicesToUpdate[i]];
assert(t.flags & TILEFLAG_OWN_EFFDATA); // known to be set if this ends up on the list
t.eff->update(dt, &t);
}
}
void TileStorage::doInteraction(const Vector& pos, const Vector& vel, float mult, float touchWidth)
{
for(size_t i = 0; i < indicesToCollide.size(); ++i)
{
TileData& t = tiles[indicesToCollide[i]];
t.eff->doInteraction(t, pos, vel, mult, touchWidth);
}
}
void TileStorage::_moveToFront(size_t idx)
{
// move tile to front -> move it to the back of the list, to be rendered last aka on top of everything else
TileData tile = tiles[idx];
tiles.erase(tiles.begin() + idx);
tiles.push_back(tile);
}
void TileStorage::_moveToBack(size_t idx)
{
// move tile to back -> move it to the front of the list, to be rendered first aka underneath everything else
TileData tile = tiles[idx];
tiles.erase(tiles.begin() + idx);
tiles.insert(tiles.begin(), tile);
}
void TileStorage::moveToOther(TileStorage& other, const size_t *indices, size_t n)
{
for(size_t i = 0; i < n; ++i)
other.tiles.push_back(tiles[indices[i]]);
std::vector<TileData> tmp;
tmp.swap(tiles);
tiles.reserve(tmp.size() - n);
for(size_t i = 0; i < tmp.size(); ++i)
{
for(size_t k = 0; k < n; ++i) // not particularly efficient, could be much better by sorting first but eh
if(indices[k] == i)
goto skip;
tiles.push_back(tmp[i]);
skip: ;
}
refreshAll();
other.refreshAll();
}
static void dropAttachments(TileData& t)
{
if(t.flags & TILEFLAG_OWN_EFFDATA)
{
delete t.eff;
t.flags &= ~TILEFLAG_OWN_EFFDATA;
}
t.eff = NULL;
}
void TileStorage::deleteSome(const size_t* indices, size_t n)
{
std::vector<TileData> tmp;
tmp.swap(tiles);
tiles.reserve(tmp.size() - n);
for(size_t i = 0; i < tmp.size(); ++i)
{
for(size_t k = 0; k < n; ++i) // not particularly efficient, could be much better by sorting first but eh
if(indices[k] == i)
{
dropAttachments(tmp[i]);
goto skip;
}
tiles.push_back(tmp[i]);
skip: ;
}
refreshAll();
}
void TileStorage::destroyAll()
{
const size_t n = tiles.size();
for(size_t i = 0; i < n; ++i)
dropAttachments(tiles[i]);
tiles.clear();
indicesToCollide.clear();
indicesToUpdate.clear();
}
void TileStorage::setTag(unsigned tag, const size_t* indices, size_t n)
{
for(size_t i = 0; i < n; ++i)
tiles[indices[i]].tag = tag;
// don't need to refresh here
}
void TileStorage::setEffect(int idx, const size_t* indices, size_t n)
{
for(size_t i = 0; i < n; ++i)
effstore.assignEffect(tiles[indices[i]], idx);
refreshAll();
}
void TileStorage::refreshAll()
{
indicesToCollide.clear();
indicesToUpdate.clear();
const size_t n = tiles.size();
for(size_t i = 0; i < n; ++i)
{
const TileData& t = tiles[i];
if(const TileEffectData *e = t.eff)
{
if(t.flags & TILEFLAG_OWN_EFFDATA)
{
indicesToUpdate.push_back(i);
if(e->efxtype == EFX_WAVY)
indicesToCollide.push_back(i);
}
}
}
}
void TileStorage::clearSelection()
{
const size_t n = tiles.size();
for(size_t i = 0; i < n; ++i)
tiles[i].flags &= ~TILEFLAG_SELECTED;
}
TileEffectData::TileEffectData(const TileEffectConfig& cfg)
: efxtype(cfg.type), efxidx(cfg.index)
, grid(NULL), blend(BLEND_DEFAULT)
{
switch(cfg.type)
{
case EFX_WAVY:
{
float bity = 20; // FIXME
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;
g->gridType = GRID_UNDEFINED; // by default it's GRID_WAVY, but that would reset during update
wavy.angleOffset = 0;
wavy.magnitude = 0;
wavy.lerpIn = 0;
wavy.hitPerc = 0;
wavy.effectMult = 0;
wavy.waving = false;
wavy.flip = false;
wavy.touching = false;
}
break;
case EFX_SEGS:
{
RenderGrid *g = new RenderGrid(cfg.u.segs.x, cfg.u.segs.y);
grid = g;
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;
case EFX_ALPHA:
{
alpha.x = cfg.u.alpha.val0;
alpha.interpolateTo(cfg.u.alpha.val1, cfg.u.alpha.time, -1, cfg.u.alpha.pingpong, cfg.u.alpha.ease);
blend = cfg.u.alpha.blend;
}
break;
}
}
TileEffectData::~TileEffectData()
{
delete grid;
}
void TileEffectData::Wavy::update(float dt)
{
if (touching)
{
touching = false;
float ramp = touchVel.getLength2D()/800.0f;
if (ramp < 0) ramp = 0;
if (ramp > 1) ramp = 1;
magnitude = 100 * ramp + 16;
if (touchVel.x < 0)
magnitude = -magnitude;
angleOffset = (hitPerc-0.5f)*PI;
wavySave = wavy;
lerpIn = 0;
}
if (waving)
{
// TODO: set waving=false if magnitude==0 ?
float spd = PI*1.1f;
float magRedSpd = 48;
float lerpSpd = 5.0;
float wavySz = float(wavy.size());
for (size_t i = 0; i < wavy.size(); i++)
{
float weight = float(i)/wavySz;
if (flip)
weight = 1.0f-weight;
if (weight < 0.125f)
weight *= 0.5f;
wavy[i] = sinf(angleOffset + (float(i)/wavySz)*PI)*(magnitude*effectMult)*weight;
if (!wavySave.empty())
{
if (lerpIn < 1)
wavy[i] = wavy[i] * lerpIn + (wavySave[i] * (1.0f-lerpIn));
}
}
if (lerpIn < 1)
{
lerpIn += dt*lerpSpd;
if (lerpIn > 1)
lerpIn = 1;
}
angleOffset += dt*spd;
if (magnitude > 0)
{
magnitude -= magRedSpd*dt;
if (magnitude < 0)
magnitude = 0;
}
else
{
magnitude += magRedSpd*dt;
if (magnitude > 0)
magnitude = 0;
}
}
}
void TileEffectData::update(float dt, const TileData *t)
{
switch(efxtype)
{
case EFX_WAVY:
wavy.update(dt);
if(const size_t N = wavy.wavy.size())
grid->setFromWavy(&wavy.wavy[0], N, t->et->w);
break;
case EFX_SEGS:
grid->update(dt);
break;
case EFX_ALPHA:
alpha.update(dt);
break;
}
}
void TileEffectData::doInteraction(const TileData& t, const Vector& pos, const Vector& vel, float mult, float touchWidth)
{
assert(efxtype == EFX_WAVY);
const Vector tp(t.x, t.y);
if (pos.x > tp.x-touchWidth && pos.x < tp.x+touchWidth)
{
float h = t.et->h*t.scaley;
float h2 = h * 0.5f;
if (pos.y < tp.y+h2 && pos.y > tp.y-h2)
{
wavy.touching = true;
wavy.waving = true;
float hitPerc = tp.y - h2 - pos.y;
hitPerc /= h;
hitPerc = (1.0f-hitPerc)-1.0f;
wavy.hitPerc = hitPerc;
wavy.touchVel = vel;
wavy.effectMult = mult;
}
}
}
void TileEffectStorage::assignEffect(TileData& t, int index) const
{
dropAttachments(t);
if(index < 0)
return;
size_t idx = size_t(index);
if(idx < prepared.size() && prepared[idx])
{
t.eff = prepared[idx];
}
else if(idx < configs.size())
{
t.eff = new TileEffectData(configs[idx]);
t.flags |= TILEFLAG_OWN_EFFDATA;
}
}
void TileEffectStorage::update(float dt)
{
for(size_t i = 0; i < prepared.size(); ++i)
if(TileEffectData *eff = prepared[i])
eff->update(dt, NULL);
}

View file

@ -3,9 +3,7 @@
#include <vector>
#include "Vector.h"
class ElementTemplate;
class Texture;
#include "EngineEnums.h"
// A Tile is a very stripped down RenderObject that bypasses the default
// rendering pipeline for efficiency reasons.
@ -23,36 +21,159 @@ class Texture;
- Does not have offset, internalOffset, gravity, etc etc that RenderObject has
- Parallax scroll factor is solely influenced by layer, not individually
- RGB is never tinted, alpha may come from efx
Further observations:
- Aside from EFX_WAVY, all tiles with the same effect index can share a global modulator,
ie. the alpha value is the same per-tile unless the tile is spawned when the map is in progress.
And on map reload everything is back to the same value for each tile with the same effect and params.
So we can totally exclude the editor.
Gotaches:
- Keeping a pointer to a TileData is not safe.
*/
class ElementTemplate;
class Texture;
class RenderGrid;
class TileRender;
enum EFXType
{
EFX_SEGS,
EFX_ALPHA,
EFX_WAVY
};
// static configuration for one effect type
struct TileEffectConfig
{
public:
EFXType type;
unsigned index;
union
{
struct
{
int x, y;
float dgox, dgoy, dgmx, dgmy, dgtm;
bool dgo;
} segs;
struct
{
float radius, min, max;
int segsy;
bool flip;
} wavy;
struct
{
float val0, val1, time;
bool pingpong, ease;
BlendType blend;
} alpha;
} u;
};
enum TileFlags
{
TILEFLAG_NONE = 0,
TILEFLAG_REPEAT = 0x01, // texture repeats and uses texscale for the repeat factor
TILEFLAG_SOLID = 0x02, // generates OT_INVISIBLE
TILEFLAG_SOLID_THICK = 0x04, // generates more OT_INVISIBLE
TILEFLAG_SOLID_IN = 0x08, // instead of OT_INVISIBLE, generate OT_INVISIBLEIN
TILEFLAG_HURT = 0x10, // always generate OT_HURT
TILEFLAG_FH = 0x20, // flipped horizontally
TILEFLAG_NONE = 0,
TILEFLAG_REPEAT = 0x01, // texture repeats and uses texscale for the repeat factor
TILEFLAG_SOLID = 0x02, // generates OT_INVISIBLE
TILEFLAG_SOLID_THICK = 0x04, // generates more OT_INVISIBLE
TILEFLAG_SOLID_IN = 0x08, // instead of OT_INVISIBLE, generate OT_INVISIBLEIN
TILEFLAG_HURT = 0x10, // always generate OT_HURT
TILEFLAG_FH = 0x20, // flipped horizontally
TILEFLAG_OWN_EFFDATA = 0x40, // tile owns its TileEffectData, can modify & must delete
TILEFLAG_HIDDEN = 0x80, // don't render tile
TILEFLAG_SELECTED = 0x100
};
// sort-of-POD
struct TileData;
struct TileEffectData
{
TileEffectData(const TileEffectConfig& cfg);
~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 to ElementEffect
RenderGrid *grid;
InterpolatedVector alpha;
BlendType blend;
struct Wavy
{
std::vector<float> wavy, wavySave;
Vector touchVel;
float angleOffset, magnitude, lerpIn;
float min, max;
float hitPerc, effectMult;
bool waving, flip, touching;
void update(float dt);
};
Wavy wavy;
};
// POD and as compact as possible
// the idea is that these are linearly adjacent in memory in the order they are rendered,
// to maximize cache & prefetch efficiency
struct TileData
{
float x, y, rotation, texscale;
Vector scale, beforeScaleOffset;
int efx;
unsigned flags; // TileFlags
unsigned tag;
ElementTemplate *et;
float x, y, rotation, texscale;
float scalex, scaley;
float beforeScaleOffsetX, beforeScaleOffsetY;
unsigned flags; // TileFlags
unsigned tag;
ElementTemplate *et; // texture, texcoords, etc is here
TileEffectData *eff;
};
class TileEffectStorage
{
public:
void assignEffect(TileData& t, int index) const;
void update(float dt);
std::vector<TileEffectData*> prepared;
std::vector<TileEffectConfig> configs;
};
class TileStorage
{
friend class TileRender;
public:
std::vector<TileData> tiles;
void refresh(); // call when adding/removing/reordering tiles or changing efx
TileStorage(const TileEffectStorage& eff);
~TileStorage();
void moveToFront(size_t idx);
void moveToBack(size_t idx);
void moveToOther(TileStorage& other, const size_t *indices, size_t n);
void deleteSome(const size_t *indices, size_t n);
void setTag(unsigned tag, const size_t *indices, size_t n);
void setEffect(int idx, const size_t *indices, size_t n);
void update(float dt);
void doInteraction(const Vector& pos, const Vector& vel, float mult, float touchWidth);
void refreshAll(); // call this after changing properties or moving to front/back
void destroyAll();
void clearSelection();
private:
std::vector<TileData> tiles;
std::vector<size_t> indicesToUpdate;
std::vector<size_t> indicesToCollide;
const TileEffectStorage& effstore;
void _refreshTile(const TileData& t);
void _moveToFront(size_t idx);
void _moveToBack(size_t idx);
};

View file

@ -2,9 +2,12 @@
#include "RenderBase.h"
#include "Core.h"
#include "Tileset.h"
#include "RenderGrid.h"
#include "RenderObject.h"
TileRender::TileRender(const TileStorage& tiles)
: storage(tiles)
: storage(tiles), renderBorders(false)
{
}
@ -12,11 +15,36 @@ TileRender::~TileRender()
{
}
// shamelessly ripped from paint.net default palette
static const Vector s_tagColors[] =
{
/* 0 */ Vector(0.5f, 0.5f, 0.5f),
/* 1 */ Vector(1,0,0),
/* 2 */ Vector(1, 0.415686f, 0),
/* 3 */ Vector(1,0.847059f, 0),
/* 4 */ Vector(0.298039f,1,0),
/* 5 */ Vector(0,1,1),
/* 6 */ Vector(0,0.580392,1),
/* 7 */ Vector(0,0.149020f,1),
/* 8 */ Vector(0.282353f,0,1),
/* 9 */ Vector(0.698039f,0,1),
/* 10 */ Vector(1,0,1), // anything outside of the pretty range
};
static inline const Vector& getTagColor(int tag)
{
const unsigned idx = std::min<unsigned>(unsigned(tag), Countof(s_tagColors)-1);
return s_tagColors[idx];
}
void TileRender::onRender(const RenderState& rs) const
{
// prepare. get parallax scroll factors
const RenderObjectLayer& rl = core->renderObjectLayers[this->layer];
Vector M = rl.followCameraMult; // affected by parallaxLock
const Vector M = rl.followCameraMult; // affected by parallaxLock
const float F = rl.followCamera;
// Formula from RenderObject::getFollowCameraPosition() and optimized for speed
@ -26,18 +54,20 @@ void TileRender::onRender(const RenderState& rs) const
unsigned lastTexRepeat = false;
unsigned lastTexId = 0;
BlendType blend = BLEND_DEFAULT; // TODO: influenced by efx
const bool renderBorders = true; // TODO: when layer selected in editor
const bool renderBorders = this->renderBorders;
//bool mustSetColor = false;
for(size_t i = 0; i < storage.tiles.size(); ++i)
{
const TileData& tile = storage.tiles[i];
if(tile.flags & TILEFLAG_HIDDEN)
continue;
const Vector tilepos(tile.x, tile.y);
const Vector tmp = T + (F * tilepos);
const Vector pos = tilepos * M1 + (tmp * M); // lerp, used to select whether to use original v or parallax-corrected v
rs.gpu.setBlend(blend);
ElementTemplate * const et = tile.et;
if(Texture * const tex = et->tex.content())
{
@ -51,34 +81,47 @@ void TileRender::onRender(const RenderState& rs) const
}
}
else
{
lastTexId = 0;
glBindTexture(GL_TEXTURE_2D, 0); // unlikely
}
glPushMatrix();
glTranslatef(pos.x, pos.y, pos.z);
glRotatef(tile.rotation, 0, 0, 1);
if(tile.flags & TILEFLAG_FH)
if(tile.flags & TILEFLAG_FH) // TODO: This is not necessary! Since we have no children, flipped texcoords are fine
glRotatef(180, 0, 1, 0);
// this is only relevant in editor mode and is always 0 otherwise
glTranslatef(tile.beforeScaleOffset.x, tile.beforeScaleOffset.y, tile.beforeScaleOffset.z);
glTranslatef(tile.beforeScaleOffsetX, tile.beforeScaleOffsetY, 0);
glScalef(tile.scale.x, tile.scale.y, 1);
glScalef(tile.scalex * et->w, tile.scaley * et->h, 1);
//glScalef(tile.scalex * et->w, tile.scaley * et->h, 1); // TODO use this + fixed verts
// TODO: only need to do this when prev. tile had different alpha
BlendType blend = BLEND_DEFAULT;
float alpha = rs.alpha;
RenderGrid *grid = NULL;
const TileEffectData * const eff = tile.eff;
if(eff)
{
const float alpha = 1; // TODO: via efx
Vector col = rs.color;
glColor4f(col.x, col.y, col.z, rs.alpha*alpha);
grid = eff->grid;
alpha *= eff->alpha.x;
blend = eff->blend;
}
const float _w2 = float(int(et->w)) * 0.5f;
const float _h2 = float(int(et->h)) * 0.5f;
rs.gpu.setBlend(blend);
// render texture
// TODO: only need to do this when prev. tile had different alpha
glColor4f(rs.color.x, rs.color.y, rs.color.z, alpha);
const Vector upperLeftTextureCoordinates(et->tu1, et->tv1);
const Vector lowerRightTextureCoordinates(et->tu2, et->tv2);
if(!grid)
{
const Vector upperLeftTextureCoordinates(et->tu1, et->tv1);
const Vector lowerRightTextureCoordinates(et->tu2, et->tv2);
const float _w2 = et->w * 0.5f;
const float _h2 = et->h * 0.5f;
glBegin(GL_QUADS);
{
@ -96,14 +139,29 @@ void TileRender::onRender(const RenderState& rs) const
}
glEnd();
}
else
{
RenderState rx(rs);
rx.alpha = alpha;
grid->render(rx, upperLeftTextureCoordinates, lowerRightTextureCoordinates);
if (RenderObject::renderCollisionShape)
{
glBindTexture(GL_TEXTURE_2D, 0);
grid->renderDebugPoints(rs);
lastTexId = 0;
}
}
if(renderBorders)
{
lastTexId = 0;
glBindTexture(GL_TEXTURE_2D, 0);
Vector color(0.5f,0.5f,0.5f); // TODO: (1,1,1) when selected
float c = (tile.flags & TILEFLAG_SELECTED) ? 1.0f : 0.5f;
Vector color(c,c,c);
color *= getTagColor(tile.tag);
const float _w2 = et->w * 0.5f;
const float _h2 = et->h * 0.5f;
glColor4f(color.x, color.y, color.z, 1.0f);
glPointSize(16);
@ -129,7 +187,3 @@ void TileRender::onRender(const RenderState& rs) const
RenderObject::lastTextureApplied = lastTexId;
RenderObject::lastTextureRepeat = !!lastTexRepeat;
}
void TileRender::onUpdate(float dt)
{
}

View file

@ -15,7 +15,8 @@ public:
TileRender(const TileStorage& tiles);
virtual ~TileRender();
virtual void onRender(const RenderState& rs) const;
virtual void onUpdate(float dt);
bool renderBorders;
private:
};

View file

@ -15,7 +15,7 @@ public:
// lazily assigned when tex is loaded
CountedPtr<Texture> tex;
unsigned w,h; // custom size if used, otherwise texture size
float w,h; // custom size if used, otherwise texture size
// fixed
float tu1, tu2, tv1, tv2; // texcoords