Skip to content

Instantly share code, notes, and snippets.

@Reputeless
Created May 22, 2019 11:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Reputeless/47c8949f6337d25c17d22ebbe11fdbc4 to your computer and use it in GitHub Desktop.
Save Reputeless/47c8949f6337d25c17d22ebbe11fdbc4 to your computer and use it in GitHub Desktop.
# include <Siv3D.hpp> // Siv3D August 2016 v2
namespace s3d
{
inline constexpr int32 CaluculateFanQuality(const double r) noexcept
{
return r <= 1.0 ? 3
: r <= 6.0 ? 5
: r <= 12.0 ? 8
: static_cast<int32>(std::min(64.0, r * 0.2 + 6));
}
struct TexturedRoundRect
{
RoundRect rect;
Texture texture;
FloatRect uvRect;
TexturedRoundRect() = default;
TexturedRoundRect(
const Texture& _texture,
float l,
float t,
float r,
float b,
const RoundRect& _rect)
: rect(_rect)
, texture(_texture)
, uvRect(l, t, r, b) {}
TexturedRoundRect(
const Texture& _texture,
const FloatRect& _uvRect,
const RoundRect& _rect)
: rect(_rect)
, texture(_texture)
, uvRect(_uvRect) {}
const RoundRect& draw(const ColorF& diffuse = Palette::White) const
{
const double rr = std::min({ rect.w * 0.5, rect.h * 0.5, rect.r });
const float scale = static_cast<float>(Graphics2D::GetMaxScaling());
const int32 quality = CaluculateFanQuality(rr * scale);
const double radDelta = Math::HalfPi / (quality - 1);
Array<Float2> fanPositions(quality);
for (int32 i = 0; i < quality; ++i)
{
fanPositions[i] = Vec2(Circular(rr, radDelta * i));
}
const bool uniteV = (rect.h * 0.5 == rr);
const bool uniteH = (rect.w * 0.5 == rr);
const std::array<Float2, 4> centers =
{ {
{ rect.x + rect.w - rr, rect.y + rr },
{ rect.x + rect.w - rr, rect.y + rect.h - rr },
{ rect.x + rr, rect.y + rect.h - rr },
{ rect.x + rr, rect.y + rr },
} };
const uint32 vertexSize = (quality - uniteV + quality - uniteH) * 2;
const uint32 indexSize = (vertexSize - 2) * 3;
Sprite sprite(vertexSize, indexSize);
{
SpriteVertex* pVertex = sprite.vertices.data();
for (int32 i = 0; i < quality - uniteV; ++i)
{
pVertex->pos = centers[0] + fanPositions[i];
++pVertex;
}
for (int32 i = 0; i < quality - uniteH; ++i)
{
pVertex->pos = centers[1] + Float2(fanPositions[quality - i - 1].x, -fanPositions[quality - i - 1].y);
++pVertex;
}
for (int32 i = 0; i < quality - uniteV; ++i)
{
pVertex->pos = centers[2] + Float2(-fanPositions[i].x, -fanPositions[i].y);
++pVertex;
}
for (int32 i = 0; i < quality - uniteH; ++i)
{
pVertex->pos = centers[3] + Float2(-fanPositions[quality - i - 1].x, fanPositions[quality - i - 1].y);
++pVertex;
}
}
{
const float uOffst = uvRect.left;
const float vOffst = uvRect.top;
const float left = static_cast<float>(rect.x);
const float ws = (uvRect.right - uvRect.left) / static_cast<float>(rect.w);
const float top = static_cast<float>(rect.y);
const float hs = (uvRect.bottom - uvRect.top) / static_cast<float>(rect.h);
SpriteVertex* pVertex = sprite.vertices.data();
for (size_t i = 0; i < vertexSize; ++i)
{
const float u = uOffst + (pVertex->pos.x - left) * ws;
const float v = vOffst + (pVertex->pos.y - top) * hs;
(pVertex++)->tex.set(u, v);
}
}
{
const Float4 colorF = diffuse.rgba();
SpriteVertex* pVertex = sprite.vertices.data();
for (size_t i = 0; i < vertexSize; ++i)
{
(pVertex++)->color = ColorF(colorF.x, colorF.y, colorF.z, colorF.w);
}
}
{
uint32* pIndex = sprite.indices.data();
for (uint32 i = 0; i < (vertexSize - 2); ++i)
{
pIndex[i * 3 + 1] = i + 1;
pIndex[i * 3 + 2] = (i + 2 < vertexSize) ? (i + 2) : 0;
}
}
sprite.draw(texture);
return rect;
}
RoundRect drawAt(double x, double y, const ColorF& diffuse = Palette::White) const
{
RoundRect rr = rect;
rr.setCenter(x, y);
return TexturedRoundRect(texture, uvRect, rr).draw(diffuse);
}
RoundRect drawAt(const Vec2& pos, const ColorF& diffuse = Palette::White) const
{
return drawAt(pos.x, pos.y, diffuse);
}
};
inline TexturedRoundRect RoundTex(const RoundRect& rect, const Texture& texture)
{
return TexturedRoundRect(texture,
0.0f, 0.0f, 1.0f, 1.0f,
rect);
}
inline TexturedRoundRect RoundTex(const RoundRect& rect, const TextureRegion& textureRegion)
{
return TexturedRoundRect(textureRegion.texture,
textureRegion.uvRect,
rect);
}
}
void Main()
{
const Texture texture(L"example/siv3d-kun.png");
const RoundRect rrect(40, 40, 80, 80, 8);
while (System::Update())
{
rrect.draw(Palette::Skyblue);
RoundTex(rrect, texture(85, 5, 120, 120)).draw();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment