mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-02-03 10:04:01 +00:00
Rework + optimize map tile storage & rendering, initial working draft.
class Element is completely gone. (The files are still there but no longer compiled in. Will delete later) Broken still: - support for vertical flip - the editor - culling
This commit is contained in:
parent
e8c405cd9e
commit
bd5b2b3495
31 changed files with 1704 additions and 1422 deletions
|
@ -6721,11 +6721,7 @@ void Avatar::onUpdate(float dt)
|
|||
|
||||
if(!core->particlesPaused && elementEffectMult > 0)
|
||||
{
|
||||
ElementUpdateList& elems = game->elementInteractionList;
|
||||
for (ElementUpdateList::iterator it = elems.begin(); it != elems.end(); ++it)
|
||||
{
|
||||
(*it)->doInteraction(this, elementEffectMult, 16);
|
||||
}
|
||||
dsq->tilemgr.doTileInteraction(position, vel, elementEffectMult, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,6 @@ SET(AQUARIA_SRCS
|
|||
Damage.h
|
||||
DSQ.cpp
|
||||
DSQ.h
|
||||
Element.cpp
|
||||
Element.h
|
||||
Elements.h
|
||||
Emote.cpp
|
||||
Entity.cpp
|
||||
Entity.h
|
||||
|
@ -95,6 +92,8 @@ SET(AQUARIA_SRCS
|
|||
StringBank_gen.h
|
||||
SubtitlePlayer.cpp
|
||||
SubtitlePlayer.h
|
||||
TileMgr.cpp
|
||||
TileMgr.h
|
||||
TileVector.h
|
||||
ToolTip.cpp
|
||||
ToolTip.h
|
||||
|
|
|
@ -3482,7 +3482,7 @@ void Continuity::reset()
|
|||
knowsSong.clear();
|
||||
loadSongBank();
|
||||
loadEatBank();
|
||||
dsq->loadElementEffects();
|
||||
dsq->loadTileEffects();
|
||||
form = FORM_NORMAL;
|
||||
costume = "";
|
||||
dsq->emote.load("data/naijaemote.txt");
|
||||
|
|
208
Aquaria/DSQ.cpp
208
Aquaria/DSQ.cpp
|
@ -209,9 +209,6 @@ DSQ::DSQ(const std::string& fileSystem, const std::string& extraDataDir)
|
|||
avgFPS.resize(user.video.fpsSmoothing);
|
||||
|
||||
cursor = cursorGlow = 0;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
firstElementOnLayer[i] = 0;
|
||||
}
|
||||
|
||||
DSQ::~DSQ()
|
||||
|
@ -267,82 +264,6 @@ void DSQ::newGame()
|
|||
game->transitionToScene("NaijaCave");
|
||||
}
|
||||
|
||||
void DSQ::loadElementEffects()
|
||||
{
|
||||
bool found = false;
|
||||
std::string fn;
|
||||
if (mod.isActive())
|
||||
{
|
||||
fn = mod.getPath() + "elementeffects.txt";
|
||||
if(exists(fn))
|
||||
found = true;
|
||||
}
|
||||
if(!found)
|
||||
fn = "data/elementeffects.txt";
|
||||
|
||||
InStream inFile(fn.c_str());
|
||||
elementEffects.clear();
|
||||
std::string line;
|
||||
while (std::getline(inFile, line))
|
||||
{
|
||||
debugLog("Line: " + line);
|
||||
std::istringstream is(line);
|
||||
ElementEffect e;
|
||||
int efxType = EFX_NONE;
|
||||
int idx;
|
||||
std::string type;
|
||||
is >> idx >> type;
|
||||
if (type == "EFX_SEGS")
|
||||
{
|
||||
efxType = EFX_SEGS;
|
||||
is >> e.segsx >> e.segsy >> e.segs_dgox >> e.segs_dgoy >> e.segs_dgmx >> e.segs_dgmy >> e.segs_dgtm >> e.segs_dgo;
|
||||
}
|
||||
else if (type == "EFX_WAVY")
|
||||
{
|
||||
debugLog("loading wavy");
|
||||
efxType = EFX_WAVY;
|
||||
is >> e.segsy >> e.wavy_radius >> e.wavy_flip;
|
||||
|
||||
}
|
||||
else if (type == "EFX_ALPHA")
|
||||
{
|
||||
efxType = EFX_ALPHA;
|
||||
float to_x, time, loop, pingPong, ease;
|
||||
int blend;
|
||||
is >> blend >> e.alpha.x >> to_x >> time >> loop >> pingPong >> ease;
|
||||
e.alpha.interpolateTo(to_x, time, loop, pingPong, ease);
|
||||
e.blendType = blend < _BLEND_MAXSIZE ? (BlendType)blend : BLEND_DISABLED;
|
||||
}
|
||||
e.type = efxType;
|
||||
elementEffects.push_back(e);
|
||||
}
|
||||
inFile.close();
|
||||
}
|
||||
|
||||
ElementEffect DSQ::getElementEffectByIndex(size_t e)
|
||||
{
|
||||
if (e < elementEffects.size())
|
||||
{
|
||||
return elementEffects[e];
|
||||
}
|
||||
|
||||
ElementEffect empty;
|
||||
empty.type = EFX_NONE;
|
||||
empty.alpha = 0;
|
||||
empty.blendType = BLEND_DEFAULT;
|
||||
empty.color = 0;
|
||||
empty.segsx = empty.segsy = 0;
|
||||
empty.segs_dgmx = empty.segs_dgmy = 0;
|
||||
empty.segs_dgo = 0;
|
||||
empty.segs_dgox = empty.segs_dgoy = 0;
|
||||
empty.segs_dgtm = 0;
|
||||
empty.wavy_flip = false;
|
||||
empty.wavy_max = empty.wavy_min = 0;
|
||||
empty.wavy_radius = 0;
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
void DSQ::centerMessage(const std::string &text, float y, int type)
|
||||
{
|
||||
Vector pos(400,y);
|
||||
|
@ -773,7 +694,7 @@ void DSQ::init()
|
|||
PSIZEOF(RenderObject);
|
||||
PSIZEOF(Quad);
|
||||
PSIZEOF(CollideQuad);
|
||||
PSIZEOF(Element);
|
||||
PSIZEOF(TileData);
|
||||
PSIZEOF(Shot);
|
||||
PSIZEOF(Bone);
|
||||
PSIZEOF(PauseQuad);
|
||||
|
@ -3553,6 +3474,74 @@ bool DSQ::canOpenEditor() const
|
|||
return isDeveloperKeys() || (mod.isActive() && !mod.isEditorBlocked());
|
||||
}
|
||||
|
||||
void DSQ::loadTileEffects()
|
||||
{
|
||||
bool found = false;
|
||||
std::string fn;
|
||||
if (mod.isActive())
|
||||
{
|
||||
fn = mod.getPath() + "elementeffects.txt";
|
||||
if(exists(fn))
|
||||
found = true;
|
||||
}
|
||||
if(!found)
|
||||
fn = "data/elementeffects.txt";
|
||||
|
||||
return tilemgr.loadTileEffects(fn.c_str());
|
||||
}
|
||||
|
||||
bool DSQ::loadTileset(std::string pack, const unsigned char *usedIdx, size_t usedIdxLen)
|
||||
{
|
||||
stringToLower(pack);
|
||||
|
||||
std::string fn;
|
||||
if (mod.isActive())
|
||||
fn = mod.getPath() + "tilesets/" + pack + ".txt";
|
||||
else
|
||||
fn = "data/tilesets/" + pack + ".txt";
|
||||
|
||||
if(!tilemgr.tileset.loadFile(fn.c_str(), usedIdx, usedIdxLen))
|
||||
{
|
||||
errorLog ("Could not load tileset [" + fn + "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Aquarian alphabet letters
|
||||
if(const CountedPtr<Texture> aqtex = getTexture("aquarian"))
|
||||
{
|
||||
const float cell = 64.0f/512.0f;
|
||||
for (int i = 0; i < 27; i++)
|
||||
{
|
||||
ElementTemplate t;
|
||||
t.idx = 1024+i;
|
||||
t.tex = aqtex;
|
||||
t.loaded = true;
|
||||
int x = i,y=0;
|
||||
while (x >= 6)
|
||||
{
|
||||
x -= 6;
|
||||
y++;
|
||||
}
|
||||
|
||||
t.tu1 = x*cell;
|
||||
t.tv1 = y*cell;
|
||||
t.tu2 = t.tu1 + cell;
|
||||
t.tv2 = t.tv1 + cell;
|
||||
|
||||
t.tv2 = 1 - t.tv2;
|
||||
t.tv1 = 1 - t.tv1;
|
||||
std::swap(t.tv1,t.tv2);
|
||||
|
||||
t.w = 512*cell;
|
||||
t.h = 512*cell;
|
||||
|
||||
tilemgr.tileset.elementTemplates.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DSQ::isQuitFlag()
|
||||
{
|
||||
return watchQuitFlag;
|
||||
|
@ -3751,6 +3740,8 @@ void DSQ::onUpdate(float dt)
|
|||
// This queries pressed keys and updates ActionMapper
|
||||
Core::onUpdate(dt);
|
||||
|
||||
tilemgr.update(dt);
|
||||
|
||||
|
||||
mod.update(dt);
|
||||
|
||||
|
@ -3912,7 +3903,8 @@ void DSQ::onUpdate(float dt)
|
|||
os << sound->getVolumeString() << std::endl;
|
||||
os << "runInBG: " << settings.runInBackground << " nested: " << getNestedMains() << std::endl;
|
||||
os << globalResolutionScale.x << ", " << globalResolutionScale.y << std::endl;
|
||||
os << "elemu: " << game->elementUpdateList.size() << " elemi: " << game->elementInteractionList.size() << std::endl;
|
||||
TileStorage::Sizes tsz = tilemgr.getStats();
|
||||
os << "Tiles: " << tsz.tiles << ", u: " << tsz.update << ", i: " << tsz.collide << std::endl;
|
||||
os << "Lua mem: " << scriptInterface.gcGetStats() << " KB" << std::endl;
|
||||
|
||||
cmDebug->position = Vector(20 - virtualOffX,50);
|
||||
|
@ -4093,20 +4085,6 @@ void DSQ::playVisualEffect(int vfx, Vector position, Entity *target)
|
|||
}
|
||||
}
|
||||
|
||||
void DSQ::addElement(Element *e)
|
||||
{
|
||||
elements.push_back(e);
|
||||
if (e->bgLayer >= 0 && e->bgLayer < 16)
|
||||
{
|
||||
e->bgLayerNext = firstElementOnLayer[e->bgLayer];
|
||||
firstElementOnLayer[e->bgLayer] = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
e->bgLayerNext = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DSQ::modifyDt(float &dt)
|
||||
{
|
||||
if (isDeveloperKeys())
|
||||
|
@ -4149,46 +4127,6 @@ void DSQ::modifyDt(float &dt)
|
|||
dt *= gameSpeed.x;
|
||||
}
|
||||
|
||||
void DSQ::removeElement(Element *element)
|
||||
{
|
||||
for (size_t i = 0; i < elements.size(); i++)
|
||||
{
|
||||
if (elements[i] == element)
|
||||
{
|
||||
removeElement(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// only happens in editor, no need to optimize
|
||||
void DSQ::removeElement(size_t idx)
|
||||
{
|
||||
ElementContainer copy = elements;
|
||||
clearElements();
|
||||
size_t i = 0;
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
addElement(copy[i]);
|
||||
}
|
||||
for (i = idx+1; i < copy.size(); i++)
|
||||
{
|
||||
addElement(copy[i]);
|
||||
}
|
||||
copy.clear();
|
||||
|
||||
if (!game->elementUpdateList.empty())
|
||||
game->rebuildElementUpdateList();
|
||||
}
|
||||
|
||||
void DSQ::clearElements()
|
||||
{
|
||||
elements.clear();
|
||||
for (int i = 0; i < 16; i++)
|
||||
firstElementOnLayer[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
void DSQ::addEntity(Entity *entity)
|
||||
{
|
||||
size_t i;
|
||||
|
|
|
@ -22,12 +22,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define DSQ_H
|
||||
|
||||
#include "AquariaCompileConfig.h"
|
||||
#include "../BBGE/Core.h"
|
||||
#include "../BBGE/Quad.h"
|
||||
#include "Element.h"
|
||||
#include "../BBGE/BitmapFont.h"
|
||||
#include "../BBGE/ScreenTransition.h"
|
||||
#include "../BBGE/Precacher.h"
|
||||
#include "Core.h"
|
||||
#include "Quad.h"
|
||||
#include "TileMgr.h"
|
||||
#include "BitmapFont.h"
|
||||
#include "ScreenTransition.h"
|
||||
#include "Precacher.h"
|
||||
#include "ScriptInterface.h"
|
||||
#include "GameEnums.h"
|
||||
#include "Mod.h"
|
||||
|
@ -186,21 +186,6 @@ public:
|
|||
|
||||
int getEntityLayerToLayer(int layer);
|
||||
|
||||
void addElement(Element *e);
|
||||
size_t getNumElements() const {return elements.size();}
|
||||
Element *getElement(size_t idx) const {return elements[idx];}
|
||||
Element *getFirstElementOnLayer(size_t layer) const {return layer>15 ? 0 : firstElementOnLayer[layer];}
|
||||
void clearElements();
|
||||
// Used only by scene editor:
|
||||
void removeElement(size_t idx);
|
||||
void removeElement(Element *e);
|
||||
ElementContainer getElementsCopy() const {return elements;}
|
||||
|
||||
protected: // These should never be accessed from outside (use the functions above).
|
||||
ElementContainer elements;
|
||||
Element *firstElementOnLayer[16];
|
||||
public:
|
||||
|
||||
void addEntity(Entity *entity);
|
||||
void removeEntity(Entity *e);
|
||||
void clearEntities();
|
||||
|
@ -267,10 +252,9 @@ public:
|
|||
bool isDeveloperKeys() const;
|
||||
bool canOpenEditor() const;
|
||||
|
||||
void loadElementEffects();
|
||||
ElementEffect getElementEffectByIndex(size_t e);
|
||||
typedef std::vector<ElementEffect> ElementEffects;
|
||||
ElementEffects elementEffects;
|
||||
void loadTileEffects();
|
||||
bool loadTileset(std::string pack, const unsigned char *usedIdx, size_t usedIdxLen);
|
||||
TileMgr tilemgr;
|
||||
|
||||
bool playedVoice(const std::string &file);
|
||||
|
||||
|
|
|
@ -34,22 +34,6 @@ enum EFXType
|
|||
EFX_MAX
|
||||
};
|
||||
|
||||
enum ElementFlag
|
||||
{
|
||||
EF_NONE = 0,
|
||||
EF_SOLID = 1,
|
||||
EF_MOVABLE = 2,
|
||||
EF_HURT = 3,
|
||||
EF_SOLID2 = 4,
|
||||
EF_SOLID3 = 5,
|
||||
EF_MAX = 6
|
||||
/*
|
||||
EF_GLASS = 0x00000020,
|
||||
EF_FORCEBREAK = 0x00000100,
|
||||
EF_HURT = 0x00000200
|
||||
*/
|
||||
};
|
||||
|
||||
struct ElementEffectData
|
||||
{
|
||||
ElementEffectData();
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007, 2010 - Bit-Blot
|
||||
|
||||
This file is part of Aquaria.
|
||||
|
||||
Aquaria is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __elements__
|
||||
#define __elements__
|
||||
|
||||
#include "Element.h"
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -330,7 +330,7 @@ void Entity::setEntityProperty(EntityProperty ep, bool value)
|
|||
entityProperties[ep] = value;
|
||||
}
|
||||
|
||||
bool Entity::isEntityProperty(EntityProperty ep)
|
||||
bool Entity::isEntityProperty(EntityProperty ep) const
|
||||
{
|
||||
return entityProperties[ep];
|
||||
}
|
||||
|
@ -2012,7 +2012,7 @@ void Entity::onEnterState(int action)
|
|||
}
|
||||
}
|
||||
|
||||
bool Entity::isPullable()
|
||||
bool Entity::isPullable() const
|
||||
{
|
||||
return ((isEntityProperty(EP_MOVABLE)) || (frozenTimer > 0));
|
||||
}
|
||||
|
@ -2106,11 +2106,14 @@ void Entity::setInvincible(bool inv)
|
|||
invincible = inv;
|
||||
}
|
||||
|
||||
bool Entity::isInDarkness()
|
||||
bool Entity::isInDarkness() const
|
||||
{
|
||||
for (Element *e = dsq->getFirstElementOnLayer(12); e; e = e->bgLayerNext)
|
||||
const TileStorage& ts = dsq->tilemgr.tilestore[12];
|
||||
const size_t n = ts.tiles.size();
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
{
|
||||
if (e->isCoordinateInside(position))
|
||||
const TileData& t = ts.tiles[i];
|
||||
if(t.isVisible() && t.isCoordinateInside(position.x, position.y))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -117,9 +117,9 @@ public:
|
|||
virtual void lightFlare(){}
|
||||
virtual void sporesDropped(const Vector &pos, int type) {}
|
||||
|
||||
bool isPullable();
|
||||
bool isPullable() const;
|
||||
|
||||
bool isInDarkness();
|
||||
bool isInDarkness() const;
|
||||
|
||||
bool isPresent() const
|
||||
{
|
||||
|
@ -224,7 +224,7 @@ public:
|
|||
float damageTime;
|
||||
|
||||
void setEntityProperty(EntityProperty ep, bool value=true);
|
||||
bool isEntityProperty(EntityProperty ep);
|
||||
bool isEntityProperty(EntityProperty ep) const;
|
||||
virtual void song(SongType songType){}
|
||||
bool updateCurrents(float dt);
|
||||
void updateVel2(float dt, bool override=false);
|
||||
|
|
460
Aquaria/Game.cpp
460
Aquaria/Game.cpp
|
@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "../BBGE/LensFlare.h"
|
||||
#include "../BBGE/RoundedRect.h"
|
||||
#include "../BBGE/SimpleIStringStream.h"
|
||||
#include "TileRender.h"
|
||||
|
||||
#include "ttvfs_stdio.h"
|
||||
#include "ReadXML.h"
|
||||
|
@ -47,6 +48,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "Beam.h"
|
||||
#include "Hair.h"
|
||||
|
||||
|
||||
#ifdef BBGE_USE_GLM
|
||||
#include "glm/glm.hpp"
|
||||
#include "glm/gtx/transform.hpp"
|
||||
|
@ -316,63 +318,6 @@ void Game::transitionToScene(std::string scene)
|
|||
core->enqueueJumpState("Game", false);
|
||||
}
|
||||
|
||||
ElementTemplate *Game::getElementTemplateByIdx(size_t idx)
|
||||
{
|
||||
return tileset.getByIdx(idx);
|
||||
}
|
||||
|
||||
Element* Game::createElement(size_t idx, Vector position, size_t bgLayer, RenderObject *copy, ElementTemplate *et)
|
||||
{
|
||||
if (idx == -1) return 0;
|
||||
|
||||
if (!et)
|
||||
et = this->getElementTemplateByIdx(idx);
|
||||
|
||||
Element *element = new Element();
|
||||
if (et)
|
||||
{
|
||||
element->setTexturePointer(et->getTexture());
|
||||
}
|
||||
|
||||
element->position = position;
|
||||
element->position.z = -0.05f;
|
||||
element->templateIdx = idx;
|
||||
|
||||
element->bgLayer = bgLayer;
|
||||
|
||||
if (et)
|
||||
{
|
||||
if (et->w != -1 && et->h != -1)
|
||||
element->setWidthHeight(et->w, et->h);
|
||||
}
|
||||
if (et)
|
||||
{
|
||||
if (et->tu1 != 0 || et->tu2 != 0 || et->tv1 != 0 || et->tv2 != 0)
|
||||
{
|
||||
element->upperLeftTextureCoordinates = Vector(et->tu1, et->tv1);
|
||||
element->lowerRightTextureCoordinates = Vector(et->tu2, et->tv2);
|
||||
}
|
||||
}
|
||||
if (copy)
|
||||
{
|
||||
element->scale = copy->scale;
|
||||
if (copy->isfh())
|
||||
element->flipHorizontal();
|
||||
if (copy->isfv())
|
||||
element->flipVertical();
|
||||
element->rotation = copy->rotation;
|
||||
Quad *q = dynamic_cast<Quad*>(copy);
|
||||
if (q)
|
||||
{
|
||||
element->repeatTextureToFill(q->isRepeatingTextureToFill());
|
||||
}
|
||||
}
|
||||
addRenderObject(element, LR_ELEMENTS1+bgLayer);
|
||||
dsq->addElement(element);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
void Game::addObsRow(unsigned tx, unsigned ty, unsigned len)
|
||||
{
|
||||
ObsRow obsRow(tx, ty, len);
|
||||
|
@ -386,12 +331,27 @@ void Game::clearObsRows()
|
|||
|
||||
void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
|
||||
{
|
||||
if (q->texture)
|
||||
GridFiller f;
|
||||
f.obs = obsType;
|
||||
f.trim = trim;
|
||||
f.fh = q->isfh();
|
||||
f.position = q->position;
|
||||
f.rotation = q->rotation.z;
|
||||
f.scale = q->scale;
|
||||
f.texture = q->texture.content();
|
||||
f.width = q->width;
|
||||
f.height = q->height;
|
||||
fillGrid(f);
|
||||
}
|
||||
|
||||
void Game::fillGrid(const GridFiller& gf)
|
||||
{
|
||||
if (gf.texture)
|
||||
{
|
||||
std::vector<TileVector> obs;
|
||||
TileVector tpos(q->position);
|
||||
int widthscale = q->getWidth()*q->scale.x;
|
||||
int heightscale = q->getHeight()*q->scale.y;
|
||||
TileVector tpos(gf.position);
|
||||
int widthscale = int(gf.width*gf.scale.x);
|
||||
int heightscale = int(gf.height*gf.scale.y);
|
||||
int w2 = widthscale/2;
|
||||
int h2 = heightscale/2;
|
||||
w2/=TILE_SIZE;
|
||||
|
@ -401,15 +361,15 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
|
|||
|
||||
int w = 0, h = 0;
|
||||
size_t size = 0;
|
||||
unsigned char *data = q->texture->getBufferAndSize(&w, &h, &size);
|
||||
unsigned char *data = gf.texture->getBufferAndSize(&w, &h, &size);
|
||||
if (!data)
|
||||
{
|
||||
debugLog("Failed to get buffer in Game::fillGridFromQuad()");
|
||||
return;
|
||||
}
|
||||
|
||||
int szx = TILE_SIZE/q->scale.x;
|
||||
int szy = TILE_SIZE/q->scale.y;
|
||||
int szx = TILE_SIZE/gf.scale.x;
|
||||
int szy = TILE_SIZE/gf.scale.y;
|
||||
if (szx < 1) szx = 1;
|
||||
if (szy < 1) szy = 1;
|
||||
|
||||
|
@ -424,8 +384,8 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
|
|||
{
|
||||
// starting position =
|
||||
// tx / scale.x
|
||||
unsigned int px = int(tx/q->scale.x) + x;
|
||||
unsigned int py = int(ty/q->scale.y) + y;
|
||||
unsigned int px = int(tx/gf.scale.x) + x;
|
||||
unsigned int py = int(ty/gf.scale.y) + y;
|
||||
if (px < unsigned(w) && py < unsigned(h))
|
||||
{
|
||||
unsigned int p = (py*unsigned(w)*4) + (px*4) + 3; // position of alpha component
|
||||
|
@ -453,7 +413,7 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
|
|||
|
||||
free(data);
|
||||
|
||||
if (trim)
|
||||
if (gf.trim)
|
||||
{
|
||||
std::vector<TileVector> obsCopy;
|
||||
obsCopy.swap(obs);
|
||||
|
@ -492,8 +452,8 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
|
|||
const float h2f = float(h2);
|
||||
for (size_t i = 0; i < obs.size(); i++)
|
||||
{
|
||||
glm::mat4 transformMatrix = glm::rotate(q->rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
if(q->isfh())
|
||||
glm::mat4 transformMatrix = glm::rotate(gf.rotation, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
if(gf.fh)
|
||||
transformMatrix *= glm::rotate(180.0f, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
|
||||
transformMatrix *= glm::translate(float(obs[i].x)-w2f, float(obs[i].y)-h2f, 0.0f);
|
||||
|
@ -502,7 +462,7 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
|
|||
|
||||
TileVector tvec(tpos.x+w2+x, tpos.y+h2+y);
|
||||
if (!isObstructed(tvec))
|
||||
addGrid(tvec, obsType);
|
||||
addGrid(tvec, gf.obs);
|
||||
}
|
||||
#else
|
||||
glPushMatrix();
|
||||
|
@ -511,8 +471,8 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim)
|
|||
{
|
||||
glLoadIdentity();
|
||||
|
||||
glRotatef(q->rotation.z, 0, 0, 1);
|
||||
if (q->isfh())
|
||||
glRotatef(gf.rotation, 0, 0, 1);
|
||||
if (gf.fh)
|
||||
{
|
||||
glRotatef(180, 0, 1, 0);
|
||||
}
|
||||
|
@ -585,16 +545,21 @@ void Game::reconstructGrid(bool force)
|
|||
if (!force && isSceneEditorActive()) return;
|
||||
|
||||
clearGrid();
|
||||
for (size_t i = 0; i < dsq->getNumElements(); i++)
|
||||
std::vector<GridFiller> fillers;
|
||||
dsq->tilemgr.exportGridFillers(fillers);
|
||||
|
||||
std::ostringstream os;
|
||||
os << "ReconstructGrid using " << fillers.size() << " tiles";
|
||||
debugLog(os.str());
|
||||
|
||||
for (size_t i = 0; i < fillers.size(); i++)
|
||||
{
|
||||
Element *e = dsq->getElement(i);
|
||||
e->fillGrid();
|
||||
fillGrid(fillers[i]);
|
||||
}
|
||||
|
||||
ObsRow *o;
|
||||
for (size_t i = 0; i < obsRows.size(); i++)
|
||||
{
|
||||
o = &obsRows[i];
|
||||
const ObsRow *o = &obsRows[i];
|
||||
for (unsigned tx = 0; tx < o->len; tx++)
|
||||
{
|
||||
setGrid(TileVector(o->tx + tx, o->ty), OT_BLACK);
|
||||
|
@ -1612,109 +1577,107 @@ bool Game::loadSceneXML(std::string scene)
|
|||
saveFile->InsertEndChild(newSF);
|
||||
}
|
||||
|
||||
struct ElementDef
|
||||
{
|
||||
ElementDef(int lr)
|
||||
: layer(lr), idx(0), x(0), y(0), rot(0), fh(0), fv(0), flags(0), efxIdx(-1), repeat(0)
|
||||
, tag(0), sx(1), sy(1), rsx(1), rsy(1)
|
||||
{}
|
||||
|
||||
int layer, idx, x, y, rot, fh, fv, flags, efxIdx, repeat, tag;
|
||||
float sx, sy, rsx, rsy;
|
||||
};
|
||||
std::vector<ElementDef> elemsDefs;
|
||||
elemsDefs.reserve(256);
|
||||
std::vector<TileDef> tilesDefs;
|
||||
tilesDefs.reserve(256);
|
||||
|
||||
XMLElement *simpleElements = doc.FirstChildElement("SE");
|
||||
while (simpleElements)
|
||||
{
|
||||
const size_t defsBeginIdx = elemsDefs.size();
|
||||
const int layer = atoi(simpleElements->Attribute("l"));
|
||||
const size_t defsBeginIdx = tilesDefs.size();
|
||||
|
||||
if (const char *attr = simpleElements->Attribute("d"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(4); // legacy crap
|
||||
TileDef d(4); // legacy crap
|
||||
while (is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot;
|
||||
elemsDefs.push_back(d);
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
const int layer = atoi(simpleElements->Attribute("l"));
|
||||
if(layer < 0 || layer >= MAX_TILE_LAYERS)
|
||||
{
|
||||
errorLog("Save file specifies invalid layer in SE tag, ignoring (if you save the map now, you may lose data!)");
|
||||
goto next_SE;
|
||||
}
|
||||
|
||||
if (const char *attr = simpleElements->Attribute("e"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(layer);
|
||||
TileDef d(layer);
|
||||
while(is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot;
|
||||
elemsDefs.push_back(d);
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
if (const char *attr = simpleElements->Attribute("f"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(layer);
|
||||
TileDef d(layer);
|
||||
while(is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot >> d.sx;
|
||||
d.sy = d.sx;
|
||||
elemsDefs.push_back(d);
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
if (const char *attr = simpleElements->Attribute("g"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(layer);
|
||||
TileDef d(layer);
|
||||
while(is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.fh >> d.fv;
|
||||
d.sy = d.sx;
|
||||
elemsDefs.push_back(d);
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
if (const char *attr = simpleElements->Attribute("h"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(layer);
|
||||
TileDef d(layer);
|
||||
while(is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.fh >> d.fv >> d.flags;
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.fh >> d.fv >> d.ef;
|
||||
d.sy = d.sx;
|
||||
elemsDefs.push_back(d);
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
if (const char *attr = simpleElements->Attribute("i"))
|
||||
{
|
||||
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(layer);
|
||||
TileDef d(layer);
|
||||
while(is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.fh >> d.fv >> d.flags >> d.efxIdx;
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.fh >> d.fv >> d.ef >> d.efxIdx;
|
||||
d.sy = d.sx;
|
||||
elemsDefs.push_back(d);
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
if (const char *attr = simpleElements->Attribute("j"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(layer);
|
||||
TileDef d(layer);
|
||||
while(is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.fh >> d.fv >> d.flags >> d.efxIdx >> d.repeat;
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.fh >> d.fv >> d.ef >> d.efxIdx >> d.repeat;
|
||||
d.sy = d.sx;
|
||||
elemsDefs.push_back(d);
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
if (const char *attr = simpleElements->Attribute("k"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
ElementDef d(layer);
|
||||
TileDef d(layer);
|
||||
while(is >> d.idx)
|
||||
{
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.sy >> d.fh >> d.fv >> d.flags >> d.efxIdx >> d.repeat;
|
||||
elemsDefs.push_back(d);
|
||||
is >> d.x >> d.y >> d.rot >> d.sx >> d.sy >> d.fh >> d.fv >> d.ef >> d.efxIdx >> d.repeat;
|
||||
tilesDefs.push_back(d);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1723,9 +1686,9 @@ bool Game::loadSceneXML(std::string scene)
|
|||
if (const char *attr = simpleElements->Attribute("repeatScale"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
for(size_t i = defsBeginIdx; i < elemsDefs.size(); ++i)
|
||||
for(size_t i = defsBeginIdx; i < tilesDefs.size(); ++i)
|
||||
{
|
||||
ElementDef& d = elemsDefs[i];
|
||||
TileDef& d = tilesDefs[i];
|
||||
if(d.repeat)
|
||||
{
|
||||
if(!(is >> d.rsx >> d.rsy))
|
||||
|
@ -1736,76 +1699,64 @@ bool Game::loadSceneXML(std::string scene)
|
|||
if (const char *attr = simpleElements->Attribute("tag"))
|
||||
{
|
||||
SimpleIStringStream is(attr, SimpleIStringStream::REUSE);
|
||||
for(size_t i = defsBeginIdx; i < elemsDefs.size(); ++i)
|
||||
for(size_t i = defsBeginIdx; i < tilesDefs.size(); ++i)
|
||||
{
|
||||
ElementDef& d = elemsDefs[i];
|
||||
TileDef& d = tilesDefs[i];
|
||||
if(!(is >> d.tag))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
next_SE:
|
||||
simpleElements = simpleElements->NextSiblingElement("SE");
|
||||
}
|
||||
|
||||
dsq->tilemgr.clearTiles();
|
||||
|
||||
if(fullTilesetReload)
|
||||
{
|
||||
fullTilesetReload = false;
|
||||
tileset.clear();
|
||||
dsq->tilemgr.tileset.clear();
|
||||
// used by SceneEditor
|
||||
// no elements exist right now -> textures will be cleared and reloaded
|
||||
// no tiles exist right now -> textures will be cleared and reloaded
|
||||
dsq->texmgr.clearUnused();
|
||||
}
|
||||
|
||||
// figure out which textures in the tileset are used and preload those that are actually used
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Scene has " << elemsDefs.size() << " elements";
|
||||
os << "Scene has " << tilesDefs.size() << " static tiles";
|
||||
debugLog(os.str());
|
||||
|
||||
unsigned char usedIdx[1024] = {0};
|
||||
for(size_t i = 0; i < elemsDefs.size(); ++i)
|
||||
for(size_t i = 0; i < tilesDefs.size(); ++i)
|
||||
{
|
||||
unsigned idx = elemsDefs[i].idx;
|
||||
TileDef& d = tilesDefs[i];
|
||||
unsigned idx = d.idx;
|
||||
if(idx < Countof(usedIdx))
|
||||
usedIdx[idx] = 1;
|
||||
|
||||
|
||||
// HACK: due to a renderer bug in old versions, we need to fix the rotation
|
||||
// for horizontally flipped tiles on parallax layers to make maps look correct.
|
||||
// See commit 4b52730be253dbfce9bea6f604c772a87da104e3
|
||||
// bgLayer IDs (which are NOT LR_* constants):
|
||||
// 0..8 are normal layers (keys 1-9)
|
||||
// 9,10,11; 13,14,15 are parallax ones, 15 is closest, 9 is furthest away
|
||||
// 12 is the dark layer
|
||||
if(d.fh && d.layer >= 9 && d.layer <= 15 && d.layer != 12
|
||||
&& dsq->renderObjectLayers[LR_ELEMENTS1 + d.layer].followCamera != 0)
|
||||
{
|
||||
d.rot = -d.rot;
|
||||
}
|
||||
}
|
||||
|
||||
loadElementTemplates(tilesetToLoad, &usedIdx[0], Countof(usedIdx));
|
||||
dsq->loadTileset(tilesetToLoad, &usedIdx[0], Countof(usedIdx));
|
||||
}
|
||||
|
||||
// Now that all SE tags have been processed, spawn them
|
||||
for(size_t i = 0; i < elemsDefs.size(); ++i)
|
||||
{
|
||||
const ElementDef& d = elemsDefs[i];
|
||||
|
||||
Element *e = createElement(d.idx, Vector(d.x,d.y), d.layer);
|
||||
e->elementFlag = (ElementFlag)d.flags;
|
||||
if (d.fh)
|
||||
e->flipHorizontal();
|
||||
if (d.fv)
|
||||
e->flipVertical();
|
||||
|
||||
e->scale = Vector(d.sx, d.sy);
|
||||
e->rotation.z = d.rot;
|
||||
e->repeatToFillScale.x = d.rsx;
|
||||
e->repeatToFillScale.y = d.rsy;
|
||||
e->setElementEffectByIndex(d.efxIdx);
|
||||
if (d.repeat)
|
||||
e->repeatTextureToFill(true); // also applies repeatToFillScale
|
||||
e->setTag(d.tag);
|
||||
|
||||
// HACK: due to a renderer bug in old versions, we need to fix the rotation
|
||||
// for horizontally flipped tiles on parallax layers to make maps look correct.
|
||||
// See commit 4b52730be253dbfce9bea6f604c772a87da104e3
|
||||
// bgLayer IDs (which are NOT LR_* constants):
|
||||
// 0..8 are normal layers (keys 1-9)
|
||||
// 9,10,11; 13,14,15 are parallax ones, 15 is closest, 9 is furthest away
|
||||
// 12 is the dark layer
|
||||
if(d.fh && d.layer >= 9 && d.layer <= 15 && d.layer != 12
|
||||
&& dsq->renderObjectLayers[e->layer].followCamera != 0)
|
||||
{
|
||||
e->rotation.z = -e->rotation.z;
|
||||
}
|
||||
}
|
||||
if(!tilesDefs.empty())
|
||||
dsq->tilemgr.createTiles(&tilesDefs[0], tilesDefs.size());
|
||||
|
||||
this->reconstructGrid(true);
|
||||
|
||||
|
@ -1835,7 +1786,6 @@ bool Game::loadSceneXML(std::string scene)
|
|||
spawnEntities(&toSpawn[0], toSpawn.size());
|
||||
|
||||
this->reconstructGrid(true);
|
||||
rebuildElementUpdateList();
|
||||
|
||||
findMaxCameraValues();
|
||||
|
||||
|
@ -2058,49 +2008,71 @@ bool Game::saveScene(std::string scene)
|
|||
saveFile.InsertEndChild(pathXml);
|
||||
}
|
||||
|
||||
std::ostringstream simpleElements[LR_MAX];
|
||||
std::ostringstream simpleElements_repeatScale[LR_MAX];
|
||||
std::ostringstream simpleElements_tag[LR_MAX];
|
||||
unsigned tagBitsUsed[LR_MAX] = { 0 };
|
||||
|
||||
for (size_t i = 0; i < dsq->getNumElements(); i++)
|
||||
for(size_t lr = 0; lr < MAX_TILE_LAYERS; ++lr)
|
||||
{
|
||||
Element *e = dsq->getElement(i);
|
||||
const TileStorage& ts = dsq->tilemgr.tilestore[lr];
|
||||
std::ostringstream simpleElements;
|
||||
std::ostringstream simpleElements_repeatScale;
|
||||
std::ostringstream simpleElements_tag;
|
||||
unsigned tagBitsUsed = 0;
|
||||
|
||||
float rot = e->rotation.z;
|
||||
const size_t N = ts.tiles.size();
|
||||
const bool isParallax = lr >= 9 && lr <= 15 && lr != 12
|
||||
&& dsq->renderObjectLayers[LR_ELEMENTS1 + lr].followCamera != 0;
|
||||
|
||||
// HACK: Intentionally store the wrong rotation for parallax layers,
|
||||
// to make loading a scene and the same hack there result in the correct value.
|
||||
// This is to ensure compatibility with older game versions that have the renderer bug.
|
||||
// See commit 4b52730be253dbfce9bea6f604c772a87da104e3
|
||||
if(e->isfh() && e->bgLayer >= 9 && e->bgLayer <= 15 && e->bgLayer != 12
|
||||
&& dsq->renderObjectLayers[e->layer].followCamera != 0)
|
||||
for (size_t i = 0; i < N; i++)
|
||||
{
|
||||
rot = -rot;
|
||||
TileDef d(lr, ts.tiles[i]);
|
||||
|
||||
// HACK: Intentionally store the wrong rotation for parallax layers,
|
||||
// to make loading a scene and the same hack there result in the correct value.
|
||||
// This is to ensure compatibility with older game versions that have the renderer bug.
|
||||
// See commit 4b52730be253dbfce9bea6f604c772a87da104e3
|
||||
if(isParallax && d.fh)
|
||||
d.rot = -d.rot;
|
||||
|
||||
simpleElements
|
||||
<< d.idx << " "
|
||||
<< int(d.x) << " "
|
||||
<< int(d.y) << " "
|
||||
<< int(d.rot) << " "
|
||||
<< d.sx << " "
|
||||
<< d.sy << " "
|
||||
<< int(d.fh) << " "
|
||||
<< int(d.fv) << " "
|
||||
<< d.ef << " "
|
||||
<< d.efxIdx << " "
|
||||
<< d.repeat << " ";
|
||||
|
||||
if(d.repeat)
|
||||
{
|
||||
simpleElements_repeatScale
|
||||
<< d.rsx << " "
|
||||
<< d.rsy << " ";
|
||||
}
|
||||
|
||||
simpleElements_tag << d.tag << " ";
|
||||
tagBitsUsed |= d.tag;
|
||||
}
|
||||
|
||||
std::ostringstream& SE = simpleElements[e->bgLayer];
|
||||
SE << e->templateIdx << " "
|
||||
<< int(e->position.x) << " "
|
||||
<< int(e->position.y) << " "
|
||||
<< int(rot) << " "
|
||||
<< e->scale.x << " "
|
||||
<< e->scale.y << " "
|
||||
<< int(e->isfh()) << " "
|
||||
<< int(e->isfv()) << " "
|
||||
<< e->elementFlag << " "
|
||||
<< e->getElementEffectIndex()<< " "
|
||||
<< e->isRepeatingTextureToFill() << " ";
|
||||
|
||||
if(e->isRepeatingTextureToFill())
|
||||
std::string s = simpleElements.str();
|
||||
if (!s.empty())
|
||||
{
|
||||
std::ostringstream& SE_rs = simpleElements_repeatScale[e->bgLayer];
|
||||
SE_rs << e->repeatToFillScale.x << " "
|
||||
<< e->repeatToFillScale.y << " ";
|
||||
}
|
||||
XMLElement *simpleElementsXML = saveFile.NewElement("SE");
|
||||
simpleElementsXML->SetAttribute("k", s.c_str());
|
||||
simpleElementsXML->SetAttribute("l", (unsigned)lr);
|
||||
std::string str = simpleElements_repeatScale.str();
|
||||
if(!str.empty())
|
||||
simpleElementsXML->SetAttribute("repeatScale", str.c_str());
|
||||
if(tagBitsUsed) // skip writing tags on layers where it's all zero (mainly to avoid putting a long string of 0's for border elements)
|
||||
{
|
||||
str = simpleElements_tag.str();
|
||||
if(!str.empty())
|
||||
simpleElementsXML->SetAttribute("tag", str.c_str());
|
||||
}
|
||||
|
||||
simpleElements_tag[e->bgLayer] << e->tag << " ";
|
||||
tagBitsUsed[e->bgLayer] |= e->tag;
|
||||
saveFile.InsertEndChild(simpleElementsXML);
|
||||
}
|
||||
}
|
||||
|
||||
if (entitySaveData.size() > 0)
|
||||
|
@ -2127,28 +2099,6 @@ bool Game::saveScene(std::string scene)
|
|||
saveFile.InsertEndChild(entitiesNode);
|
||||
}
|
||||
|
||||
for (int i = 0; i < LR_MAX; i++)
|
||||
{
|
||||
std::string s = simpleElements[i].str();
|
||||
if (!s.empty())
|
||||
{
|
||||
XMLElement *simpleElementsXML = saveFile.NewElement("SE");
|
||||
simpleElementsXML->SetAttribute("k", s.c_str());
|
||||
simpleElementsXML->SetAttribute("l", i);
|
||||
std::string str = simpleElements_repeatScale[i].str();
|
||||
if(!str.empty())
|
||||
simpleElementsXML->SetAttribute("repeatScale", str.c_str());
|
||||
if(tagBitsUsed[i]) // skip writing tags on layers where it's all zero (mainly to avoid putting a long string of 0's for border elements)
|
||||
{
|
||||
str = simpleElements_tag[i].str();
|
||||
if(!str.empty())
|
||||
simpleElementsXML->SetAttribute("tag", str.c_str());
|
||||
}
|
||||
|
||||
saveFile.InsertEndChild(simpleElementsXML);
|
||||
}
|
||||
}
|
||||
|
||||
bool result = saveFile.SaveFile(fn.c_str()) == XML_SUCCESS;
|
||||
if (result)
|
||||
debugLog("Successfully saved map: " + fn);
|
||||
|
@ -2389,25 +2339,6 @@ int game_collideParticle(Vector pos)
|
|||
return game->isObstructed(t);
|
||||
}
|
||||
|
||||
void Game::rebuildElementUpdateList()
|
||||
{
|
||||
for (int i = LR_ELEMENTS1; i <= LR_ELEMENTS8; i++)
|
||||
dsq->getRenderObjectLayer(i)->update = false;
|
||||
|
||||
elementUpdateList.clear();
|
||||
elementInteractionList.clear();
|
||||
for (size_t i = 0; i < dsq->getNumElements(); i++)
|
||||
{
|
||||
Element *e = dsq->getElement(i);
|
||||
const int eeidx = e->getElementEffectIndex();
|
||||
if (eeidx != -1 && e->layer >= LR_ELEMENTS1 && e->layer <= LR_ELEMENTS8)
|
||||
elementUpdateList.push_back(e);
|
||||
ElementEffect ee = dsq->getElementEffectByIndex(eeidx);
|
||||
if(ee.type == EFX_WAVY)
|
||||
elementInteractionList.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
float Game::getTimer(float mod)
|
||||
{
|
||||
return timer*mod;
|
||||
|
@ -2556,6 +2487,11 @@ void Game::applyState()
|
|||
dsq->overlay->alpha = 1;
|
||||
dsq->overlay->color = 0;
|
||||
|
||||
for (unsigned i = 0; i < MAX_TILE_LAYERS; ++i)
|
||||
{
|
||||
TileRender *tr = new TileRender(dsq->tilemgr.tilestore[i]);
|
||||
addRenderObject(tr, LR_ELEMENTS1 + i);
|
||||
}
|
||||
|
||||
for (int i = LR_ELEMENTS1; i <= LR_ELEMENTS12; i++) // LR_ELEMENTS13 is darkness, stop before that
|
||||
{
|
||||
|
@ -2607,7 +2543,7 @@ void Game::applyState()
|
|||
StateObject::applyState();
|
||||
|
||||
dsq->clearEntities();
|
||||
dsq->clearElements();
|
||||
dsq->tilemgr.clearTiles();
|
||||
|
||||
damageSprite = new Quad;
|
||||
{
|
||||
|
@ -4422,12 +4358,6 @@ void Game::update(float dt)
|
|||
StateObject::update(dt);
|
||||
|
||||
|
||||
for (ElementUpdateList::iterator e = elementUpdateList.begin(); e != elementUpdateList.end(); e++)
|
||||
{
|
||||
(*e)->update(dt);
|
||||
}
|
||||
|
||||
|
||||
size_t i = 0;
|
||||
for (i = 0; i < getNumPaths(); i++)
|
||||
{
|
||||
|
@ -4669,57 +4599,6 @@ void Game::snapCam()
|
|||
warpCameraTo(*cameraFollow);
|
||||
}
|
||||
|
||||
bool Game::loadElementTemplates(std::string pack, const unsigned char *usedIdx, size_t usedIdxLen)
|
||||
{
|
||||
stringToLower(pack);
|
||||
|
||||
std::string fn;
|
||||
if (dsq->mod.isActive())
|
||||
fn = dsq->mod.getPath() + "tilesets/" + pack + ".txt";
|
||||
else
|
||||
fn = "data/tilesets/" + pack + ".txt";
|
||||
|
||||
if(!tileset.loadFile(fn.c_str(), usedIdx, usedIdxLen))
|
||||
{
|
||||
errorLog ("Could not load tileset [" + fn + "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Aquarian alphabet letters
|
||||
if(const CountedPtr<Texture> aqtex = dsq->getTexture("aquarian"))
|
||||
{
|
||||
const float cell = 64.0f/512.0f;
|
||||
for (int i = 0; i < 27; i++)
|
||||
{
|
||||
ElementTemplate t;
|
||||
t.idx = 1024+i;
|
||||
t.tex = aqtex;
|
||||
int x = i,y=0;
|
||||
while (x >= 6)
|
||||
{
|
||||
x -= 6;
|
||||
y++;
|
||||
}
|
||||
|
||||
t.tu1 = x*cell;
|
||||
t.tv1 = y*cell;
|
||||
t.tu2 = t.tu1 + cell;
|
||||
t.tv2 = t.tv1 + cell;
|
||||
|
||||
t.tv2 = 1 - t.tv2;
|
||||
t.tv1 = 1 - t.tv1;
|
||||
std::swap(t.tv1,t.tv2);
|
||||
|
||||
t.w = 512*cell;
|
||||
t.h = 512*cell;
|
||||
|
||||
tileset.elementTemplates.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Game::clearGrid(int v)
|
||||
{
|
||||
// ensure that grid is really a byte-array
|
||||
|
@ -4789,9 +4668,6 @@ void Game::removeState()
|
|||
|
||||
core->particlesPaused = false;
|
||||
|
||||
elementUpdateList.clear();
|
||||
elementInteractionList.clear();
|
||||
|
||||
dsq->setCursor(CURSOR_NORMAL);
|
||||
dsq->darkLayer.toggle(0);
|
||||
dsq->shakeCamera(0,0);
|
||||
|
@ -4824,7 +4700,7 @@ void Game::removeState()
|
|||
clearPaths();
|
||||
|
||||
StateObject::removeState();
|
||||
dsq->clearElements();
|
||||
dsq->tilemgr.clearTiles();
|
||||
dsq->clearEntities();
|
||||
avatar = 0;
|
||||
sceneEditor.shutdown();
|
||||
|
|
|
@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "ScriptedEntity.h"
|
||||
#include "TileVector.h"
|
||||
#include "SceneEditor.h"
|
||||
#include "Tileset.h"
|
||||
#include "TileMgr.h"
|
||||
|
||||
#include <tinyxml2.h>
|
||||
using namespace tinyxml2;
|
||||
|
@ -112,8 +112,6 @@ public:
|
|||
int idx;
|
||||
};
|
||||
|
||||
typedef std::vector<Element*> ElementUpdateList;
|
||||
|
||||
struct EntitySaveData
|
||||
{
|
||||
public:
|
||||
|
@ -160,8 +158,6 @@ public:
|
|||
|
||||
// pass usedIdx == NULL to preload all textures from tileset
|
||||
// pass usedIdx != NULL to preload only textures where usedIdx[i] != 0
|
||||
bool loadElementTemplates(std::string pack, const unsigned char *usedIdx, size_t usedIdxLen);
|
||||
Element* createElement(size_t etidx, Vector position, size_t bgLayer=0, RenderObject *copy=0, ElementTemplate *et=0);
|
||||
|
||||
void updateParticlePause();
|
||||
|
||||
|
@ -184,11 +180,8 @@ public:
|
|||
void handleShotCollisionsSkeletal(Entity *e);
|
||||
void handleShotCollisionsHair(Entity *e, int num = 0, float perc = 0);
|
||||
|
||||
Tileset tileset;
|
||||
std::string sceneName, sceneDisplayName;
|
||||
|
||||
ElementTemplate *getElementTemplateByIdx(size_t idx);
|
||||
|
||||
bool saveScene(std::string scene);
|
||||
|
||||
void postInitEntities();
|
||||
|
@ -306,6 +299,7 @@ public:
|
|||
|
||||
ObsType lastCollideTileType;
|
||||
|
||||
void fillGrid(const GridFiller& gf);
|
||||
void fillGridFromQuad(Quad *q, ObsType ot=OT_INVISIBLEIN, bool trim=true);
|
||||
|
||||
bool isDamageTypeAvatar(DamageType dt);
|
||||
|
@ -370,8 +364,6 @@ public:
|
|||
|
||||
void ensureLimit(Entity *e, int num, int state=0);
|
||||
|
||||
void rebuildElementUpdateList();
|
||||
|
||||
float getTimer(float mod=1);
|
||||
float getHalfTimer(float mod=1);
|
||||
|
||||
|
@ -389,8 +381,6 @@ public:
|
|||
std::string saveMusic;
|
||||
GridRender *gridRender, *gridRender2, *gridRender3, *edgeRender, *gridRenderEnt, *gridRenderUser1, *gridRenderUser2;
|
||||
void toggleGridRender();
|
||||
ElementUpdateList elementUpdateList;
|
||||
ElementUpdateList elementInteractionList;
|
||||
|
||||
bool invinciblity;
|
||||
|
||||
|
|
|
@ -8,19 +8,6 @@
|
|||
|
||||
class Path;
|
||||
|
||||
struct ElementEffect
|
||||
{
|
||||
public:
|
||||
int type;
|
||||
int segsx, segsy;
|
||||
float segs_dgox, segs_dgoy, segs_dgmx, segs_dgmy, segs_dgtm, segs_dgo;
|
||||
float wavy_radius, wavy_min, wavy_max;
|
||||
bool wavy_flip;
|
||||
InterpolatedVector alpha;
|
||||
InterpolatedVector color;
|
||||
BlendType blendType;
|
||||
};
|
||||
|
||||
struct EmoteData
|
||||
{
|
||||
EmoteData()
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,10 @@
|
|||
class Element;
|
||||
class Entity;
|
||||
class Path;
|
||||
class PathRender;
|
||||
class TileStorage;
|
||||
|
||||
class MultiTileHelper;
|
||||
|
||||
struct EntityGroupEntity
|
||||
{
|
||||
|
@ -78,20 +82,14 @@ public:
|
|||
void update(float dt);
|
||||
void prevElement();
|
||||
void nextElement();
|
||||
void doPrevElement();
|
||||
Element *cycleElementNext(Element *e);
|
||||
Element *cycleElementPrev(Element *e);
|
||||
void cyclePlacer(int direction);
|
||||
void cycleSelectedTiles(int direction); // transmute selected to next/prev in tileset
|
||||
void selectZero();
|
||||
void selectEnd();
|
||||
void placeElement();
|
||||
void flipElementHorz();
|
||||
void flipElementVert();
|
||||
void deleteSelectedElement();
|
||||
void deleteElement(int selectedIdx);
|
||||
virtual void action(int id, int state, int source, InputDevice device);
|
||||
void scaleElementUp();
|
||||
void scaleElementDown();
|
||||
void scaleElement1();
|
||||
void placeAvatar();
|
||||
|
||||
void executeButtonID(int bid);
|
||||
|
@ -117,7 +115,7 @@ public:
|
|||
EditTypes editType;
|
||||
EditorStates state;
|
||||
|
||||
Element *getElementAtCursor();
|
||||
int getTileAtCursor(); // <0 when no tile, otherwise index
|
||||
Entity *getEntityAtCursor();
|
||||
|
||||
void mouseButtonLeftUp();
|
||||
|
@ -125,7 +123,6 @@ public:
|
|||
void moveToBack();
|
||||
void moveToFront();
|
||||
int bgLayer;
|
||||
Element *editingElement;
|
||||
Entity *editingEntity;
|
||||
Path *editingPath;
|
||||
|
||||
|
@ -133,21 +130,13 @@ public:
|
|||
size_t selectedNode;
|
||||
|
||||
Path *getSelectedPath();
|
||||
void changeDepth();
|
||||
void updateEntitySaveData(Entity *editingEntity);
|
||||
void moveLayer();
|
||||
void moveElementToLayer(Element *e, int bgLayer);
|
||||
void toggleElementRepeat();
|
||||
bool multiSelecting;
|
||||
Vector multiSelectPoint;
|
||||
std::vector <Element*> selectedElements;
|
||||
std::vector <size_t> selectedTiles; // indices
|
||||
|
||||
Vector groupCenter;
|
||||
Vector getSelectedElementsCenter();
|
||||
|
||||
Quad dummy;
|
||||
|
||||
void updateSelectedElementPosition(Vector position);
|
||||
void updateSelectedElementPosition(Vector rel);
|
||||
int selectedEntityType;
|
||||
|
||||
SelectedEntity selectedEntity;
|
||||
|
@ -203,8 +192,10 @@ protected:
|
|||
void enterScaleState();
|
||||
void enterRotateState();
|
||||
void enterMoveState();
|
||||
void enterAnyStateHelper(EditorStates newstate);
|
||||
|
||||
Vector oldPosition, oldRotation, oldScale, cursorOffset, oldRepeatScale;
|
||||
float oldRotation;
|
||||
Vector oldPosition, oldScale, cursorOffset, oldRepeatScale;
|
||||
|
||||
Entity *movingEntity;
|
||||
|
||||
|
@ -234,12 +225,20 @@ protected:
|
|||
void mouseButtonLeft();
|
||||
void mouseButtonRight();
|
||||
|
||||
void setActiveLayer(unsigned bglayer);
|
||||
TileStorage& getCurrentLayerTiles();
|
||||
void clearSelection();
|
||||
MultiTileHelper *createMultiTileHelperFromSelection();
|
||||
void destroyMultiTileHelper();
|
||||
|
||||
size_t curElement;
|
||||
|
||||
Quad *placer;
|
||||
MultiTileHelper *multi;
|
||||
DebugFont *text;
|
||||
bool on;
|
||||
InterpolatedVector oldGlobalScale;
|
||||
PathRender *pathRender;
|
||||
};
|
||||
|
||||
#endif // AQUARIA_SCENEEDITOR_H
|
||||
|
|
|
@ -5908,11 +5908,7 @@ luaFunc(entity_doElementInteraction)
|
|||
if (!touchWidth)
|
||||
touchWidth = 16;
|
||||
|
||||
ElementUpdateList& elems = game->elementInteractionList;
|
||||
for (ElementUpdateList::iterator it = elems.begin(); it != elems.end(); ++it)
|
||||
{
|
||||
(*it)->doInteraction(e, mult, touchWidth);
|
||||
}
|
||||
dsq->tilemgr.doTileInteraction(e->position, e->vel, mult, touchWidth);
|
||||
}
|
||||
luaReturnNil();
|
||||
}
|
||||
|
@ -7640,44 +7636,59 @@ luaFunc(node_setElementsInLayerActive)
|
|||
Path *p = path(L);
|
||||
if (p)
|
||||
{
|
||||
int l = lua_tointeger(L, 2);
|
||||
unsigned l = lua_tointeger(L, 2);
|
||||
bool v = getBool(L, 3);
|
||||
int tag = lua_tointeger(L, 3);
|
||||
for (Element *e = dsq->getFirstElementOnLayer(l); e; e = e->bgLayerNext)
|
||||
|
||||
if(l < MAX_TILE_LAYERS)
|
||||
{
|
||||
if (e && (!tag || e->tag == tag) && p->isCoordinateInside(e->position))
|
||||
TileStorage& ts = dsq->tilemgr.tilestore[l];
|
||||
const size_t N = ts.tiles.size();
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
{
|
||||
e->setElementActive(v);
|
||||
TileData& t = ts.tiles[i];
|
||||
if((!tag || t.tag == tag) && p->isCoordinateInside(Vector(t.x, t.y)))
|
||||
t.setVisible(v);
|
||||
}
|
||||
ts.refreshAll();
|
||||
}
|
||||
}
|
||||
luaReturnNil();
|
||||
}
|
||||
|
||||
static int pushElementData(lua_State *L, const Element *e)
|
||||
static int pushTileData(lua_State *L, const TileData& t, unsigned layer)
|
||||
{
|
||||
lua_pushinteger(L, e->templateIdx);
|
||||
lua_pushstring(L, e->texture->name.c_str());
|
||||
lua_pushboolean(L, e->isElementActive());
|
||||
lua_pushinteger(L, e->bgLayer);
|
||||
lua_pushinteger(L, e->tag);
|
||||
lua_pushinteger(L, t.et->idx);
|
||||
lua_pushstring(L, t.et->tex->name.c_str());
|
||||
lua_pushboolean(L, t.isVisible());
|
||||
lua_pushinteger(L, layer);
|
||||
lua_pushinteger(L, t.tag);
|
||||
return 5;
|
||||
}
|
||||
|
||||
// (layer, func)
|
||||
luaFunc(refreshElementsOnLayerCallback)
|
||||
{
|
||||
const int layer = lua_tointeger(L, 1);
|
||||
const unsigned layer = lua_tointeger(L, 1);
|
||||
size_t done = 0;
|
||||
for (Element *e = dsq->getFirstElementOnLayer(layer); e; e = e->bgLayerNext)
|
||||
|
||||
if(layer < MAX_TILE_LAYERS)
|
||||
{
|
||||
lua_pushvalue(L, 2); // the callback
|
||||
int args = pushElementData(L, e);
|
||||
lua_call(L, args, 1);
|
||||
bool newon = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
e->setElementActive(newon);
|
||||
++done;
|
||||
TileStorage& ts = dsq->tilemgr.tilestore[layer];
|
||||
const size_t N = ts.tiles.size();
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
{
|
||||
lua_pushvalue(L, 2); // the callback
|
||||
TileData& t = ts.tiles[i];
|
||||
int args = pushTileData(L, t, layer);
|
||||
lua_call(L, args, 1);
|
||||
bool newon = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
t.setVisible(newon);
|
||||
++done;
|
||||
}
|
||||
if(done)
|
||||
ts.refreshAll();
|
||||
}
|
||||
luaReturnInt(done);
|
||||
}
|
||||
|
@ -7686,23 +7697,31 @@ luaFunc(refreshElementsOnLayerCallback)
|
|||
luaFunc(refreshElementsWithTagCallback)
|
||||
{
|
||||
const int tag = lua_tointeger(L, 1);
|
||||
const size_t N = dsq->getNumElements();
|
||||
size_t done = 0;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
size_t total = 0;
|
||||
for(unsigned layer = 0; layer < MAX_TILE_LAYERS; ++layer)
|
||||
{
|
||||
Element *e = dsq->getElement(i);
|
||||
if(e->tag == tag)
|
||||
TileStorage& ts = dsq->tilemgr.tilestore[layer];
|
||||
const size_t N = ts.tiles.size();
|
||||
size_t done = 0;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
{
|
||||
lua_pushvalue(L, 2); // the callback
|
||||
int args = pushElementData(L, e);
|
||||
lua_call(L, args, 1);
|
||||
bool newon = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
e->setElementActive(newon);
|
||||
++done;
|
||||
TileData& t = ts.tiles[i];
|
||||
if(t.tag == tag)
|
||||
{
|
||||
lua_pushvalue(L, 2); // the callback
|
||||
int args = pushTileData(L, t, layer);
|
||||
lua_call(L, args, 1);
|
||||
bool newon = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
t.setVisible(newon);
|
||||
++done;
|
||||
}
|
||||
}
|
||||
if(done)
|
||||
ts.refreshAll();
|
||||
total += done;
|
||||
}
|
||||
luaReturnInt(done);
|
||||
luaReturnInt(total);
|
||||
}
|
||||
|
||||
|
||||
|
|
278
Aquaria/TileMgr.cpp
Normal file
278
Aquaria/TileMgr.cpp
Normal file
|
@ -0,0 +1,278 @@
|
|||
#include "TileMgr.h"
|
||||
#include <assert.h>
|
||||
#include "Base.h"
|
||||
#include "ttvfs_stdio.h"
|
||||
|
||||
|
||||
static const unsigned s_tileFlags[] =
|
||||
{
|
||||
/* EF_NONE -> */ TILEFLAG_NONE,
|
||||
/* EF_SOLID -> */ TILEFLAG_SOLID,
|
||||
/* EF_MOVABLE-> */ TILEFLAG_NONE, /* unused */
|
||||
/* EF_HURT -> */ TILEFLAG_SOLID | TILEFLAG_HURT,
|
||||
/* EF_SOLID2 -> */ TILEFLAG_SOLID | TILEFLAG_SOLID_THICK,
|
||||
/* EF_SOLID3 -> */ TILEFLAG_SOLID | TILEFLAG_SOLID_THICK | TILEFLAG_SOLID_IN
|
||||
};
|
||||
|
||||
|
||||
TileFlags TileMgr::GetTileFlags(ElementFlag ef)
|
||||
{
|
||||
//compile_assert(Countof(s_tileFlags) == EF_MAX);
|
||||
unsigned tf = TILEFLAG_NONE;
|
||||
if(unsigned(ef) < Countof(s_tileFlags))
|
||||
tf = s_tileFlags[ef];
|
||||
return (TileFlags)tf;
|
||||
}
|
||||
|
||||
ElementFlag TileMgr::GetElementFlag(TileFlags tf)
|
||||
{
|
||||
unsigned ef = EF_NONE;
|
||||
if(tf & TILEFLAG_SOLID)
|
||||
{
|
||||
if(tf & TILEFLAG_HURT)
|
||||
ef = EF_HURT;
|
||||
else if(tf & TILEFLAG_SOLID_IN)
|
||||
ef = EF_SOLID3;
|
||||
else if(tf & TILEFLAG_SOLID_THICK)
|
||||
ef = EF_SOLID2;
|
||||
else
|
||||
ef = EF_SOLID;
|
||||
}
|
||||
return (ElementFlag)ef;
|
||||
}
|
||||
|
||||
|
||||
TileMgr::TileMgr()
|
||||
{
|
||||
}
|
||||
|
||||
TileMgr::~TileMgr()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void TileMgr::update(float dt)
|
||||
{
|
||||
tileEffects.update(dt);
|
||||
for(size_t i = 0; i < Countof(tilestore); ++i)
|
||||
tilestore[i].update(dt);
|
||||
}
|
||||
|
||||
void TileMgr::destroy()
|
||||
{
|
||||
clearTiles();
|
||||
tileset.clear();
|
||||
tileEffects.clear();
|
||||
}
|
||||
|
||||
size_t TileMgr::getNumTiles() const
|
||||
{
|
||||
size_t num = 0;
|
||||
for(size_t i = 0; i < Countof(tilestore); ++i)
|
||||
num += tilestore[i].size();
|
||||
return num;
|
||||
}
|
||||
|
||||
TileStorage::Sizes TileMgr::getStats() const
|
||||
{
|
||||
TileStorage::Sizes tsz {};
|
||||
for(size_t i = 0; i < Countof(tilestore); ++i)
|
||||
{
|
||||
TileStorage::Sizes sz = tilestore[i].stats();
|
||||
tsz.tiles += sz.tiles;
|
||||
tsz.collide += sz.collide;
|
||||
tsz.update += sz.update;
|
||||
}
|
||||
return tsz;
|
||||
}
|
||||
|
||||
void TileMgr::clearTiles()
|
||||
{
|
||||
for(size_t i = 0; i < Countof(tilestore); ++i)
|
||||
tilestore[i].destroyAll();
|
||||
}
|
||||
|
||||
void TileMgr::doTileInteraction(const Vector& pos, const Vector& vel, float mult, float touchWidth)
|
||||
{
|
||||
for(size_t i = 0; i < Countof(tilestore); ++i)
|
||||
tilestore[i].doInteraction(pos, vel, mult, touchWidth);
|
||||
}
|
||||
|
||||
TileData* TileMgr::createOneTile(unsigned tilesetID, unsigned layer, float x, float y, ElementFlag ef, int effidx)
|
||||
{
|
||||
TileData *t = _createTile(tilesetID, layer, x, y, ef, effidx);
|
||||
if(t)
|
||||
{
|
||||
TileStorage& ts = tilestore[layer];
|
||||
ts.refreshAll();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void TileMgr::createTiles(const TileDef* defs, size_t n)
|
||||
{
|
||||
char used[Countof(tilestore)] = {0};
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
{
|
||||
const TileDef& d = defs[i];
|
||||
TileData *t = _createTile(d.idx, d.layer, d.x, d.y, (ElementFlag)d.ef, d.efxIdx);
|
||||
if(t)
|
||||
{
|
||||
used[d.layer] = 1;
|
||||
|
||||
if(d.fh)
|
||||
t->flags |= TILEFLAG_FH;
|
||||
if(d.repeat)
|
||||
t->flags |= TILEFLAG_REPEAT;
|
||||
|
||||
// FIXME: handle fv
|
||||
|
||||
t->rotation = d.rot;
|
||||
t->texscaleX = d.rsx;
|
||||
t->texscaleY = d.rsy;
|
||||
t->tag = d.tag;
|
||||
t->scalex = d.sx;
|
||||
t->scaley = d.sy;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < Countof(used); ++i)
|
||||
if(used[i])
|
||||
tilestore[i].refreshAll();
|
||||
}
|
||||
|
||||
void TileMgr::exportGridFillers(std::vector<GridFiller>& fillers) const
|
||||
{
|
||||
for(size_t k = 0; k < Countof(tilestore); ++k)
|
||||
{
|
||||
const TileStorage& ts = tilestore[k];
|
||||
const size_t N = ts.size();
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
{
|
||||
const TileData& t = ts.tiles[i];
|
||||
if((t.flags & TILEFLAG_SOLID) && !(t.flags & TILEFLAG_HIDDEN) && t.et)
|
||||
{
|
||||
GridFiller gf;
|
||||
gf.fh = !!(t.flags & TILEFLAG_FH);
|
||||
gf.position = Vector(t.x, t.y);
|
||||
gf.rotation = t.rotation;
|
||||
gf.scale = Vector(t.scalex, t.scaley);
|
||||
gf.texture = t.et->tex.content();
|
||||
gf.width = t.et->w;
|
||||
gf.height = t.et->h;
|
||||
gf.trim = !(t.flags & TILEFLAG_SOLID_THICK);
|
||||
if(t.flags & TILEFLAG_HURT)
|
||||
gf.obs = OT_HURT;
|
||||
else if(t.flags & TILEFLAG_SOLID_IN)
|
||||
gf.obs = OT_INVISIBLEIN;
|
||||
else
|
||||
gf.obs = OT_INVISIBLE;
|
||||
|
||||
fillers.push_back(gf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TileData* TileMgr::_createTile(unsigned tilesetID, unsigned layer, float x, float y, ElementFlag ef, int effidx)
|
||||
{
|
||||
if(layer >= Countof(tilestore))
|
||||
return NULL;
|
||||
|
||||
TileData t;
|
||||
t.x = x;
|
||||
t.y = y;
|
||||
t.rotation = 0;
|
||||
t.texscaleX = 1;
|
||||
t.texscaleY = 1;
|
||||
t.scalex = 1;
|
||||
t.scaley = 1;
|
||||
t.beforeScaleOffsetX = 0;
|
||||
t.beforeScaleOffsetY = 0;
|
||||
t.flags = GetTileFlags(ef);
|
||||
t.tag = 0;
|
||||
t.et = tileset.getByIdx(tilesetID);
|
||||
assert(t.et);
|
||||
/* t.eff = */ tileEffects.assignEffect(t, effidx);
|
||||
|
||||
TileStorage& ts = tilestore[layer];
|
||||
ts.tiles.push_back(t);
|
||||
return &ts.tiles.back();
|
||||
}
|
||||
|
||||
void TileMgr::loadTileEffects(const char *fn)
|
||||
{
|
||||
debugLog(fn);
|
||||
InStream inFile(fn);
|
||||
if(!inFile)
|
||||
{
|
||||
errorLog("TileMgr::loadTileEffects: Failed to open file");
|
||||
return;
|
||||
}
|
||||
|
||||
clearTiles();
|
||||
tileEffects.clear();
|
||||
|
||||
std::string line;
|
||||
while (std::getline(inFile, line))
|
||||
{
|
||||
debugLog("Line: " + line);
|
||||
std::istringstream is(line);
|
||||
TileEffectConfig e;
|
||||
int efxType = EFX_NONE;
|
||||
|
||||
std::string type;
|
||||
is >> e.index >> type;
|
||||
if (type == "EFX_SEGS")
|
||||
{
|
||||
efxType = EFX_SEGS;
|
||||
is >> e.u.segs.x >> e.u.segs.y >> e.u.segs.dgox >> e.u.segs.dgoy >> e.u.segs.dgmx >> e.u.segs.dgmy >> e.u.segs.dgtm >> e.u.segs.dgo;
|
||||
}
|
||||
else if (type == "EFX_WAVY")
|
||||
{
|
||||
debugLog("loading wavy");
|
||||
efxType = EFX_WAVY;
|
||||
is >> e.u.wavy.segsy >> e.u.wavy.radius >> e.u.wavy.flip;
|
||||
|
||||
}
|
||||
else if (type == "EFX_ALPHA")
|
||||
{
|
||||
efxType = EFX_ALPHA;
|
||||
int loop_unused, blend; // loop is unused because we always loop forever
|
||||
is >> blend >> e.u.alpha.val0 >> e.u.alpha.val1 >> e.u.alpha.time >> loop_unused >> e.u.alpha.pingpong >> e.u.alpha.ease;
|
||||
e.u.alpha.blend = blend < _BLEND_MAXSIZE ? (BlendType)blend : BLEND_DISABLED;
|
||||
}
|
||||
if(efxType != EFX_NONE)
|
||||
{
|
||||
e.type = (EFXType)efxType;
|
||||
const size_t newsize = size_t(e.index) + 1;
|
||||
if(tileEffects.configs.size() < newsize)
|
||||
tileEffects.configs.resize(newsize);
|
||||
tileEffects.configs[e.index] = e;
|
||||
}
|
||||
else
|
||||
errorLog("elementeffects.txt: Error on this line:\n" + line);
|
||||
}
|
||||
inFile.close();
|
||||
|
||||
tileEffects.finalize();
|
||||
}
|
||||
|
||||
TileDef::TileDef(unsigned lr)
|
||||
: layer(lr), idx(0), x(0), y(0), rot(0), fh(0), fv(0), ef(0), efxIdx(-1), repeat(0)
|
||||
, tag(0), sx(1), sy(1), rsx(1), rsy(1)
|
||||
{
|
||||
}
|
||||
|
||||
TileDef::TileDef(unsigned lr, const TileData& t)
|
||||
: layer(lr), idx((unsigned)t.et->idx), x(t.x), y(t.y), rot(t.rotation)
|
||||
, fh(!!(t.flags & TILEFLAG_FH))
|
||||
, fv(false) // FIXME
|
||||
, ef(TileMgr::GetElementFlag((TileFlags)t.flags))
|
||||
, efxIdx(t.eff ? t.eff->efxidx : -1)
|
||||
, repeat(!!(t.flags & TILEFLAG_REPEAT))
|
||||
, tag(t.tag)
|
||||
, sx(t.scalex), sy(t.scaley)
|
||||
, rsx(t.texscaleX), rsy(t.texscaleY)
|
||||
{
|
||||
}
|
85
Aquaria/TileMgr.h
Normal file
85
Aquaria/TileMgr.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
#ifndef TILEMGR_H
|
||||
#define TILEMGR_H
|
||||
|
||||
#include "Tile.h"
|
||||
#include "Tileset.h"
|
||||
#include "GameEnums.h"
|
||||
|
||||
enum { MAX_TILE_LAYERS = 16 };
|
||||
|
||||
// Legacy!
|
||||
// These are needed as-is when loading and saving maps.
|
||||
// The values are stored in the map and can't be changed.
|
||||
enum ElementFlag
|
||||
{
|
||||
EF_NONE = 0,
|
||||
EF_SOLID = 1,
|
||||
EF_MOVABLE = 2, // unused
|
||||
EF_HURT = 3,
|
||||
EF_SOLID2 = 4,
|
||||
EF_SOLID3 = 5,
|
||||
//EF_MAX = 6
|
||||
};
|
||||
|
||||
// temporary struct to fill grid with
|
||||
struct GridFiller
|
||||
{
|
||||
ObsType obs;
|
||||
bool trim;
|
||||
|
||||
const Texture *texture;
|
||||
Vector scale, position;
|
||||
float width, height, rotation;
|
||||
bool fh;
|
||||
};
|
||||
|
||||
// struct with all tile properties for batch creation of tiles
|
||||
struct TileDef
|
||||
{
|
||||
TileDef(unsigned lr);
|
||||
TileDef(unsigned lr, const TileData& t);
|
||||
|
||||
unsigned layer, idx;
|
||||
int x, y, rot, fh, fv, ef, efxIdx, repeat, tag;
|
||||
float sx, sy, rsx, rsy;
|
||||
};
|
||||
|
||||
class TileMgr
|
||||
{
|
||||
public:
|
||||
TileMgr();
|
||||
~TileMgr();
|
||||
|
||||
void update(float dt);
|
||||
void destroy();
|
||||
|
||||
void loadTileEffects(const char *fn);
|
||||
|
||||
size_t getNumTiles() const;
|
||||
TileStorage::Sizes getStats() const;
|
||||
void clearTiles();
|
||||
void doTileInteraction(const Vector& pos, const Vector& vel, float mult, float touchWidth);
|
||||
|
||||
// don't store the returned pointer anywhere! Use it to set extra things, but then drop it.
|
||||
// It will become invalid when more tiles are added.
|
||||
// This function is also quite ineffieient and is intended for editor use only!
|
||||
TileData *createOneTile(unsigned tilesetID, unsigned layer, float x, float y, ElementFlag ef = EF_NONE, int effidx = -1);
|
||||
|
||||
void createTiles(const TileDef *defs, size_t n);
|
||||
void exportGridFillers(std::vector<GridFiller>& fillers) const;
|
||||
|
||||
TileStorage tilestore[MAX_TILE_LAYERS];
|
||||
TileEffectStorage tileEffects;
|
||||
Tileset tileset;
|
||||
|
||||
static TileFlags GetTileFlags(ElementFlag ef);
|
||||
static ElementFlag GetElementFlag(TileFlags tf);
|
||||
|
||||
private:
|
||||
TileData *_createTile(unsigned tilesetID, unsigned layer, float x, float y, ElementFlag ef = EF_NONE, int effidx = -1);
|
||||
|
||||
TileMgr(const TileMgr&); // no-copy
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -97,6 +97,7 @@ RenderObject::RenderObject()
|
|||
|
||||
shareAlphaWithChildren = false;
|
||||
shareColorWithChildren = false;
|
||||
neverFollowCamera = false;
|
||||
}
|
||||
|
||||
RenderObject::~RenderObject()
|
||||
|
|
|
@ -242,6 +242,7 @@ public:
|
|||
bool _hidden;
|
||||
bool _fv, _fh;
|
||||
bool _markedForDelete;
|
||||
bool neverFollowCamera;
|
||||
|
||||
unsigned char pm; // unsigned char to save space
|
||||
|
||||
|
|
|
@ -229,6 +229,8 @@ void RenderObjectLayer::prepareRender()
|
|||
toRender.push_back(NULL); // terminate
|
||||
core->totalRenderObjectCount += n;
|
||||
|
||||
// TODO: set followCameraMult = (0,0) when followCamera == 0 ?
|
||||
|
||||
switch(followCameraLock)
|
||||
{
|
||||
default:
|
||||
|
|
|
@ -41,6 +41,8 @@ Vector RenderObject::getFollowCameraPosition(const Vector& v) const
|
|||
{
|
||||
assert(layer != LR_NONE);
|
||||
assert(!parent); // this makes no sense when we're not a root object
|
||||
if(neverFollowCamera)
|
||||
return v;
|
||||
const RenderObjectLayer &rl = core->renderObjectLayers[layer];
|
||||
Vector M = rl.followCameraMult;
|
||||
float F = followCamera;
|
||||
|
|
|
@ -47,7 +47,7 @@ Texture::~Texture()
|
|||
unload();
|
||||
}
|
||||
|
||||
void Texture::readRGBA(unsigned char *pixels)
|
||||
void Texture::readRGBA(unsigned char *pixels) const
|
||||
{
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glBindTexture(GL_TEXTURE_2D, gltexid);
|
||||
|
@ -207,7 +207,7 @@ bool Texture::upload(const ImageData& img, bool mipmap)
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned char * Texture::getBufferAndSize(int *wparam, int *hparam, size_t *sizeparam)
|
||||
unsigned char * Texture::getBufferAndSize(int *wparam, int *hparam, size_t *sizeparam) const
|
||||
{
|
||||
const size_t bytes = size_t(width) * size_t(height) * 4;
|
||||
unsigned char *data = (unsigned char*)malloc(bytes);
|
||||
|
|
|
@ -46,9 +46,9 @@ public:
|
|||
int width, height;
|
||||
|
||||
void writeRGBA(int tx, int ty, int w, int h, const unsigned char *pixels);
|
||||
void readRGBA(unsigned char *pixels);
|
||||
void readRGBA(unsigned char *pixels) const;
|
||||
|
||||
unsigned char *getBufferAndSize(int *w, int *h, size_t *size); // returned memory must be free()'d
|
||||
unsigned char *getBufferAndSize(int *w, int *h, size_t *size) const; // returned memory must be free()'d
|
||||
|
||||
std::string name, filename;
|
||||
bool upload(const ImageData& img, bool mipmap);
|
||||
|
|
|
@ -269,24 +269,31 @@ Texture *TextureMgr::finalize(TexLoadTmp& tt)
|
|||
return tex;
|
||||
}
|
||||
|
||||
void TextureMgr::loadBatch(Texture * pdst[], const std::string texnames[], size_t n, LoadMode mode, ProgressCallback cb, void *cbUD)
|
||||
size_t TextureMgr::loadBatch(Texture * pdst[], const std::string texnames[], size_t n, LoadMode mode, ProgressCallback cb, void *cbUD)
|
||||
{
|
||||
size_t doneCB = 0;
|
||||
|
||||
if(threads.empty())
|
||||
{
|
||||
size_t loaded = 0;
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
{
|
||||
Texture *tex = load(texnames[i], mode);
|
||||
if(pdst)
|
||||
pdst[i] = tex;
|
||||
if(cb)
|
||||
cb(++doneCB, cbUD);
|
||||
loaded += !!tex;
|
||||
}
|
||||
return;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
// Important that this is pre-allocated. We store pointers to elements and
|
||||
// send them to threads, so this must never reallocate.
|
||||
std::vector<TexLoadTmp> tmp(n);
|
||||
|
||||
size_t inprogress = 0, doneCB = 0;
|
||||
size_t inprogress = 0;
|
||||
size_t loaded = 0;
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
{
|
||||
TexLoadTmp& tt = tmp[i];
|
||||
|
@ -301,6 +308,7 @@ void TextureMgr::loadBatch(Texture * pdst[], const std::string texnames[], size_
|
|||
pdst[i] = tt.curTex;
|
||||
if(cb)
|
||||
cb(++doneCB, cbUD);
|
||||
++loaded;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -320,7 +328,9 @@ void TextureMgr::loadBatch(Texture * pdst[], const std::string texnames[], size_
|
|||
pdst[tt.arrayidx] = tex;
|
||||
if(cb)
|
||||
cb(++doneCB, cbUD);
|
||||
loaded += !!tex;
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
Texture* TextureMgr::load(const std::string& texname, LoadMode mode)
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
OVERWRITE, // always overwrite
|
||||
};
|
||||
|
||||
void loadBatch(Texture *pdst[], const std::string texnames[], size_t n, LoadMode mode = KEEP, ProgressCallback cb = 0, void *cbUD = 0);
|
||||
size_t loadBatch(Texture *pdst[], const std::string texnames[], size_t n, LoadMode mode = KEEP, ProgressCallback cb = 0, void *cbUD = 0);
|
||||
Texture *load(const std::string& texname, LoadMode mode);
|
||||
void reloadAll(LoadMode mode);
|
||||
|
||||
|
|
203
BBGE/Tile.cpp
203
BBGE/Tile.cpp
|
@ -2,9 +2,9 @@
|
|||
#include "RenderGrid.h"
|
||||
#include "Tileset.h"
|
||||
#include "Base.h"
|
||||
#include <algorithm>
|
||||
|
||||
TileStorage::TileStorage(const TileEffectStorage& eff)
|
||||
: effstore(eff)
|
||||
TileStorage::TileStorage()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -13,16 +13,31 @@ TileStorage::~TileStorage()
|
|||
destroyAll();
|
||||
}
|
||||
|
||||
void TileStorage::moveToFront(size_t idx)
|
||||
TileStorage::Sizes TileStorage::stats() const
|
||||
{
|
||||
_moveToFront(idx);
|
||||
refreshAll();
|
||||
Sizes sz;
|
||||
sz.tiles = tiles.size();
|
||||
sz.update = indicesToUpdate.size();
|
||||
sz.collide = indicesToCollide.size();
|
||||
return sz;
|
||||
}
|
||||
|
||||
void TileStorage::moveToBack(size_t idx)
|
||||
void TileStorage::moveToFront(const size_t *indices, size_t n)
|
||||
{
|
||||
_moveToBack(idx);
|
||||
refreshAll();
|
||||
if(n)
|
||||
{
|
||||
_moveToFront(indices, n);
|
||||
refreshAll();
|
||||
}
|
||||
}
|
||||
|
||||
void TileStorage::moveToBack(const size_t *indices, size_t n)
|
||||
{
|
||||
if(n)
|
||||
{
|
||||
_moveToBack(indices, n);
|
||||
refreshAll();
|
||||
}
|
||||
}
|
||||
|
||||
void TileStorage::update(float dt)
|
||||
|
@ -44,24 +59,58 @@ void TileStorage::doInteraction(const Vector& pos, const Vector& vel, float mult
|
|||
}
|
||||
}
|
||||
|
||||
void TileStorage::_moveToFront(size_t idx)
|
||||
void TileStorage::_moveToFront(const size_t *indices, size_t n)
|
||||
{
|
||||
// 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);
|
||||
|
||||
if(n == 1)
|
||||
{
|
||||
TileData tile = tiles[*indices];
|
||||
tiles.erase(tiles.begin() + *indices);
|
||||
tiles.push_back(tile);
|
||||
return;
|
||||
}
|
||||
|
||||
_moveToPos(size(), indices, n);
|
||||
}
|
||||
|
||||
void TileStorage::_moveToBack(size_t idx)
|
||||
void TileStorage::_moveToBack(const size_t *indices, size_t n)
|
||||
{
|
||||
// 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);
|
||||
|
||||
if(n == 1)
|
||||
{
|
||||
TileData tile = tiles[*indices];
|
||||
tiles.erase(tiles.begin() + *indices);
|
||||
tiles.insert(tiles.begin(), tile);
|
||||
return;
|
||||
}
|
||||
|
||||
_moveToPos(0, indices, n);
|
||||
}
|
||||
|
||||
void TileStorage::moveToOther(TileStorage& other, const size_t *indices, size_t n)
|
||||
void TileStorage::_moveToPos(size_t where, const size_t * indices, size_t n)
|
||||
{
|
||||
std::vector<size_t> tmp(indices, indices + n);
|
||||
std::sort(tmp.begin(), tmp.end());
|
||||
|
||||
std::vector<TileData> tt(n);
|
||||
|
||||
// sorted indices -> preserve relative order of tiles
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
tt[i] = tiles[tmp[i]];
|
||||
|
||||
// SORTED indices, erasing from the BACK -> we don't get a destructive index shift
|
||||
for(size_t i = tmp.size(); i --> 0; )
|
||||
tiles.erase(tiles.begin() + tmp[i]);
|
||||
|
||||
tiles.insert(tiles.begin() + where, tt.begin(), tt.end());
|
||||
}
|
||||
|
||||
size_t TileStorage::moveToOther(TileStorage& other, const size_t *indices, size_t n)
|
||||
{
|
||||
const size_t firstNewIdx = other.tiles.size();
|
||||
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
other.tiles.push_back(tiles[indices[i]]);
|
||||
|
||||
|
@ -81,6 +130,7 @@ void TileStorage::moveToOther(TileStorage& other, const size_t *indices, size_t
|
|||
|
||||
refreshAll();
|
||||
other.refreshAll();
|
||||
return firstNewIdx;
|
||||
}
|
||||
|
||||
static void dropAttachments(TileData& t)
|
||||
|
@ -133,13 +183,51 @@ void TileStorage::setTag(unsigned tag, const size_t* indices, size_t n)
|
|||
// don't need to refresh here
|
||||
}
|
||||
|
||||
void TileStorage::setEffect(int idx, const size_t* indices, size_t n)
|
||||
void TileStorage::setEffect(const TileEffectStorage& effstore, 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::changeFlags(unsigned flagsToSet, unsigned flagsToUnset, const size_t* indices, size_t n)
|
||||
{
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
{
|
||||
unsigned& f = tiles[indices[i]].flags;
|
||||
unsigned tmp = f & ~flagsToUnset;
|
||||
f = tmp | flagsToSet;
|
||||
}
|
||||
}
|
||||
|
||||
size_t TileStorage::cloneSome(const TileEffectStorage& effstore, const size_t* indices, size_t n)
|
||||
{
|
||||
const size_t ret = tiles.size(); // new starting index of clone tiles
|
||||
|
||||
// cloning tiles is very simple, but owned pointers will be duplicated and need to be fixed up
|
||||
const size_t N = ret + n;
|
||||
tiles.resize(N);
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
tiles[ret + i] = tiles[indices[i]];
|
||||
|
||||
// cleanup pointers
|
||||
for(size_t i = ret; i < N; ++i) // loop only over newly added tiles
|
||||
{
|
||||
TileData& t = tiles[i];
|
||||
if((t.flags & TILEFLAG_OWN_EFFDATA) && t.eff)
|
||||
{
|
||||
int efx = t.eff->efxidx;
|
||||
t.eff = NULL; // not our pointer, just pretend it was never there
|
||||
t.flags &= TILEFLAG_OWN_EFFDATA;
|
||||
effstore.assignEffect(t, efx); // recreate effect properly
|
||||
}
|
||||
}
|
||||
|
||||
refreshAll();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TileStorage::refreshAll()
|
||||
{
|
||||
indicesToCollide.clear();
|
||||
|
@ -149,13 +237,16 @@ void TileStorage::refreshAll()
|
|||
for(size_t i = 0; i < n; ++i)
|
||||
{
|
||||
const TileData& t = tiles[i];
|
||||
if(const TileEffectData *e = t.eff)
|
||||
if(!(t.flags & TILEFLAG_HIDDEN))
|
||||
{
|
||||
if(t.flags & TILEFLAG_OWN_EFFDATA)
|
||||
if(const TileEffectData *e = t.eff)
|
||||
{
|
||||
indicesToUpdate.push_back(i);
|
||||
if(e->efxtype == EFX_WAVY)
|
||||
indicesToCollide.push_back(i);
|
||||
if(t.flags & TILEFLAG_OWN_EFFDATA)
|
||||
{
|
||||
indicesToUpdate.push_back(i);
|
||||
if(e->efxtype == EFX_WAVY)
|
||||
indicesToCollide.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,10 +261,14 @@ void TileStorage::clearSelection()
|
|||
|
||||
TileEffectData::TileEffectData(const TileEffectConfig& cfg)
|
||||
: efxtype(cfg.type), efxidx(cfg.index)
|
||||
, grid(NULL), blend(BLEND_DEFAULT)
|
||||
, grid(NULL), alpha(1), blend(BLEND_DEFAULT)
|
||||
{
|
||||
switch(cfg.type)
|
||||
{
|
||||
case EFX_NONE:
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
case EFX_WAVY:
|
||||
{
|
||||
float bity = 20; // FIXME
|
||||
|
@ -184,7 +279,7 @@ TileEffectData::TileEffectData(const TileEffectConfig& cfg)
|
|||
|
||||
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
|
||||
g->gridType = GRID_UNDEFINED; // we do the grid update manually
|
||||
|
||||
wavy.angleOffset = 0;
|
||||
wavy.magnitude = 0;
|
||||
|
@ -328,6 +423,15 @@ void TileEffectData::doInteraction(const TileData& t, const Vector& pos, const V
|
|||
}
|
||||
}
|
||||
|
||||
TileEffectStorage::TileEffectStorage()
|
||||
{
|
||||
}
|
||||
|
||||
TileEffectStorage::~TileEffectStorage()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void TileEffectStorage::assignEffect(TileData& t, int index) const
|
||||
{
|
||||
dropAttachments(t);
|
||||
|
@ -343,6 +447,9 @@ void TileEffectStorage::assignEffect(TileData& t, int index) const
|
|||
}
|
||||
else if(idx < configs.size())
|
||||
{
|
||||
if(configs[idx].type == EFX_NONE)
|
||||
return;
|
||||
|
||||
t.eff = new TileEffectData(configs[idx]);
|
||||
t.flags |= TILEFLAG_OWN_EFFDATA;
|
||||
}
|
||||
|
@ -354,3 +461,49 @@ void TileEffectStorage::update(float dt)
|
|||
if(TileEffectData *eff = prepared[i])
|
||||
eff->update(dt, NULL);
|
||||
}
|
||||
|
||||
void TileEffectStorage::clear()
|
||||
{
|
||||
clearPrepared();
|
||||
configs.clear();
|
||||
}
|
||||
|
||||
void TileEffectStorage::clearPrepared()
|
||||
{
|
||||
for(size_t i = 0; i < prepared.size(); ++i)
|
||||
delete prepared[i];
|
||||
prepared.clear();
|
||||
}
|
||||
|
||||
|
||||
void TileEffectStorage::finalize()
|
||||
{
|
||||
clearPrepared();
|
||||
prepared.resize(configs.size(), (TileEffectData*)NULL);
|
||||
|
||||
for(size_t i = 0; i < configs.size(); ++i)
|
||||
{
|
||||
TileEffectConfig& c = configs[i];
|
||||
|
||||
c.index = unsigned(i); // just in case
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
bool TileData::isCoordinateInside(float cx, float cy, float minsize) const
|
||||
{
|
||||
|
||||
float hw = fabsf(et->w * scalex)*0.5f;
|
||||
float hh = fabsf(et->h * scaley)*0.5f;
|
||||
if (hw < minsize)
|
||||
hw = minsize;
|
||||
if (hh < minsize)
|
||||
hh = minsize;
|
||||
|
||||
return cx >= x - hw && cx <= x + hw
|
||||
&& cy >= y - hh && cy <= y + hh;
|
||||
}
|
||||
|
|
84
BBGE/Tile.h
84
BBGE/Tile.h
|
@ -28,8 +28,13 @@ Further observations:
|
|||
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.
|
||||
|
||||
Assumptions:
|
||||
- Most tiles that exist are going to be rendered
|
||||
- Only few tiles have an effect attached
|
||||
|
||||
Gotaches:
|
||||
- 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
|
||||
*/
|
||||
|
||||
class ElementTemplate;
|
||||
|
@ -39,12 +44,13 @@ class TileRender;
|
|||
|
||||
enum EFXType
|
||||
{
|
||||
EFX_NONE,
|
||||
EFX_SEGS,
|
||||
EFX_ALPHA,
|
||||
EFX_WAVY
|
||||
};
|
||||
|
||||
// static configuration for one effect type
|
||||
// static configuration for one effect type. POD.
|
||||
struct TileEffectConfig
|
||||
{
|
||||
public:
|
||||
|
@ -85,9 +91,10 @@ enum TileFlags
|
|||
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_OWN_EFFDATA = 0x40, // tile owns its TileEffectData, can update, must delete
|
||||
TILEFLAG_HIDDEN = 0x80, // don't render tile
|
||||
TILEFLAG_SELECTED = 0x100
|
||||
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.
|
||||
};
|
||||
|
||||
struct TileData;
|
||||
|
@ -100,7 +107,7 @@ struct TileEffectData
|
|||
void doInteraction(const TileData& t, const Vector& pos, const Vector& vel, float mult, float touchWidth);
|
||||
|
||||
const EFXType efxtype;
|
||||
const unsigned efxidx; // index to ElementEffect
|
||||
const unsigned efxidx; // index of TileEffect
|
||||
RenderGrid *grid;
|
||||
InterpolatedVector alpha;
|
||||
BlendType blend;
|
||||
|
@ -116,46 +123,70 @@ struct TileEffectData
|
|||
void update(float dt);
|
||||
};
|
||||
Wavy wavy;
|
||||
|
||||
private:
|
||||
TileEffectData(const TileEffectData&); // no-copy
|
||||
};
|
||||
|
||||
// POD and as compact as possible
|
||||
// POD and as compact as possible. Intended for rendering as quickly 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;
|
||||
float scalex, scaley;
|
||||
float beforeScaleOffsetX, beforeScaleOffsetY;
|
||||
float x, y, scalex, scaley, texscaleX, texscaleY;
|
||||
float beforeScaleOffsetX, beforeScaleOffsetY; // almost always 0. // TODO: this is nasty, ideally get rid of this
|
||||
float rotation;
|
||||
unsigned flags; // TileFlags
|
||||
unsigned tag;
|
||||
ElementTemplate *et; // texture, texcoords, etc is here
|
||||
TileEffectData *eff;
|
||||
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
|
||||
|
||||
// helpers for external access
|
||||
inline void setVisible(bool on) { if(on) flags &= ~TILEFLAG_HIDDEN; else flags |= TILEFLAG_HIDDEN; }
|
||||
inline bool isVisible() const { return !(flags & TILEFLAG_HIDDEN); }
|
||||
bool isCoordinateInside(float cx, float cy, float minsize = 0) const;
|
||||
};
|
||||
|
||||
class TileEffectStorage
|
||||
{
|
||||
public:
|
||||
TileEffectStorage();
|
||||
~TileEffectStorage();
|
||||
void finalize(); // first fill configs[], then call this
|
||||
void assignEffect(TileData& t, int index) const;
|
||||
void update(float dt);
|
||||
void clear(); // do NOT call this while there are tiles that may reference one in prepared[]
|
||||
|
||||
std::vector<TileEffectData*> prepared;
|
||||
std::vector<TileEffectConfig> configs;
|
||||
|
||||
private:
|
||||
void clearPrepared();
|
||||
std::vector<TileEffectData*> prepared;
|
||||
|
||||
TileEffectStorage(const TileEffectStorage&); // no-copy
|
||||
};
|
||||
|
||||
class TileStorage
|
||||
{
|
||||
friend class TileRender;
|
||||
public:
|
||||
TileStorage(const TileEffectStorage& eff);
|
||||
TileStorage();
|
||||
~TileStorage();
|
||||
|
||||
void moveToFront(size_t idx);
|
||||
void moveToBack(size_t idx);
|
||||
void moveToOther(TileStorage& other, const size_t *indices, size_t n);
|
||||
void moveToFront(const size_t *indices, size_t n);
|
||||
void moveToBack(const size_t *indices, size_t n);
|
||||
|
||||
// returns starting index of new tiles. Since new tiles are always appended at the end,
|
||||
// the new indices corresponding to the moved tiles are [retn .. retn+n)
|
||||
size_t moveToOther(TileStorage& other, const size_t *indices, size_t n);
|
||||
size_t cloneSome(const TileEffectStorage& effstore, 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 setEffect(const TileEffectStorage& effstore, int idx, const size_t *indices, size_t n);
|
||||
|
||||
void changeFlags(unsigned flagsToSet, unsigned flagsToUnset, const size_t *indices, size_t n);
|
||||
|
||||
void update(float dt);
|
||||
void doInteraction(const Vector& pos, const Vector& vel, float mult, float touchWidth);
|
||||
|
@ -164,16 +195,27 @@ public:
|
|||
|
||||
void clearSelection();
|
||||
|
||||
struct Sizes
|
||||
{
|
||||
size_t tiles, update, collide;
|
||||
};
|
||||
Sizes stats() const;
|
||||
size_t size() const { return tiles.size(); }
|
||||
|
||||
|
||||
std::vector<TileData> tiles; // must call refreshAll() after changing this
|
||||
|
||||
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);
|
||||
void _moveToFront(const size_t *indices, size_t n);
|
||||
void _moveToBack(const size_t *indices, size_t n);
|
||||
void _moveToPos(size_t where, const size_t *indices, size_t n);
|
||||
|
||||
TileStorage(const TileStorage&); // no-copy
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
TileRender::TileRender(const TileStorage& tiles)
|
||||
: storage(tiles), renderBorders(false)
|
||||
{
|
||||
this->cull = false;
|
||||
this->neverFollowCamera = true;
|
||||
}
|
||||
|
||||
TileRender::~TileRender()
|
||||
|
@ -46,6 +48,7 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
const RenderObjectLayer& rl = core->renderObjectLayers[this->layer];
|
||||
const Vector M = rl.followCameraMult; // affected by parallaxLock
|
||||
const float F = rl.followCamera;
|
||||
const bool parallax = rl.followCamera > 0;
|
||||
|
||||
// Formula from RenderObject::getFollowCameraPosition() and optimized for speed
|
||||
const Vector C = core->screenCenter;
|
||||
|
@ -61,15 +64,18 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
for(size_t i = 0; i < storage.tiles.size(); ++i)
|
||||
{
|
||||
const TileData& tile = storage.tiles[i];
|
||||
if(tile.flags & TILEFLAG_HIDDEN)
|
||||
if(tile.flags & (TILEFLAG_HIDDEN | TILEFLAG_EDITOR_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
|
||||
Vector pos(tile.x, tile.y);
|
||||
if(parallax)
|
||||
{
|
||||
const Vector tmp = T + (F * pos);
|
||||
pos = pos * M1 + (tmp * M); // lerp, used to select whether to use original v or parallax-corrected v
|
||||
}
|
||||
|
||||
ElementTemplate * const et = tile.et;
|
||||
if(Texture * const tex = et->tex.content())
|
||||
const ElementTemplate * const et = tile.et;
|
||||
if(const Texture * const tex = et->tex.content())
|
||||
{
|
||||
unsigned texid = tex->gltexid;
|
||||
unsigned rep = tile.flags & TILEFLAG_REPEAT;
|
||||
|
@ -96,7 +102,7 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
// this is only relevant in editor mode and is always 0 otherwise
|
||||
glTranslatef(tile.beforeScaleOffsetX, tile.beforeScaleOffsetY, 0);
|
||||
|
||||
glScalef(tile.scalex * et->w, tile.scaley * et->h, 1);
|
||||
glScalef(tile.scalex, tile.scaley, 1);
|
||||
//glScalef(tile.scalex * et->w, tile.scaley * et->h, 1); // TODO use this + fixed verts
|
||||
|
||||
BlendType blend = BLEND_DEFAULT;
|
||||
|
@ -141,6 +147,9 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
}
|
||||
else
|
||||
{
|
||||
glPushMatrix();
|
||||
glScalef(et->w, et->h, 1);
|
||||
|
||||
RenderState rx(rs);
|
||||
rx.alpha = alpha;
|
||||
grid->render(rx, upperLeftTextureCoordinates, lowerRightTextureCoordinates);
|
||||
|
@ -150,6 +159,8 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
grid->renderDebugPoints(rs);
|
||||
lastTexId = 0;
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
if(renderBorders)
|
||||
|
@ -183,7 +194,11 @@ void TileRender::onRender(const RenderState& rs) const
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
RenderObject::lastTextureApplied = lastTexId;
|
||||
RenderObject::lastTextureRepeat = !!lastTexRepeat;
|
||||
}
|
||||
|
||||
void TileRender::onUpdate(float dt)
|
||||
{
|
||||
//this->position = core->screenCenter;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ public:
|
|||
|
||||
TileRender(const TileStorage& tiles);
|
||||
virtual ~TileRender();
|
||||
virtual void onRender(const RenderState& rs) const;
|
||||
virtual void onRender(const RenderState& rs) const OVERRIDE;
|
||||
virtual void onUpdate(float dt) OVERRIDE;
|
||||
|
||||
bool renderBorders;
|
||||
|
||||
|
|
190
BBGE/Tileset.cpp
190
BBGE/Tileset.cpp
|
@ -5,6 +5,15 @@
|
|||
#include "TextureMgr.h"
|
||||
#include "Core.h"
|
||||
|
||||
Tileset::Tileset()
|
||||
{
|
||||
}
|
||||
|
||||
Tileset::~Tileset()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t usedIdxLen)
|
||||
{
|
||||
elementTemplates.clear();
|
||||
|
@ -13,24 +22,34 @@ bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t used
|
|||
if(!in)
|
||||
return false;
|
||||
|
||||
bool warn = false;
|
||||
std::string line, gfx;
|
||||
while (std::getline(in, line))
|
||||
{
|
||||
gfx.clear();
|
||||
int idx=-1, w=0, h=0;
|
||||
SimpleIStringStream is(line.c_str(), SimpleIStringStream::REUSE);
|
||||
is >> idx >> gfx >> w >> h;
|
||||
if(idx >= 0)
|
||||
if(idx >= 0 && !gfx.empty())
|
||||
{
|
||||
ElementTemplate t;
|
||||
t.idx = idx;
|
||||
t.gfx = gfx;
|
||||
t.w = w;
|
||||
t.h = h;
|
||||
elementTemplates.push_back(t);
|
||||
if(idx < 1024)
|
||||
{
|
||||
ElementTemplate t;
|
||||
t.idx = idx;
|
||||
t.gfx = gfx;
|
||||
t.w = w;
|
||||
t.h = h;
|
||||
elementTemplates.push_back(t);
|
||||
}
|
||||
else
|
||||
warn = true;
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
|
||||
if(warn)
|
||||
errorLog("Tileset indices of 1024 and above are reserved; ignored during load");
|
||||
|
||||
std::sort(elementTemplates.begin(), elementTemplates.end());
|
||||
|
||||
// begin preloading textures
|
||||
|
@ -48,47 +67,174 @@ bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t used
|
|||
// drop duplicates
|
||||
usedTex.resize(std::distance(usedTex.begin(), std::unique(usedTex.begin(), usedTex.end())));
|
||||
|
||||
std::ostringstream os;
|
||||
os << "Loading " << usedTex.size()
|
||||
<< " used textures out of the " << elementTemplates.size() << " tileset entries";
|
||||
debugLog(os.str());
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Loading " << usedTex.size()
|
||||
<< " used textures out of the " << elementTemplates.size() << " tileset entries";
|
||||
debugLog(os.str());
|
||||
}
|
||||
|
||||
// preload all used textures
|
||||
size_t loaded = 0;
|
||||
if(usedTex.size())
|
||||
core->texmgr.loadBatch(NULL, &usedTex[0], usedTex.size());
|
||||
loaded = core->texmgr.loadBatch(NULL, &usedTex[0], usedTex.size());
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Loaded " << loaded << " textures successfully";
|
||||
debugLog(os.str());
|
||||
}
|
||||
|
||||
// finalize
|
||||
size_t nfailed = 0;
|
||||
std::ostringstream failed;
|
||||
for (size_t i = 0; i < elementTemplates.size(); i++)
|
||||
{
|
||||
ElementTemplate& et = elementTemplates[i];
|
||||
// only check those that are actualy loaded; otherwise this would load in textures
|
||||
// that we didn't bother to batch-load above
|
||||
if(!usedIdx || (et.idx < usedIdxLen && usedIdx[et.idx]))
|
||||
{
|
||||
if(!et.getTexture()) // assigns width/height and caches texture pointer
|
||||
{
|
||||
++nfailed;
|
||||
failed << et.gfx << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(nfailed)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "The following " << nfailed << " textures failed to load and would be used by tiles:";
|
||||
debugLog(os.str());
|
||||
debugLog(failed.str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::clear()
|
||||
{
|
||||
for(size_t i = 0; i < dummies.size(); ++i)
|
||||
delete dummies[i];
|
||||
dummies.clear();
|
||||
elementTemplates.clear();
|
||||
}
|
||||
|
||||
ElementTemplate *Tileset::getByIdx(size_t idx)
|
||||
const ElementTemplate *Tileset::getByIdx(size_t idx)
|
||||
{
|
||||
for (size_t i = 0; i < elementTemplates.size(); i++)
|
||||
{
|
||||
if (elementTemplates[i].idx == idx)
|
||||
ElementTemplate& et = elementTemplates[i];
|
||||
if (et.idx == idx)
|
||||
{
|
||||
return &elementTemplates[i];
|
||||
et.getTexture(); // HACK: make sure the texture is loaded before this gets used
|
||||
return &et;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
// a tile that gets an ET attached must remember its tileset id even if the entry is not present
|
||||
// in the tileset. since the tile does not store the idx as an integer, we need to return a dummy element.
|
||||
for (size_t i = 0; i < dummies.size(); i++)
|
||||
{
|
||||
ElementTemplate *et = dummies[i];
|
||||
if (et->idx == idx)
|
||||
return et;
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Tileset idx " << idx << " not found, creating dummy";
|
||||
debugLog(os.str());
|
||||
}
|
||||
|
||||
ElementTemplate *dummy = new ElementTemplate;
|
||||
dummy->idx = idx;
|
||||
dummies.push_back(dummy);
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
const ElementTemplate* Tileset::getAdjacent(size_t idx, int direction, bool wraparound)
|
||||
{
|
||||
ElementTemplate *et = _getAdjacent(idx, direction, wraparound);
|
||||
if(et)
|
||||
et->getTexture(); // load just in case
|
||||
return et;
|
||||
}
|
||||
|
||||
Texture* ElementTemplate::getTexture()
|
||||
{
|
||||
if(tex)
|
||||
if(loaded)
|
||||
return tex.content();
|
||||
|
||||
tex = core->getTexture(gfx);
|
||||
if(!w)
|
||||
w = tex->width;
|
||||
if(!h)
|
||||
h = tex->height;
|
||||
loaded = true;
|
||||
tex = core->getTexture(gfx); // may end up NULL
|
||||
if(tex)
|
||||
{
|
||||
if(!w)
|
||||
w = tex->width;
|
||||
if(!h)
|
||||
h = tex->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!w)
|
||||
w = 64;
|
||||
if(!h)
|
||||
h = 64;
|
||||
}
|
||||
|
||||
return tex.content();
|
||||
|
||||
}
|
||||
|
||||
ElementTemplate * Tileset::_getAdjacent(size_t idx, int direction, bool wraparound)
|
||||
{
|
||||
assert(direction == 1 || direction == -1);
|
||||
const size_t maxn = elementTemplates.size();
|
||||
size_t closest = 0;
|
||||
int mindiff = 0;
|
||||
for (size_t i = 0; i < maxn; i++)
|
||||
{
|
||||
if (elementTemplates[i].idx == idx)
|
||||
{
|
||||
if(wraparound)
|
||||
{
|
||||
if(!i && direction < 0)
|
||||
return &elementTemplates.back();
|
||||
if(i + direction >= maxn)
|
||||
return &elementTemplates[0];
|
||||
}
|
||||
else
|
||||
|
||||
i += direction; // may underflow
|
||||
return i < maxn ? &elementTemplates[i] : NULL;
|
||||
}
|
||||
int diff = labs((int)elementTemplates[i].idx - (int)idx);
|
||||
if(diff < mindiff || !mindiff)
|
||||
{
|
||||
mindiff = diff;
|
||||
closest = i;
|
||||
}
|
||||
}
|
||||
|
||||
// not found? pick whatever was closest to the non-existing idx, and go back/forward from there
|
||||
|
||||
// avoid going "twice" in the given direction
|
||||
if(closest < idx && direction < 0)
|
||||
direction = 0; // this is already a step back, don't step again
|
||||
else if(closest > idx && direction > 0)
|
||||
direction = 0; // this is already a step forward, don't step again
|
||||
else if(wraparound)
|
||||
{
|
||||
if(!closest && direction < 0)
|
||||
return &elementTemplates.back();
|
||||
if(closest + direction >= maxn)
|
||||
return &elementTemplates[0];
|
||||
}
|
||||
|
||||
size_t i = closest + direction;
|
||||
return i < maxn ? &elementTemplates[i] : NULL;
|
||||
}
|
||||
|
|
|
@ -8,32 +8,47 @@
|
|||
class ElementTemplate
|
||||
{
|
||||
public:
|
||||
ElementTemplate() { w=0; h=0; idx=-1; tu1=tv1=0; tu2=tv2=1; }
|
||||
ElementTemplate() { w=0; h=0; idx=-1; tu1=tv1=0; tu2=tv2=1; loaded=false; }
|
||||
inline bool operator<(const ElementTemplate& o) const { return idx < o.idx; }
|
||||
|
||||
Texture *getTexture(); // loads if not already loaded
|
||||
|
||||
// lazily assigned when tex is loaded
|
||||
CountedPtr<Texture> tex;
|
||||
CountedPtr<Texture> tex; // NULL if failed to load or not yet loaded
|
||||
float w,h; // custom size if used, otherwise texture size
|
||||
|
||||
// fixed
|
||||
float tu1, tu2, tv1, tv2; // texcoords
|
||||
size_t idx;
|
||||
std::string gfx;
|
||||
|
||||
bool loaded;
|
||||
};
|
||||
|
||||
class Tileset
|
||||
{
|
||||
public:
|
||||
Tileset();
|
||||
~Tileset();
|
||||
|
||||
// pass usedIdx == NULL to preload all textures from tileset
|
||||
// pass usedIdx != NULL to preload only textures where usedIdx[i] != 0
|
||||
bool loadFile(const char *fn, const unsigned char *usedIdx, size_t usedIdxLen);
|
||||
void clear();
|
||||
|
||||
ElementTemplate *getByIdx(size_t idx);
|
||||
// return valid ET if found, or creates a dummy if not. never returns NULL.
|
||||
const ElementTemplate *getByIdx(size_t idx);
|
||||
|
||||
// search for non-dummy ET in a given direction. used to cycle through ETs.
|
||||
// never returns dummy ET. May return NULL.
|
||||
const ElementTemplate *getAdjacent(size_t idx, int direction, bool wraparound);
|
||||
|
||||
std::vector<ElementTemplate> elementTemplates;
|
||||
|
||||
private:
|
||||
ElementTemplate *_getAdjacent(size_t idx, int direction, bool wraparound);
|
||||
|
||||
std::vector<ElementTemplate*> dummies;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue