mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-12-03 00:15:46 +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:
parent
0818fbcdb4
commit
e8c405cd9e
11 changed files with 591 additions and 65 deletions
|
@ -133,11 +133,11 @@ void Element::updateEffects(float dt)
|
||||||
weight = 1.0f-weight;
|
weight = 1.0f-weight;
|
||||||
if (weight < 0.125f)
|
if (weight < 0.125f)
|
||||||
weight *= 0.5f;
|
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->wavySave.empty())
|
||||||
{
|
{
|
||||||
if (eff->wavyLerpIn < 1)
|
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:
|
case EFX_WAVY:
|
||||||
{
|
{
|
||||||
|
|
||||||
eff->wavy.resize(e.segsy);
|
eff->wavy.resize(e.segsy, 0.0f);
|
||||||
float bity = float(getHeight())/float(e.segsy);
|
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->wavyFlip = e.wavy_flip;
|
||||||
eff->wavyMin = bity;
|
eff->wavyMin = bity;
|
||||||
eff->wavyMax = bity*1.2f;
|
eff->wavyMax = bity*1.2f;
|
||||||
|
|
|
@ -25,6 +25,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
class Entity;
|
class Entity;
|
||||||
|
|
||||||
|
enum EFXType
|
||||||
|
{
|
||||||
|
EFX_NONE =-1,
|
||||||
|
EFX_SEGS =0,
|
||||||
|
EFX_ALPHA ,
|
||||||
|
EFX_WAVY ,
|
||||||
|
EFX_MAX
|
||||||
|
};
|
||||||
|
|
||||||
enum ElementFlag
|
enum ElementFlag
|
||||||
{
|
{
|
||||||
|
@ -52,7 +60,7 @@ struct ElementEffectData
|
||||||
float hitPerc, effectMult;
|
float hitPerc, effectMult;
|
||||||
bool wavyWaving, wavyFlip, touching;
|
bool wavyWaving, wavyFlip, touching;
|
||||||
Vector touchVel;
|
Vector touchVel;
|
||||||
std::vector<Vector> wavy, wavySave;
|
std::vector<float> wavy, wavySave;
|
||||||
int elementEffectIndex; // used by editor only
|
int elementEffectIndex; // used by editor only
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -202,15 +202,6 @@ enum FormUpgradeType
|
||||||
FORMUPGRADE_MAX
|
FORMUPGRADE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EFXType
|
|
||||||
{
|
|
||||||
EFX_NONE =-1,
|
|
||||||
EFX_SEGS =0,
|
|
||||||
EFX_ALPHA ,
|
|
||||||
EFX_WAVY ,
|
|
||||||
EFX_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
enum EmoteType
|
enum EmoteType
|
||||||
{
|
{
|
||||||
EMOTE_NAIJAEVILLAUGH = 0,
|
EMOTE_NAIJAEVILLAUGH = 0,
|
||||||
|
|
|
@ -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 NX = grid.width() - 1;
|
||||||
const size_t H = grid.height();
|
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;
|
const size_t wavy_y = (H - y)-1;
|
||||||
if (wavy_y < len)
|
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);
|
Vector * const row = grid.row(y);
|
||||||
for (size_t x = 0; x < NX; x++)
|
for (size_t x = 0; x < NX; x++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
void setAlpha(size_t x, size_t y, float a);
|
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 setSegs(float dgox, float dgoy, float dgmx, float dgmy, float dgtm, bool dgo);
|
||||||
void setStripPoints(bool vert, const Vector *points, size_t n);
|
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 width() const { return grid.width(); }
|
||||||
size_t height() const { return grid.height(); }
|
size_t height() const { return grid.height(); }
|
||||||
|
|
|
@ -32,6 +32,7 @@ class Core;
|
||||||
class StateData;
|
class StateData;
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
|
// TODO: move all the other bools from RenderObject here
|
||||||
enum RenderObjectFlags
|
enum RenderObjectFlags
|
||||||
{
|
{
|
||||||
RO_CLEAR = 0x00,
|
RO_CLEAR = 0x00,
|
||||||
|
|
354
BBGE/Tile.cpp
354
BBGE/Tile.cpp
|
@ -1,2 +1,356 @@
|
||||||
#include "Tile.h"
|
#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);
|
||||||
|
}
|
||||||
|
|
137
BBGE/Tile.h
137
BBGE/Tile.h
|
@ -3,9 +3,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Vector.h"
|
#include "Vector.h"
|
||||||
|
#include "EngineEnums.h"
|
||||||
class ElementTemplate;
|
|
||||||
class Texture;
|
|
||||||
|
|
||||||
// A Tile is a very stripped down RenderObject that bypasses the default
|
// A Tile is a very stripped down RenderObject that bypasses the default
|
||||||
// rendering pipeline for efficiency reasons.
|
// rendering pipeline for efficiency reasons.
|
||||||
|
@ -23,8 +21,61 @@ class Texture;
|
||||||
- Does not have offset, internalOffset, gravity, etc etc that RenderObject has
|
- Does not have offset, internalOffset, gravity, etc etc that RenderObject has
|
||||||
- Parallax scroll factor is solely influenced by layer, not individually
|
- Parallax scroll factor is solely influenced by layer, not individually
|
||||||
- RGB is never tinted, alpha may come from efx
|
- 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
|
enum TileFlags
|
||||||
{
|
{
|
||||||
TILEFLAG_NONE = 0,
|
TILEFLAG_NONE = 0,
|
||||||
|
@ -34,25 +85,95 @@ enum TileFlags
|
||||||
TILEFLAG_SOLID_IN = 0x08, // instead of OT_INVISIBLE, generate OT_INVISIBLEIN
|
TILEFLAG_SOLID_IN = 0x08, // instead of OT_INVISIBLE, generate OT_INVISIBLEIN
|
||||||
TILEFLAG_HURT = 0x10, // always generate OT_HURT
|
TILEFLAG_HURT = 0x10, // always generate OT_HURT
|
||||||
TILEFLAG_FH = 0x20, // flipped horizontally
|
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
|
struct TileData
|
||||||
{
|
{
|
||||||
float x, y, rotation, texscale;
|
float x, y, rotation, texscale;
|
||||||
Vector scale, beforeScaleOffset;
|
float scalex, scaley;
|
||||||
int efx;
|
float beforeScaleOffsetX, beforeScaleOffsetY;
|
||||||
unsigned flags; // TileFlags
|
unsigned flags; // TileFlags
|
||||||
unsigned tag;
|
unsigned tag;
|
||||||
ElementTemplate *et;
|
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
|
class TileStorage
|
||||||
{
|
{
|
||||||
|
friend class TileRender;
|
||||||
public:
|
public:
|
||||||
|
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<TileData> tiles;
|
||||||
void refresh(); // call when adding/removing/reordering tiles or changing efx
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
#include "RenderBase.h"
|
#include "RenderBase.h"
|
||||||
#include "Core.h"
|
#include "Core.h"
|
||||||
#include "Tileset.h"
|
#include "Tileset.h"
|
||||||
|
#include "RenderGrid.h"
|
||||||
|
#include "RenderObject.h"
|
||||||
|
|
||||||
|
|
||||||
TileRender::TileRender(const TileStorage& tiles)
|
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
|
void TileRender::onRender(const RenderState& rs) const
|
||||||
{
|
{
|
||||||
// prepare. get parallax scroll factors
|
// prepare. get parallax scroll factors
|
||||||
const RenderObjectLayer& rl = core->renderObjectLayers[this->layer];
|
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;
|
const float F = rl.followCamera;
|
||||||
|
|
||||||
// Formula from RenderObject::getFollowCameraPosition() and optimized for speed
|
// Formula from RenderObject::getFollowCameraPosition() and optimized for speed
|
||||||
|
@ -26,18 +54,20 @@ void TileRender::onRender(const RenderState& rs) const
|
||||||
|
|
||||||
unsigned lastTexRepeat = false;
|
unsigned lastTexRepeat = false;
|
||||||
unsigned lastTexId = 0;
|
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)
|
for(size_t i = 0; i < storage.tiles.size(); ++i)
|
||||||
{
|
{
|
||||||
const TileData& tile = storage.tiles[i];
|
const TileData& tile = storage.tiles[i];
|
||||||
|
if(tile.flags & TILEFLAG_HIDDEN)
|
||||||
|
continue;
|
||||||
|
|
||||||
const Vector tilepos(tile.x, tile.y);
|
const Vector tilepos(tile.x, tile.y);
|
||||||
const Vector tmp = T + (F * tilepos);
|
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
|
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;
|
ElementTemplate * const et = tile.et;
|
||||||
if(Texture * const tex = et->tex.content())
|
if(Texture * const tex = et->tex.content())
|
||||||
{
|
{
|
||||||
|
@ -51,35 +81,48 @@ void TileRender::onRender(const RenderState& rs) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
lastTexId = 0;
|
||||||
glBindTexture(GL_TEXTURE_2D, 0); // unlikely
|
glBindTexture(GL_TEXTURE_2D, 0); // unlikely
|
||||||
|
}
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(pos.x, pos.y, pos.z);
|
glTranslatef(pos.x, pos.y, pos.z);
|
||||||
|
|
||||||
glRotatef(tile.rotation, 0, 0, 1);
|
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);
|
glRotatef(180, 0, 1, 0);
|
||||||
|
|
||||||
// this is only relevant in editor mode and is always 0 otherwise
|
// 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
|
grid = eff->grid;
|
||||||
Vector col = rs.color;
|
alpha *= eff->alpha.x;
|
||||||
glColor4f(col.x, col.y, col.z, rs.alpha*alpha);
|
blend = eff->blend;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float _w2 = float(int(et->w)) * 0.5f;
|
rs.gpu.setBlend(blend);
|
||||||
const float _h2 = float(int(et->h)) * 0.5f;
|
|
||||||
|
// TODO: only need to do this when prev. tile had different alpha
|
||||||
|
glColor4f(rs.color.x, rs.color.y, rs.color.z, alpha);
|
||||||
|
|
||||||
// render texture
|
|
||||||
{
|
|
||||||
const Vector upperLeftTextureCoordinates(et->tu1, et->tv1);
|
const Vector upperLeftTextureCoordinates(et->tu1, et->tv1);
|
||||||
const Vector lowerRightTextureCoordinates(et->tu2, et->tv2);
|
const Vector lowerRightTextureCoordinates(et->tu2, et->tv2);
|
||||||
|
|
||||||
|
if(!grid)
|
||||||
|
{
|
||||||
|
const float _w2 = et->w * 0.5f;
|
||||||
|
const float _h2 = et->h * 0.5f;
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
{
|
{
|
||||||
glTexCoord2f(upperLeftTextureCoordinates.x, 1.0f-upperLeftTextureCoordinates.y);
|
glTexCoord2f(upperLeftTextureCoordinates.x, 1.0f-upperLeftTextureCoordinates.y);
|
||||||
|
@ -96,14 +139,29 @@ void TileRender::onRender(const RenderState& rs) const
|
||||||
}
|
}
|
||||||
glEnd();
|
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)
|
if(renderBorders)
|
||||||
{
|
{
|
||||||
lastTexId = 0;
|
lastTexId = 0;
|
||||||
glBindTexture(GL_TEXTURE_2D, 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);
|
glColor4f(color.x, color.y, color.z, 1.0f);
|
||||||
glPointSize(16);
|
glPointSize(16);
|
||||||
|
@ -129,7 +187,3 @@ void TileRender::onRender(const RenderState& rs) const
|
||||||
RenderObject::lastTextureApplied = lastTexId;
|
RenderObject::lastTextureApplied = lastTexId;
|
||||||
RenderObject::lastTextureRepeat = !!lastTexRepeat;
|
RenderObject::lastTextureRepeat = !!lastTexRepeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileRender::onUpdate(float dt)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ public:
|
||||||
TileRender(const TileStorage& tiles);
|
TileRender(const TileStorage& tiles);
|
||||||
virtual ~TileRender();
|
virtual ~TileRender();
|
||||||
virtual void onRender(const RenderState& rs) const;
|
virtual void onRender(const RenderState& rs) const;
|
||||||
virtual void onUpdate(float dt);
|
|
||||||
|
bool renderBorders;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@ public:
|
||||||
|
|
||||||
// lazily assigned when tex is loaded
|
// lazily assigned when tex is loaded
|
||||||
CountedPtr<Texture> tex;
|
CountedPtr<Texture> tex;
|
||||||
unsigned w,h; // custom size if used, otherwise texture size
|
float w,h; // custom size if used, otherwise texture size
|
||||||
|
|
||||||
// fixed
|
// fixed
|
||||||
float tu1, tu2, tv1, tv2; // texcoords
|
float tu1, tu2, tv1, tv2; // texcoords
|
||||||
|
|
Loading…
Reference in a new issue