render improvments using some cache

This commit is contained in:
Eduardo Bart 2011-08-30 20:39:14 -03:00
parent 27ccb472d2
commit 4d10b0dd49
13 changed files with 211 additions and 102 deletions

View File

@ -28,7 +28,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
SET(CXX_WARNS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-unused-variable -Wno-switch") SET(CXX_WARNS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-unused-variable -Wno-switch")
SET(CMAKE_CXX_FLAGS "-std=c++0x -pipe ${CXX_WARNS}") SET(CMAKE_CXX_FLAGS "-std=c++0x -pipe ${CXX_WARNS}")
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -ggdb3 -fno-inline") SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -ggdb3 -fno-inline")
SET(CMAKE_CXX_FLAGS_RELEASE "-O2") SET(CMAKE_CXX_FLAGS_RELEASE "-O2 -rdynamic")
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -g -fno-inline") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -g -fno-inline")
ENDIF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_COMPILER_IS_GNUCXX)

View File

@ -22,7 +22,7 @@ end
local function destroyMainInterface() local function destroyMainInterface()
if gameUi then if Game.gameUi then
Game.gameUi:destroy() Game.gameUi:destroy()
Game.gameUi = nil Game.gameUi = nil
end end

View File

@ -58,10 +58,6 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/any.hpp> #include <boost/any.hpp>
#ifndef nullptr
#define nullptr NULL
#endif
// global constants // global constants
#include "const.h" #include "const.h"

View File

@ -37,7 +37,7 @@ public:
virtual void enableBilinearFilter(); virtual void enableBilinearFilter();
/// Get OpenGL texture id /// Get OpenGL texture id
virtual uint getId() const { return m_textureId; } uint getId() const { return m_textureId; }
/// Copy pixels from OpenGL texture /// Copy pixels from OpenGL texture
std::vector<uint8> getPixels(); std::vector<uint8> getPixels();

View File

@ -42,4 +42,8 @@ typedef int8_t int8;
typedef std::function<void()> SimpleCallback; typedef std::function<void()> SimpleCallback;
typedef std::function<bool()> BooleanCallback; typedef std::function<bool()> BooleanCallback;
#ifndef nullptr
#define nullptr NULL
#endif
#endif #endif

View File

