18 if (i >=
text.size())
return 0;
19 const auto *
s =
reinterpret_cast<const unsigned char *
>(
text.data() + i);
20 const size_t rem =
text.size() - i;
21 unsigned char c0 =
s[0];
26 if ((c0 & 0xE0) == 0xC0 && rem >= 2 && (
s[1] & 0xC0) == 0x80) {
28 return ((c0 & 0x1F) << 6) | (
s[1] & 0x3F);
30 if ((c0 & 0xF0) == 0xE0 && rem >= 3 && (
s[1] & 0xC0) == 0x80 && (
s[2] & 0xC0) == 0x80) {
32 return ((c0 & 0x0F) << 12) | ((
s[1] & 0x3F) << 6) | (
s[2] & 0x3F);
34 if ((c0 & 0xF8) == 0xF0 && rem >= 4 && (
s[1] & 0xC0) == 0x80 && (
s[2] & 0xC0) == 0x80 &&
35 (
s[3] & 0xC0) == 0x80) {
37 return ((c0 & 0x07) << 18) | ((
s[1] & 0x3F) << 12) | ((
s[2] & 0x3F) << 6) | (
s[3] & 0x3F);
45std::vector<int> decodeCodepoints(
const std::string &
text) {
48 while (i <
text.size()) {
50 if (cp == 0)
continue;
51 out.push_back(
static_cast<int>(cp));
61 for (
int c = 0x20;
c <= 0x7E; ++
c)
s.push_back(
static_cast<char>(
c));
66 if (gfx ==
nullptr)
throw eve::Exception(
"Font: Graphics instance is null");
67 if (data ==
nullptr)
throw eve::Exception(
"Font: FontData is null");
71 std::unique_ptr<image::ImageData> bitmap;
72 int bearingX, bearingY, advance;
75 std::vector<int> codepoints = decodeCodepoints(charset);
76 std::vector<Raster> rasters;
77 rasters.reserve(codepoints.size());
80 std::unordered_map<int, bool> seen;
81 seen.reserve(codepoints.size());
83 long long totalArea = 0;
85 const int padding = 1;
87 for (
int cp : codepoints) {
88 if (seen.count(cp))
continue;
93 const int w = bmp ? bmp->getWidth() : 0;
94 const int h = bmp ? bmp->getHeight() : 0;
95 totalArea +=
static_cast<long long>(
w + padding) *
static_cast<long long>(
h + padding);
96 maxGlyphSide = std::max({maxGlyphSide,
w,
h});
102 if (rasters.empty()) {
112 int atlasWidth = std::max<int>(64,
static_cast<int>(std::sqrt(
static_cast<double>(totalArea)) * 1.2) + 1);
113 atlasWidth = std::max(atlasWidth, maxGlyphSide + 2 * padding);
115 std::vector<size_t>
order(rasters.size());
117 std::sort(
order.begin(),
order.end(), [&](
size_t a,
size_t b) {
118 return rasters[a].bitmap->getHeight() > rasters[b].bitmap->getHeight();
124 std::vector<Rect>
placed(rasters.size());
126 int penX = padding, penY = padding, shelfH = 0;
127 int atlasHeight = padding;
129 const int w = rasters[
idx].bitmap->getWidth();
130 const int h = rasters[
idx].bitmap->getHeight();
131 if (penX +
w + padding > atlasWidth) {
133 penY += shelfH + padding;
137 shelfH = std::max(shelfH,
h);
139 atlasHeight = std::max(atlasHeight, penY + shelfH + padding);
143 glyphs.reserve(rasters.size());
144 for (
size_t idx = 0;
idx < rasters.size(); ++
idx) {
145 const Raster &
r = rasters[
idx];
146 const int w =
r.bitmap->getWidth();
147 const int h =
r.bitmap->getHeight();
152 g.bearingX =
r.bearingX;
153 g.bearingY =
r.bearingY;
154 g.advance =
r.advance;
156 if (
w > 0 &&
h > 0) {
158 g.u0 =
static_cast<float>(
placed[
idx].x) /
static_cast<float>(atlasWidth);
159 g.v0 =
static_cast<float>(
placed[
idx].y) /
static_cast<float>(atlasHeight);
160 g.u1 =
static_cast<float>(
placed[
idx].x +
w) /
static_cast<float>(atlasWidth);
161 g.v1 =
static_cast<float>(
placed[
idx].y +
h) /
static_cast<float>(atlasHeight);
164 glyphs.emplace(
r.codepoint,
g);
178bool Font::hasGlyph(
int codepoint)
const {
return glyphs.find(codepoint) != glyphs.end(); }
181 auto it = glyphs.find(codepoint);
182 return it == glyphs.end() ? nullptr : &it->second;
EVENGINE_API_FOUNDATION public API.
CPU-side decoded font face (FreeType FT_Face + owned font bytes). Does not upload to GPU — rasterize ...
float getWidth(std::string text) const
Returns the width.
int getGlyphAdvance(int codepoint) const
Returns the glyph advance.
float getBaseline() const
Returns the baseline.
int getGlyphBearingX(int codepoint) const
Returns the glyph bearing x.
image::ImageData * newGlyphImageData(int codepoint)
Rasterize one glyph to RGBA8 ImageData (RGB white, A from FreeType gray). Returns a 0x0 ImageData if ...
int getGlyphBearingY(int codepoint) const
Returns the glyph bearing y.
float getAscent() const
Returns the ascent.
float getLineHeight() const
Returns the line height.
bool hasGlyph(int codepoint) const
字形 / 文本测量。
float getAscent() const
Returns the ascent.
Font(Graphics *gfx, font::FontData *data, std::string charset=defaultCharset())
Font.
static std::string defaultCharset()
Printable ASCII (0x20..0x7E), used when no explicit charset is given.
bool hasGlyph(int codepoint) const
Whether codepoint was rasterized into this Font's atlas.
float getBaseline() const
Distance from the top of a line to the baseline (== getAscent()).
const Glyph * findGlyph(int codepoint) const
Returns nullptr if codepoint isn't in this Font's atlas.
float getHeight() const
Line height in pixels at the FontData's decoded pixel size.
float getWidth(const std::string &text) const
Pixel width of text (UTF-8), including kerning; delegates to FontData.
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
Creates a texture. @ownership Caller deletes unless documented otherwise.
Represents raw pixel data.
void paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, int sh)
Paste part of one ImageData onto another. The subregion defined by the top-left corner (sx,...
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
uint32_t nextCodepointUtf8(const std::string &text, size_t &i)
Decodes one UTF-8 codepoint from text starting at byte offset i, advancing i past it....
Axis-aligned integer rectangle (screen/tile space).