mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
UI: Rounded rectangles from precomputed atlas corners
UIAtlas generates an antialiased white corner for each radius in ROUND_RECT_RADII (8, 16, 24, 32 UI units) and each style (filled, and thin/medium/thick outlines from ROUND_RECT_THICKNESS) at the atlas DPI. DrawBuffer::DrawRoundRect mirrors the corner into all four corners and stretches the corner's last texel row/column along the edges, so a round rect is 9 quads (8 for outlines). Other radii use the nearest corner, scaled. The LogoScreen temporarily draws some for testing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
42bb9b134b
commit
110fb7fd6a
5 files changed
+182
-2
No files matched your search
@@ -429,6 +429,84 @@ void DrawBuffer::DrawImage4Grid(ImageID atlas_image, float x1, float y1, float x
|
||||
DrawTexRect(xb, yb, x2, y2, um, vm, u2, v2, color);
|
||||
}
|
||||
|
||||
const char *RoundRectCornerImageName(int radiusIndex, RoundRectStyle style) {
|
||||
// Generated from the indices, so the tables in the header are all there is to edit.
|
||||
struct Names {
|
||||
char names[ROUND_RECT_RADIUS_COUNT][(int)RoundRectStyle::COUNT][16];
|
||||
Names() {
|
||||
for (int r = 0; r < ROUND_RECT_RADIUS_COUNT; r++) {
|
||||
for (int s = 0; s < (int)RoundRectStyle::COUNT; s++) {
|
||||
snprintf(names[r][s], sizeof(names[r][s]), "I_RRECT_%d_%d", r, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
static const Names names;
|
||||
return names.names[radiusIndex][(int)style];
|
||||
}
|
||||
|
||||
void DrawBuffer::DrawRoundRect(float x1, float y1, float x2, float y2, float radius, Color color, RoundRectStyle style) {
|
||||
if (!atlas || x2 <= x1 || y2 <= y1) {
|
||||
return;
|
||||
}
|
||||
if (roundRectAtlasImages_ != atlas->images) {
|
||||
for (int r = 0; r < ROUND_RECT_RADIUS_COUNT; r++) {
|
||||
for (int s = 0; s < (int)RoundRectStyle::COUNT; s++) {
|
||||
roundRectCorners_[r][s] = atlas->getImage(ImageID(RoundRectCornerImageName(r, (RoundRectStyle)s)));
|
||||
}
|
||||
}
|
||||
roundRectAtlasImages_ = atlas->images;
|
||||
}
|
||||
|
||||
int radiusIndex = 0;
|
||||
for (int i = 1; i < ROUND_RECT_RADIUS_COUNT; i++) {
|
||||
if (fabsf(ROUND_RECT_RADII[i] - radius) < fabsf(ROUND_RECT_RADII[radiusIndex] - radius)) {
|
||||
radiusIndex = i;
|
||||
}
|
||||
}
|
||||
const AtlasImage *image = roundRectCorners_[radiusIndex][(int)style];
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool filled = style == RoundRectStyle::Filled;
|
||||
const float dpiScale = atlas->dpiScale;
|
||||
const float r = ROUND_RECT_RADII[radiusIndex] * dpiScale;
|
||||
const int center = RoundRectCornerCenter(r);
|
||||
|
||||
// The corner quad runs from the center of texel 0 to the center of the last texel, which holds
|
||||
// the straight edge profile that gets stretched along the sides. Shrink it to fit small rects.
|
||||
float scale = std::max(radius, 0.0f) / ROUND_RECT_RADII[radiusIndex];
|
||||
const float maxScale = std::min(x2 - x1, y2 - y1) * dpiScale / (2.0f * (r + 0.5f));
|
||||
scale = std::min(scale, maxScale);
|
||||
if (scale <= 0.0f) {
|
||||
if (filled) {
|
||||
DrawImageCenterTexel(ImageID("I_SOLIDWHITE"), x1, y1, x2, y2, color);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const float texel = scale / dpiScale;
|
||||
const float outside = (center - r - 0.5f) * texel; // From the rect edge out to texel 0's center.
|
||||
const float inside = (r + 0.5f) * texel; // From the rect edge in to the last texel's center.
|
||||
|
||||
const float xs[4] = { x1 - outside, x1 + inside, x2 - inside, x2 + outside };
|
||||
const float ys[4] = { y1 - outside, y1 + inside, y2 - inside, y2 + outside };
|
||||
const float us[4] = { image->u1, image->u2, image->u2, image->u1 };
|
||||
const float vs[4] = { image->v1, image->v2, image->v2, image->v1 };
|
||||
|
||||
for (int y = 0; y < 3; y++) {
|
||||
if (ys[y + 1] <= ys[y]) {
|
||||
continue;
|
||||
}
|
||||
for (int x = 0; x < 3; x++) {
|
||||
if (xs[x + 1] <= xs[x] || (x == 1 && y == 1 && !filled)) {
|
||||
continue;
|
||||
}
|
||||
DrawTexRect(xs[x], ys[y], xs[x + 1], ys[y + 1], us[x], vs[y], us[x + 1], vs[y + 1], color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawBuffer::DrawImage2GridH(ImageID atlas_image, float x1, float y1, float x2, Color color, float corner_scale) {
|
||||
const AtlasImage *image = atlas->getImage(atlas_image);
|
||||
float um = (image->u1 + image->u2) * 0.5f;
|
||||
|
||||
Reference in new issue
Block a user