Skip to content

Commit 30db726

Browse files
authored
Merge pull request #1536 from tehKaiN/ctrlImageButton-cropping
Add support for image cropping inside ctrlImageButton
2 parents 5dd0526 + c5d5616 commit 30db726

13 files changed

Lines changed: 330 additions & 32 deletions

libs/common/include/helpers/mathFuncs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ constexpr T interpolate(const T startVal, const T endVal, const U elapsedTime, c
7070
}
7171

7272
/// Linear interpolation, similar to C++20's std::lerp()
73-
constexpr float lerp(const float startVal, const float endVal, const float ratio) noexcept
73+
template<typename T>
74+
constexpr T lerp(const T startVal, const T endVal, const T ratio) noexcept
7475
{
7576
return startVal + ratio * (endVal - startVal);
7677
}

libs/s25main/controls/ctrlBaseImage.cpp

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,44 @@ Rect ctrlBaseImage::GetImageRect() const
2020
return Rect(-img_->GetOrigin(), img_->GetSize());
2121
}
2222

23-
void ctrlBaseImage::DrawImage(const DrawPoint& pos) const
23+
void ctrlBaseImage::DrawImage(const Rect& dstArea) const
2424
{
25-
DrawImage(pos, modulationColor_);
25+
DrawImage(dstArea, modulationColor_);
2626
}
2727

28-
void ctrlBaseImage::DrawImage(const DrawPoint& pos, unsigned color) const
28+
void ctrlBaseImage::DrawImage(const Rect& dstArea, unsigned color) const
2929
{
30-
if(img_)
31-
img_->DrawFull(pos, color);
30+
if(img_ == nullptr)
31+
return;
32+
33+
auto dst = dstArea;
34+
auto imageSize = img_->GetSize();
35+
auto dstSize = dstArea.getSize();
36+
Rect srcArea = Rect(DrawPoint::all(0), imageSize);
37+
38+
if(imageSize.x > dstSize.x)
39+
{
40+
auto halfDelta = (imageSize.x - dstSize.x) / 2;
41+
srcArea.left += halfDelta;
42+
srcArea.right -= halfDelta;
43+
} else if(imageSize.x < dstSize.x)
44+
{
45+
auto halfDelta = (dstSize.x - imageSize.x) / 2;
46+
dst.left += halfDelta;
47+
dst.right -= halfDelta;
48+
}
49+
50+
if(imageSize.y > dstSize.y)
51+
{
52+
auto halfDelta = (imageSize.y - dstSize.y) / 2;
53+
srcArea.top += halfDelta;
54+
srcArea.bottom -= halfDelta;
55+
} else if(imageSize.y < dstSize.y)
56+
{
57+
auto halfDelta = (dstSize.y - imageSize.y) / 2;
58+
dst.top += halfDelta;
59+
dst.bottom -= halfDelta;
60+
}
61+
62+
img_->Draw(dst, srcArea, color);
3263
}

libs/s25main/controls/ctrlBaseImage.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ class ctrlBaseImage
2424
/// Swap the images of those controls
2525
void SwapImage(ctrlBaseImage& other);
2626
Rect GetImageRect() const;
27-
void DrawImage(const DrawPoint& pos) const;
28-
void DrawImage(const DrawPoint& pos, unsigned color) const;
27+
28+
/// Draw the image on specified rectangular area. The image is centered inside dstArea and cropped to its size.
29+
void DrawImage(const Rect& dstArea) const;
30+
void DrawImage(const Rect& dstArea, unsigned color) const;
2931

3032
private:
3133
ITexture* img_;

libs/s25main/controls/ctrlImage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ ctrlImage::~ctrlImage() = default;
1717
*/
1818
void ctrlImage::Draw_()
1919
{
20-
DrawImage(GetDrawPos());
20+
DrawImage(Rect(GetDrawPos(), GetImageRect().getSize()));
2121
}
2222

2323
bool ctrlImage::Msg_MouseMove(const MouseCoords& mc)

libs/s25main/controls/ctrlImageButton.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// SPDX-License-Identifier: GPL-2.0-or-later
44

55
#include "ctrlImageButton.h"
6+
#include <ogl/ITexture.h>
67

78
ctrlImageButton::ctrlImageButton(Window* parent, unsigned id, const DrawPoint& pos, const Extent& size,
89
const TextureColor tc, ITexture* const image, const std::string& tooltip)
@@ -11,11 +12,27 @@ ctrlImageButton::ctrlImageButton(Window* parent, unsigned id, const DrawPoint& p
1112

1213
void ctrlImageButton::DrawContent() const
1314
{
14-
DrawPoint pos = GetDrawPos() + DrawPoint(GetSize()) / 2;
15+
// Adding of origin compensates for its substraction inside ITexture::Draw()
16+
auto pos = GetDrawPos() + GetImage()->GetOrigin();
17+
auto size = GetSize();
18+
19+
if(hasBorder)
20+
{
21+
// Ensure that 3D border is not drawn on
22+
const unsigned borderThickness = 2;
23+
pos += DrawPoint::all(borderThickness);
24+
size -= Extent::all(2 * borderThickness);
25+
}
26+
1527
if((state == ButtonState::Pressed || isChecked) && isEnabled)
28+
{
1629
pos += DrawPoint::all(2);
30+
size -= Extent::all(2);
31+
}
32+
33+
Rect drawRect(pos, size);
1734
if(!isEnabled && GetModulationColor() == COLOR_WHITE)
18-
DrawImage(pos, 0xFF555555);
35+
DrawImage(drawRect, 0xFF555555);
1936
else
20-
DrawImage(pos);
37+
DrawImage(drawRect);
2138
}

libs/s25main/ogl/ITexture.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include "Point.h"
8+
#include "Rect.h"
89

910
class ITexture
1011
{
@@ -15,4 +16,8 @@ class ITexture
1516
virtual Position GetOrigin() const = 0;
1617
virtual Extent GetSize() const = 0;
1718
virtual void DrawFull(const Position& dstPos, unsigned color = 0xFFFFFFFFu) = 0;
19+
20+
/// Draws portion of image specified by srcArea on area defined by dstArea.
21+
/// In case of srcArea and dstArea size mismatch, scaling will occur.
22+
virtual void Draw(Rect dstArea, Rect srcArea, unsigned color = 0xFFFFFFFFu) = 0;
1823
};

libs/s25main/ogl/glArchivItem_Bitmap.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ class glArchivItem_Bitmap : public virtual libsiedler2::baseArchivItem_Bitmap, p
2626
void DrawPart(const Rect& destArea, const DrawPoint& offset, unsigned color = COLOR_WHITE);
2727
/// Draw a rectangular part of the texture from the origin of it
2828
void DrawPart(const Rect& destArea, unsigned color = COLOR_WHITE);
29-
/// Draw only percent% of the height of the image
29+
/// Draw only percent% of the height of the image, counting from the bottom of the image
3030
void DrawPercent(const DrawPoint& dstPos, unsigned percent, unsigned color = COLOR_WHITE);
31-
32-
protected:
3331
/// Draw the texture.
3432
/// src_w/h default to the full bitmap size
3533
/// dst_w/h default the src_w/h
36-
void Draw(Rect dstArea, Rect srcArea, unsigned color = COLOR_WHITE);
34+
void Draw(Rect dstArea, Rect srcArea, unsigned color = COLOR_WHITE) override;
35+
36+
protected:
3737
void FillTexture() override;
3838
Extent CalcTextureSize() const override;
3939
};

libs/s25main/ogl/glArchivItem_Bitmap_Player.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ void glArchivItem_Bitmap_Player::drawForPlayer(const DrawPoint& dst, unsigned pl
4242
DrawFull(dst, COLOR_WHITE, playerColor);
4343
}
4444

45+
void glArchivItem_Bitmap_Player::Draw(Rect dstArea, Rect srcArea, unsigned color /*= COLOR_WHITE*/)
46+
{
47+
Draw(dstArea, srcArea, color, COLOR_WHITE);
48+
}
49+
4550
void glArchivItem_Bitmap_Player::Draw(Rect dstArea, Rect srcArea, unsigned color /*= COLOR_WHITE*/,
4651
unsigned player_color /*= COLOR_WHITE*/)
4752
{

libs/s25main/ogl/glArchivItem_Bitmap_Player.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class glArchivItem_Bitmap_Player : public libsiedler2::ArchivItem_Bitmap_Player,
2929
virtual void DrawFull(const Position& dstPos, unsigned color = COLOR_WHITE) override;
3030
/// Draw in player colors
3131
void drawForPlayer(const DrawPoint& dst, unsigned playerColor);
32+
void Draw(Rect dstArea, Rect srcArea, unsigned color = COLOR_WHITE) override;
3233

3334
protected:
3435
void Draw(Rect dstArea, Rect srcArea, unsigned color = COLOR_WHITE, unsigned player_color = COLOR_WHITE);

libs/s25main/ogl/glSmartBitmap.cpp

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
#include "glSmartBitmap.h"
66
#include "Loader.h"
77
#include "drivers/VideoDriverWrapper.h"
8+
#include "helpers/mathFuncs.h"
89
#include "ogl/glBitmapItem.h"
910
#include "libsiedler2/ArchivItem_Bitmap.h"
1011
#include "libsiedler2/ArchivItem_Bitmap_Player.h"
1112
#include "libsiedler2/PixelBufferBGRA.h"
1213
#include "s25util/colors.h"
1314
#include <glad/glad.h>
15+
#include <cmath>
1416
#include <limits>
1517

1618
namespace {
@@ -238,12 +240,32 @@ void glSmartBitmap::generateTexture()
238240
}
239241
}
240242

