mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-25 09:44:02 +00:00
Worldmap overhaul, part 1
In short: - No more grid-for-alpha; everything uses generated textures now (With proper bilinear filtering so it looks like the old method) - All tiles are now shown partially uncovered at the same time; selecting one is no longer needed - Gems can now be local (associated to a tile) or global. Local games move with their tile, global ones stay where they were placed Background: Originally there were two possible implementations of how to render the world map: - One used write-alpha-to-texture to implement graual uncovering. - The other (permanently enabled) used the DrawGrid to render the map tiles as a fine grid, each little square having its own alpha value The downside of the first method was that it didn't look as good as the second, so i guess that's why it was never fully finished. The main downside of the second method was that it burned a lot of vertices just to do alpha, so only one tile at a time could show the detailed grid. I also never liked how an entire tile was effectively fully uncovered once the map was first entered, taking away a lot of the exploration feeling that could have been there if everything that hasn't been explored would be completely invisible. I've added this worldmap uncovering method as an optional config param, <WorldMap revealMethod="1"/> but i've decided to fully switch over now. Things left to be done: - create a WorldMapRender instance only once and keep the tiles across map loads - add debug option to reload/recreate worldmap at runtime - cleanup gem storage and carry over the player gem properly (ged rid of std::list) - remove "worldmap" grid render type - Add more user "pyramid" gems as world map markers. More colors! - check that gems and beacons still work as they should
This commit is contained in:
parent
97cea29235
commit
c44c67a063
19 changed files with 811 additions and 717 deletions
|
@ -5012,6 +5012,11 @@ void Avatar::setCollisionAvoidanceData(int range, float mod)
|
|||
_collisionAvoidMod = mod;
|
||||
}
|
||||
|
||||
Vector Avatar::getPositionForMap() const
|
||||
{
|
||||
return warpInLocal.isZero() ? position : warpInLocal;
|
||||
}
|
||||
|
||||
bool Avatar::canQuickSong()
|
||||
{
|
||||
return !isSinging() && !isEntityDead() && isInputEnabled() && quickSongCastDelay <= 0;
|
||||
|
|
|
@ -320,6 +320,7 @@ public:
|
|||
|
||||
void setSeeMapMode(SeeMapMode mode) { _seeMapMode = mode; }
|
||||
SeeMapMode getSeeMapMode() const { return _seeMapMode; }
|
||||
Vector getPositionForMap() const; // same as position, but special when inside a local warp
|
||||
|
||||
int leaches;
|
||||
float shieldPoints;
|
||||
|
|
|
@ -105,6 +105,7 @@ SET(AQUARIA_SRCS
|
|||
Web.h
|
||||
WorldMap.h
|
||||
WorldMapRender.cpp
|
||||
WorldMapRender.h
|
||||
WorldMapTiles.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "ttvfs_stdio.h"
|
||||
#include "ReadXML.h"
|
||||
#include "Web.h"
|
||||
#include "WorldMap.h"
|
||||
#include "WorldMapRender.h"
|
||||
|
||||
#include <tinyxml2.h>
|
||||
using namespace tinyxml2;
|
||||
|
@ -2368,33 +2370,33 @@ void Continuity::saveFile(int slot, Vector position, unsigned char *scrShotData,
|
|||
}
|
||||
doc.InsertEndChild(gems);
|
||||
|
||||
XMLElement *worldMap = doc.NewElement("WorldMap");
|
||||
XMLElement *wmap = doc.NewElement("WorldMap");
|
||||
{
|
||||
std::ostringstream os;
|
||||
for (size_t i = 0; i < dsq->continuity.worldMap.getNumWorldMapTiles(); i++)
|
||||
for (size_t i = 0; i < worldMap.worldMapTiles.size(); i++)
|
||||
{
|
||||
WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
|
||||
if (tile->revealed)
|
||||
const WorldMapTile& tile = worldMap.worldMapTiles[i];
|
||||
if (tile.revealed)
|
||||
{
|
||||
os << tile->index << " ";
|
||||
os << tile.index << " ";
|
||||
}
|
||||
}
|
||||
worldMap->SetAttribute("b", os.str().c_str());
|
||||
wmap->SetAttribute("b", os.str().c_str());
|
||||
|
||||
if (game->worldMapRender)
|
||||
{
|
||||
std::ostringstream os;
|
||||
for (size_t i = 0; i < dsq->continuity.worldMap.getNumWorldMapTiles(); i++)
|
||||
for (size_t i = 0; i < worldMap.worldMapTiles.size(); i++)
|
||||
{
|
||||
WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
|
||||
os << tile->index << " ";
|
||||
tile->dataToString(os);
|
||||
const WorldMapTile& tile = worldMap.worldMapTiles[i];
|
||||
os << tile.index << " ";
|
||||
tile.dataToString(os);
|
||||
os << " ";
|
||||
}
|
||||
worldMap->SetAttribute("va", os.str().c_str());
|
||||
wmap->SetAttribute("va", os.str().c_str());
|
||||
}
|
||||
}
|
||||
doc.InsertEndChild(worldMap);
|
||||
doc.InsertEndChild(wmap);
|
||||
|
||||
XMLElement *vox = doc.NewElement("VO");
|
||||
{
|
||||
|
@ -2895,24 +2897,24 @@ bool Continuity::loadFile(int slot)
|
|||
}
|
||||
}
|
||||
|
||||
XMLElement *worldMap = doc.FirstChildElement("WorldMap");
|
||||
if (worldMap)
|
||||
XMLElement *wmap = doc.FirstChildElement("WorldMap");
|
||||
if (wmap)
|
||||
{
|
||||
if (worldMap->Attribute("b"))
|
||||
if (wmap->Attribute("b"))
|
||||
{
|
||||
std::string s = worldMap->Attribute("b");
|
||||
std::string s = wmap->Attribute("b");
|
||||
std::istringstream is(s);
|
||||
int idx;
|
||||
while (is >> idx)
|
||||
{
|
||||
dsq->continuity.worldMap.revealMapIndex(idx);
|
||||
worldMap.revealMapIndex(idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (worldMap->Attribute("va") && dsq->continuity.worldMap.getNumWorldMapTiles())
|
||||
if (const char *va = wmap->Attribute("va"))
|
||||
{
|
||||
std::istringstream is(worldMap->Attribute("va"));
|
||||
SimpleIStringStream is(va, SimpleIStringStream::REUSE);
|
||||
|
||||
WorldMapTile dummy;
|
||||
|
||||
|
@ -2922,7 +2924,7 @@ bool Continuity::loadFile(int slot)
|
|||
|
||||
while (is >> idx)
|
||||
{
|
||||
WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(idx);
|
||||
WorldMapTile *tile = worldMap.getWorldMapTileByIndex(idx);
|
||||
|
||||
if (!tile)
|
||||
{
|
||||
|
@ -3343,24 +3345,28 @@ void Continuity::removeGemData(GemData *gemData)
|
|||
}
|
||||
}
|
||||
|
||||
GemData *Continuity::pickupGem(std::string name, bool effects)
|
||||
|
||||
|
||||
GemData *Continuity::pickupGem(const std::string& name, bool effects)
|
||||
{
|
||||
GemData g;
|
||||
g.name = name;
|
||||
g.mapName = game->sceneName;
|
||||
int sz = gems.size();
|
||||
|
||||
//HACK: (hacky) using effects to determine the starting position of the gem
|
||||
if (!effects)
|
||||
// HACK: First gem silently picked up ever with this texture needs special treatment
|
||||
bool isPlayerGem = !effects && gems.empty() && !nocasecmp(name, "Naija-Token");
|
||||
if(isPlayerGem)
|
||||
{
|
||||
g.pos = game->worldMapRender->getAvatarWorldMapPosition() + Vector(sz*16-64, -64);
|
||||
g.global = false; // the player is always on a map
|
||||
g.blink = true;
|
||||
}
|
||||
else
|
||||
g.isplayer = isPlayerGem;
|
||||
|
||||
Vector avatarPos = game->avatar->getPositionForMap();
|
||||
if(!game->worldMapRender->getWorldToPlayerTile(g.pos, avatarPos, g.global))
|
||||
{
|
||||
if (!gems.empty())
|
||||
g.pos = game->worldMapRender->getAvatarWorldMapPosition();
|
||||
else
|
||||
g.pos = Vector(0,0);
|
||||
debugLog("pickupgem failed, no worldmap tile for current map");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gems.push_back(g);
|
||||
|
@ -3372,21 +3378,32 @@ GemData *Continuity::pickupGem(std::string name, bool effects)
|
|||
GemGet *gg = new GemGet(g.name);
|
||||
game->addRenderObject(gg, LR_MINIMAP);
|
||||
|
||||
|
||||
|
||||
if (!getFlag("tokenHint"))
|
||||
{
|
||||
setFlag("tokenHint", 1);
|
||||
game->setControlHint(stringbank.get(4), false, false, false, 8);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// return the last one
|
||||
return &gems.back();
|
||||
}
|
||||
|
||||
void Continuity::setCurrentMap(const std::string& mapname)
|
||||
{
|
||||
worldMap.revealMap(mapname);
|
||||
|
||||
for (Gems::iterator i = this->gems.begin(); i != this->gems.end(); i++)
|
||||
{
|
||||
GemData& g = *i;
|
||||
if(g.isplayer)
|
||||
{
|
||||
g.mapName = mapname;
|
||||
game->worldMapRender->updateGem(&g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Continuity::entityDied(Entity *eDead)
|
||||
{
|
||||
if (statsAndAchievements)
|
||||
|
|
|
@ -162,9 +162,11 @@ public:
|
|||
typedef std::list<BeaconData> Beacons;
|
||||
Beacons beacons;
|
||||
|
||||
GemData *pickupGem(std::string name, bool effects = true);
|
||||
GemData *pickupGem(const std::string& name, bool effects = true);
|
||||
void removeGemData(GemData *gemData);
|
||||
|
||||
void setCurrentMap(const std::string& mapname);
|
||||
|
||||
|
||||
typedef std::vector<std::string> VoiceOversPlayed;
|
||||
VoiceOversPlayed voiceOversPlayed;
|
||||
|
|
|
@ -48,6 +48,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "Ingredient.h"
|
||||
#include "Beam.h"
|
||||
#include "Hair.h"
|
||||
#include "WorldMapRender.h"
|
||||
|
||||
|
||||
#ifdef BBGE_USE_GLM
|
||||
|
@ -2183,11 +2184,28 @@ void Game::createGradient()
|
|||
}
|
||||
}
|
||||
|
||||
bool Game::isInGameMenu()
|
||||
bool Game::isInGameMenu() const
|
||||
{
|
||||
return themenu->isInGameMenu();
|
||||
}
|
||||
|
||||
bool Game::isOnWorldMap() const
|
||||
{
|
||||
return worldMapRender->isOn();
|
||||
}
|
||||
|
||||
void Game::toggleWorldMap(bool on)
|
||||
{
|
||||
if (dsq->continuity.gems.empty())
|
||||
dsq->continuity.pickupGem("Naija-Token", false);
|
||||
worldMapRender->toggle(on);
|
||||
}
|
||||
|
||||
void Game::toggleWorldMap()
|
||||
{
|
||||
toggleWorldMap(!isOnWorldMap());
|
||||
}
|
||||
|
||||
bool Game::isValidTarget(Entity *e, Entity *me)
|
||||
{
|
||||
return (e != me && e->isNormalLayer() && e->isPresent() && e->getEntityType() == ET_ENEMY && e->isAvatarAttackTarget());
|
||||
|
@ -2443,14 +2461,6 @@ void Game::action(int id, int state, int source, InputDevice device)
|
|||
}
|
||||
}
|
||||
|
||||
void Game::toggleWorldMap()
|
||||
{
|
||||
if (worldMapRender)
|
||||
{
|
||||
worldMapRender->toggle(!worldMapRender->isOn());
|
||||
}
|
||||
}
|
||||
|
||||
void Game::applyState()
|
||||
{
|
||||
bool verbose = true;
|
||||
|
@ -2762,7 +2772,7 @@ void Game::applyState()
|
|||
|
||||
// ----------------- SCENE IS LOADED BELOW HERE -------------------
|
||||
|
||||
dsq->continuity.worldMap.revealMap(sceneName);
|
||||
dsq->continuity.setCurrentMap(sceneName);
|
||||
|
||||
if (verbose) debugLog("Adding Avatar");
|
||||
addRenderObject(avatar, LR_ENTITIES);
|
||||
|
@ -2794,9 +2804,9 @@ void Game::applyState()
|
|||
timerText->followCamera = 1;
|
||||
addRenderObject(timerText, LR_MINIMAP);
|
||||
|
||||
worldMapRender = 0;
|
||||
|
||||
worldMapRender = new WorldMapRender;
|
||||
worldMapRender = new WorldMapRender(dsq->continuity.worldMap);
|
||||
worldMapRender->init();
|
||||
worldMapRender->setCurrentMap(sceneName.c_str());
|
||||
addRenderObject(worldMapRender, LR_WORLDMAP);
|
||||
|
||||
sceneToLoad="";
|
||||
|
@ -4251,6 +4261,11 @@ bool Game::isControlHint()
|
|||
return controlHint_bg->alpha.x != 0;
|
||||
}
|
||||
|
||||
WorldMapTileContainer* Game::getCurrentWorldMapTile() const
|
||||
{
|
||||
return worldMapRender ? worldMapRender->getCurrentTile() : NULL;
|
||||
}
|
||||
|
||||
bool Game::trace(Vector start, Vector target)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -65,6 +65,7 @@ class ToolTip;
|
|||
class Ingredient;
|
||||
class ManaBall;
|
||||
class Beam;
|
||||
class WorldMapTileContainer;
|
||||
|
||||
#include "Path.h"
|
||||
|
||||
|
@ -137,8 +138,6 @@ public:
|
|||
void clearGrid(int v = 0);
|
||||
void clearDynamicGrid(unsigned char maskbyte = OT_MASK_BLACK);
|
||||
|
||||
void toggleWorldMap();
|
||||
|
||||
void action(int id, int state, int source, InputDevice device);
|
||||
|
||||
InGameMenu *getInGameMenu() { return themenu; }
|
||||
|
@ -254,7 +253,10 @@ public:
|
|||
SceneEditor sceneEditor;
|
||||
bool isSceneEditorActive() {return sceneEditor.isOn();}
|
||||
|
||||
bool isInGameMenu();
|
||||
bool isInGameMenu() const;
|
||||
bool isOnWorldMap() const;
|
||||
void toggleWorldMap(bool on);
|
||||
void toggleWorldMap(); // on or off
|
||||
|
||||
typedef std::vector<EntityClass> EntityTypeList;
|
||||
EntityTypeList entityTypeList;
|
||||
|
@ -313,6 +315,7 @@ public:
|
|||
int getNumberOfEntitiesNamed(const std::string &name);
|
||||
MiniMapRender *miniMapRender;
|
||||
WorldMapRender *worldMapRender;
|
||||
WorldMapTileContainer *getCurrentWorldMapTile() const;
|
||||
|
||||
bool loadingScene;
|
||||
bool doScreenTrans;
|
||||
|
|
|
@ -21,13 +21,15 @@ struct EmoteData
|
|||
|
||||
struct GemData
|
||||
{
|
||||
GemData() { canMove=false; blink = false; }
|
||||
GemData() { canMove=false; blink = false; global = false; isplayer = false; }
|
||||
std::string name;
|
||||
std::string userString;
|
||||
std::string mapName;
|
||||
Vector pos;
|
||||
bool canMove;
|
||||
bool blink; // not saved
|
||||
bool global; // local gems use their parent container's coordinate system, global gems are placed directly on the map screen
|
||||
bool isplayer;
|
||||
};
|
||||
|
||||
struct BeaconData
|
||||
|
|
|
@ -23,14 +23,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "GameEnums.h"
|
||||
#include "GameStructs.h"
|
||||
#include "../BBGE/Quad.h"
|
||||
#include "Quad.h"
|
||||
#include "ActionMapper.h"
|
||||
#include "VertexBuffer.h"
|
||||
|
||||
class GemMover;
|
||||
|
||||
struct MinimapIcon;
|
||||
struct WorldMapTile;
|
||||
struct GemData;
|
||||
class AquariaMenuItem;
|
||||
class BitmapText;
|
||||
|
||||
|
@ -93,43 +91,6 @@ public:
|
|||
static bool setMaxHealthMarkerTex(const std::string& name);
|
||||
};
|
||||
|
||||
class WorldMapRender : public RenderObject, public ActionMapper
|
||||
{
|
||||
public:
|
||||
WorldMapRender();
|
||||
void destroy();
|
||||
void toggle(bool on);
|
||||
bool isOn();
|
||||
Vector getAvatarWorldMapPosition();
|
||||
Vector getWorldToTile(WorldMapTile *tile, Vector position, bool fromCenter, bool tilePos);
|
||||
void setProperTileColor(WorldMapTile *tile);
|
||||
void action(int id, int state, int source, InputDevice device);
|
||||
GemMover* addGem(GemData *gemData);
|
||||
void bindInput();
|
||||
void createGemHint(const std::string &gfx);
|
||||
void addAllGems();
|
||||
void fixGems();
|
||||
void removeGem(GemMover *gemMover);
|
||||
void onToggleHelpScreen();
|
||||
bool isCursorOffHud();
|
||||
|
||||
protected:
|
||||
Quad *addHintQuad1, *addHintQuad2;
|
||||
AquariaMenuItem *helpButton;
|
||||
float doubleClickTimer;
|
||||
float inputDelay;
|
||||
BitmapText *areaLabel, *areaLabel2, *areaLabel3;
|
||||
WorldMapTile *originalActiveTile;
|
||||
void setVis(WorldMapTile *tile);
|
||||
void clearVis(WorldMapTile *tile);
|
||||
bool on;
|
||||
void onUpdate(float dt);
|
||||
unsigned char *savedTexData;
|
||||
bool mb;
|
||||
Vector lastMousePosition; // See FIXME in WorldMapRender.cpp --achurch
|
||||
void updateEditor();
|
||||
};
|
||||
|
||||
class PathRender : public RenderObject
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -376,7 +376,7 @@ void MiniMapRender::onUpdate(float dt)
|
|||
_isCursorIn = false;
|
||||
if (alpha.x == 1)
|
||||
{
|
||||
if (!game->isInGameMenu() && (!game->isPaused() || (game->isPaused() && game->worldMapRender->isOn())))
|
||||
if (!game->isInGameMenu() && (!game->isPaused() || (game->isPaused() && game->isOnWorldMap())))
|
||||
{
|
||||
if (isCursorInButtons())
|
||||
{
|
||||
|
@ -397,7 +397,7 @@ void MiniMapRender::onUpdate(float dt)
|
|||
|
||||
bool btn=false;
|
||||
|
||||
if (!game->worldMapRender->isOn())
|
||||
if (!game->isOnWorldMap())
|
||||
{
|
||||
for (size_t i = 0; i < buttons.size(); i++)
|
||||
{
|
||||
|
@ -421,20 +421,16 @@ void MiniMapRender::onUpdate(float dt)
|
|||
|
||||
if (!btn && !radarHide && (!dsq->mod.isActive() || dsq->mod.hasWorldMap()))
|
||||
{
|
||||
if (game->worldMapRender->isOn())
|
||||
if (game->isOnWorldMap())
|
||||
{
|
||||
game->worldMapRender->toggle(false);
|
||||
game->toggleWorldMap(false);
|
||||
clickEffect(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (doubleClickDelay > 0 && !core->isStateJumpPending())
|
||||
{
|
||||
|
||||
if (dsq->continuity.gems.empty())
|
||||
dsq->continuity.pickupGem("Naija-Token");
|
||||
|
||||
game->worldMapRender->toggle(true);
|
||||
game->toggleWorldMap(true);
|
||||
|
||||
clickEffect(0);
|
||||
|
||||
|
|
|
@ -2357,7 +2357,7 @@ void SceneEditor::toggle(bool on)
|
|||
if (core->getNestedMains() > 1) return;
|
||||
if (game->isInGameMenu()) return;
|
||||
if (!on && editType == ET_SELECTENTITY) return;
|
||||
if (game->worldMapRender && game->worldMapRender->isOn()) return;
|
||||
if (game->isOnWorldMap()) return;
|
||||
this->on = on;
|
||||
autoSaveTimer = 0;
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ extern "C" {
|
|||
#include "Shader.h"
|
||||
#include "ActionMapper.h"
|
||||
#include "QuadGrid.h"
|
||||
#include "WorldMapRender.h"
|
||||
|
||||
|
||||
#include "MathFunctions.h"
|
||||
|
@ -8855,16 +8856,15 @@ luaFunc(setGemPosition)
|
|||
Vector pos(lua_tonumber(L, 2), lua_tonumber(L, 3));
|
||||
bool result = false;
|
||||
|
||||
WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(mapname);
|
||||
if(tile)
|
||||
WorldMapTileContainer *tc = game->worldMapRender->getTileByName(mapname.c_str());
|
||||
if(tc)
|
||||
{
|
||||
pos = game->worldMapRender->getWorldToTile(tile, pos, true, true);
|
||||
if(gemId < dsq->continuity.gems.size())
|
||||
{
|
||||
Continuity::Gems::iterator it = dsq->continuity.gems.begin();
|
||||
std::advance(it, gemId);
|
||||
GemData& gem = *it;
|
||||
gem.pos = pos;
|
||||
gem.pos = gem.global ? tc->worldPosToMapPos(pos) : tc->worldPosToTilePos(pos);
|
||||
gem.mapName = mapname;
|
||||
result = true;
|
||||
}
|
||||
|
@ -8925,9 +8925,7 @@ luaFunc(removeGem)
|
|||
{
|
||||
Continuity::Gems::iterator it = dsq->continuity.gems.begin();
|
||||
std::advance(it, gemId);
|
||||
dsq->continuity.removeGemData(&(*it));
|
||||
if(game->worldMapRender->isOn())
|
||||
game->worldMapRender->fixGems();
|
||||
game->worldMapRender->removeGem(&(*it));
|
||||
}
|
||||
luaReturnNil();
|
||||
}
|
||||
|
|
|
@ -439,10 +439,10 @@ void StatsAndAchievements::EvaluateAchievement( Achievement &achievement )
|
|||
{
|
||||
// check world map data somehow
|
||||
bool hasAllMap = true;
|
||||
for (size_t i = 0; i < dsq->continuity.worldMap.getNumWorldMapTiles(); i++)
|
||||
for (size_t i = 0; i < dsq->continuity.worldMap.worldMapTiles.size(); i++)
|
||||
{
|
||||
WorldMapTile *tile = dsq->continuity.worldMap.getWorldMapTile(i);
|
||||
if (!tile->revealed && (nocasecmp(tile->name, "thirteenlair") != 0)) {
|
||||
const WorldMapTile& tile = dsq->continuity.worldMap.worldMapTiles[i];
|
||||
if (!tile.revealed && (nocasecmp(tile.name, "thirteenlair") != 0)) {
|
||||
|
||||
hasAllMap = false;
|
||||
break;
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#include <string>
|
||||
#include "Vector.h"
|
||||
#include "GameEnums.h"
|
||||
#include "Image.h"
|
||||
#include "Refcounted.h"
|
||||
#include "Texture.h"
|
||||
#include "SimpleIStringStream.h"
|
||||
|
||||
#define MAPVIS_SUBDIV 64
|
||||
|
||||
|
@ -15,21 +19,23 @@ struct WorldMapTile
|
|||
~WorldMapTile();
|
||||
|
||||
void markVisited(int left, int top, int right, int bottom);
|
||||
void dataToString(std::ostringstream &os);
|
||||
void stringToData(std::istringstream &is);
|
||||
const unsigned char *getData() const {return data;}
|
||||
void dataToString(std::ostringstream &os) const;
|
||||
void stringToData(SimpleIStringStream &is);
|
||||
|
||||
ImageData generateAlphaImage(size_t w, size_t h); // free() data when no longer needed
|
||||
bool updateDiscoveredTex();
|
||||
|
||||
std::string name;
|
||||
Vector gridPos;
|
||||
float scale, scale2;
|
||||
bool revealed, prerevealed;
|
||||
bool revealed, prerevealed, dirty;
|
||||
int layer, index;
|
||||
int stringIndex;
|
||||
|
||||
Quad *q;
|
||||
|
||||
protected:
|
||||
unsigned char *data;
|
||||
Array2d<unsigned char> visited;
|
||||
|
||||
CountedPtr<Texture> originalTex, generatedTex;
|
||||
};
|
||||
|
||||
struct WorldMap
|
||||
|
@ -37,12 +43,8 @@ struct WorldMap
|
|||
WorldMap();
|
||||
void load();
|
||||
void save();
|
||||
void hideMap();
|
||||
void revealMap(const std::string &name);
|
||||
WorldMapTile *getWorldMapTile(const std::string &name);
|
||||
size_t getNumWorldMapTiles();
|
||||
WorldMapTile *getWorldMapTile(size_t index);
|
||||
|
||||
WorldMapTile *getWorldMapTileByIndex(int index);
|
||||
void revealMapIndex(int index);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
90
Aquaria/WorldMapRender.h
Normal file
90
Aquaria/WorldMapRender.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#ifndef WORLDMAPRENDER_H
|
||||
#define WORLDMAPRENDER_H
|
||||
|
||||
#include "Quad.h"
|
||||
#include "ActionMapper.h"
|
||||
|
||||
class GemMover;
|
||||
struct WorldMapTile;
|
||||
struct GemData;
|
||||
class BitmapText;
|
||||
class AquariaMenuItem;
|
||||
struct WorldMap;
|
||||
class Gradient;
|
||||
|
||||
|
||||
// This is used for properly positioning the tile and gems on top of it.
|
||||
// Affected by scale2 -- gems also move with scale2.
|
||||
class WorldMapTileContainer : public RenderObject
|
||||
{
|
||||
public:
|
||||
WorldMapTileContainer(WorldMapTile& tile);
|
||||
virtual ~WorldMapTileContainer();
|
||||
|
||||
virtual void onUpdate(float dt) OVERRIDE;
|
||||
|
||||
void refresh(); // Called whenever we need to prepare for rendering
|
||||
|
||||
void removeGems();
|
||||
void addGem(GemMover *gem);
|
||||
bool removeGem(GemMover *gem);
|
||||
GemMover *removeGem(const GemData *gem);
|
||||
GemMover *getGem(const GemData *gemData) const;
|
||||
void updateGems();
|
||||
|
||||
Vector worldPosToTilePos(const Vector& p) const;
|
||||
Vector worldPosToMapPos(const Vector& p) const;
|
||||
|
||||
WorldMapTile& tile;
|
||||
Quad q; // The actual world map tile, additionally affected by scale (NOT scale2), and always at (0, 0)
|
||||
std::vector<GemMover*> gems;
|
||||
};
|
||||
|
||||
class WorldMapRender : public RenderObject, public ActionMapper
|
||||
{
|
||||
public:
|
||||
WorldMapRender(WorldMap& wm);
|
||||
virtual ~WorldMapRender();
|
||||
void init();
|
||||
void toggle(bool on);
|
||||
bool isOn();
|
||||
void setProperTileColor(WorldMapTileContainer& wt);
|
||||
void action(int id, int state, int source, InputDevice device);
|
||||
GemMover* addGem(GemData *gemData);
|
||||
void updateGem(const GemData *gemData);
|
||||
void removeGem(GemMover *gemMover);
|
||||
void removeGem(const GemData *gemData);
|
||||
GemMover *getGem(const GemData *gemData) const;
|
||||
WorldMapTileContainer *getTileWithGem(const GemData *gemData) const;
|
||||
void bindInput();
|
||||
void createGemHint(const std::string &gfx);
|
||||
void onToggleHelpScreen();
|
||||
bool isCursorOffHud();
|
||||
void updateAllTilesColor();
|
||||
WorldMapTileContainer *getCurrentTile() { return playerTile; }
|
||||
bool getWorldToPlayerTile(Vector& dst, const Vector& pos, bool global) const;
|
||||
WorldMapTileContainer *getTileByName(const char *name) const;
|
||||
WorldMapTileContainer * setCurrentMap(const char *mapname);
|
||||
|
||||
protected:
|
||||
Quad *addHintQuad1, *addHintQuad2;
|
||||
AquariaMenuItem *helpButton;
|
||||
float doubleClickTimer;
|
||||
float inputDelay;
|
||||
BitmapText *areaLabel, *areaLabel2, *areaLabel3;
|
||||
WorldMapTileContainer *playerTile; // tile where the player is located
|
||||
WorldMapTileContainer *selectedTile; // starts out == playerTile but changed on selection
|
||||
bool on;
|
||||
void onUpdate(float dt);
|
||||
bool mb, wasEditorSaveDown;
|
||||
Vector lastMousePosition; // See FIXME in WorldMapRender.cpp --achurch
|
||||
void updateEditor();
|
||||
std::vector<WorldMapTileContainer*> tiles;
|
||||
WorldMap& worldmap;
|
||||
Quad *tophud;
|
||||
Gradient *underlay;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "DSQ.h"
|
||||
#include "ttvfs_stdio.h"
|
||||
#include <fstream>
|
||||
#include "stb_image_resize.h"
|
||||
|
||||
#if MAPVIS_SUBDIV % 8 != 0
|
||||
#error MAPVIS_SUBDIV must be a multiple of 8
|
||||
|
@ -39,23 +40,19 @@ WorldMapTile::WorldMapTile()
|
|||
scale = scale2 = 1;
|
||||
layer = 0;
|
||||
index = -1;
|
||||
data = 0;
|
||||
q = 0;
|
||||
stringIndex = 0;
|
||||
dirty = true;
|
||||
generatedTex = new Texture;
|
||||
}
|
||||
|
||||
WorldMapTile::~WorldMapTile()
|
||||
{
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void WorldMapTile::markVisited(int left, int top, int right, int bottom)
|
||||
{
|
||||
if (data == 0)
|
||||
{
|
||||
data = new unsigned char[dataSize];
|
||||
memset(data, 0, dataSize);
|
||||
}
|
||||
if(visited.empty())
|
||||
visited.init(rowSize, MAPVIS_SUBDIV);
|
||||
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
|
@ -66,19 +63,32 @@ void WorldMapTile::markVisited(int left, int top, int right, int bottom)
|
|||
if (bottom > MAPVIS_SUBDIV - 1)
|
||||
bottom = MAPVIS_SUBDIV - 1;
|
||||
|
||||
// Accumulate bits that were changed
|
||||
unsigned changed = 0;
|
||||
|
||||
for (int y = top; y <= bottom; y++)
|
||||
{
|
||||
unsigned char *row = visited.row(y);
|
||||
for (int x = left; x <= right; x++)
|
||||
{
|
||||
data[y*rowSize + x/8] |= 1 << (x%8);
|
||||
unsigned char& val = row[x/8];
|
||||
unsigned char add = 1 << (x%8);
|
||||
changed |= (val ^ add) & add;
|
||||
val |= add;
|
||||
}
|
||||
}
|
||||
|
||||
if(changed)
|
||||
{
|
||||
//debugLog("worldmap[" + name + "] visited something new");
|
||||
dirty = true; // Only mark as dirty if we've uncovered something new
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the data array to string format for saving.
|
||||
void WorldMapTile::dataToString(std::ostringstream &os)
|
||||
void WorldMapTile::dataToString(std::ostringstream &os) const
|
||||
{
|
||||
if (!data)
|
||||
if (visited.empty())
|
||||
{
|
||||
os << "0 0";
|
||||
return;
|
||||
|
@ -88,6 +98,7 @@ void WorldMapTile::dataToString(std::ostringstream &os)
|
|||
|
||||
char *outbuf = new char[((dataSize+2)/3)*4 + 1];
|
||||
char *ptr = outbuf;
|
||||
const unsigned char * const data = visited.data();
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i+3 <= dataSize; i += 3, ptr += 4)
|
||||
|
@ -121,18 +132,21 @@ void WorldMapTile::dataToString(std::ostringstream &os)
|
|||
|
||||
unsigned int count = 0;
|
||||
std::ostringstream tempStream;
|
||||
unsigned char *ptr = data;
|
||||
for (unsigned int y = 0; y < MAPVIS_SUBDIV; y++, ptr += rowSize)
|
||||
|
||||
for (unsigned int y = 0; y < MAPVIS_SUBDIV; y++)
|
||||
{
|
||||
const unsigned char *row = visited.row(y);
|
||||
for (unsigned int x = 0; x < MAPVIS_SUBDIV; x += 8)
|
||||
{
|
||||
unsigned char dataByte = ptr[x/8];
|
||||
for (unsigned int x2 = 0; x2 < 8; x2++)
|
||||
if(unsigned char dataByte = row[x/8])
|
||||
{
|
||||
if (dataByte & (1 << x2))
|
||||
for (unsigned int x2 = 0; x2 < 8; x2++)
|
||||
{
|
||||
tempStream << " " << (x+x2) << " " << y;
|
||||
count++;
|
||||
if (dataByte & (1 << x2))
|
||||
{
|
||||
tempStream << " " << (x+x2) << " " << y;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,10 +158,10 @@ void WorldMapTile::dataToString(std::ostringstream &os)
|
|||
}
|
||||
|
||||
// Parse a string from a save file and store in the data array.
|
||||
void WorldMapTile::stringToData(std::istringstream &is)
|
||||
void WorldMapTile::stringToData(SimpleIStringStream &is)
|
||||
{
|
||||
delete[] data;
|
||||
data = 0;
|
||||
dirty = true;
|
||||
visited.init(rowSize, MAPVIS_SUBDIV);
|
||||
|
||||
int subdiv;
|
||||
std::string countOrType;
|
||||
|
@ -182,15 +196,13 @@ void WorldMapTile::stringToData(std::istringstream &is)
|
|||
return;
|
||||
}
|
||||
|
||||
data = new unsigned char[dataSize];
|
||||
memset(data, 0, dataSize);
|
||||
if (countOrType == "b") // Raw bitmap (base64-encoded)
|
||||
{
|
||||
std::string encodedData = "";
|
||||
is >> encodedData;
|
||||
const char *in = encodedData.c_str();
|
||||
unsigned char *out = data;
|
||||
unsigned char * const top = data + dataSize;
|
||||
unsigned char *out = visited.data();
|
||||
unsigned char * const top = out + dataSize;
|
||||
while (in[0] != 0 && in[1] != 0 && out < top)
|
||||
{
|
||||
unsigned char ch0, ch1, ch2, ch3;
|
||||
|
@ -222,6 +234,8 @@ void WorldMapTile::stringToData(std::istringstream &is)
|
|||
}
|
||||
else // List of coordinate pairs
|
||||
{
|
||||
visited.fill(0);
|
||||
|
||||
int count = 0;
|
||||
std::istringstream is2(countOrType);
|
||||
is2 >> count;
|
||||
|
@ -231,11 +245,88 @@ void WorldMapTile::stringToData(std::istringstream &is)
|
|||
int x, y;
|
||||
is >> x >> y;
|
||||
if (x >= 0 && x < MAPVIS_SUBDIV && y >= 0 && y < MAPVIS_SUBDIV)
|
||||
data[y*rowSize + x/8] |= 1 << (x%8);
|
||||
visited(x/8, y) |= 1 << (x%8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageData WorldMapTile::generateAlphaImage(size_t w, size_t h)
|
||||
{
|
||||
ImageData ret = {0};
|
||||
if(visited.empty())
|
||||
return ret;
|
||||
|
||||
// stbir can't deal with 1-bit images, so let's make a 1-channel black or white image first
|
||||
Array2d<unsigned char> tmp(MAPVIS_SUBDIV, MAPVIS_SUBDIV);
|
||||
unsigned char *dst = tmp.data();
|
||||
for(size_t y = 0; y < MAPVIS_SUBDIV; ++y)
|
||||
{
|
||||
const unsigned char * const src = visited.row(y);
|
||||
for(size_t x = 0; x < MAPVIS_SUBDIV; x += 8)
|
||||
{
|
||||
unsigned c = src[x/8];
|
||||
for(size_t bit = 0; bit < 8; ++bit)
|
||||
*dst++ = (c & (1 << bit)) ? 0xff : 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
os << "worldmap[" << name << "] Generate alpha from vis data, resize to (" << w << ", " << h << ")";
|
||||
debugLog(os.str());
|
||||
|
||||
ret.pixels = (unsigned char*)malloc(w * h);
|
||||
if(ret.pixels)
|
||||
{
|
||||
ret.w = w;
|
||||
ret.h = h;
|
||||
ret.channels = 1;
|
||||
|
||||
stbir_resize_uint8_generic(
|
||||
tmp.data(), MAPVIS_SUBDIV, MAPVIS_SUBDIV, 0,
|
||||
ret.pixels, w, h, 0,
|
||||
1, STBIR_ALPHA_CHANNEL_NONE, 0,
|
||||
STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, NULL
|
||||
);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If there was a shader to use one texture for colors and another for alpha this wouldn't be needed
|
||||
// TODO: If we ever get this far, do this with shaders. Software resize sucks so bad...
|
||||
bool WorldMapTile::updateDiscoveredTex()
|
||||
{
|
||||
int w, h;
|
||||
size_t sz;
|
||||
const unsigned char * texbuf = originalTex->getBufferAndSize(&w, &h, &sz);
|
||||
std::vector<unsigned char> tmp(sz);
|
||||
{
|
||||
const ImageData aimg = generateAlphaImage(w, h);
|
||||
if(!aimg.pixels)
|
||||
return false;
|
||||
const unsigned char *ap = aimg.pixels;
|
||||
unsigned char *dst = &tmp[0];
|
||||
for(size_t i = 0; i < sz; i += 4)
|
||||
{
|
||||
*dst++ = *texbuf++;
|
||||
*dst++ = *texbuf++;
|
||||
*dst++ = *texbuf++;
|
||||
*dst++ = (*texbuf++ * *ap++) >> 8; // inaccurate fixed-point multiplication; ends up 0xfe as the highest possible value but whatev
|
||||
}
|
||||
free(aimg.pixels);
|
||||
}
|
||||
|
||||
ImageData up;
|
||||
up.pixels = &tmp[0];
|
||||
up.channels = 4;
|
||||
up.w = w;
|
||||
up.h = h;
|
||||
|
||||
generatedTex->upload(up, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
WorldMap::WorldMap()
|
||||
{
|
||||
|
@ -338,26 +429,3 @@ WorldMapTile *WorldMap::getWorldMapTileByIndex(int index)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WorldMap::hideMap()
|
||||
{
|
||||
for (size_t i = 0; i < worldMapTiles.size(); i++)
|
||||
{
|
||||
worldMapTiles[i].revealed = false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t WorldMap::getNumWorldMapTiles()
|
||||
{
|
||||
return worldMapTiles.size();
|
||||
}
|
||||
|
||||
WorldMapTile *WorldMap::getWorldMapTile(size_t index)
|
||||
{
|
||||
if (index >= worldMapTiles.size()) return 0;
|
||||
|
||||
return &worldMapTiles[index];
|
||||
}
|
||||
|
||||
|
|
|
@ -100,11 +100,7 @@ void Texture::unload()
|
|||
glDeleteTextures(1, &gltexid);
|
||||
gltexid = 0;
|
||||
}
|
||||
if(_pixbuf)
|
||||
{
|
||||
free(_pixbuf);
|
||||
_pixbuf = NULL;
|
||||
}
|
||||
_freePixbuf();
|
||||
}
|
||||
|
||||
size_t Texture::sizeBytes() const
|
||||
|
@ -112,6 +108,26 @@ size_t Texture::sizeBytes() const
|
|||
return size_t(width) * size_t(height) * 4;
|
||||
}
|
||||
|
||||
bool Texture::uploadAndKeep(ImageData& img, bool mipmap)
|
||||
{
|
||||
bool ok = upload(img, mipmap); // this also clears pixbuf
|
||||
if(ok)
|
||||
{
|
||||
_pixbuf = img.pixels;
|
||||
img.pixels = NULL;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void Texture::_freePixbuf()
|
||||
{
|
||||
if(_pixbuf)
|
||||
{
|
||||
free(_pixbuf);
|
||||
_pixbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::apply() const
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, gltexid);
|
||||
|
@ -223,6 +239,8 @@ bool Texture::upload(const ImageData& img, bool mipmap)
|
|||
|
||||
width = img.w;
|
||||
height = img.h;
|
||||
_mipmap = mipmap;
|
||||
_freePixbuf();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,10 +70,12 @@ public:
|
|||
|
||||
std::string name, filename;
|
||||
bool upload(const ImageData& img, bool mipmap);
|
||||
bool uploadAndKeep(ImageData& img, bool mipmap);
|
||||
|
||||
bool success;
|
||||
|
||||
protected:
|
||||
void _freePixbuf();
|
||||
|
||||
int ow, oh;
|
||||
bool _mipmap;
|
||||
|
|
Loading…
Reference in a new issue