diff --git a/src/client/spritemanager.cpp b/src/client/spritemanager.cpp index 108a325f5a..4c639b831c 100644 --- a/src/client/spritemanager.cpp +++ b/src/client/spritemanager.cpp @@ -213,15 +213,14 @@ ImagePtr SpriteManager::getSpriteImage(const int id, bool& isLoading) const auto threadId = g_app.isLoadingAsyncTexture() ? stdext::getThreadId() : 0; if (const auto& sf = m_spritesFiles[threadId % m_spritesFiles.size()]) { - if (g_app.isLoadingAsyncTexture() && sf->m_loadingState.exchange(SpriteLoadState::LOADING, std::memory_order_acq_rel) == SpriteLoadState::LOADING) { + if (sf->m_loadingState.exchange(SpriteLoadState::LOADING, std::memory_order_acq_rel) == SpriteLoadState::LOADING) { isLoading = true; return nullptr; } auto image = m_spritesHd ? getSpriteImageHd(id, sf->file) : getSpriteImage(id, sf->file); - if (g_app.isLoadingAsyncTexture()) - sf->m_loadingState.store(SpriteLoadState::LOADED, std::memory_order_release); + sf->m_loadingState.store(SpriteLoadState::LOADED, std::memory_order_release); return image; } @@ -273,8 +272,8 @@ ImagePtr SpriteManager::getSpriteImage(const int id, const FileStreamPtr& file) int read = 0; bool hasAlpha = false; - constexpr int MAX_PIXEL_BLOCK = 4096; - uint8_t tempBuffer[MAX_PIXEL_BLOCK * 4]; // 4 = max channels + static constexpr int MAX_PIXEL_BLOCK = 4096; + static thread_local uint8_t tempBuffer[MAX_PIXEL_BLOCK * 4]; // 4 = max channels while (read < pixelDataSize && writePos < maxWriteSize) { const uint16_t transparentPixels = file->getU16(); diff --git a/src/framework/graphics/drawpool.cpp b/src/framework/graphics/drawpool.cpp index b1cc70ccc3..9822f06f13 100644 --- a/src/framework/graphics/drawpool.cpp +++ b/src/framework/graphics/drawpool.cpp @@ -48,14 +48,15 @@ DrawPool* DrawPool::create(const DrawPoolType type) return pool; } -void DrawPool::add(const Color& color, TexturePtr texture, DrawMethod&& method, const CoordsBufferPtr& coordsBuffer) +void DrawPool::add(const Color& color, const TexturePtr& texture, DrawMethod&& method, const CoordsBufferPtr& coordsBuffer) { + Texture* textureAtlas = nullptr; if (m_atlas && texture && texture->isCached(m_atlas->getType())) { - const auto& atlas = texture->getAtlas(m_atlas->getType()); - if (atlas->isEnabled()) { - texture = m_atlas->getTexture(atlas->layer, texture->isSmooth()); + const auto region = texture->getAtlas(m_atlas->getType()); + if (region->isEnabled()) { + textureAtlas = region->atlas; if (method.src.isValid()) - method.src = Rect(atlas->x + method.src.x(), atlas->y + method.src.y(), method.src.width(), method.src.height()); + method.src = Rect(region->x + method.src.x(), region->y + method.src.y(), method.src.width(), method.src.height()); } } @@ -67,7 +68,7 @@ void DrawPool::add(const Color& color, TexturePtr texture, DrawMethod&& method, if (m_alwaysGroupDrawings) { auto& coords = m_coords.try_emplace(getCurrentState().hash, nullptr).first->second; if (!coords) { - auto state = getState(texture, color); + auto state = getState(texture, textureAtlas, color); coords = list.emplace_back(std::move(state), getCoordsBuffer()).coords.get(); } @@ -91,7 +92,7 @@ void DrawPool::add(const Color& color, TexturePtr texture, DrawMethod&& method, } if (addNewObj) { - auto state = getState(texture, color); + auto state = getState(texture, textureAtlas, color); auto& draw = list.emplace_back(std::move(state), getCoordsBuffer()); if (coordsBuffer) { @@ -176,13 +177,16 @@ bool DrawPool::updateHash(const DrawMethod& method, const TexturePtr& texture, c return true; } -DrawPool::PoolState DrawPool::getState(const TexturePtr& texture, const Color& color) +DrawPool::PoolState DrawPool::getState(const TexturePtr& texture, Texture* textureAtlas, const Color& color) { PoolState copy = getCurrentState(); if (copy.color != color) copy.color = color; - if (texture) { + if (textureAtlas) { + copy.textureId = textureAtlas->getId(); + copy.textureMatrixId = textureAtlas->getTransformMatrixId(); + } else if (texture) { if (texture->isEmpty() || !texture->canCacheInAtlas() || texture->canCacheInAtlas() && m_atlas) { copy.texture = texture; } else { diff --git a/src/framework/graphics/drawpool.h b/src/framework/graphics/drawpool.h index c93d72f159..1fcdb059a6 100644 --- a/src/framework/graphics/drawpool.h +++ b/src/framework/graphics/drawpool.h @@ -272,7 +272,7 @@ class DrawPool STATE_BLEND_EQUATION = 1 << 4, }; - void add(const Color& color, TexturePtr texture, DrawMethod&& method, const CoordsBufferPtr& coordsBuffer = nullptr); + void add(const Color& color, const TexturePtr& texture, DrawMethod&& method, const CoordsBufferPtr& coordsBuffer = nullptr); void addAction(const std::function& action); void bindFrameBuffer(const Size& size, const Color& color = Color::white); @@ -281,7 +281,7 @@ class DrawPool void setFPS(const uint16_t fps) { m_refreshDelay = 1000 / fps; } bool updateHash(const DrawMethod& method, const TexturePtr& texture, const Color& color, bool hasCoord); - PoolState getState(const TexturePtr& texture, const Color& color); + PoolState getState(const TexturePtr& texture, Texture* textureAtlas, const Color& color); PoolState& getCurrentState() { return m_states[m_lastStateIndex]; } const PoolState& getCurrentState() const { return m_states[m_lastStateIndex]; } diff --git a/src/framework/graphics/textureatlas.cpp b/src/framework/graphics/textureatlas.cpp index 0f7d0f011d..d0475198cf 100644 --- a/src/framework/graphics/textureatlas.cpp +++ b/src/framework/graphics/textureatlas.cpp @@ -71,7 +71,8 @@ void TextureAtlas::addTexture(const TexturePtr& texture) { region.layer, static_cast(width), static_cast(height), - texture->getTransformMatrixId() + texture->getTransformMatrixId(), + m_filterGroups[texture->isSmooth()].layers[region.layer].framebuffer->getTexture().get() ); texture->m_atlas[m_type] = info.get(); @@ -115,8 +116,4 @@ void TextureAtlas::flush() { } } } -} - -TexturePtr TextureAtlas::getTexture(int layer, bool smooth) const { - return m_filterGroups[smooth].layers[layer].framebuffer->getTexture(); } \ No newline at end of file diff --git a/src/framework/graphics/textureatlas.h b/src/framework/graphics/textureatlas.h index 9b0f31cdbd..241bce6af3 100644 --- a/src/framework/graphics/textureatlas.h +++ b/src/framework/graphics/textureatlas.h @@ -23,16 +23,17 @@ class AtlasRegion int16_t width; int16_t height; uint16_t transformMatrixId; - std::atomic_bool enabled = false; + Texture* atlas; + std::atomic_bool enabled; bool isEnabled() const { return enabled.load(std::memory_order_acquire); } AtlasRegion(uint32_t tid, int16_t x, int16_t y, int8_t layer, - int16_t width, int16_t height, uint16_t transformId) + int16_t width, int16_t height, uint16_t transformId, Texture* atlas) : textureID(tid), x(x), y(y), layer(layer), - width(width), height(height), transformMatrixId(transformId) { + width(width), height(height), transformMatrixId(transformId), atlas(atlas) { } }; @@ -77,8 +78,6 @@ class TextureAtlas void addTexture(const TexturePtr& texture); void removeTexture(uint32_t id, bool smooth); - TexturePtr getTexture(int layer, bool smooth) const; - Size getSize() const { return m_size; } void flush(); diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp index e7c1506c00..68d1a68874 100644 --- a/src/framework/ui/uitextedit.cpp +++ b/src/framework/ui/uitextedit.cpp @@ -75,9 +75,9 @@ void UITextEdit::drawSelf(const DrawPoolType drawPane) setProp(PropGlyphsMustRecache, false); // Hack to fix font rendering in atlas - if (!m_atlased && g_drawPool.getAtlas() && m_font->getTexture()->getAtlas(g_drawPool.getAtlas()->getType())) { - m_atlased = true; - update(); + if (g_drawPool.getAtlas() && m_font->getTexture()->getAtlas(g_drawPool.getAtlas()->getType()) != m_lastAtlasRegion) { + m_lastAtlasRegion = m_font->getTexture()->getAtlas(g_drawPool.getAtlas()->getType()); + update(false, true); } const int textLength = std::min(m_glyphsCoords.size(), m_text.length()); @@ -133,7 +133,7 @@ void UITextEdit::drawSelf(const DrawPoolType drawPane) } } -void UITextEdit::update(const bool focusCursor) +void UITextEdit::update(const bool focusCursor, bool disableAreaUpdate) { if (!getProp(PropUpdatesEnabled)) return; @@ -362,16 +362,16 @@ void UITextEdit::update(const bool focusCursor) glyphScreenCoords.setRight(textScreenCoords.right()); } + // render glyph + m_glyphsCoords[i].first = glyphScreenCoords; + m_glyphsCoords[i].second = glyphTextureCoords; + TextureAtlas* atlas = nullptr; if (g_drawPool.isValid()) atlas = g_drawPool.getAtlas(); else atlas = g_drawPool.get(DrawPoolType::FOREGROUND)->getAtlas(); - // render glyph - m_glyphsCoords[i].first = glyphScreenCoords; - m_glyphsCoords[i].second = glyphTextureCoords; - if (atlas) { if (const auto region = m_font->getTexture()->getAtlas(atlas->getType())) glyphTextureCoords = Rect(region->x + glyphTextureCoords.x(), region->y + glyphTextureCoords.y(), glyphTextureCoords.width(), glyphTextureCoords.height()); @@ -388,7 +388,7 @@ void UITextEdit::update(const bool focusCursor) m_colorCoordsBuffer.emplace_back(Color(rgba), crds); } - if (fireAreaUpdate) + if (!disableAreaUpdate && fireAreaUpdate) onTextAreaUpdate(m_textVirtualOffset, m_textVirtualSize, m_textTotalSize); repaint(); diff --git a/src/framework/ui/uitextedit.h b/src/framework/ui/uitextedit.h index ea06d362ae..dfbeb6f5c5 100644 --- a/src/framework/ui/uitextedit.h +++ b/src/framework/ui/uitextedit.h @@ -33,7 +33,7 @@ class UITextEdit final : public UIWidget void drawSelf(DrawPoolType drawPane) override; private: - void update(bool focusCursor = false); + void update(bool focusCursor = false, bool disableAreaUpdate = false); public: void setCursorPos(int pos); diff --git a/src/framework/ui/uiwidget.h b/src/framework/ui/uiwidget.h index 66013ebbb3..23d1fd44f4 100644 --- a/src/framework/ui/uiwidget.h +++ b/src/framework/ui/uiwidget.h @@ -508,7 +508,7 @@ class UIWidget : public LuaObject void updateImageCache() { if (!m_imageCachedScreenCoords.isNull()) m_imageCachedScreenCoords = {}; } void configureBorderImage() { setProp(PropImageBordered, true); updateImageCache(); } - std::vector> m_imageCoordsCache; + CoordsBufferPtr m_imageCoordsCache; Rect m_imageCachedScreenCoords; @@ -598,7 +598,7 @@ class UIWidget : public LuaObject std::vector> m_colorCoordsBuffer; float m_fontScale{ 1.f }; - bool m_atlased{ false }; + AtlasRegion* m_lastAtlasRegion = nullptr; public: void resizeToText(); diff --git a/src/framework/ui/uiwidgetimage.cpp b/src/framework/ui/uiwidgetimage.cpp index d18d30fe67..9531dab2ba 100644 --- a/src/framework/ui/uiwidgetimage.cpp +++ b/src/framework/ui/uiwidgetimage.cpp @@ -28,7 +28,9 @@ #include #include -void UIWidget::initImage() {} +void UIWidget::initImage() { + m_imageCoordsCache = std::make_shared(); +} void UIWidget::parseImageStyle(const OTMLNodePtr& styleNode) { @@ -88,26 +90,40 @@ void UIWidget::parseImageStyle(const OTMLNodePtr& styleNode) } } +void addImageRect(const TexturePtr& texture, const CoordsBufferPtr& coords, bool useRepeated, const Rect& dest, Rect src) { + if (const auto atlas = g_drawPool.getAtlas()) { + if (const auto region = texture->getAtlas(atlas->getType())) + src = Rect(region->x + src.x(), region->y + src.y(), src.width(), src.height()); + } + + if (useRepeated) + coords->addRepeatedRects(dest, src); + else + coords->addRect(dest, src); +}; + void UIWidget::drawImage(const Rect& screenCoords) { if (!m_imageTexture || !screenCoords.isValid()) return; // Hack to fix font rendering in atlas - if (!m_atlased && g_drawPool.getAtlas() && m_font->getTexture()->getAtlas(g_drawPool.getAtlas()->getType())) { - m_atlased = true; - m_imageCachedScreenCoords = {}; + if (g_drawPool.getAtlas() && m_imageTexture->getAtlas(g_drawPool.getAtlas()->getType()) != m_lastAtlasRegion) { + m_lastAtlasRegion = m_imageTexture->getAtlas(g_drawPool.getAtlas()->getType()); + updateImageCache(); } // cache vertex buffers if (m_imageCachedScreenCoords != screenCoords) { m_imageCachedScreenCoords = screenCoords; - m_imageCoordsCache.clear(); + m_imageCoordsCache->clear(); Rect drawRect = screenCoords; drawRect.translate(m_imageRect.topLeft()); if (m_imageRect.isValid()) drawRect.resize(m_imageRect.size()); + const bool useRepeated = hasProp(PropImageBordered) || hasProp(PropImageRepeated); + auto clipRect = m_imageClipRect.isValid() ? m_imageClipRect : Rect(0, 0, m_imageTexture->getSize()); if (hasProp(PropImageBordered)) { @@ -133,32 +149,32 @@ void UIWidget::drawImage(const Rect& screenCoords) // first the center if (centerSize.area() > 0) { rectCoords = Rect(drawRect.left() + leftBorder.width(), drawRect.top() + topBorder.height(), centerSize); - m_imageCoordsCache.emplace_back(rectCoords, center); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, center); } // top left corner rectCoords = Rect(drawRect.topLeft(), topLeftCorner.size()); - m_imageCoordsCache.emplace_back(rectCoords, topLeftCorner); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, topLeftCorner); // top rectCoords = Rect(drawRect.left() + topLeftCorner.width(), drawRect.topLeft().y, centerSize.width(), topBorder.height()); - m_imageCoordsCache.emplace_back(rectCoords, topBorder); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, topBorder); // top right corner rectCoords = Rect(drawRect.left() + topLeftCorner.width() + centerSize.width(), drawRect.top(), topRightCorner.size()); - m_imageCoordsCache.emplace_back(rectCoords, topRightCorner); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, topRightCorner); // left rectCoords = Rect(drawRect.left(), drawRect.top() + topLeftCorner.height(), leftBorder.width(), centerSize.height()); - m_imageCoordsCache.emplace_back(rectCoords, leftBorder); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, leftBorder); // right rectCoords = Rect(drawRect.left() + leftBorder.width() + centerSize.width(), drawRect.top() + topRightCorner.height(), rightBorder.width(), centerSize.height()); - m_imageCoordsCache.emplace_back(rectCoords, rightBorder); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, rightBorder); // bottom left corner rectCoords = Rect(drawRect.left(), drawRect.top() + topLeftCorner.height() + centerSize.height(), bottomLeftCorner.size()); - m_imageCoordsCache.emplace_back(rectCoords, bottomLeftCorner); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, bottomLeftCorner); // bottom rectCoords = Rect(drawRect.left() + bottomLeftCorner.width(), drawRect.top() + topBorder.height() + centerSize.height(), centerSize.width(), bottomBorder.height()); - m_imageCoordsCache.emplace_back(rectCoords, bottomBorder); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, bottomBorder); // bottom right corner rectCoords = Rect(drawRect.left() + bottomLeftCorner.width() + centerSize.width(), drawRect.top() + topRightCorner.height() + centerSize.height(), bottomRightCorner.size()); - m_imageCoordsCache.emplace_back(rectCoords, bottomRightCorner); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, rectCoords, bottomRightCorner); } else { if (isImageFixedRatio()) { Size textureSize = m_imageTexture->getSize(), @@ -175,25 +191,19 @@ void UIWidget::drawImage(const Rect& screenCoords) clipRect = Rect(texCoordsOffset, textureClipSize); } - m_imageCoordsCache.emplace_back(drawRect, clipRect); + addImageRect(m_imageTexture, m_imageCoordsCache, useRepeated, drawRect, clipRect); } } // smooth is now enabled by default for all textures //m_imageTexture->setSmooth(m_imageSmooth); - const bool useRepeated = hasProp(PropImageBordered) || hasProp(PropImageRepeated); const auto& texture = m_imageTexture->isAnimatedTexture() && isImageIndividualAnimation() ? std::static_pointer_cast(m_imageTexture)->get(m_currentFrame, m_imageAnimatorTimer) : m_imageTexture; g_drawPool.setDrawOrder(m_imageDrawOrder); - for (const auto& [dest, src] : m_imageCoordsCache) { - if (useRepeated) - g_drawPool.addTexturedRepeatedRect(dest, texture, src, m_imageColor); - else - g_drawPool.addTexturedRect(dest, texture, src, m_imageColor); - } + g_drawPool.addTexturedCoordsBuffer(texture, m_imageCoordsCache, m_imageColor); g_drawPool.resetDrawOrder(); } diff --git a/src/framework/ui/uiwidgettext.cpp b/src/framework/ui/uiwidgettext.cpp index d53132b9fa..df69e34232 100644 --- a/src/framework/ui/uiwidgettext.cpp +++ b/src/framework/ui/uiwidgettext.cpp @@ -106,9 +106,9 @@ void UIWidget::drawText(const Rect& screenCoords) return; // Hack to fix font rendering in atlas - if (!m_atlased && g_drawPool.getAtlas() && m_font->getTexture()->getAtlas(g_drawPool.getAtlas()->getType())) { - m_atlased = true; - m_textCachedScreenCoords = {}; + if (g_drawPool.getAtlas() && m_font->getTexture()->getAtlas(g_drawPool.getAtlas()->getType()) != m_lastAtlasRegion) { + m_lastAtlasRegion = m_font->getTexture()->getAtlas(g_drawPool.getAtlas()->getType()); + updateText(); } if (screenCoords != m_textCachedScreenCoords) {