diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-04-09 14:24:47 +0200 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-04-25 14:05:30 +0000 |
commit | c363961327621ceeb47ead653bb20c5da4e9a726 (patch) | |
tree | 3245318c3f629a1e3cae4ba9f4b54332aa660143 | |
parent | f48725cbf4e5ed620a57b1c945a109f0c225b1cd (diff) | |
download | mana-c363961327621ceeb47ead653bb20c5da4e9a726.tar.gz mana-c363961327621ceeb47ead653bb20c5da4e9a726.tar.bz2 mana-c363961327621ceeb47ead653bb20c5da4e9a726.tar.xz mana-c363961327621ceeb47ead653bb20c5da4e9a726.zip |
Simplified ImageRect handling
We don't need to keep an array of SubImage instances, but can just
remember the top, left, right and bottom margins and use those when
rendering the scaled ImageRect.
Graphics::drawRescaledImagePattern had to be extended to allow
specifying the source rectangle.
-rw-r--r-- | src/graphics.cpp | 193 | ||||
-rw-r--r-- | src/graphics.h | 57 | ||||
-rw-r--r-- | src/openglgraphics.cpp | 78 | ||||
-rw-r--r-- | src/openglgraphics.h | 5 | ||||
-rw-r--r-- | src/resources/theme.cpp | 29 | ||||
-rw-r--r-- | src/sdlgraphics.cpp | 32 | ||||
-rw-r--r-- | src/sdlgraphics.h | 6 |
7 files changed, 173 insertions, 227 deletions
diff --git a/src/graphics.cpp b/src/graphics.cpp index 9b8cce83..351ea9b0 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -25,37 +25,15 @@ #include <guichan/exception.hpp> -ImageRect::ImageRect() -{ - memset(grid, 0, sizeof(grid)); -} - ImageRect::ImageRect(ImageRect &&r) { - memcpy(grid, r.grid, sizeof(grid)); - memset(r.grid, 0, sizeof(grid)); + image = r.image; + r.image = nullptr; } ImageRect::~ImageRect() { - for (auto img : grid) - delete img; -} - -void ImageRect::setAlpha(float alpha) -{ - for (auto img : grid) - img->setAlpha(alpha); -} - -int ImageRect::minWidth() const -{ - return grid[ImageRect::UPPER_LEFT]->getWidth() + grid[ImageRect::UPPER_RIGHT]->getWidth(); -} - -int ImageRect::minHeight() const -{ - return grid[ImageRect::UPPER_LEFT]->getHeight() + grid[ImageRect::LOWER_LEFT]->getHeight(); + delete image; } @@ -89,7 +67,12 @@ bool Graphics::drawRescaledImage(const Image *image, int x, int y, int width, in return drawRescaledImage(image, 0, 0, x, y, image->getWidth(), image->getHeight(), width, height); } -bool Graphics::drawRescaledImageF(const Image *image, int srcX, int srcY, float dstX, float dstY, int width, int height, float desiredWidth, float desiredHeight, bool useColor) +bool Graphics::drawRescaledImageF(const Image *image, + int srcX, int srcY, + float dstX, float dstY, + int width, int height, + float desiredWidth, float desiredHeight, + bool useColor) { return drawRescaledImage(image, srcX, srcY, @@ -132,100 +115,72 @@ void Graphics::drawImagePattern(const Image *image, int x, int y, int w, int h) image->getWidth(), image->getHeight()); } -void Graphics::drawImageRect(int x, int y, int w, int h, - const Image *topLeft, const Image *topRight, - const Image *bottomLeft, const Image *bottomRight, - const Image *top, const Image *right, - const Image *bottom, const Image *left, - const Image *center, - FillMode fillMode) -{ - switch (fillMode) { - case FillMode::Stretch: - // Draw the center area - drawRescaledImage(center, - x + topLeft->getWidth(), - y + topLeft->getHeight(), - w - topLeft->getWidth() - topRight->getWidth(), - h - topLeft->getHeight() - bottomLeft->getHeight()); - - // Draw the sides - drawRescaledImage(top, - x + left->getWidth(), - y, - w - left->getWidth() - right->getWidth(), - top->getHeight()); - - drawRescaledImage(bottom, - x + left->getWidth(), - y + h - bottom->getHeight(), - w - left->getWidth() - right->getWidth(), - bottom->getHeight()); - - drawRescaledImage(left, - x, - y + top->getHeight(), - left->getWidth(), - h - top->getHeight() - bottom->getHeight()); - - drawRescaledImage(right, - x + w - right->getWidth(), - y + top->getHeight(), - right->getWidth(), - h - top->getHeight() - bottom->getHeight()); - break; - case FillMode::Repeat: - // Draw the center area - drawImagePattern(center, - x + topLeft->getWidth(), - y + topLeft->getHeight(), - w - topLeft->getWidth() - topRight->getWidth(), - h - topLeft->getHeight() - bottomLeft->getHeight()); - - // Draw the sides - drawImagePattern(top, - x + left->getWidth(), - y, - w - left->getWidth() - right->getWidth(), - top->getHeight()); - - drawImagePattern(bottom, - x + left->getWidth(), - y + h - bottom->getHeight(), - w - left->getWidth() - right->getWidth(), - bottom->getHeight()); - - drawImagePattern(left, - x, - y + top->getHeight(), - left->getWidth(), - h - top->getHeight() - bottom->getHeight()); - - drawImagePattern(right, - x + w - right->getWidth(), - y + top->getHeight(), - right->getWidth(), - h - top->getHeight() - bottom->getHeight()); - break; +void Graphics::drawRescaledImagePattern(const Image *image, + int x, int y, + int w, int h, + int scaledWidth, int scaledHeight) +{ + drawRescaledImagePattern(image, + 0, 0, + image->getWidth(), + image->getHeight(), + x, y, + w, h, + scaledWidth, + scaledHeight); +} + +void Graphics::drawImageRect(const ImageRect &imgRect, int x, int y, int w, int h) +{ + const int srcGridX[4] = {0, + imgRect.left, + imgRect.image->getWidth() - imgRect.right, + imgRect.image->getWidth()}; + const int srcGridY[4] = {0, + imgRect.top, + imgRect.image->getHeight() - imgRect.bottom, + imgRect.image->getHeight()}; + + const int dstGridX[4] = {x, x + imgRect.left, x + w - imgRect.right, x + w}; + const int dstGridY[4] = {y, y + imgRect.top, y + h - imgRect.bottom, y + h}; + + for (unsigned ix = 0; ix < 3; ix++) + { + for (unsigned iy = 0; iy < 3; iy++) + { + const int srcW = srcGridX[ix + 1] - srcGridX[ix]; + const int srcH = srcGridY[iy + 1] - srcGridY[iy]; + + const int dstW = dstGridX[ix + 1] - dstGridX[ix]; + const int dstH = dstGridY[iy + 1] - dstGridY[iy]; + + if (srcW <= 0 || srcH <= 0 || dstW <= 0 || dstH <= 0) + continue; + + switch (imgRect.fillMode) + { + case FillMode::Stretch: + drawRescaledImage(imgRect.image, + srcGridX[ix], + srcGridY[iy], + dstGridX[ix], + dstGridY[iy], + srcW, srcH, + dstW, dstH); + break; + case FillMode::Repeat: + drawRescaledImagePattern(imgRect.image, + srcGridX[ix], + srcGridY[iy], + srcW, srcH, + dstGridX[ix], + dstGridY[iy], + dstW, dstH, + srcW, srcH); + break; + } + } } - - // Draw the corners - drawImage(topLeft, x, y); - drawImage(topRight, x + w - topRight->getWidth(), y); - drawImage(bottomLeft, x, y + h - bottomLeft->getHeight()); - drawImage(bottomRight, - x + w - bottomRight->getWidth(), - y + h - bottomRight->getHeight()); -} - -void Graphics::drawImageRect(int x, int y, int w, int h, - const ImageRect &imgRect) -{ - drawImageRect(x, y, w, h, - imgRect.grid[0], imgRect.grid[2], imgRect.grid[6], imgRect.grid[8], - imgRect.grid[1], imgRect.grid[5], imgRect.grid[7], imgRect.grid[3], - imgRect.grid[4], - imgRect.fillMode); } void Graphics::_beginDraw() diff --git a/src/graphics.h b/src/graphics.h index 4b03023d..038b0c6b 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -67,7 +67,7 @@ public: LOWER_RIGHT = 8 }; - ImageRect(); + ImageRect() = default; ImageRect(const ImageRect &) = delete; ImageRect(ImageRect &&); ~ImageRect(); @@ -75,12 +75,15 @@ public: ImageRect &operator=(const ImageRect &) = delete; ImageRect &operator=(ImageRect &&r) = delete; - Image *grid[9]; + Image *image = nullptr; + int top = 0; + int left = 0; + int bottom = 0; + int right = 0; FillMode fillMode = FillMode::Stretch; - void setAlpha(float alpha); - int minWidth() const; - int minHeight() const; + int minWidth() const { return left + right; } + int minHeight() const { return top + bottom; } }; /** @@ -127,7 +130,8 @@ class Graphics : public gcn::Graphics /** * Draws a rescaled version of the image. */ - virtual bool drawRescaledImage(const Image *image, int srcX, int srcY, + virtual bool drawRescaledImage(const Image *image, + int srcX, int srcY, int dstX, int dstY, int width, int height, int desiredWidth, int desiredHeight, @@ -171,41 +175,34 @@ class Graphics : public gcn::Graphics int w, int h); /** - * Draw a pattern based on a rescaled version of the given image... + * Draw a pattern based on a rescaled version of the given image. */ - virtual void drawRescaledImagePattern(const Image *image, - int x, int y, - int w, int h, - int scaledWidth, - int scaledHeight) = 0; + void drawRescaledImagePattern(const Image *image, + int x, int y, + int w, int h, + int scaledWidth, + int scaledHeight); /** - * Draws a rectangle using images. 4 corner images, 4 side images and 1 - * image for the inside. + * Draw a pattern based on a rescaled version of the given image. */ - void drawImageRect(int x, int y, int w, int h, - const Image *topLeft, const Image *topRight, - const Image *bottomLeft, const Image *bottomRight, - const Image *top, const Image *right, - const Image *bottom, const Image *left, - const Image *center, - FillMode fillMode = FillMode::Stretch); + virtual void drawRescaledImagePattern(const Image *image, + int srcX, int srcY, + int srcW, int srcH, + int dstX, int dstY, + int dstW, int dstH, + int scaledWidth, + int scaledHeight) = 0; /** * Draws a rectangle using images. 4 corner images, 4 side images and 1 * image for the inside. */ - void drawImageRect(int x, int y, int w, int h, - const ImageRect &imgRect); + void drawImageRect(const ImageRect &imgRect, int x, int y, int w, int h); - /** - * Draws a rectangle using images. 4 corner images, 4 side images and 1 - * image for the inside. - */ - void drawImageRect(const gcn::Rectangle &area, - const ImageRect &imgRect) + void drawImageRect(const ImageRect &imgRect, const gcn::Rectangle &area) { - drawImageRect(area.x, area.y, area.width, area.height, imgRect); + drawImageRect(imgRect, area.x, area.y, area.width, area.height); } /** diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index 51d8cde3..ecd98ea1 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -397,8 +397,10 @@ void OpenGLGraphics::drawImagePattern(const Image *image, int x, int y, int w, i } void OpenGLGraphics::drawRescaledImagePattern(const Image *image, - int x, int y, - int w, int h, + int srcX, int srcY, + int srcW, int srcH, + int dstX, int dstY, + int dstW, int dstH, int scaledWidth, int scaledHeight) { @@ -408,12 +410,10 @@ void OpenGLGraphics::drawRescaledImagePattern(const Image *image, if (scaledWidth == 0 || scaledHeight == 0) return; - const int srcX = image->mBounds.x; - const int srcY = image->mBounds.y; + srcX += image->mBounds.x; + srcY += image->mBounds.y; - const int iw = image->getWidth(); - const int ih = image->getHeight(); - if (iw == 0 || ih == 0) + if (srcW == 0 || srcH == 0) return; glColor4f(1.0f, 1.0f, 1.0f, image->mAlpha); @@ -434,17 +434,17 @@ void OpenGLGraphics::drawRescaledImagePattern(const Image *image, const float texX1 = static_cast<float>(srcX) / tw; const float texY1 = static_cast<float>(srcY) / th; - const float tFractionW = iw / tw; - const float tFractionH = ih / th; + const float tFractionW = srcW / tw; + const float tFractionH = srcH / th; - for (int py = 0; py < h; py += scaledHeight) + for (int py = 0; py < dstH; py += scaledHeight) { - const int height = (py + scaledHeight >= h) ? h - py : scaledHeight; - const int dstY = y + py; - for (int px = 0; px < w; px += scaledWidth) + const int height = (py + scaledHeight >= dstH) ? dstH - py : scaledHeight; + const int destY = dstY + py; + for (int px = 0; px < dstW; px += scaledWidth) { - int width = (px + scaledWidth >= w) ? w - px : scaledWidth; - int dstX = x + px; + int width = (px + scaledWidth >= dstW) ? dstW - px : scaledWidth; + int destX = dstX + px; const float visibleFractionW = (float) width / scaledWidth; const float visibleFractionH = (float) height / scaledHeight; @@ -463,17 +463,17 @@ void OpenGLGraphics::drawRescaledImagePattern(const Image *image, mFloatTexArray[vp + 6] = texX1; mFloatTexArray[vp + 7] = texY2; - mIntVertArray[vp + 0] = dstX; - mIntVertArray[vp + 1] = dstY; + mIntVertArray[vp + 0] = destX; + mIntVertArray[vp + 1] = destY; - mIntVertArray[vp + 2] = dstX + width; - mIntVertArray[vp + 3] = dstY; + mIntVertArray[vp + 2] = destX + width; + mIntVertArray[vp + 3] = destY; - mIntVertArray[vp + 4] = dstX + width; - mIntVertArray[vp + 5] = dstY + height; + mIntVertArray[vp + 4] = destX + width; + mIntVertArray[vp + 5] = destY + height; - mIntVertArray[vp + 6] = dstX; - mIntVertArray[vp + 7] = dstY + height; + mIntVertArray[vp + 6] = destX; + mIntVertArray[vp + 7] = destY + height; vp += 8; if (vp >= vLimit) @@ -488,17 +488,17 @@ void OpenGLGraphics::drawRescaledImagePattern(const Image *image, } else { - const float scaleFactorW = (float) scaledWidth / iw; - const float scaleFactorH = (float) scaledHeight / ih; + const float scaleFactorW = (float) scaledWidth / srcW; + const float scaleFactorH = (float) scaledHeight / srcH; - for (int py = 0; py < h; py += scaledHeight) + for (int py = 0; py < dstH; py += scaledHeight) { - const int height = (py + scaledHeight >= h) ? h - py : scaledHeight; - const int dstY = y + py; - for (int px = 0; px < w; px += scaledWidth) + const int height = (py + scaledHeight >= dstH) ? dstH - py : scaledHeight; + const int destY = dstY + py; + for (int px = 0; px < dstW; px += scaledWidth) { - int width = (px + scaledWidth >= w) ? w - px : scaledWidth; - int dstX = x + px; + int width = (px + scaledWidth >= dstW) ? dstW - px : scaledWidth; + int destX = dstX + px; mIntTexArray[vp + 0] = srcX; mIntTexArray[vp + 1] = srcY; @@ -512,17 +512,17 @@ void OpenGLGraphics::drawRescaledImagePattern(const Image *image, mIntTexArray[vp + 6] = srcX; mIntTexArray[vp + 7] = srcY + height / scaleFactorH; - mIntVertArray[vp + 0] = dstX; - mIntVertArray[vp + 1] = dstY; + mIntVertArray[vp + 0] = destX; + mIntVertArray[vp + 1] = destY; - mIntVertArray[vp + 2] = dstX + width; - mIntVertArray[vp + 3] = dstY; + mIntVertArray[vp + 2] = destX + width; + mIntVertArray[vp + 3] = destY; - mIntVertArray[vp + 4] = dstX + width; - mIntVertArray[vp + 5] = dstY + height; + mIntVertArray[vp + 4] = destX + width; + mIntVertArray[vp + 5] = destY + height; - mIntVertArray[vp + 6] = dstX; - mIntVertArray[vp + 7] = dstY + height; + mIntVertArray[vp + 6] = destX; + mIntVertArray[vp + 7] = destY + height; vp += 8; if (vp >= vLimit) diff --git a/src/openglgraphics.h b/src/openglgraphics.h index b342d9e5..1494ce52 100644 --- a/src/openglgraphics.h +++ b/src/openglgraphics.h @@ -80,7 +80,10 @@ class OpenGLGraphics final : public Graphics * Draw a pattern based on a rescaled version of the given image... */ void drawRescaledImagePattern(const Image *image, - int x, int y, int w, int h, + int srcX, int srcY, + int srcW, int srcH, + int dstX, int dstY, + int dstW, int dstH, int scaledWidth, int scaledHeight) override; void updateScreen() override; diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp index c76499b9..d4d59ede 100644 --- a/src/resources/theme.cpp +++ b/src/resources/theme.cpp @@ -120,11 +120,11 @@ void Skin::draw(Graphics *graphics, const WidgetState &state) const if constexpr (std::is_same_v<T, ImageRect>) { - graphics->drawImageRect(state.x + part.offsetX, + graphics->drawImageRect(data, + state.x + part.offsetX, state.y + part.offsetY, state.width, - state.height, - data); + state.height); } else if constexpr (std::is_same_v<T, Image*>) { @@ -204,7 +204,7 @@ void Skin::updateAlpha(float alpha) for (auto &part : state.parts) { if (auto rect = std::get_if<ImageRect>(&part.data)) - rect->setAlpha(alpha); + rect->image->setAlpha(alpha); else if (auto img = std::get_if<Image *>(&part.data)) (*img)->setAlpha(alpha); } @@ -601,24 +601,13 @@ void Theme::readSkinStateImgNode(XML::Node node, SkinState &state) const if (left + right + top + bottom > 0) { auto &border = part.data.emplace<ImageRect>(); + border.left = left; + border.right = right; + border.top = top; + border.bottom = bottom; + border.image = image->getSubImage(x, y, width, height); node.attribute("fill", border.fillMode); - - const int gridx[4] = {x, x + left, x + width - right, x + width}; - const int gridy[4] = {y, y + top, y + height - bottom, y + height}; - unsigned a = 0; - - for (unsigned y = 0; y < 3; y++) - { - for (unsigned x = 0; x < 3; x++) - { - border.grid[a] = image->getSubImage(gridx[x], - gridy[y], - gridx[x + 1] - gridx[x], - gridy[y + 1] - gridy[y]); - a++; - } - } } else { diff --git a/src/sdlgraphics.cpp b/src/sdlgraphics.cpp index 0fec9ab7..9256471a 100644 --- a/src/sdlgraphics.cpp +++ b/src/sdlgraphics.cpp @@ -204,8 +204,10 @@ bool SDLGraphics::drawRescaledImageF(const Image *image, #endif void SDLGraphics::drawRescaledImagePattern(const Image *image, - int x, int y, - int w, int h, + int srcX, int srcY, + int srcW, int srcH, + int dstX, int dstY, + int dstW, int dstH, int scaledWidth, int scaledHeight) { @@ -217,24 +219,22 @@ void SDLGraphics::drawRescaledImagePattern(const Image *image, return; SDL_Rect srcRect; - srcRect.x = image->mBounds.x; - srcRect.y = image->mBounds.y; + srcRect.x = image->mBounds.x + srcX; + srcRect.y = image->mBounds.y + srcY; - for (int py = 0; py < h; py += scaledHeight) // Y position on pattern plane + for (int py = 0; py < dstH; py += scaledHeight) // Y position on pattern plane { - int dh = (py + scaledHeight >= h) ? h - py : scaledHeight; - int dstY = y + py + mClipStack.top().yOffset; + SDL_Rect dstRect; + dstRect.h = (py + scaledHeight >= dstH) ? dstH - py : scaledHeight; + dstRect.y = dstY + py + mClipStack.top().yOffset; - for (int px = 0; px < w; px += scaledWidth) // X position on pattern plane + for (int px = 0; px < dstW; px += scaledWidth) // X position on pattern plane { - int dw = (px + scaledWidth >= w) ? w - px : scaledWidth; - int dstX = x + px + mClipStack.top().xOffset; - - SDL_Rect dstRect; - dstRect.x = dstX; dstRect.y = dstY; - dstRect.w = dw; dstRect.h = dh; - srcRect.w = image->mBounds.w * dw / scaledWidth; - srcRect.h = image->mBounds.h * dh / scaledHeight; + dstRect.x = dstX + px + mClipStack.top().xOffset; + dstRect.w = (px + scaledWidth >= dstW) ? dstW - px : scaledWidth; + + srcRect.w = srcW * dstRect.w / scaledWidth; + srcRect.h = srcH * dstRect.h / scaledHeight; if (SDL_RenderCopy(mRenderer, image->mTexture, &srcRect, &dstRect)) return; diff --git a/src/sdlgraphics.h b/src/sdlgraphics.h index 2b7635a5..7cdea414 100644 --- a/src/sdlgraphics.h +++ b/src/sdlgraphics.h @@ -57,8 +57,10 @@ public: #endif void drawRescaledImagePattern(const Image *image, - int x, int y, - int w, int h, + int srcX, int srcY, + int srcW, int srcH, + int dstX, int dstY, + int dstW, int dstH, int scaledWidth, int scaledHeight) override; |