diff --git a/init.lua b/init.lua index e2abdc63..030f88ba 100644 --- a/init.lua +++ b/init.lua @@ -57,6 +57,7 @@ elseif settings:exists('layout') then end g_resources.setLayout(layout) +g_game.enableFeature(Game64Textures) -- load mods g_modules.discoverModules() g_modules.ensureModuleLoaded("corelib") diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index b2b71b1a..c2500e20 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -132,10 +132,18 @@ local function onTibia12HTTPResult(session, playdata) account.subStatus = math.floor((session["premiumuntil"] - g_clock.seconds()) / 86400) end - local things = { - data = {G.clientVersion .. "/Tibia.dat", ""}, - sprites = {G.clientVersion .. "/Tibia.spr", ""}, - } + local things + if not g_game.getFeature(Game64Textures) then + things = { + data = {G.clientVersion .. "/Tibia.dat", ""}, + sprites = {G.clientVersion .. "/Tibia.spr", ""}, + } + else + things = { + data = {G.clientVersion .. "/Tibia.dat", ""}, + sprites = {G.clientVersion .. "/TibiaHD.cwm", ""}, + } + end local incorrectThings = validateThings(things) if #incorrectThings > 0 then @@ -465,10 +473,18 @@ function EnterGame.doLogin() return EnterGame.onError("Invalid server, it should be in format IP:PORT or it should be http url to login script") end - local things = { - data = {G.clientVersion .. "/Tibia.dat", ""}, - sprites = {G.clientVersion .. "/Tibia.spr", ""}, - } + local things + if not g_game.getFeature(Game64Textures) then + things = { + data = {G.clientVersion .. "/Tibia.dat", ""}, + sprites = {G.clientVersion .. "/Tibia.spr", ""}, + } + else + things = { + data = {G.clientVersion .. "/Tibia.dat", ""}, + sprites = {G.clientVersion .. "/TibiaHD.cwm", ""}, + } + end local incorrectThings = validateThings(things) if #incorrectThings > 0 then diff --git a/modules/game_things/things.lua b/modules/game_things/things.lua index 648bc108..1ecfd705 100644 --- a/modules/game_things/things.lua +++ b/modules/game_things/things.lua @@ -12,8 +12,10 @@ end function load() local version = g_game.getClientVersion() local things = g_settings.getNode('things') + g_game.enableFeature(Game64Textures) - local datPath, sprPath + local datPath, sprPath, hdPath + local isHdMod = false if things and things["data"] ~= nil and things["sprites"] ~= nil then datPath = '/things/' .. things["data"] sprPath = '/things/' .. things["sprites"] @@ -26,6 +28,11 @@ function load() sprPath = resolvepath('/things/' .. version .. '/Tibia') end end + + if g_game.getFeature(Game64Textures) then + hdPath = resolvepath('/things/' .. version .. '/TibiaHD') + isHdMod = true + end local errorMessage = '' if not g_things.loadDat(datPath) then @@ -38,10 +45,10 @@ function load() errorMessage = errorMessage .. tr("Unable to load dat file, please place a valid dat in '%s'", datPath) .. '\n' end end - if not g_sprites.loadSpr(sprPath, false) then - errorMessage = errorMessage .. tr("Unable to load spr file, please place a valid spr in '%s'", sprPath) + + if not g_sprites.loadSpr(sprPath, isHdMod) then + errorMessage = errorMessage .. tr("Unable to load spr file, please place a valid spr in '%s'", sprPath) end - loaded = (errorMessage:len() == 0) if errorMessage:len() > 0 then diff --git a/src/client/const.h b/src/client/const.h index f1c41be7..f7ea4b2f 100644 --- a/src/client/const.h +++ b/src/client/const.h @@ -28,7 +28,6 @@ namespace Otc { enum : int { - TILE_PIXELS = 32, // change to 64 if you want to use 64x64 HD sprites MAX_ELEVATION = 24, SEA_FLOOR = 7, diff --git a/src/client/creature.cpp b/src/client/creature.cpp index 072556b4..f6866a8f 100644 --- a/src/client/creature.cpp +++ b/src/client/creature.cpp @@ -84,8 +84,9 @@ void Creature::draw(const Point& dest, bool animate, LightView* lightView) if (!canBeSeen()) return; + const int sprSize = g_sprites.spriteSize(); Point jumpOffset = Point(m_jumpOffset.x, m_jumpOffset.y); - Point creatureCenter = dest - jumpOffset + m_walkOffset - getDisplacement() + Point(Otc::TILE_PIXELS / 2, Otc::TILE_PIXELS / 2); + Point creatureCenter = dest - jumpOffset + m_walkOffset - getDisplacement() + Point(sprSize / 2, sprSize / 2); drawBottomWidgets(creatureCenter, m_walking ? m_walkDirection : m_direction); Point animationOffset = animate ? m_walkOffset : Point(0, 0); @@ -93,11 +94,11 @@ void Creature::draw(const Point& dest, bool animate, LightView* lightView) animationOffset -= getDisplacement(); if (m_showTimedSquare && animate) { - g_drawQueue->addBoundingRect(Rect(dest - jumpOffset + (animationOffset - getDisplacement() + 2), Size(28, 28)), 2, m_timedSquareColor); + g_drawQueue->addBoundingRect(Rect(dest - jumpOffset + (animationOffset - getDisplacement() + 2 * g_sprites.getOffsetFactor()), Size(sprSize - 4, sprSize - 4)), 2 * g_sprites.getOffsetFactor(), m_timedSquareColor); } if (m_showStaticSquare && animate) { - g_drawQueue->addBoundingRect(Rect(dest - jumpOffset + (animationOffset - getDisplacement()), Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)), 2, m_staticSquareColor); + g_drawQueue->addBoundingRect(Rect(dest - jumpOffset + (animationOffset - getDisplacement()), Size(sprSize, sprSize)), 2 * g_sprites.getOffsetFactor(), m_staticSquareColor); } size_t drawQueueSize = g_drawQueue->size(); @@ -144,7 +145,12 @@ void Creature::drawInformation(const Point& point, bool useGray, const Rect& par fillColor = m_informationColor; // calculate main rects - Rect backgroundRect = Rect(point.x + m_informationOffset.x - (13.5), point.y + m_informationOffset.y, 27, 4); + Rect backgroundRect; + if (g_sprites.isHdMod() == false) { + backgroundRect = Rect(point.x + m_informationOffset.x - (13.5), point.y + m_informationOffset.y, 27, 4); + }else { + backgroundRect = Rect(point.x + m_informationOffset.x * g_sprites.getOffsetFactor(), point.y + m_informationOffset.y * g_sprites.getOffsetFactor(), 27, 4); + } backgroundRect.bind(parentRect); //debug @@ -159,7 +165,12 @@ void Creature::drawInformation(const Point& point, bool useGray, const Rect& par } Size nameSize = m_nameCache.getTextSize(); - Rect textRect = Rect(point.x + m_informationOffset.x - nameSize.width() / 2.0, point.y + m_informationOffset.y - 12, nameSize); + Rect textRect; + if (g_sprites.isHdMod() == false) { + textRect = Rect(point.x + m_informationOffset.x - nameSize.width() / 2.0, point.y + m_informationOffset.y - 12, nameSize); + } else { + textRect = Rect(point.x + m_informationOffset.x - nameSize.width() / 2.0 + 14.5, point.y + m_informationOffset.y - 13, nameSize); + } textRect.bind(parentRect); // distance them @@ -263,7 +274,7 @@ void Creature::drawInformation(const Point& point, bool useGray, const Rect& par if (m_text) { auto extraTextSize = m_text->getCachedText().getTextSize(); - Rect extraTextRect = Rect(point.x + m_informationOffset.x - extraTextSize.width() / 2.0, point.y + m_informationOffset.y + 15, extraTextSize); + Rect extraTextRect = Rect(point.x + m_informationOffset.x * g_sprites.getOffsetFactor() - extraTextSize.width() / 2.0, point.y + (m_informationOffset.y + 15) * g_sprites.getOffsetFactor(), extraTextSize); m_text->drawText(extraTextRect.center(), extraTextRect); } } @@ -297,7 +308,7 @@ bool Creature::isInsideOffset(Point offset) { // for worse precision: // Rect rect(getDrawOffset() - (m_walking ? m_walkOffset : Point(0,0)), Size(Otc::TILE_PIXELS - getDisplacementY(), Otc::TILE_PIXELS - getDisplacementX())); - Rect rect(getDrawOffset() - getDisplacement(), Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)); + Rect rect(getDrawOffset() - getDisplacement(), Size(g_sprites.spriteSize(), g_sprites.spriteSize())); return rect.contains(offset); } @@ -493,15 +504,15 @@ void Creature::updateWalkAnimation(uint8 totalPixelsWalked) if (footAnimPhases == 0) { m_walkAnimationPhase = 0; - } else if (g_clock.millis() >= m_footLastStep + footDelay && totalPixelsWalked < Otc::TILE_PIXELS) { + } else if (g_clock.millis() >= m_footLastStep + footDelay && totalPixelsWalked < g_sprites.spriteSize()) { m_footStep++; m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases); m_footLastStep = (g_clock.millis() - m_footLastStep) > footDelay * 1.5 ? g_clock.millis() : m_footLastStep + footDelay; - } else if (m_walkAnimationPhase == 0 && totalPixelsWalked < Otc::TILE_PIXELS) { + } else if (m_walkAnimationPhase == 0 && totalPixelsWalked < g_sprites.spriteSize()) { m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases); } - if (totalPixelsWalked == Otc::TILE_PIXELS && !m_walkFinishAnimEvent) { + if (totalPixelsWalked == g_sprites.spriteSize() && !m_walkFinishAnimEvent) { auto self = static_self_cast(); m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] { self->m_footStep = 0; @@ -517,26 +528,26 @@ void Creature::updateWalkOffset(uint8 totalPixelsWalked, bool inNextFrame) Point& walkOffset = inNextFrame ? m_walkOffsetInNextFrame : m_walkOffset; walkOffset = Point(0, 0); if (m_walkDirection == Otc::North || m_walkDirection == Otc::NorthEast || m_walkDirection == Otc::NorthWest) - walkOffset.y = Otc::TILE_PIXELS - totalPixelsWalked; + walkOffset.y = g_sprites.spriteSize() - totalPixelsWalked; else if (m_walkDirection == Otc::South || m_walkDirection == Otc::SouthEast || m_walkDirection == Otc::SouthWest) - walkOffset.y = totalPixelsWalked - Otc::TILE_PIXELS; + walkOffset.y = totalPixelsWalked - g_sprites.spriteSize(); if (m_walkDirection == Otc::East || m_walkDirection == Otc::NorthEast || m_walkDirection == Otc::SouthEast) - walkOffset.x = totalPixelsWalked - Otc::TILE_PIXELS; + walkOffset.x = totalPixelsWalked - g_sprites.spriteSize(); else if (m_walkDirection == Otc::West || m_walkDirection == Otc::NorthWest || m_walkDirection == Otc::SouthWest) - walkOffset.x = Otc::TILE_PIXELS - totalPixelsWalked; + walkOffset.x = g_sprites.spriteSize() - totalPixelsWalked; } void Creature::updateWalkingTile() { // determine new walking tile TilePtr newWalkingTile; - Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()), - Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()), - Otc::TILE_PIXELS, Otc::TILE_PIXELS); + Rect virtualCreatureRect(g_sprites.spriteSize() + (m_walkOffset.x - getDisplacementX()), + g_sprites.spriteSize() + (m_walkOffset.y - getDisplacementY()), + g_sprites.spriteSize(), g_sprites.spriteSize()); for (int xi = -1; xi <= 1 && !newWalkingTile; ++xi) { for (int yi = -1; yi <= 1 && !newWalkingTile; ++yi) { - Rect virtualTileRect((xi + 1) * Otc::TILE_PIXELS, (yi + 1) * Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS); + Rect virtualTileRect((xi + 1) * g_sprites.spriteSize(), (yi + 1) * g_sprites.spriteSize(), g_sprites.spriteSize(), g_sprites.spriteSize()); // only render creatures where bottom right is inside tile rect if (virtualTileRect.contains(virtualCreatureRect.bottomRight())) { @@ -575,15 +586,15 @@ void Creature::nextWalkUpdate() self->m_walkUpdateEvent = nullptr; self->nextWalkUpdate(); }, g_game.getFeature(Otc::GameNewUpdateWalk) && isLocalPlayer() ? - std::ceil(((float)getStepDuration(true) / g_app.getFps()) * 2) : (float)getStepDuration() / Otc::TILE_PIXELS); + std::ceil(((float)getStepDuration(true) / g_app.getFps()) * 2) : (float)getStepDuration() / g_sprites.spriteSize()); } } void Creature::updateWalk() { - float walkTicksPerPixel = ((float)(getStepDuration(true) + (g_game.getFeature(Otc::GameNewUpdateWalk) ? 0 : 10))) / (float)Otc::TILE_PIXELS; - uint8 totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, Otc::TILE_PIXELS); - uint8 totalPixelsWalkedInNextFrame = std::min((m_walkTimer.ticksElapsed() + (g_game.getFeature(Otc::GameNewUpdateWalk) ? std::max(1000.f / g_app.getFps(), 1.0f) : 15)) / walkTicksPerPixel, Otc::TILE_PIXELS); + float walkTicksPerPixel = ((float)(getStepDuration(true) + (g_game.getFeature(Otc::GameNewUpdateWalk) ? 0 : 10))) / (float)g_sprites.spriteSize(); + uint8 totalPixelsWalked = std::min(m_walkTimer.ticksElapsed() / walkTicksPerPixel, g_sprites.spriteSize()); + uint8 totalPixelsWalkedInNextFrame = std::min((m_walkTimer.ticksElapsed() + (g_game.getFeature(Otc::GameNewUpdateWalk) ? std::max(1000.f / g_app.getFps(), 1.0f) : 15)) / walkTicksPerPixel, g_sprites.spriteSize()); // needed for paralyze effect m_walkedPixels = std::max(m_walkedPixels, totalPixelsWalked); @@ -927,48 +938,48 @@ uint16 Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir) Point Creature::getDisplacement() { if (m_outfit.getCategory() == ThingCategoryEffect) - return Point(8, 8); + return Point(8, 8) * g_sprites.getOffsetFactor(); else if (m_outfit.getCategory() == ThingCategoryItem) return Point(0, 0); if (m_outfit.getMount() != 0) { auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature); - return datType->getDisplacement(); + return datType->getDisplacement() * g_sprites.getOffsetFactor(); } - return Thing::getDisplacement(); + return Thing::getDisplacement() * g_sprites.getOffsetFactor(); } int Creature::getDisplacementX() { if (m_outfit.getCategory() == ThingCategoryEffect) - return 8; + return 8 * g_sprites.getOffsetFactor(); else if (m_outfit.getCategory() == ThingCategoryItem) return 0; if (m_outfit.getMount() != 0) { auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature); - return datType->getDisplacementX(); + return datType->getDisplacementX() * g_sprites.getOffsetFactor(); } - return Thing::getDisplacementX(); + return Thing::getDisplacementX() * g_sprites.getOffsetFactor(); } int Creature::getDisplacementY() { if (m_outfit.getCategory() == ThingCategoryEffect) - return 8; + return 8 * g_sprites.getOffsetFactor(); else if (m_outfit.getCategory() == ThingCategoryItem) return 0; if (m_outfit.getMount() != 0) { auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature); if (datType) { - return datType->getDisplacementY(); + return datType->getDisplacementY() * g_sprites.getOffsetFactor(); } } - return Thing::getDisplacementY(); + return Thing::getDisplacementY() * g_sprites.getOffsetFactor(); } int Creature::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase) diff --git a/src/client/lightview.cpp b/src/client/lightview.cpp index 9ff92bb5..c43aecaf 100644 --- a/src/client/lightview.cpp +++ b/src/client/lightview.cpp @@ -21,6 +21,7 @@ */ #include "lightview.h" +#include "spritemanager.h" #include void LightView::addLight(const Point& pos, uint8_t color, uint8_t intensity) @@ -37,7 +38,7 @@ void LightView::addLight(const Point& pos, uint8_t color, uint8_t intensity) void LightView::setFieldBrightness(const Point& pos, size_t start, uint8_t color) { - size_t index = (pos.y / Otc::TILE_PIXELS) * m_mapSize.width() + (pos.x / Otc::TILE_PIXELS); + size_t index = (pos.y / g_sprites.spriteSize()) * m_mapSize.width() + (pos.x / g_sprites.spriteSize()); if (index >= m_tiles.size()) return; m_tiles[index].start = start; m_tiles[index].color = color; @@ -52,7 +53,7 @@ void LightView::draw() // render thread for (int x = 0; x < m_mapSize.width(); ++x) { for (int y = 0; y < m_mapSize.height(); ++y) { - Point pos(x * Otc::TILE_PIXELS + Otc::TILE_PIXELS / 2, y * Otc::TILE_PIXELS + Otc::TILE_PIXELS / 2); + Point pos(x * g_sprites.spriteSize() + g_sprites.spriteSize() / 2, y * g_sprites.spriteSize() + g_sprites.spriteSize() / 2); int index = (y * m_mapSize.width() + x); int colorIndex = index * 4; buffer[colorIndex] = m_globalLight.r(); @@ -63,7 +64,7 @@ void LightView::draw() // render thread Light& light = m_lights[i]; float distance = std::sqrt((pos.x - light.pos.x) * (pos.x - light.pos.x) + (pos.y - light.pos.y) * (pos.y - light.pos.y)); - distance /= Otc::TILE_PIXELS; + distance /= g_sprites.spriteSize(); float intensity = (-distance + light.intensity) * 0.2f; if (intensity < 0.01f) continue; if (intensity > 1.0f) intensity = 1.0f; @@ -83,8 +84,8 @@ void LightView::draw() // render thread Size size = m_src.size(); CoordsBuffer coords; coords.addRect(RectF(m_dest.left(), m_dest.top(), m_dest.width(), m_dest.height()), - RectF((float)offset.x / Otc::TILE_PIXELS, (float)offset.y / Otc::TILE_PIXELS, - (float)size.width() / Otc::TILE_PIXELS, (float)size.height() / Otc::TILE_PIXELS)); + RectF((float)offset.x / g_sprites.spriteSize(), (float)offset.y / g_sprites.spriteSize(), + (float)size.width() / g_sprites.spriteSize(), (float)size.height() / g_sprites.spriteSize())); g_painter->resetColor(); g_painter->setCompositionMode(Painter::CompositionMode_Multiply); diff --git a/src/client/mapview.cpp b/src/client/mapview.cpp index 832aa130..315a8de4 100644 --- a/src/client/mapview.cpp +++ b/src/client/mapview.cpp @@ -161,7 +161,7 @@ void MapView::drawFloor(short floor, const Position& cameraPosition, const TileP tile->drawBottom(tileDrawPos, m_lightView.get()); if (m_crosshair && tile == crosshairTile) { - g_drawQueue->addTexturedRect(Rect(tileDrawPos, tileDrawPos + Otc::TILE_PIXELS - 1), + g_drawQueue->addTexturedRect(Rect(tileDrawPos, tileDrawPos + g_sprites.spriteSize() - 1), m_crosshair, Rect(0, 0, m_crosshair->getSize())); } @@ -185,7 +185,7 @@ void MapView::drawFloor(short floor, const Position& cameraPosition, const TileP tile->drawBottom(tileDrawPos, m_lightView.get()); if (m_crosshair && tile == crosshairTile) { - g_drawQueue->addTexturedRect(Rect(tileDrawPos, tileDrawPos + Otc::TILE_PIXELS - 1), + g_drawQueue->addTexturedRect(Rect(tileDrawPos, tileDrawPos + g_sprites.spriteSize() - 1), m_crosshair, Rect(0, 0, m_crosshair->getSize())); } @@ -451,7 +451,7 @@ Position MapView::getPosition(const Point& point, const Size& mapSize) Point framebufferPos = Point(point.x * sh, point.y * sv); Point realPos = (framebufferPos + srcRect.topLeft()); - Point centerOffset = realPos / Otc::TILE_PIXELS; + Point centerOffset = realPos / g_sprites.spriteSize(); Point tilePos2D = getVisibleCenterOffset() - m_drawDimension.toPoint() + centerOffset + Point(2,2); if(tilePos2D.x + cameraPosition.x < 0 && tilePos2D.y + cameraPosition.y < 0) @@ -479,7 +479,7 @@ Point MapView::getPositionOffset(const Point& point, const Size& mapSize) Point framebufferPos = Point(point.x * sh, point.y * sv); Point realPos = (framebufferPos + srcRect.topLeft()); - return Point(realPos.x % Otc::TILE_PIXELS, realPos.y % Otc::TILE_PIXELS); + return Point(realPos.x % g_sprites.spriteSize(), realPos.y % g_sprites.spriteSize()); } void MapView::move(int x, int y) @@ -508,7 +508,7 @@ void MapView::move(int x, int y) Rect MapView::calcFramebufferSource(const Size& destSize, bool inNextFrame) { - float scaleFactor = g_sprites.spriteSize()/(float)Otc::TILE_PIXELS; + float scaleFactor = g_sprites.spriteSize()/(float)g_sprites.spriteSize(); Point drawOffset = ((m_drawDimension - m_visibleDimension - Size(1,1)).toPoint()/2) * g_sprites.spriteSize(); if(isFollowingCreature()) drawOffset += m_followingCreature->getWalkOffset(inNextFrame) * scaleFactor; diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 87e76519..3d98ec3b 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -24,6 +24,7 @@ #include "minimap.h" #include "tile.h" #include "game.h" +#include "spritemanager.h" #include #include @@ -169,7 +170,7 @@ Rect Minimap::getTileRect(const Position& pos, const Rect& screenRect, const Pos if(screenRect.isEmpty() || pos.z != mapCenter.z) return Rect(); - int tileSize = Otc::TILE_PIXELS * scale; + int tileSize = g_sprites.spriteSize() * scale; Rect tileRect(0,0,tileSize, tileSize); tileRect.moveCenter(getTilePoint(pos, screenRect, mapCenter, scale)); return tileRect; diff --git a/src/client/missile.cpp b/src/client/missile.cpp index 5d5cf74b..a0bc9ff5 100644 --- a/src/client/missile.cpp +++ b/src/client/missile.cpp @@ -24,6 +24,7 @@ #include "thingtypemanager.h" #include "map.h" #include "tile.h" +#include "spritemanager.h" #include #include @@ -76,7 +77,7 @@ void Missile::setPath(const Position& fromPosition, const Position& toPosition) m_position = fromPosition; m_delta = Point(toPosition.x - fromPosition.x, toPosition.y - fromPosition.y); m_duration = 150 * std::sqrt(m_delta.length()); - m_delta *= Otc::TILE_PIXELS; + m_delta *= g_sprites.spriteSize(); m_animationTimer.restart(); // schedule removal diff --git a/src/client/outfit.cpp b/src/client/outfit.cpp index 86f92c95..291e7334 100644 --- a/src/client/outfit.cpp +++ b/src/client/outfit.cpp @@ -53,13 +53,13 @@ void Outfit::draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, Point wingDest = dest; if (g_game.getFeature(Otc::GameWingOffset) && m_wings) - dest -= Point(6, 6); + dest -= Point(6, 6) * g_sprites.getOffsetFactor(); auto type = g_things.rawGetThingType(m_category == ThingCategoryCreature ? m_id : m_auxId, m_category); if (!type) return; if (g_game.getFeature(Otc::GameCenteredOutfits)) { - dest.x += ((type->getWidth() - 1) * (Otc::TILE_PIXELS / 2)); + dest.x += ((type->getWidth() - 1) * (g_sprites.spriteSize() / 2)); } int animationPhase = walkAnimationPhase; @@ -78,8 +78,8 @@ void Outfit::draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, } } offset = tick <= floatingTicks / 2 ? tick * (maxoffset / (floatingTicks / 2)) : (2 * maxoffset) - tick * (maxoffset / (floatingTicks / 2)); - dest -= Point(offset, offset); - wingDest -= Point(offset, offset); + dest -= Point(offset, offset) * g_sprites.getOffsetFactor(); + wingDest -= Point(offset, offset) * g_sprites.getOffsetFactor(); }; if (animate && m_category == ThingCategoryCreature) { @@ -135,9 +135,9 @@ void Outfit::draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, } } - dest -= mountType->getDisplacement(); + dest -= mountType->getDisplacement() * g_sprites.getOffsetFactor(); mountType->draw(dest, 0, direction, 0, 0, mountAnimationPhase, Color::white, lightView); - dest += type->getDisplacement(); + dest += type->getDisplacement() * g_sprites.getOffsetFactor(); } }; @@ -211,8 +211,8 @@ void Outfit::draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, int auraWidth = auraType->getWidth(); if (auraHeight > 1 || auraWidth > 1) { Point offset = Point (auraWidth > 1 ? (auraWidth - 1) * 16 : 0, auraHeight > 1 ? (auraHeight - 1) * 16 : 0); - topAuraDest += offset; - auraDest += offset; + topAuraDest += offset * g_sprites.getOffsetFactor(); + auraDest += offset * g_sprites.getOffsetFactor(); } } @@ -225,9 +225,9 @@ void Outfit::draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, if (m_wings && (direction == Otc::South || direction == Otc::East)) { if (g_game.getFeature(Otc::GameWingOffset) && zPattern > 0) { if (direction == Otc::East) - wingDest -= Point(6, 2); + wingDest -= Point(6, 2) * g_sprites.getOffsetFactor(); else - wingDest -= Point(0, 6); + wingDest -= Point(0, 6) * g_sprites.getOffsetFactor(); } drawWings(); } @@ -280,11 +280,11 @@ void Outfit::draw(Point dest, Otc::Direction direction, uint walkAnimationPhase, if (g_game.getFeature(Otc::GameAuraFrontAndBack)){ if (zPattern > 0) { if (direction == Otc::East) - topAuraDest -= Point(12, 6); + topAuraDest -= Point(12, 6) * g_sprites.getOffsetFactor(); else if (direction == Otc::South) - topAuraDest -= Point(1, 12); + topAuraDest -= Point(1, 12) * g_sprites.getOffsetFactor(); else - topAuraDest -= Point(4, 6); + topAuraDest -= Point(4, 6) * g_sprites.getOffsetFactor(); } drawTopAura(); } diff --git a/src/client/spritemanager.cpp b/src/client/spritemanager.cpp index 9cc7cf59..94d90135 100644 --- a/src/client/spritemanager.cpp +++ b/src/client/spritemanager.cpp @@ -27,6 +27,7 @@ #include #include #include +#include SpriteManager g_sprites; @@ -41,42 +42,18 @@ void SpriteManager::terminate() unload(); } -bool SpriteManager::loadSpr(std::string file) +bool SpriteManager::loadSpr(std::string file, bool isHdMod) { m_spritesCount = 0; m_signature = 0; - m_spriteSize = Otc::TILE_PIXELS; m_loaded = false; m_sprites.clear(); + m_isHdMod = isHdMod; - try { - file = g_resources.guessFilePath(file, "spr"); - - m_spritesFile = g_resources.openFile(file, g_game.getFeature(Otc::GameDontCacheFiles)); - - m_signature = m_spritesFile->getU32(); - if (m_signature == *((uint32_t*)"OTV8")) { - m_signature = m_spritesFile->getU32(); - m_spritesCount = m_spritesFile->getU32(); - m_sprites.resize(m_spritesCount + 1); - for (int i = 1; i <= m_spritesCount; ++i) { - int bufferSize = m_spritesFile->getU16(); - if (bufferSize == 0) continue; - m_sprites[i].resize(bufferSize + 1); - m_sprites[i][0] = 0; - m_spritesFile->read(m_sprites[i].data() + 1, bufferSize); - } - m_spritesFile = nullptr; - } else { - m_spritesCount = g_game.getFeature(Otc::GameSpritesU32) ? m_spritesFile->getU32() : m_spritesFile->getU16(); - m_spritesOffset = m_spritesFile->tell(); - } - m_loaded = true; - g_lua.callGlobalField("g_sprites", "onLoadSpr", file); - return true; - } catch (stdext::exception& e) { - g_logger.error(stdext::format("Failed to load sprites from '%s': %s", file, e.what())); - return false; + if (isHdMod) { + return loadHdSpr(file); + } else { + return loadCasualSpr(file); } } @@ -320,12 +297,104 @@ void SpriteManager::unload() } ImagePtr SpriteManager::getSpriteImage(int id) +{ + if (m_isHdMod) { + return getSpriteImageHd(id); + } + else { + return getSpriteImageCasual(id); + } +} + +bool SpriteManager::loadCasualSpr(std::string file) +{ + m_spriteSize = 32u; + try { + file = g_resources.guessFilePath(file, "spr"); + + m_spritesFile = g_resources.openFile(file, g_game.getFeature(Otc::GameDontCacheFiles)); + + m_signature = m_spritesFile->getU32(); + if (m_signature == *((uint32_t*)"OTV8")) { + m_signature = m_spritesFile->getU32(); + m_spritesCount = m_spritesFile->getU32(); + m_sprites.resize(m_spritesCount + 1); + for (int i = 1; i <= m_spritesCount; ++i) { + int bufferSize = m_spritesFile->getU16(); + if (bufferSize == 0) continue; + m_sprites[i].resize(bufferSize + 1); + m_sprites[i][0] = 0; + m_spritesFile->read(m_sprites[i].data() + 1, bufferSize); + } + m_spritesFile = nullptr; + } + else { + m_spritesCount = g_game.getFeature(Otc::GameSpritesU32) ? m_spritesFile->getU32() : m_spritesFile->getU16(); + m_spritesOffset = m_spritesFile->tell(); + } + m_loaded = true; + g_lua.callGlobalField("g_sprites", "onLoadSpr", file); + return true; + } + catch (stdext::exception& e) { + g_logger.error(stdext::format("Failed to load sprites from '%s': %s", file, e.what())); + return false; + } +} + +bool SpriteManager::loadHdSpr(std::string file) +{ + m_spriteSize = 64u; + std::unordered_map cachedDataLocal; + + try { + auto inFilePath = g_resources.guessFilePath(file, "cwm"); + auto spritesFile = g_resources.openFile(inFilePath, true); + + std::string fileBuffer = std::string(spritesFile->size(), '\0'); + spritesFile->read(fileBuffer.data(), fileBuffer.size()); + spritesFile->close(); + + PngUnpacker pu(std::move(fileBuffer)); + pu.unpackFiles(); + + const std::vector& packedData = pu.getPackedFileData(); + + size_t metadataSize = pu.getMetadata().size(); + + for (const auto& fileMetadata : pu.getMetadata()) { + uint32_t imageID = std::stoi(fileMetadata.getFileName()); + cachedDataLocal[imageID].resize(fileMetadata.getFileSize()); + + std::copy_n(&packedData[fileMetadata.getOffset()], fileMetadata.getFileSize(), cachedDataLocal[imageID].begin()); + } + + m_spritesCount = cachedDataLocal.size(); + m_cachedData = std::move(cachedDataLocal); + + if (m_spritesCount == 0) { + g_logger.error(stdext::format("Failed to load sprites from '%s': %s - no files", file)); + return false; + } + + m_loaded = true; + return true; + } + catch (stdext::exception& e) { + g_logger.error(stdext::format("Failed to load sprites from '%s': %s", file, e.what())); + return false; + } + + return false; +} + +ImagePtr SpriteManager::getSpriteImageCasual(int id) { try { int spriteDataSize = m_spriteSize * m_spriteSize * 4; if (!m_sprites.empty()) { - if (id >= (int)m_sprites.size()) + if (id >= (int)m_sprites.size()) return nullptr; auto& buffer = m_sprites[id]; if (buffer.size() < 5) @@ -351,7 +420,7 @@ ImagePtr SpriteManager::getSpriteImage(int id) bufferPos += 2; uint16_t coloredPixels = *(uint16_t*)(&buffer[bufferPos]); bufferPos += 2; - + writePos += transparentPixels * 4; for (int i = 0; i < coloredPixels; ++i) { pixels[writePos++] = buffer[bufferPos++]; @@ -359,7 +428,8 @@ ImagePtr SpriteManager::getSpriteImage(int id) pixels[writePos++] = buffer[bufferPos++]; if (hasAlpha) { pixels[writePos] = buffer[bufferPos++]; - } else { + } + else { pixels[writePos] = 0xFF; } writePos += 1; @@ -407,7 +477,8 @@ ImagePtr SpriteManager::getSpriteImage(int id) m_spritesFile->read(&pixels[writePos], std::min(coloredPixels * 4, spriteDataSize - writePos)); writePos += coloredPixels * 4; read += 4 + (4 * coloredPixels); - } else { + } + else { for (int i = 0; i < coloredPixels && writePos < spriteDataSize; i++) { pixels[writePos + 0] = m_spritesFile->getU8(); pixels[writePos + 1] = m_spritesFile->getU8(); @@ -420,8 +491,42 @@ ImagePtr SpriteManager::getSpriteImage(int id) } return image; - } catch (stdext::exception & e) { + } + catch (stdext::exception& e) { g_logger.error(stdext::format("Failed to get sprite id %d: %s", id, e.what())); return nullptr; } -} \ No newline at end of file +} + +ImagePtr SpriteManager::getSpriteImageHd(int id) +{ + if (id == 0 || !m_loaded) + return nullptr; + + if (m_cachedData.find(id) == m_cachedData.end()) + { + return nullptr; + } + + auto it = m_images.find(id); + + ImagePtr image; + if (it == m_images.end()) { + + try { + image = Image::loadPNG(m_cachedData[id].data(), m_cachedData[id].size()); + } + catch (std::exception e) + { + return nullptr; + } + if (image) { + m_images[id] = image; + } + } + else { + image = it->second; + } + + return image; +} diff --git a/src/client/spritemanager.h b/src/client/spritemanager.h index 22e286b7..19e00697 100644 --- a/src/client/spritemanager.h +++ b/src/client/spritemanager.h @@ -30,17 +30,12 @@ //@bindsingleton g_sprites class SpriteManager { - enum { - SPRITE_SIZE = Otc::TILE_PIXELS, - SPRITE_DATA_SIZE = SPRITE_SIZE*SPRITE_SIZE * 4 - }; - public: SpriteManager(); void terminate(); - bool loadSpr(std::string file); + bool loadSpr(std::string file, bool isHdMod); void unload(); #ifdef WITH_ENCRYPTION @@ -57,15 +52,26 @@ class SpriteManager bool isLoaded() { return m_loaded; } int spriteSize() { return m_spriteSize; } + float getOffsetFactor() const { return static_cast(m_spriteSize) / 32.0f; } + bool isHdMod() const { return m_isHdMod; } private: + bool loadCasualSpr(std::string file); + bool loadHdSpr(std::string file); + + ImagePtr getSpriteImageCasual(int id); + ImagePtr getSpriteImageHd(int id); bool m_loaded = false; + bool m_isHdMod = false; uint32 m_signature; int m_spritesCount; int m_spritesOffset; - int m_spriteSize = Otc::TILE_PIXELS; + int m_spriteSize; FileStreamPtr m_spritesFile; std::vector> m_sprites; + + std::unordered_map m_images; + std::unordered_map m_cachedData; }; extern SpriteManager g_sprites; diff --git a/src/client/statictext.cpp b/src/client/statictext.cpp index b04a8b66..c94ab2ec 100644 --- a/src/client/statictext.cpp +++ b/src/client/statictext.cpp @@ -22,6 +22,7 @@ #include "statictext.h" #include "map.h" +#include "spritemanager.h" #include #include #include @@ -38,7 +39,7 @@ StaticText::StaticText() void StaticText::drawText(const Point& dest, const Rect& parentRect) { Size textSize = m_cachedText.getTextSize(); - Rect rect = Rect(dest - Point(textSize.width() / 2, textSize.height()) + Point(20, 5), textSize); + Rect rect = Rect(dest - Point(textSize.width() / 2, textSize.height()) + Point(20, 5 - (5 * (g_sprites.getOffsetFactor() - 1))), textSize); Rect boundRect = rect; boundRect.bind(parentRect); diff --git a/src/client/thingtype.cpp b/src/client/thingtype.cpp index 6c4c4bf8..540a8874 100644 --- a/src/client/thingtype.cpp +++ b/src/client/thingtype.cpp @@ -288,10 +288,10 @@ void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileS sizes.push_back(m_size); if(width > 1 || height > 1) { m_realSize = fin->getU8(); - m_exactSize = std::min(m_realSize, std::max(width * Otc::TILE_PIXELS, height * Otc::TILE_PIXELS)); + m_exactSize = std::min(m_realSize, std::max(width * g_sprites.spriteSize(), height * g_sprites.spriteSize())); } else - m_exactSize = Otc::TILE_PIXELS; + m_exactSize = g_sprites.spriteSize(); m_layers = fin->getU8(); m_numPatternX = fin->getU8(); @@ -510,7 +510,7 @@ DrawQueueItem* ThingType::draw(const Point& dest, int layer, int xPattern, int y Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex]; Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex]; - Rect screenRect(dest + (textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * Otc::TILE_PIXELS), textureRect.size()); + Rect screenRect(dest + (textureOffset - m_displacement * g_sprites.getOffsetFactor() - (m_size.toPoint() - Point(1, 1)) * g_sprites.spriteSize()), textureRect.size()); bool useOpacity = m_opacity < 1.0f; if (useOpacity) @@ -545,16 +545,16 @@ DrawQueueItem* ThingType::draw(const Rect& dest, int layer, int xPattern, int yP if (useOpacity) color.setAlpha(m_opacity); - Size size = m_size * Otc::TILE_PIXELS; + Size size = m_size * g_sprites.spriteSize(); if (!size.isValid()) return nullptr; // size correction for some too big items if ((m_size.width() > 1 || m_size.height() > 1) && - textureRect.width() <= Otc::TILE_PIXELS && textureRect.height() <= Otc::TILE_PIXELS) { - size = Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS); - textureOffset = Point((Otc::TILE_PIXELS - textureRect.width()) / m_size.width(), - (Otc::TILE_PIXELS - textureRect.height()) / m_size.height()); + textureRect.width() <= g_sprites.spriteSize() && textureRect.height() <= g_sprites.spriteSize()) { + size = Size(g_sprites.spriteSize(), g_sprites.spriteSize()); + textureOffset = Point((g_sprites.spriteSize() - textureRect.width()) / m_size.width(), + (g_sprites.spriteSize() - textureRect.height()) / m_size.height()); } float scale = std::min((float)dest.width() / size.width(), (float)dest.height() / size.height()); @@ -585,7 +585,7 @@ std::shared_ptr ThingType::drawOutfit(const Point& dest, int m Size size = textureRect.size(); if (!size.isValid()) return nullptr; - Rect screenRect(dest + (textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * Otc::TILE_PIXELS), textureRect.size()); + Rect screenRect(dest + (textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * g_sprites.spriteSize()), textureRect.size()); bool useOpacity = m_opacity < 1.0f; if (useOpacity) @@ -619,7 +619,7 @@ Rect ThingType::getDrawSize(const Point& dest, int layer, int xPattern, int yPat Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex]; Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex]; - return Rect(dest + textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * Otc::TILE_PIXELS, textureRect.size()); + return Rect(dest + textureOffset - m_displacement - (m_size.toPoint() - Point(1, 1)) * g_sprites.spriteSize(), textureRect.size()); } @@ -708,7 +708,7 @@ const TexturePtr& ThingType::getTexture(int animationPhase) Size ThingType::getBestTextureDimension(int w, int h, int count) { - const int MAX = Otc::TILE_PIXELS; + const int MAX = g_sprites.spriteSize(); int k = 1; while(k < w) diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 207bd394..3cd2b2ce 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -47,7 +47,7 @@ void Tile::drawGround(const Point& dest, LightView* lightView) m_topDraws = 0; m_drawElevation = 0; if (m_fill != Color::alpha) { - g_drawQueue->addFilledRect(Rect(dest, Otc::TILE_PIXELS, Otc::TILE_PIXELS), m_fill); + g_drawQueue->addFilledRect(Rect(dest, g_sprites.spriteSize(), g_sprites.spriteSize()), m_fill); return; } @@ -58,7 +58,7 @@ void Tile::drawGround(const Point& dest, LightView* lightView) if (thing->isHidden()) continue; - thing->draw(dest - m_drawElevation, true, lightView); + thing->draw(dest - m_drawElevation * g_sprites.getOffsetFactor(), true, lightView); m_drawElevation = std::min(m_drawElevation + thing->getElevation(), Otc::MAX_ELEVATION); } } @@ -79,7 +79,7 @@ void Tile::drawBottom(const Point& dest, LightView* lightView) if (thing->isHidden() || !afterBottom) continue; - thing->draw(dest - m_drawElevation, true, lightView); + thing->draw(dest - m_drawElevation * g_sprites.getOffsetFactor(), true, lightView); m_drawElevation = std::min(m_drawElevation + thing->getElevation(), Otc::MAX_ELEVATION); } } @@ -93,7 +93,7 @@ void Tile::drawBottom(const Point& dest, LightView* lightView) if (thing->isHidden()) continue; - thing->draw(dest - m_drawElevation, true, lightView); + thing->draw(dest - m_drawElevation * g_sprites.getOffsetFactor() , true, lightView); m_drawElevation = std::min(m_drawElevation + thing->getElevation(), Otc::MAX_ELEVATION); if (thing->isLyingCorpse()) { @@ -108,8 +108,8 @@ void Tile::drawBottom(const Point& dest, LightView* lightView) if (x == 0 && y == 0) continue; if (const TilePtr& tile = g_map.getTile(m_position.translated(x, y))) { - tile->drawCreatures(dest + Point(x * Otc::TILE_PIXELS, y * Otc::TILE_PIXELS), lightView); - tile->drawTop(dest + Point(x * Otc::TILE_PIXELS, y * Otc::TILE_PIXELS), lightView); + tile->drawCreatures(dest + Point(x * g_sprites.spriteSize(), y * g_sprites.spriteSize()), lightView); + tile->drawTop(dest + Point(x * g_sprites.spriteSize(), y * g_sprites.spriteSize()), lightView); } } } @@ -131,8 +131,8 @@ void Tile::drawCreatures(const Point& dest, LightView* lightView) for (const CreaturePtr& creature : m_walkingCreatures) { if (creature->isHidden()) continue; - Point creatureDest(dest.x + ((creature->getPrewalkingPosition().x - m_position.x) * Otc::TILE_PIXELS - m_drawElevation), - dest.y + ((creature->getPrewalkingPosition().y - m_position.y) * Otc::TILE_PIXELS - m_drawElevation)); + Point creatureDest(dest.x + ((creature->getPrewalkingPosition().x - m_position.x) * g_sprites.spriteSize() - m_drawElevation * g_sprites.getOffsetFactor()), + dest.y + ((creature->getPrewalkingPosition().y - m_position.y) * g_sprites.spriteSize() - m_drawElevation * g_sprites.getOffsetFactor())); creature->draw(creatureDest, true, lightView); } @@ -147,7 +147,7 @@ void Tile::drawCreatures(const Point& dest, LightView* lightView) CreaturePtr creature = thing->static_self_cast(); if (!creature || creature->isWalking()) continue; - creature->draw(dest - m_drawElevation, true, lightView); + creature->draw(dest - m_drawElevation * g_sprites.getOffsetFactor(), true, lightView); } } @@ -162,8 +162,8 @@ void Tile::drawTop(const Point& dest, LightView* lightView) for (const CreaturePtr& creature : m_walkingCreatures) { if (creature->isHidden()) continue; - Point creatureDest(dest.x + ((creature->getPrewalkingPosition().x - m_position.x) * Otc::TILE_PIXELS - m_drawElevation), - dest.y + ((creature->getPrewalkingPosition().y - m_position.y) * Otc::TILE_PIXELS - m_drawElevation)); + Point creatureDest(dest.x + ((creature->getPrewalkingPosition().x - m_position.x) * g_sprites.spriteSize() - m_drawElevation), + dest.y + ((creature->getPrewalkingPosition().y - m_position.y) * g_sprites.spriteSize() - m_drawElevation)); creature->draw(creatureDest, true, lightView); } @@ -178,7 +178,7 @@ void Tile::drawTop(const Point& dest, LightView* lightView) CreaturePtr creature = thing->static_self_cast(); if (!creature || creature->isWalking()) continue; - creature->draw(dest - m_drawElevation, true, lightView); + creature->draw(dest - m_drawElevation * g_sprites.getOffsetFactor(), true, lightView); } // effects @@ -186,7 +186,7 @@ void Tile::drawTop(const Point& dest, LightView* lightView) for (int i = limit; i >= 0; --i) { if (m_effects[i]->isHidden()) continue; - m_effects[i]->draw(dest - m_drawElevation, m_position.x - g_map.getCentralPosition().x, m_position.y - g_map.getCentralPosition().y, true, lightView); + m_effects[i]->draw(dest - m_drawElevation * g_sprites.getOffsetFactor(), m_position.x - g_map.getCentralPosition().x, m_position.y - g_map.getCentralPosition().y, true, lightView); } // top @@ -564,10 +564,10 @@ CreaturePtr Tile::getTopCreatureEx(Point offset) for (const CreaturePtr& c : tile->getCreatures()) { if (c->isLocalPlayer()) { localPlayer = c; - localPlayerOffset = Point(offset.x - xy[0] * Otc::TILE_PIXELS, offset.y - xy[1] * Otc::TILE_PIXELS); + localPlayerOffset = Point(offset.x - xy[0] * g_sprites.spriteSize(), offset.y - xy[1] * g_sprites.spriteSize()); continue; } - if (c->isInsideOffset(Point(offset.x - xy[0] * Otc::TILE_PIXELS, offset.y - xy[1] * Otc::TILE_PIXELS))) + if (c->isInsideOffset(Point(offset.x - xy[0] * g_sprites.spriteSize(), offset.y - xy[1] * g_sprites.spriteSize()))) return c; } } diff --git a/src/client/uicreature.cpp b/src/client/uicreature.cpp index 782287ff..1be8ee69 100644 --- a/src/client/uicreature.cpp +++ b/src/client/uicreature.cpp @@ -21,6 +21,7 @@ */ #include "uicreature.h" +#include "spritemanager.h" #include #include @@ -50,7 +51,7 @@ void UICreature::drawSelf(Fw::DrawPane drawPane) } if(m_scale >= 0.01) // TODO: make it correctly - m_creature->drawOutfit(Rect(getPaddingRect().topLeft(), Otc::TILE_PIXELS * m_scale, Otc::TILE_PIXELS * m_scale), m_direction, m_imageColor, m_animate); + m_creature->drawOutfit(Rect(getPaddingRect().topLeft(), g_sprites.spriteSize() * m_scale, g_sprites.spriteSize() * m_scale), m_direction, m_imageColor, m_animate); else m_creature->drawOutfit(getPaddingRect(), m_direction, m_imageColor, m_animate); } diff --git a/src/client/uiitem.cpp b/src/client/uiitem.cpp index 47ffafcc..7f2714f0 100644 --- a/src/client/uiitem.cpp +++ b/src/client/uiitem.cpp @@ -21,6 +21,7 @@ */ #include "uiitem.h" +#include "spritemanager.h" #include #include #include @@ -46,7 +47,7 @@ void UIItem::drawSelf(Fw::DrawPane drawPane) if(m_itemVisible && m_item) { Rect drawRect = getPaddingRect(); - int exactSize = std::max(Otc::TILE_PIXELS, m_item->getExactSize()); + int exactSize = std::max(g_sprites.spriteSize(), m_item->getExactSize()); if(exactSize == 0) return; diff --git a/src/framework/graphics/image.h b/src/framework/graphics/image.h index 53f4cf1e..f2738033 100644 --- a/src/framework/graphics/image.h +++ b/src/framework/graphics/image.h @@ -25,6 +25,7 @@ #include "declarations.h" #include +#include class Image : public stdext::shared_object { @@ -33,6 +34,18 @@ class Image : public stdext::shared_object static ImagePtr load(std::string file); static ImagePtr loadPNG(const std::string& file); + static ImagePtr loadPNG(const void* data, uint32_t size) + { + std::string temp((char*)data, size); + std::stringstream fin(temp); + ImagePtr image; + apng_data apng; + if (load_apng(fin, &apng) == 0) { + image = ImagePtr(new Image(Size(apng.width, apng.height), apng.bpp, apng.pdata)); + free_apng(&apng); + } + return image; + } void savePNG(const std::string& fileName); diff --git a/src/framework/util/pngunpacker.cpp b/src/framework/util/pngunpacker.cpp new file mode 100644 index 00000000..c125011c --- /dev/null +++ b/src/framework/util/pngunpacker.cpp @@ -0,0 +1,53 @@ +#include "pngunpacker.h" + +FileMetadata::FileMetadata(std::istream& istr) +{ + /* Read offset */ + istr.read(reinterpret_cast(&offset), sizeof(uint32_t)); + + /* Read file size */ + istr.read(reinterpret_cast(&fileSize), sizeof(uint32_t)); + + /* Read filename length */ + uint16_t filenameLen = 0; + istr.read(reinterpret_cast(&filenameLen), sizeof(uint16_t)); + + /* Read file name */ + fileName.resize(filenameLen); + istr.read(const_cast(fileName.data()), filenameLen); +} + +bool PngUnpacker::unpackFiles() +{ + packedFileData.clear(); + metadata.clear(); + + if (fileContent.size() == 0) { + g_logger.error(stdext::format("Failed to load sprites from - no files")); + return false; + } + + std::stringstream packedDataSS(std::move(fileContent)); + + /* Read entry count */ + uint32_t entryCount = 0; + packedDataSS.read(reinterpret_cast(&entryCount), sizeof(uint32_t)); + + if (entryCount == 0) { + g_logger.error(stdext::format("Failed to load sprites - no files")); + return false; + } + + metadata.reserve(entryCount); + for (uint32_t i = 0; i < entryCount; ++i) { + metadata.emplace_back(packedDataSS); + } + + /* Read packed files data */ + std::streamsize currPos = packedDataSS.tellg(); + std::streamsize bytesLeft = fileContent.size() - currPos; + packedFileData.resize(bytesLeft); + + packedDataSS.read(packedFileData.data(), packedFileData.size()); + return true; +} \ No newline at end of file diff --git a/src/framework/util/pngunpacker.h b/src/framework/util/pngunpacker.h new file mode 100644 index 00000000..ac0348d2 --- /dev/null +++ b/src/framework/util/pngunpacker.h @@ -0,0 +1,39 @@ +#ifndef __PNG_UNPACKER_H +#define __PNG_UNPACKER_H + +#include +#include + + /* File unpacking related */ +class FileMetadata +{ +public: + FileMetadata(std::istream& istr); + + const std::string& getFileName() const { return fileName; } + uint32_t getOffset() const { return offset; } + uint32_t getFileSize() const { return fileSize; } +private: + std::string fileName; + uint32_t offset = 0; + uint32_t fileSize = 0; +}; + +class PngUnpacker +{ +public: + PngUnpacker(std::string fileContent) : + fileContent(std::move(fileContent)) + {} + + bool unpackFiles(); + + const std::vector& getPackedFileData() const { return packedFileData; } + const std::vector& getMetadata() const { return metadata; } +private: + std::string fileContent; + std::vector packedFileData; + std::vector metadata; +}; + +#endif \ No newline at end of file diff --git a/vc16/otclient.vcxproj b/vc16/otclient.vcxproj index 6a9ffb47..6ceec749 100644 --- a/vc16/otclient.vcxproj +++ b/vc16/otclient.vcxproj @@ -220,6 +220,7 @@ false + false @@ -403,6 +404,7 @@ + diff --git a/vc16/otclient.vcxproj.filters b/vc16/otclient.vcxproj.filters index 45e82781..49c260c5 100644 --- a/vc16/otclient.vcxproj.filters +++ b/vc16/otclient.vcxproj.filters @@ -195,6 +195,9 @@ Source Files\client + + Header Files\framework\util + @@ -755,6 +758,9 @@ Header Files\client + + Header Files\framework\util +