@ -115,15 +115,15 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
thingAttributes.speed = Fw::getU16(fin); thingAttributes.speed = Fw::getU16(fin);
thingAttributes.group = Otc::ThingGroundGroup; thingAttributes.group = Otc::ThingGroundGroup;
break; break;
case 0x01: // All OnTop case 0x01: // Must be drawn behind creatures foot, e.g.: ground, carpets, borders...
thingAttributes.alwaysOnTop = true; thingAttributes.alwaysOnTop = true;
thingAttributes.alwaysOnTopOrder = 1; thingAttributes.alwaysOnTopOrder = 1;
break; break;
case 0x02: // Can walk trough (open doors, arces, bug pen fence) case 0x02: // Must be drawn over tile items, e.g.: trees, walls, stairs, rocks, statues...
thingAttributes.alwaysOnTop = true; thingAttributes.alwaysOnTop = true;
thingAttributes.alwaysOnTopOrder = 2; thingAttributes.alwaysOnTopOrder = 2;
break; break;
case 0x03: // Can walk trough (arces) case 0x03: // Can walk trough and must be drawn over creatures, e.g: open doors, arces, bug pen fence
thingAttributes.alwaysOnTop = true; thingAttributes.alwaysOnTop = true;
thingAttributes.alwaysOnTopOrder = 3; thingAttributes.alwaysOnTopOrder = 3;
break; break;
@ -133,7 +133,7 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
case 0x05: // Stackable case 0x05: // Stackable
thingAttributes.stackable = true; thingAttributes.stackable = true;
break; break;
case 0x06: // Unknown case 0x06: // Unknown, some corpses, stairs, even ground ????
break; break;
case 0x07: // Useable case 0x07: // Useable
thingAttributes.useable = true; thingAttributes.useable = true;
@ -167,7 +167,7 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
case 0x0F: // Blocks pathfind algorithms (monsters) case 0x0F: // Blocks pathfind algorithms (monsters)
thingAttributes.blockPathFind = true; thingAttributes.blockPathFind = true;
break; break;
case 0x10: // Blocks monster movement (flowers, parcels etc) case 0x10: // Pickupable
thingAttributes.pickupable = true; thingAttributes.pickupable = true;
break; break;
case 0x11: // Hangable objects (wallpaper etc) case 0x11: // Hangable objects (wallpaper etc)
@ -186,9 +186,10 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
thingAttributes.lightLevel = Fw::getU16(fin); thingAttributes.lightLevel = Fw::getU16(fin);
thingAttributes.lightColor = Fw::getU16(fin); thingAttributes.lightColor = Fw::getU16(fin);
break; break;
case 0x16: case 0x16: // Unknown, just a few monuments
break; break;
case 0x17: // Changes floor case 0x17: // Changes floor, e.g: holes
thingAttributes.changesFloor = true;
break; break;
case 0x18: // Thing must be drawed with offset case 0x18: // Thing must be drawed with offset
thingAttributes.hasHeight = true; thingAttributes.hasHeight = true;
@ -200,7 +201,7 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
thingAttributes.drawNextOffset = Fw::getU8(fin); thingAttributes.drawNextOffset = Fw::getU8(fin);
Fw::getU8(fin); Fw::getU8(fin);
break; break;
case 0x1A: case 0x1A: // Unknown, some corpses
//thingAttributes.hasHeight = true; //thingAttributes.hasHeight = true;
break; break;
case 0x1B: case 0x1B:
@ -213,12 +214,12 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes
if(Fw::getU16(fin) == 1112) if(Fw::getU16(fin) == 1112)
thingAttributes.readable = true; thingAttributes.readable = true;
break; break;
case 0x1E: case 0x1E: // Unknown, only grounds
break; break;
case 0x1F: case 0x1F: // Unknown, borders that cant walk into?
thingAttributes.lookThrough = true; thingAttributes.lookThrough = true;
break; break;
case 0x20: case 0x20: // Unknown
break; break;
default: default:
throw std::runtime_error(Fw::mkstr("unknown .dat byte code: 0x", std::hex, (int)opt)); throw std::runtime_error(Fw::mkstr("unknown .dat byte code: 0x", std::hex, (int)opt));

View File