243+
void glSmartBitmap::Draw(Rect dstArea, Rect srcArea, unsigned color /*= 0xFFFFFFFF*/)
244+
{
245+
drawRect(dstArea, srcArea, color);
246+
}
247+
241248
void glSmartBitmap::draw(DrawPoint drawPt, unsigned color, unsigned player_color)
242249
{
243250
drawPercent(drawPt, 100, color, player_color);
244251
}
245252

246253
void glSmartBitmap::drawPercent(DrawPoint drawPt, unsigned percent, unsigned color, unsigned player_color)
254+
{
255+
// nothing to draw?
256+
if(!percent)
257+
return;
258+
RTTR_Assert(percent <= 100);
259+
260+
const float partDrawn = percent / 100.f;
261+
auto startY = int(std::round(size_.y * (1 - partDrawn)));
262+
auto height = size_.y - startY;
263+
Rect dstArea(drawPt.x, drawPt.y + startY, size_.x, height);
264+
Rect srcArea(0, startY, size_.x, height);
265+
drawRect(dstArea, srcArea, color, player_color);
266+
}
267+
268+
void glSmartBitmap::drawRect(Rect dstArea, Rect srcArea, unsigned color /*= 0xFFFFFFFF*/, unsigned player_color /*= 0*/)
247269
{
248270
if(!texture)
249271
{
@@ -253,35 +275,36 @@ void glSmartBitmap::drawPercent(DrawPoint drawPt, unsigned percent, unsigned col
253275
return;
254276
}
255277

256-
// nothing to draw?
257-
if(!percent)
258-
return;
259-
RTTR_Assert(percent <= 100);
260-
261-
const float partDrawn = percent / 100.f;
262278
std::array<Point<GLfloat>, 8> vertices, curTexCoords;
263279
std::array<GL_RGBAColor, 8> colors;
264280

281+
auto drawPt = dstArea.getOrigin();
265282
drawPt -= origin_;
266-
vertices[2] = Point<GLfloat>(drawPt) + size_;
283+
vertices[2] = Point<GLfloat>(dstArea.getEndPt() - origin_); // destination bottom
267284

268285
vertices[0].x = vertices[1].x = GLfloat(drawPt.x);
269286
vertices[3].x = vertices[2].x;
270287

271-
vertices[0].y = vertices[3].y = GLfloat(drawPt.y + size_.y * (1.f - partDrawn));
272-
vertices[1].y = vertices[2].y;
288+
vertices[0].y = vertices[3].y = GLfloat(drawPt.y); // destination top
289+
vertices[1].y = vertices[2].y; // destination bottom
273290

274291
colors[0].r = GetRed(color);
275292
colors[0].g = GetGreen(color);
276293
colors[0].b = GetBlue(color);
277294
colors[0].a = GetAlpha(color);
278295
colors[3] = colors[2] = colors[1] = colors[0];
279296

280-
curTexCoords[0] = texCoords[0];
281-
curTexCoords[1] = texCoords[1];
282-
curTexCoords[2] = texCoords[2];
283-
curTexCoords[3] = texCoords[3];
284-
curTexCoords[0].y = curTexCoords[3].y = curTexCoords[1].y - (curTexCoords[1].y - curTexCoords[0].y) * partDrawn;
297+
// 0--3/4--7
298+
// | | |
299+
// 1--2/5--6
300+
// Remap srcArea to texture coords
301+
curTexCoords[0].x = helpers::lerp(texCoords[0].x, texCoords[3].x, srcArea.getOrigin().x / float(size_.x));
302+
curTexCoords[0].y = helpers::lerp(texCoords[0].y, texCoords[1].y, srcArea.getOrigin().y / float(size_.y));
303+
curTexCoords[2].x = helpers::lerp(texCoords[0].x, texCoords[3].x, srcArea.getEndPt().x / float(size_.x));
304+
curTexCoords[2].y = helpers::lerp(texCoords[0].y, texCoords[1].y, srcArea.getEndPt().y / float(size_.y));
305+
306+
curTexCoords[1] = PointF(curTexCoords[0].x, curTexCoords[2].y);
307+
curTexCoords[3] = PointF(curTexCoords[2].x, curTexCoords[0].y);
285308

286309
int numQuads;
287310
if(player_color && hasPlayer)

0 commit comments

Comments
 (0)