diff --git a/modules/game_npctrade/npctrade.lua b/modules/game_npctrade/npctrade.lua index 454fc659..79bb83e6 100644 --- a/modules/game_npctrade/npctrade.lua +++ b/modules/game_npctrade/npctrade.lua @@ -210,10 +210,10 @@ local function onOpenNpcTrade(items) newItem.name = item[2] newItem.weight = item[3] / 100 - if item[4] >= 0 then + if item[4] > 0 then newItem.price = item[4] table.insert(tradeItems[BUY], newItem) - elseif item[5] >= 0 then + elseif item[5] > 0 then newItem.price = item[5] table.insert(tradeItems[SELL], newItem) else diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 7c796d64..46712e91 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -13,7 +13,7 @@ SET(BUILD_REVISION "custom" CACHE "Git revision string (intended for releases)" # set debug as default build type IF(NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE RelWithDebInfo) + SET(CMAKE_BUILD_TYPE Debug) ENDIF() # setup compiler options diff --git a/src/framework/graphics/image.cpp b/src/framework/graphics/image.cpp index 547138ba..102a3529 100644 --- a/src/framework/graphics/image.cpp +++ b/src/framework/graphics/image.cpp @@ -83,3 +83,23 @@ void Image::overwriteMask(const Color& maskedColor, const Color& insideColor, co a = writeColor.a(); } } + +void Image::append(const Point& dest, const ImagePtr& other) +{ + if(!other) + return; + + uint8* otherPixels = other->getPixelData(); + for(int p = 0; p < other->getPixelCount(); ++p) { + int x = p % other->getWidth(); + int y = p / other->getWidth(); + int pos = ((dest.y + y) * m_size.width() + (dest.x + x)) * 4; + + if(otherPixels[p*4+3] == 0xFF) { + m_pixels[pos+0] = otherPixels[p*4+0]; + m_pixels[pos+1] = otherPixels[p*4+1]; + m_pixels[pos+2] = otherPixels[p*4+2]; + m_pixels[pos+3] = otherPixels[p*4+3]; + } + } +} diff --git a/src/framework/graphics/image.h b/src/framework/graphics/image.h index 012f1df1..33a0655f 100644 --- a/src/framework/graphics/image.h +++ b/src/framework/graphics/image.h @@ -35,6 +35,7 @@ public: static ImagePtr loadPNG(const std::string& file); void overwriteMask(const Color& maskedColor, const Color& insideColor = Color::white, const Color& outsideColor = Color::alpha); + void append(const Point& dest, const ImagePtr &other); std::vector& getPixels() { return m_pixels; } uint8* getPixelData() { return &m_pixels[0]; } @@ -43,6 +44,7 @@ public: int getWidth() { return m_size.width(); } int getHeight() { return m_size.height(); } int getBpp() { return m_bpp; } + uint8* getPixel(int x, int y) { return &m_pixels[(y * m_size.width() + x) * 4]; } private: std::vector m_pixels; diff --git a/src/framework/graphics/texture.cpp b/src/framework/graphics/texture.cpp index 4b6f0127..801384bc 100644 --- a/src/framework/graphics/texture.cpp +++ b/src/framework/graphics/texture.cpp @@ -142,6 +142,7 @@ void Texture::generateMipmaps() //FIXME: disabled because mipmaps size needs to be in base of 2, // and the current algorithmn does not support that //generateSoftwareMipmaps(getPixels()); + logTraceError("non power of 2."); } } diff --git a/src/otclient/core/creature.cpp b/src/otclient/core/creature.cpp index 969275c4..899c242f 100644 --- a/src/otclient/core/creature.cpp +++ b/src/otclient/core/creature.cpp @@ -133,6 +133,7 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani outfitProgram->setUniformValue(FEET_COLOR_UNIFORM, m_outfit.getFeetColor()); */ + m_type->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase); for(int h = 0; h < getDimensionHeight(); h++) { for(int w = 0; w < getDimensionWidth(); w++) { // setup texture outfit mask @@ -145,7 +146,6 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani */ Point p = dest + (-Point(w,h)*Otc::TILE_PIXELS)*scaleFactor; - m_type->draw(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 0, animationPhase); if(getLayers() > 1) { g_painter->setCompositionMode(Painter::CompositionMode_Multiply); @@ -190,7 +190,7 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani if(m_outfit.getCategory() == ThingsType::Effect) animationPhase = std::min(animationPhase+1, getAnimationPhases()); - m_type->draw(dest, scaleFactor, 0, 0, 0, animationPhase); + m_type->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase); } } diff --git a/src/otclient/core/effect.cpp b/src/otclient/core/effect.cpp index 36ae0459..1ea7b45e 100644 --- a/src/otclient/core/effect.cpp +++ b/src/otclient/core/effect.cpp @@ -32,7 +32,7 @@ void Effect::draw(const Point& dest, float scaleFactor, bool animate) int animationPhase = 0; if(animate) animationPhase = std::min((int)(m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME), getAnimationPhases() - 1); - m_type->draw(dest, scaleFactor, 0, 0, 0, animationPhase); + m_type->draw(dest, scaleFactor, 0, 0, 0, 0, animationPhase); } void Effect::startAnimation() diff --git a/src/otclient/core/item.cpp b/src/otclient/core/item.cpp index 0d6624ee..bfeeefa3 100644 --- a/src/otclient/core/item.cpp +++ b/src/otclient/core/item.cpp @@ -181,7 +181,7 @@ void Item::draw(const Point& dest, float scaleFactor, bool animate) */ // now we can draw the item - m_type->draw(dest, scaleFactor, xPattern, yPattern, zPattern, animationPhase); + m_type->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase); // release draw shader g_painter->resetShaderProgram(); diff --git a/src/otclient/core/missile.cpp b/src/otclient/core/missile.cpp index bf3c6cae..264f62a1 100644 --- a/src/otclient/core/missile.cpp +++ b/src/otclient/core/missile.cpp @@ -63,7 +63,7 @@ void Missile::draw(const Point& dest, float scaleFactor, bool animate) } float fraction = m_animationTimer.ticksElapsed() / m_duration; - m_type->draw(dest + m_delta * fraction * scaleFactor, scaleFactor, xPattern, yPattern, 0, 0); + m_type->draw(dest + m_delta * fraction * scaleFactor, 0, scaleFactor, xPattern, yPattern, 0, 0); } void Missile::setPath(const Position& fromPosition, const Position& toPosition) diff --git a/src/otclient/core/thingstype.cpp b/src/otclient/core/thingstype.cpp index a611def4..698f063e 100644 --- a/src/otclient/core/thingstype.cpp +++ b/src/otclient/core/thingstype.cpp @@ -48,6 +48,7 @@ bool ThingsType::load(const std::string& file) for(int i = 0; i < LastCategory; ++i) { m_things[i].resize(numThings[i]); for(int id = 0; id < numThings[i]; ++id) { + m_things[i][id].m_category = i; if(!parseThingType(fin, m_things[i][id])) { logError("corrupt or dat file"); return false; @@ -142,10 +143,13 @@ bool ThingsType::parseThingType(const FileStreamPtr& fin, ThingType& thingType) return false; thingType.m_spritesIndex.resize(totalSprites); - thingType.m_sprites.resize(totalSprites); for(int i = 0; i < totalSprites; i++) thingType.m_spritesIndex[i] = fin->getU16(); + thingType.m_textures.resize(thingType.m_dimensions[ThingType::AnimationPhases]); + thingType.m_texturesFramesRects.resize(thingType.m_dimensions[ThingType::AnimationPhases]); + thingType.m_texturesFramesOffsets.resize(thingType.m_dimensions[ThingType::AnimationPhases]); + return true; } diff --git a/src/otclient/core/thingtype.cpp b/src/otclient/core/thingtype.cpp index 22a1cb72..4fe73b1e 100644 --- a/src/otclient/core/thingtype.cpp +++ b/src/otclient/core/thingtype.cpp @@ -21,6 +21,7 @@ */ #include "thingtype.h" +#include "thingstype.h" #include "spritemanager.h" #include @@ -34,23 +35,20 @@ ThingType::ThingType() m_properties.fill(false); } -void ThingType::draw(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase) +void ThingType::draw(const Point& dest, float scaleFactor, int layer, int xPattern, int yPattern, int zPattern, int animationPhase) { - int scaledSize = Otc::TILE_PIXELS * scaleFactor; + const TexturePtr& texture = getTexture(animationPhase); // rects might not be calculated yet. + + int frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern); + Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex]; + Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex]; Point displacement(m_parameters[DisplacementX], m_parameters[DisplacementY]); + Rect screenRect(dest - displacement - Point(32 * m_dimensions[Width] * scaleFactor, 32 * m_dimensions[Height] * scaleFactor) + Point(32, 32) + textureOffset, + textureRect.size() * scaleFactor); - Rect drawRect(dest - displacement*scaleFactor, Size(scaledSize, scaledSize)); g_painter->setColor(Color::white); - g_painter->drawTexturedRect(drawRect, getSprite(w, h, layer, xPattern, yPattern, zPattern, animationPhase)); -} - -void ThingType::draw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int animationPhase) -{ - for(int l = 0; l < m_dimensions[Layers]; ++l) - for(int w = 0; w < m_dimensions[Width]; ++w) - for(int h = 0; h < m_dimensions[Height]; ++h) - draw(dest - Point(w,h)*Otc::TILE_PIXELS*scaleFactor, scaleFactor, w, h, xPattern, yPattern, zPattern, l, animationPhase); + g_painter->drawTexturedRect(screenRect, texture, textureRect); } void ThingType::drawMask(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase, ThingType::SpriteMask mask) @@ -63,26 +61,6 @@ void ThingType::drawMask(const Point& dest, float scaleFactor, int w, int h, int g_painter->drawTexturedRect(drawRect, getSpriteMask(w, h, layer, xPattern, yPattern, zPattern, animationPhase, mask)); } -TexturePtr& ThingType::getSprite(int w, int h, int l, int x, int y, int z, int a) -{ - uint index = getSpriteIndex(w,h,l,x,y,z,a); - TexturePtr& spriteTexture = m_sprites[index]; - if(!spriteTexture) { - ImagePtr spriteImage = g_sprites.getSpriteImage(m_spritesIndex[index]); - if(!spriteImage) - spriteTexture = g_graphics.getEmptyTexture(); - else { - spriteTexture = TexturePtr(new Texture(spriteImage)); - spriteTexture->setSmooth(true); - - if(g_graphics.canUseMipmaps()) - spriteTexture->generateSoftwareMipmaps(spriteImage->getPixels()); - } - } - - return spriteTexture; -} - TexturePtr& ThingType::getSpriteMask(int w, int h, int l, int x, int y, int z, int a, ThingType::SpriteMask mask) { if(m_spritesMask.size() == 0) @@ -108,3 +86,103 @@ TexturePtr& ThingType::getSpriteMask(int w, int h, int l, int x, int y, int z, i return maskTexture; } + +TexturePtr& ThingType::getTexture(int animationPhase) +{ + TexturePtr& animationPhaseTexture = m_textures[animationPhase]; + if(!animationPhaseTexture) { + + int textureLayers = m_dimensions[Layers]; + if(m_category != ThingsType::Creature) // we dont need layers in texture. they can be 'rendered' now. + textureLayers = 1; + + int indexSize = textureLayers * m_dimensions[PatternX] * m_dimensions[PatternY] * m_dimensions[PatternZ]; + Size textureSize = getBestDimension(m_dimensions[Width], m_dimensions[Height], indexSize); + ImagePtr fullImage = ImagePtr(new Image(textureSize * 32)); + + m_texturesFramesRects[animationPhase].resize(indexSize); + m_texturesFramesOffsets[animationPhase].resize(indexSize); + + for(int z = 0; z < m_dimensions[PatternZ]; ++z) { + for(int y = 0; y < m_dimensions[PatternY]; ++y) { + for(int x = 0; x < m_dimensions[PatternX]; ++x) { + for(int l = 0; l < m_dimensions[Layers]; ++l) { + + int frameIndex = getTextureIndex(l % textureLayers, x, y, z); + Point framePos = Point(frameIndex % (textureSize.width() / m_dimensions[Width]) * m_dimensions[Width], + frameIndex / (textureSize.width() / m_dimensions[Width]) * m_dimensions[Height]) * 32; + + for(int h = 0; h < m_dimensions[Height]; ++h) { + for(int w = 0; w < m_dimensions[Width]; ++w) { + uint spriteIndex = getSpriteIndex(w, h, l, x, y, z, animationPhase); + ImagePtr spriteImage = g_sprites.getSpriteImage(m_spritesIndex[spriteIndex]); + if(spriteImage) { + Point spritePos = Point(m_dimensions[Width] - w - 1, + m_dimensions[Height] - h - 1) * 32; + + fullImage->append(framePos + spritePos, spriteImage); + } + } + } + + Rect drawRect(framePos + Point(m_dimensions[Width], m_dimensions[Height]) * 32, framePos); + for(int x = framePos.x; x < framePos.x + m_dimensions[Width] * 32; ++x) { + for(int y = framePos.y; y < framePos.y + m_dimensions[Height] * 32; ++y) { + uint8 *p = fullImage->getPixel(x,y); + if(p[3] != 0x00) { + drawRect.setTop(std::min(y, (int)drawRect.top())); + drawRect.setLeft(std::min(x, (int)drawRect.left())); + drawRect.setBottom(std::max(y, (int)drawRect.bottom())); + drawRect.setRight(std::max(x, (int)drawRect.right())); + } + } + } + + m_texturesFramesRects[animationPhase][frameIndex] = drawRect; + m_texturesFramesOffsets[animationPhase][frameIndex] = drawRect.topLeft() - framePos; + } + } + } + } + animationPhaseTexture = TexturePtr(new Texture(fullImage)); + animationPhaseTexture->setSmooth(true); + + //if(g_graphics.canUseMipmaps()) + //animationPhaseTexture->generateSoftwareMipmaps(fullImage->getPixels()); + } + return animationPhaseTexture; +} + +Size ThingType::getBestDimension(int w, int h, int count) +{ + const int MAX = 16; + + int k = 1; + while(k < w) + k<<=1; + w = k; + + k = 1; + while(k < h) + k<<=1; + h = k; + + int numSprites = w*h*count; + assert(numSprites <= MAX*MAX); + assert(w <= MAX); + assert(h <= MAX); + + Size bestDimension = Size(MAX, MAX); + for(int i=w;i<=MAX;i<<=1) { + for(int j=h;j<=MAX;j<<=1) { + Size candidateDimension = Size(i, j); + if(candidateDimension.area() < numSprites) + continue; + if((candidateDimension.area() < bestDimension.area()) || + (candidateDimension.area() == bestDimension.area() && candidateDimension.width() + candidateDimension.height() < bestDimension.width() + bestDimension.height())) + bestDimension = candidateDimension; + } + } + + return bestDimension; +} diff --git a/src/otclient/core/thingtype.h b/src/otclient/core/thingtype.h index 9947c895..df3aa9ae 100644 --- a/src/otclient/core/thingtype.h +++ b/src/otclient/core/thingtype.h @@ -24,8 +24,8 @@ #define THINGATTRIBUTES_H #include "declarations.h" - #include +#include struct ThingType { @@ -108,18 +108,20 @@ struct ThingType ThingType(); - void draw(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase); - void draw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int animationPhase); + void draw(const Point& dest, float scaleFactor, int layer, int xPattern, int yPattern, int zPattern, int animationPhase); void drawMask(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase, SpriteMask mask); TexturePtr& getSprite(int w, int h, int l, int x, int y, int z, int a); TexturePtr& getSpriteMask(int w, int h, int l, int x, int y, int z, int a, SpriteMask mask); + TexturePtr& getTexture(int animationPhase); bool getProperty(Property property) { return m_properties[property]; } int getParameter(Parameter param) { return m_parameters[param]; } int getDimension(Dimension dimension) { return m_dimensions[dimension]; } private: + Size getBestDimension(int w, int h, int count); + uint getSpriteIndex(int w, int h, int l, int x, int y, int z, int a) { uint index = ((((((a % m_dimensions[ThingType::AnimationPhases]) * m_dimensions[ThingType::PatternZ] + z) @@ -128,17 +130,28 @@ private: * m_dimensions[ThingType::Layers] + l) * m_dimensions[ThingType::Height] + h) * m_dimensions[ThingType::Width] + w; - assert(index < m_sprites.size()); + assert(index < m_spritesIndex.size()); return index; } + uint getTextureIndex(int l, int x, int y, int z) { + return ((l + * m_dimensions[ThingType::PatternZ] + z) + * m_dimensions[ThingType::PatternY] + y) + * m_dimensions[ThingType::PatternX] + x; + } + + int m_category; std::array m_dimensions; std::array m_parameters; std::array m_properties; std::vector m_spritesIndex; - std::vector m_sprites; std::vector> m_spritesMask; + std::vector m_textures; + std::vector > m_texturesFramesRects; + std::vector > m_texturesFramesOffsets; + friend class ThingsType; }; diff --git a/src/otclient/ui/uiitem.cpp b/src/otclient/ui/uiitem.cpp index ce636a0d..6f761bf8 100644 --- a/src/otclient/ui/uiitem.cpp +++ b/src/otclient/ui/uiitem.cpp @@ -53,6 +53,7 @@ void UIItem::drawSelf() g_painter->setColor(Color(231, 231, 231)); m_font->drawText(count, Rect(m_rect.topLeft(), m_rect.bottomRight() - Point(3, 0)), Fw::AlignBottomRight); } + // debug, show item id //m_font->drawText(Fw::tostring(m_item->getId()), m_rect, Fw::AlignBottomRight); } }