From 4d10b0dd49969a863f0b97f83e073a46b2892ff1 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Tue, 30 Aug 2011 20:39:14 -0300 Subject: [PATCH] render improvments using some cache --- CMakeLists.txt | 2 +- modules/game/game.lua | 2 +- src/framework/global.h | 4 - src/framework/graphics/texture.h | 2 +- src/framework/util/types.h | 4 + src/otclient/core/datmanager.cpp | 23 ++-- src/otclient/core/map.cpp | 182 +++++++++++++++++----------- src/otclient/core/map.h | 18 ++- src/otclient/core/thingattributes.h | 3 +- src/otclient/core/tile.cpp | 24 ++-- src/otclient/core/tile.h | 7 +- src/otclient/otclient.cpp | 24 ++++ src/otclient/util/position.h | 16 ++- 13 files changed, 210 insertions(+), 101 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7c3040c..2148a00d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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(CMAKE_CXX_FLAGS "-std=c++0x -pipe ${CXX_WARNS}") 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") ENDIF(CMAKE_COMPILER_IS_GNUCXX) diff --git a/modules/game/game.lua b/modules/game/game.lua index 6231f7e3..50aab512 100644 --- a/modules/game/game.lua +++ b/modules/game/game.lua @@ -22,7 +22,7 @@ end local function destroyMainInterface() - if gameUi then + if Game.gameUi then Game.gameUi:destroy() Game.gameUi = nil end diff --git a/src/framework/global.h b/src/framework/global.h index ee0d4527..167c093f 100644 --- a/src/framework/global.h +++ b/src/framework/global.h @@ -58,10 +58,6 @@ #include #include -#ifndef nullptr -#define nullptr NULL -#endif - // global constants #include "const.h" diff --git a/src/framework/graphics/texture.h b/src/framework/graphics/texture.h index 61a5b230..6196c9b7 100644 --- a/src/framework/graphics/texture.h +++ b/src/framework/graphics/texture.h @@ -37,7 +37,7 @@ public: virtual void enableBilinearFilter(); /// Get OpenGL texture id - virtual uint getId() const { return m_textureId; } + uint getId() const { return m_textureId; } /// Copy pixels from OpenGL texture std::vector getPixels(); diff --git a/src/framework/util/types.h b/src/framework/util/types.h index 339c00c5..6f6e104f 100644 --- a/src/framework/util/types.h +++ b/src/framework/util/types.h @@ -42,4 +42,8 @@ typedef int8_t int8; typedef std::function SimpleCallback; typedef std::function BooleanCallback; +#ifndef nullptr +#define nullptr NULL +#endif + #endif diff --git a/src/otclient/core/datmanager.cpp b/src/otclient/core/datmanager.cpp index 381e4ad5..0bc64fd6 100644 --- a/src/otclient/core/datmanager.cpp +++ b/src/otclient/core/datmanager.cpp @@ -115,15 +115,15 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes thingAttributes.speed = Fw::getU16(fin); thingAttributes.group = Otc::ThingGroundGroup; break; - case 0x01: // All OnTop + case 0x01: // Must be drawn behind creatures foot, e.g.: ground, carpets, borders... thingAttributes.alwaysOnTop = true; thingAttributes.alwaysOnTopOrder = 1; 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.alwaysOnTopOrder = 2; 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.alwaysOnTopOrder = 3; break; @@ -133,7 +133,7 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes case 0x05: // Stackable thingAttributes.stackable = true; break; - case 0x06: // Unknown + case 0x06: // Unknown, some corpses, stairs, even ground ???? break; case 0x07: // Useable thingAttributes.useable = true; @@ -167,7 +167,7 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes case 0x0F: // Blocks pathfind algorithms (monsters) thingAttributes.blockPathFind = true; break; - case 0x10: // Blocks monster movement (flowers, parcels etc) + case 0x10: // Pickupable thingAttributes.pickupable = true; break; case 0x11: // Hangable objects (wallpaper etc) @@ -186,9 +186,10 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes thingAttributes.lightLevel = Fw::getU16(fin); thingAttributes.lightColor = Fw::getU16(fin); break; - case 0x16: + case 0x16: // Unknown, just a few monuments break; - case 0x17: // Changes floor + case 0x17: // Changes floor, e.g: holes + thingAttributes.changesFloor = true; break; case 0x18: // Thing must be drawed with offset thingAttributes.hasHeight = true; @@ -200,7 +201,7 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes thingAttributes.drawNextOffset = Fw::getU8(fin); Fw::getU8(fin); break; - case 0x1A: + case 0x1A: // Unknown, some corpses //thingAttributes.hasHeight = true; break; case 0x1B: @@ -213,12 +214,12 @@ void DatManager::parseThingAttributesOpt(std::stringstream& fin, ThingAttributes if(Fw::getU16(fin) == 1112) thingAttributes.readable = true; break; - case 0x1E: + case 0x1E: // Unknown, only grounds break; - case 0x1F: + case 0x1F: // Unknown, borders that cant walk into? thingAttributes.lookThrough = true; break; - case 0x20: + case 0x20: // Unknown break; default: throw std::runtime_error(Fw::mkstr("unknown .dat byte code: 0x", std::hex, (int)opt)); diff --git a/src/otclient/core/map.cpp b/src/otclient/core/map.cpp index 3e3995a3..882207b2 100644 --- a/src/otclient/core/map.cpp +++ b/src/otclient/core/map.cpp @@ -37,100 +37,139 @@ void Map::draw(const Rect& rect) g_graphics.bindColor(Fw::white); m_framebuffer->bind(); - LocalPlayerPtr player = g_game.getLocalPlayer(); - int walkOffsetX = player->getWalkOffsetX(); - int walkOffsetY = player->getWalkOffsetY(); - - // player is above 7 - - int drawFloorStop = 0; - if(m_centralPosition.z <= 7) { - - // player pos it 8-6. check if we can draw upper floors. - - - // 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); - } - } + LocalPlayerPtr localPlayer = g_game.getLocalPlayer(); + int walkOffsetX = localPlayer->getWalkOffsetX(); + int walkOffsetY = localPlayer->getWalkOffsetY(); + + for(int z = NUM_Z_TILES - 1; z >= 0; --z) { + if(m_visibleTiles.size() == 0) + continue; + + int zdif = m_centralPosition.z - z; + for(int step = 0; step < 2; ++step) { + for(const TilePtr& tile : m_visibleTiles[z]) { + 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); } } } - // debug draws - g_graphics.bindColor(Fw::red); - g_graphics.drawBoundingRect(Rect(7*32, 5*32, 32, 32)); - m_framebuffer->unbind(); g_graphics.bindColor(Fw::white); m_framebuffer->draw(rect); // calculate stretch factor - float horizontalStretchFactor = (rect.width() - rect.x()) / (float)(15*32); - float verticalStretchFactor = (rect.height() - rect.y()) / (float)(11*32); + float horizontalStretchFactor = rect.width() / (float)(NUM_VISIBLE_X_TILES * NUM_TILE_PIXELS); + float verticalStretchFactor = rect.height() / (float)(NUM_VISIBLE_Y_TILES * NUM_TILE_PIXELS); // draw player names and health bars - for(int ix = -7; ix <= 7; ++ix) { - for(int iy = -5; iy <= 5; ++iy) { - Position itemPos = Position(m_centralPosition.x + ix, m_centralPosition.y + iy, m_centralPosition.z); - if(const TilePtr& tile = m_tiles[itemPos]) { + for(int x = 0; x < NUM_VISIBLE_Y_TILES; ++x) { + for(int y = 0; y <= NUM_VISIBLE_X_TILES; ++y) { + Position tilePos = Position(m_centralPosition.x + (x - 7), m_centralPosition.y + (y - 5), m_centralPosition.z); + if(const TilePtr& tile = m_tiles[tilePos]) { auto& creatures = tile->getCreatures(); + + if(creatures.size() == 0) + continue; + for(auto it = creatures.rbegin(), end = creatures.rend(); it != end; ++it) { - const ThingPtr& thing = *it; - const CreaturePtr& creature = thing->asCreature(); + CreaturePtr creature = (*it)->asCreature(); - int x = (ix + 7)*32 + 10 - tile->getDrawNextOffset(); - int y = (iy + 5)*32 - 10 - tile->getDrawNextOffset(); + int x = (7 + (tilePos.x - m_centralPosition.x))*NUM_TILE_PIXELS + 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; y += creature->getWalkOffsetY() - walkOffsetY; } + creature->drawInformation(rect.x() + x*horizontalStretchFactor, rect.y() + y*verticalStretchFactor, isCovered(tilePos, m_zstart)); + } + } + } + } +} + +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; +} - // TODO: create isCovered function. - bool useGray = (drawFloorStop != m_centralPosition.z-1); +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; +} - creature->drawInformation(x*horizontalStretchFactor, y*verticalStretchFactor, useGray); +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) @@ -140,7 +179,8 @@ void Map::addThing(ThingPtr thing, int stackpos) TilePtr& tile = m_tiles[thing->getPosition()]; if(!tile) { - tile = TilePtr(new Tile()); + tile = TilePtr(new Tile(thing->getPosition())); + update(); } tile->addThing(thing, stackpos); @@ -196,3 +236,9 @@ void Map::removeCreatureById(uint32 id) { m_creatures.erase(id); } + +void Map::setCentralPosition(const Position& centralPosition) +{ + m_centralPosition = centralPosition; + update(); +} diff --git a/src/otclient/core/map.h b/src/otclient/core/map.h index 49f593e7..b8d2028d 100644 --- a/src/otclient/core/map.h +++ b/src/otclient/core/map.h @@ -28,8 +28,22 @@ 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: 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); ThingPtr getThing(const Position& pos, int stackpos); @@ -42,7 +56,7 @@ public: void setLight(const Light& light) { m_light = light; } Light getLight() { return m_light; } - void setCentralPosition(const Position& centralPosition) { m_centralPosition = centralPosition; } + void setCentralPosition(const Position& centralPosition); Position getCentralPosition() { return m_centralPosition; } CreaturePtr getCreatureById(uint32 id); @@ -51,6 +65,8 @@ public: private: std::unordered_map m_tiles; std::map m_creatures; + std::array, NUM_Z_TILES> m_visibleTiles; + int m_zstart; Light m_light; Position m_centralPosition; diff --git a/src/otclient/core/thingattributes.h b/src/otclient/core/thingattributes.h index f8c377ac..e5f2f8e2 100644 --- a/src/otclient/core/thingattributes.h +++ b/src/otclient/core/thingattributes.h @@ -50,6 +50,7 @@ struct ThingAttributes isHangable = false; miniMapColor = 0; hasMiniMapColor = false; + changesFloor = false; subParam07 = 0; subParam08 = 0; width = 0; @@ -64,7 +65,7 @@ struct ThingAttributes } 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; uint16 speed, subParam07, subParam08, lightLevel, lightColor, miniMapColor; diff --git a/src/otclient/core/tile.cpp b/src/otclient/core/tile.cpp index 2f807e40..3689d809 100644 --- a/src/otclient/core/tile.cpp +++ b/src/otclient/core/tile.cpp @@ -28,9 +28,10 @@ #include "localplayer.h" #include -Tile::Tile() +Tile::Tile(const Position& position) { m_drawNextOffset = 0; + m_position = position; } 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); m_drawNextOffset += thingAttributes.drawNextOffset; } - } - else if(step == 1) { for(auto it = m_creatures.rbegin(), end = m_creatures.rend(); it != end; ++it) { const ThingPtr& thing = *it; 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) { const ThingPtr& thing = *it; const ThingAttributes& thingAttributes = thing->getAttributes(); @@ -83,11 +87,8 @@ void Tile::draw(int x, int y, int step) thing->draw(x, y); } } - - 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); - } + } + else if(step == 1) { } } @@ -240,3 +241,10 @@ int Tile::getStackSize(int stop) ret += m_itemsBottom.size(); return ret; } + +bool Tile::isOpaque() +{ + if(m_ground && !m_ground->getAttributes().changesFloor) + return true; + return false; +} diff --git a/src/otclient/core/tile.h b/src/otclient/core/tile.h index fc5f53a7..a7e391db 100644 --- a/src/otclient/core/tile.h +++ b/src/otclient/core/tile.h @@ -29,7 +29,7 @@ class Tile : public LuaObject { public: - Tile(); + Tile(const Position& position); void draw(int x, int y, int step); @@ -47,12 +47,17 @@ public: const ThingList& getCreatures() { return m_creatures; } int getDrawNextOffset() { return m_drawNextOffset; } + const Position& getPosition() { return m_position; } + + bool isOpaque(); + private: ThingPtr m_ground; ThingList m_itemsBottom; ThingList m_creatures; ThingList m_itemsTop; ThingList m_effects; + Position m_position; int m_drawNextOffset; }; diff --git a/src/otclient/otclient.cpp b/src/otclient/otclient.cpp index 29d8061f..02c3b94f 100644 --- a/src/otclient/otclient.cpp +++ b/src/otclient/otclient.cpp @@ -37,6 +37,8 @@ #include #include #include +#include "core/datmanager.h" +#include "core/item.h" OTClient g_client; @@ -229,6 +231,28 @@ void OTClient::render() { // everything is rendered by UI components 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() diff --git a/src/otclient/util/position.h b/src/otclient/util/position.h index 8210cd4d..c7441803 100644 --- a/src/otclient/util/position.h +++ b/src/otclient/util/position.h @@ -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 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 y; int z; @@ -77,15 +87,13 @@ struct PositionHasher : std::unary_function { } }; -template -std::ostream& operator<<(std::ostream& out, const Position& pos) +inline std::ostream& operator<<(std::ostream& out, const Position& pos) { out << pos.x << " " << pos.y << " " << pos.z; return out; } -template -std::istream& operator>>(std::istream& in, Position& pos) +inline std::istream& operator>>(std::istream& in, Position& pos) { in >> pos.x >> pos.y >> pos.z; return in;