@ -37,102 +37,141 @@ void Map::draw(const Rect& rect)
g_graphics.bindColor(Fw::white); g_graphics.bindColor(Fw::white);
m_framebuffer->bind(); m_framebuffer->bind();
LocalPlayerPtr player = g_game.getLocalPlayer(); LocalPlayerPtr localPlayer = g_game.getLocalPlayer();
int walkOffsetX = player->getWalkOffsetX(); int walkOffsetX = localPlayer->getWalkOffsetX();
int walkOffsetY = player->getWalkOffsetY(); int walkOffsetY = localPlayer->getWalkOffsetY();
// player is above 7 for(int z = NUM_Z_TILES - 1; z >= 0; --z) {
if(m_visibleTiles.size() == 0)
continue;
int drawFloorStop = 0; int zdif = m_centralPosition.z - z;
if(m_centralPosition.z <= 7) { for(int step = 0; step < 2; ++step) {
for(const TilePtr& tile : m_visibleTiles[z]) {
// player pos it 8-6. check if we can draw upper floors. int x = (7 + (tile->getPosition().x - m_centralPosition.x) - zdif) * NUM_TILE_PIXELS;
int y = (5 + (tile->getPosition().y - m_centralPosition.y) - zdif) * NUM_TILE_PIXELS;
tile->draw(x - walkOffsetX, y - walkOffsetY, step);
// if there is a window on north, east, south or west
//Position direction[4] = {Position(0, -1, 0), Position(1, 0, 0), Position(0, 1, 0), Position(-1, 0, 0)};
for(int d = 0; d < 4; ++d) {
/*if(const TilePtr& tile = m_tiles[playerPos+direction[d]]) {
const ThingAttributes& thingAttributes = thing->getAttributes();
if(thingAttributes.lookThrough) {
drawFloorStop = playerPos.z - 1;
break;
}
}*/
}
// if we have something covering us, dont show floors above.
for(int jz = 6; jz >= 0; --jz) {
Position coverPos = Position(m_centralPosition.x+(7-jz)-1, m_centralPosition.y+(7-jz)-1, jz);
if(const TilePtr& tile = m_tiles[coverPos]) {
if(tile->getStackSize(3) > 0 && jz < m_centralPosition.z) {
drawFloorStop = jz;
break;
}
}
}
for(int iz = 7; iz > 0; --iz) {
if(iz == drawFloorStop)
break;
// +1 in draws cause 64x64 items may affect view.
for(int step = 0; step < 2; ++step) {
for(int ix = -8+(m_centralPosition.z-iz); ix < + 8+7; ++ix) {
for(int iy = -6+(m_centralPosition.z-iz); iy < + 6+7; ++iy) {
Position itemPos = Position(m_centralPosition.x + ix, m_centralPosition.y + iy, iz);
if(const TilePtr& tile = m_tiles[itemPos])
tile->draw((ix + 7 - (m_centralPosition.z-iz))*32 - walkOffsetX, (iy + 5 - (m_centralPosition.z-iz))*32 - walkOffsetY, step);
}
}
} }
} }
} }
// debug draws
g_graphics.bindColor(Fw::red);
g_graphics.drawBoundingRect(Rect(7*32, 5*32, 32, 32));
m_framebuffer->unbind(); m_framebuffer->unbind();
g_graphics.bindColor(Fw::white); g_graphics.bindColor(Fw::white);
m_framebuffer->draw(rect); m_framebuffer->draw(rect);
// calculate stretch factor // calculate stretch factor
float horizontalStretchFactor = (rect.width() - rect.x()) / (float)(15*32); float horizontalStretchFactor = rect.width() / (float)(NUM_VISIBLE_X_TILES * NUM_TILE_PIXELS);
float verticalStretchFactor = (rect.height() - rect.y()) / (float)(11*32); float verticalStretchFactor = rect.height() / (float)(NUM_VISIBLE_Y_TILES * NUM_TILE_PIXELS);
// draw player names and health bars // draw player names and health bars
for(int ix = -7; ix <= 7; ++ix) { for(int x = 0; x < NUM_VISIBLE_Y_TILES; ++x) {
for(int iy = -5; iy <= 5; ++iy) { for(int y = 0; y <= NUM_VISIBLE_X_TILES; ++y) {
Position itemPos = Position(m_centralPosition.x + ix, m_centralPosition.y + iy, m_centralPosition.z); Position tilePos = Position(m_centralPosition.x + (x - 7), m_centralPosition.y + (y - 5), m_centralPosition.z);
if(const TilePtr& tile = m_tiles[itemPos]) { if(const TilePtr& tile = m_tiles[tilePos]) {
auto& creatures = tile->getCreatures(); auto& creatures = tile->getCreatures();
if(creatures.size() == 0)
continue;
for(auto it = creatures.rbegin(), end = creatures.rend(); it != end; ++it) { for(auto it = creatures.rbegin(), end = creatures.rend(); it != end; ++it) {
const ThingPtr& thing = *it; CreaturePtr creature = (*it)->asCreature();
const CreaturePtr& creature = thing->asCreature();
int x = (ix + 7)*32 + 10 - tile->getDrawNextOffset(); int x = (7 + (tilePos.x - m_centralPosition.x))*NUM_TILE_PIXELS + 10 - tile->getDrawNextOffset();
int y = (iy + 5)*32 - 10 - tile->getDrawNextOffset(); int y = (5 + (tilePos.y - m_centralPosition.y))*NUM_TILE_PIXELS - 10 - tile->getDrawNextOffset();
if(creature != player) { if(creature != localPlayer) {
x += creature->getWalkOffsetX() - walkOffsetX; x += creature->getWalkOffsetX() - walkOffsetX;
y += creature->getWalkOffsetY() - walkOffsetY; y += creature->getWalkOffsetY() - walkOffsetY;
} }
creature->drawInformation(rect.x() + x*horizontalStretchFactor, rect.y() + y*verticalStretchFactor, isCovered(tilePos, m_zstart));
// TODO: create isCovered function.
bool useGray = (drawFloorStop != m_centralPosition.z-1);
creature->drawInformation(x*horizontalStretchFactor, y*verticalStretchFactor, useGray);
} }
} }
} }
} }
} }
void Map::update()
{
m_zstart = getMaxVisibleFloor();
for(int z = 0; z < NUM_Z_TILES; ++z) {
auto& floorTiles = m_visibleTiles[z];
floorTiles.clear();
if(z < m_zstart)
continue;
for(int y = 0; y < NUM_Y_TILES; ++y) {
for(int x = 0; x < NUM_X_TILES; ++x) {
Position tilePos(m_centralPosition.x + (x - 8), m_centralPosition.y + (y - 6), m_centralPosition.z);
tilePos.coveredUp(m_centralPosition.z - z);
if(const TilePtr& tile = m_tiles[tilePos]) {
// skip tiles that are behind another tile
if(z > m_zstart && isCompletlyCovered(tilePos, m_zstart))
continue;
floorTiles.push_back(tile);
}
}
}
}
}
int Map::getMaxVisibleFloor()
{
Position tilePos = m_centralPosition;
tilePos.up();
TilePtr tile = m_tiles[tilePos];
if(tile)
return m_centralPosition.z;
tilePos = Position(m_centralPosition);
while(tilePos.z >= 0) {
tilePos.coveredUp();
tile = m_tiles[tilePos];
if(tile)
return tilePos.z + 1;
}
return 0;
}
bool Map::isCovered(const Position& pos, int maxFloor)
{
Position tilePos = pos;
tilePos.coveredUp();
while(tilePos.z >= maxFloor) {
TilePtr tile = m_tiles[tilePos];
if(tile)
return true;
tilePos.coveredUp();
}
return false;
}
bool Map::isCompletlyCovered(const Position& pos, int maxFloor)
{
Position tilePos = pos;
tilePos.coveredUp();
while(tilePos.z >= maxFloor) {
bool covered = true;
for(int x=0;x<2;++x) {
for(int y=0;y<2;++y) {
TilePtr tile = m_tiles[tilePos + Position(-x, -y, 0)];
if(!tile || !tile->isOpaque()) {
covered = false;
break;
}
}
}
if(covered)
return true;
tilePos.coveredUp();
}
return false;
}
void Map::addThing(ThingPtr thing, int stackpos) void Map::addThing(ThingPtr thing, int stackpos)
{ {
if(!thing) if(!thing)
@ -140,7 +179,8 @@ void Map::addThing(ThingPtr thing, int stackpos)
TilePtr& tile = m_tiles[thing->getPosition()]; TilePtr& tile = m_tiles[thing->getPosition()];
if(!tile) { if(!tile) {
tile = TilePtr(new Tile()); tile = TilePtr(new Tile(thing->getPosition()));
update();
} }
tile->addThing(thing, stackpos); tile->addThing(thing, stackpos);
@ -196,3 +236,9 @@ void Map::removeCreatureById(uint32 id)
{ {
m_creatures.erase(id); m_creatures.erase(id);
} }
void Map::setCentralPosition(const Position& centralPosition)
{
m_centralPosition = centralPosition;
update();
}

View File

@ -28,8 +28,22 @@
class Map class Map
{ {
enum {
NUM_X_TILES = 19,
NUM_Y_TILES = 15,
NUM_Z_TILES = 15,
NUM_VISIBLE_X_TILES = 15,
NUM_VISIBLE_Y_TILES = 11,
NUM_TILE_PIXELS = 32
};
public: public:
void draw(const Rect& rect); void draw(const Rect& rect);
void update();
int getMaxVisibleFloor();
bool isCovered(const Position& pos, int maxFloor);
bool isCompletlyCovered(const Position& pos, int maxFloor);
void addThing(ThingPtr thing, int stackpos = -1); void addThing(ThingPtr thing, int stackpos = -1);
ThingPtr getThing(const Position& pos, int stackpos); ThingPtr getThing(const Position& pos, int stackpos);
@ -42,7 +56,7 @@ public:
void setLight(const Light& light) { m_light = light; } void setLight(const Light& light) { m_light = light; }
Light getLight() { return m_light; } Light getLight() { return m_light; }
void setCentralPosition(const Position& centralPosition) { m_centralPosition = centralPosition; } void setCentralPosition(const Position& centralPosition);
Position getCentralPosition() { return m_centralPosition; } Position getCentralPosition() { return m_centralPosition; }
CreaturePtr getCreatureById(uint32 id); CreaturePtr getCreatureById(uint32 id);
@ -51,6 +65,8 @@ public:
private: private:
std::unordered_map<Position, TilePtr, PositionHasher> m_tiles; std::unordered_map<Position, TilePtr, PositionHasher> m_tiles;
std::map<uint32, CreaturePtr> m_creatures; std::map<uint32, CreaturePtr> m_creatures;
std::array<std::vector<TilePtr>, NUM_Z_TILES> m_visibleTiles;
int m_zstart;
Light m_light; Light m_light;
Position m_centralPosition; Position m_centralPosition;

View File

@ -50,6 +50,7 @@ struct ThingAttributes
isHangable = false; isHangable = false;
miniMapColor = 0; miniMapColor = 0;
hasMiniMapColor = false; hasMiniMapColor = false;
changesFloor = false;
subParam07 = 0; subParam07 = 0;
subParam08 = 0; subParam08 = 0;
width = 0; width = 0;
@ -64,7 +65,7 @@ struct ThingAttributes
} }
bool stackable, alwaysOnTop, useable, readable, moveable, blockSolid, blockProjectile, blockPathFind, pickupable, bool stackable, alwaysOnTop, useable, readable, moveable, blockSolid, blockProjectile, blockPathFind, pickupable,
isHangable, isHorizontal, isVertical, rotable, hasHeight, lookThrough, hasMiniMapColor; isHangable, isHorizontal, isVertical, rotable, hasHeight, lookThrough, hasMiniMapColor, changesFloor;
uint8 alwaysOnTopOrder, width, height, blendframes, xdiv, ydiv, zdiv, animcount, drawOffset, drawNextOffset; uint8 alwaysOnTopOrder, width, height, blendframes, xdiv, ydiv, zdiv, animcount, drawOffset, drawNextOffset;
uint16 speed, subParam07, subParam08, lightLevel, lightColor, miniMapColor; uint16 speed, subParam07, subParam08, lightLevel, lightColor, miniMapColor;

View File

@ -28,9 +28,10 @@
#include "localplayer.h" #include "localplayer.h"
#include <framework/graphics/fontmanager.h> #include <framework/graphics/fontmanager.h>
Tile::Tile() Tile::Tile(const Position& position)
{ {
m_drawNextOffset = 0; m_drawNextOffset = 0;
m_position = position;
} }
void Tile::draw(int x, int y, int step) void Tile::draw(int x, int y, int step)
@ -67,14 +68,17 @@ void Tile::draw(int x, int y, int step)
thing->draw(x - m_drawNextOffset, y - m_drawNextOffset); thing->draw(x - m_drawNextOffset, y - m_drawNextOffset);
m_drawNextOffset += thingAttributes.drawNextOffset; m_drawNextOffset += thingAttributes.drawNextOffset;
} }
}
else if(step == 1) {
for(auto it = m_creatures.rbegin(), end = m_creatures.rend(); it != end; ++it) { for(auto it = m_creatures.rbegin(), end = m_creatures.rend(); it != end; ++it) {
const ThingPtr& thing = *it; const ThingPtr& thing = *it;
thing->draw(x - m_drawNextOffset, y - m_drawNextOffset); thing->draw(x - m_drawNextOffset, y - m_drawNextOffset);
} }
for(auto it = m_effects.rbegin(), end = m_effects.rend(); it != end; ++it) {
const ThingPtr& thing = *it;
thing->draw(x - m_drawNextOffset, y - m_drawNextOffset);
}
for(auto it = m_itemsTop.rbegin(), end = m_itemsTop.rend(); it != end; ++it) { for(auto it = m_itemsTop.rbegin(), end = m_itemsTop.rend(); it != end; ++it) {
const ThingPtr& thing = *it; const ThingPtr& thing = *it;
const ThingAttributes& thingAttributes = thing->getAttributes(); const ThingAttributes& thingAttributes = thing->getAttributes();
@ -83,11 +87,8 @@ void Tile::draw(int x, int y, int step)
thing->draw(x, y); thing->draw(x, y);
} }
} }
}
for(auto it = m_effects.rbegin(), end = m_effects.rend(); it != end; ++it) { else if(step == 1) {
const ThingPtr& thing = *it;
thing->draw(x - m_drawNextOffset, y - m_drawNextOffset);
}
} }
} }
@ -240,3 +241,10 @@ int Tile::getStackSize(int stop)
ret += m_itemsBottom.size(); ret += m_itemsBottom.size();
return ret; return ret;
} }
bool Tile::isOpaque()
{
if(m_ground && !m_ground->getAttributes().changesFloor)
return true;
return false;
}

View File

@ -29,7 +29,7 @@
class Tile : public LuaObject class Tile : public LuaObject
{ {
public: public:
Tile(); Tile(const Position& position);
void draw(int x, int y, int step); void draw(int x, int y, int step);
@ -47,12 +47,17 @@ public:
const ThingList& getCreatures() { return m_creatures; } const ThingList& getCreatures() { return m_creatures; }
int getDrawNextOffset() { return m_drawNextOffset; } int getDrawNextOffset() { return m_drawNextOffset; }
const Position& getPosition() { return m_position; }
bool isOpaque();
private: private:
ThingPtr m_ground; ThingPtr m_ground;
ThingList m_itemsBottom; ThingList m_itemsBottom;
ThingList m_creatures; ThingList m_creatures;
ThingList m_itemsTop; ThingList m_itemsTop;
ThingList m_effects; ThingList m_effects;
Position m_position;
int m_drawNextOffset; int m_drawNextOffset;
}; };

View File

@ -37,6 +37,8 @@
#include <otclient/net/protocolgame.h> #include <otclient/net/protocolgame.h>
#include <otclient/core/game.h> #include <otclient/core/game.h>
#include <otclient/core/map.h> #include <otclient/core/map.h>
#include "core/datmanager.h"
#include "core/item.h"
OTClient g_client; OTClient g_client;
@ -229,6 +231,28 @@ void OTClient::render()
{ {
// everything is rendered by UI components // everything is rendered by UI components
g_ui.render(); g_ui.render();
// utility for viewing dat items
/*
int count = 0;
auto maxSize = g_graphics.getScreenSize();
ItemPtr item(new Item);
int x = 32;
int y = 32;
for(int i=100;i<11803;++i) {
if(g_dat.getItemAttributes(i).group == Otc::ThingGroundGroup && !g_dat.getItemAttributes(i).changesFloor) {
item->setId(i);
item->draw(x, y);
x += 64;
if(x > g_graphics.getScreenSize().width()) {
x = 32;
y += 64;
if(y > maxSize.height())
break;
}
}
}
*/
} }
void OTClient::loadConfigurations() void OTClient::loadConfigurations()

View File

@ -66,6 +66,16 @@ public:
bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; } bool operator==(const Position& other) const { return other.x == x && other.y == y && other.z == z; }
bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; } bool operator!=(const Position& other) const { return other.x!=x || other.y!=y || other.z!=z; }
bool isInRange(const Position& pos, int xdif, int ydif, int zdif = 1) {
return std::abs(x-pos.x) <= xdif && std::abs(y-pos.y) <= ydif && std::abs(pos.z-z) <= zdif;
}
void up(int n = 1) { z-=n; }
void down(int n = 1) { z+=n; }
void coveredUp(int n = 1) { x+=n; y+=n; z-=n; }
void coveredDown(int n = 1) { x-=n; y-=n; z+=n; }
int x; int x;
int y; int y;
int z; int z;
@ -77,15 +87,13 @@ struct PositionHasher : std::unary_function<Position, std::size_t> {
} }
}; };
template<class T> inline std::ostream& operator<<(std::ostream& out, const Position& pos)
std::ostream& operator<<(std::ostream& out, const Position& pos)
{ {
out << pos.x << " " << pos.y << " " << pos.z; out << pos.x << " " << pos.y << " " << pos.z;
return out; return out;
} }
template<class T> inline std::istream& operator>>(std::istream& in, Position& pos)
std::istream& operator>>(std::istream& in, Position& pos)
{ {
in >> pos.x >> pos.y >> pos.z; in >> pos.x >> pos.y >> pos.z;
return in; return in;