Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
FontRuntime.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "LegacyBitmap.hpp"
4
5#include <SDL3_ttf/SDL_ttf.h>
6
7#include <array>
8#include <cstddef>
9#include <cstdint>
10#include <expected>
11#include <filesystem>
12#include <optional>
13#include <memory>
14#include <span>
15#include <string>
16#include <string_view>
17#include <vector>
18
19namespace monopoly::fonts
20{
33
34 struct Error
35 {
37 std::filesystem::path path;
38 std::string detail;
39 };
40
41 struct Settings
42 {
43 std::filesystem::path fontPath;
44 std::string familyName;
45 int size{10};
46 int weight{400};
47 bool italic{};
48 bool underline{};
49 bool strikeOut{};
50
51 auto operator<=>(const Settings&) const = default;
52 };
53
54 struct Metrics
55 {
56 int width{};
57 int height{};
58 };
59
60 struct ClipRect
61 {
62 std::uint32_t x{};
63 std::uint32_t y{};
64 std::uint32_t width{};
65 std::uint32_t height{};
66 };
67
68 [[nodiscard]] std::expected<std::string, Error> transcodeUtf8(
69 std::u16string_view text);
70 [[nodiscard]] std::expected<std::string, Error> transcodeUtf8(
71 std::wstring_view text);
72
74 {
75 public:
76 static constexpr std::size_t SlotCount = 10;
77
78 Runtime();
79 ~Runtime();
80 Runtime(const Runtime&) = delete;
81 Runtime& operator=(const Runtime&) = delete;
82
83 [[nodiscard]] bool ready() const noexcept;
85 // Read a saved face without resizing the active font or flushing glyph caches.
87
88 [[nodiscard]] std::expected<void, Error> setFont(
90 std::string familyName = {});
91 [[nodiscard]] std::expected<void, Error> setSize(int points);
92 void setWeight(int weight);
93 void setItalic(bool enabled);
94 void setUnderline(bool enabled);
95 void setStrikeOut(bool enabled);
97
98 [[nodiscard]] std::expected<void, Error> saveSettings(std::size_t slot);
99 [[nodiscard]] std::expected<void, Error> restoreSettings(std::size_t slot);
100
101 [[nodiscard]] std::expected<Metrics, Error> measure(
102 std::string_view utf8) const;
103 [[nodiscard]] std::expected<Metrics, Error> measure(
104 std::u16string_view utf16) const;
105 // Source/monopoly/UDChat.cpp::CHAT_WordWrap core semantics using the
106 // currently selected font: prefer spaces, hard-break only when a
107 // word cannot fit, and treat '_' as a non-breaking space marker.
108 // The legacy caller owns its fixed wrapped-line storage; this returns
109 // an owning vector instead of reproducing that unsafe global buffer.
110 [[nodiscard]] std::expected<std::vector<std::string>, Error> wrap(
111 std::string_view utf8, int width) const;
112 // Optional coverage alpha for modern presentation; retail remains solid.
113 [[nodiscard]] std::expected<data::LegacyBitmapRGBA8, Error> render(
114 std::string_view utf8, std::uint32_t colorRef, bool antialiased = false) const;
115 [[nodiscard]] std::expected<data::LegacyBitmapRGBA8, Error> render(
116 std::u16string_view utf16, std::uint32_t colorRef, bool antialiased = false) const;
117 // Independent bounded faces for modern text; active settings and retail slots stay untouched.
118 static constexpr std::size_t PresentationFaceLimit = 32;
120 [[nodiscard]] std::expected<data::LegacyBitmapRGBA8, Error> renderPresentation(
121 std::string_view utf8, std::uint32_t colorRef, int size, int weight,
122 bool italic, bool underline = false, bool strikeOut = false, bool antialiased = true);
123 [[nodiscard]] std::expected<data::LegacyBitmapRGBA8, Error> renderClipped(
125 [[nodiscard]] std::expected<data::LegacyBitmapRGBA8, Error> renderClipped(
127 [[nodiscard]] std::expected<void, Error> blitText(
128 data::LegacyBitmapRGBA8& destination, std::string_view utf8,
129 int x, int y, std::uint32_t colorRef) const;
130 [[nodiscard]] std::expected<void, Error> blitText(
131 data::LegacyBitmapRGBA8& destination, std::u16string_view utf16,
132 int x, int y, std::uint32_t colorRef) const;
133
134 private:
135 [[nodiscard]] std::expected<void, Error> reopen();
136 void applyStyle() noexcept;
137
138 struct CloseFont { void operator()(TTF_Font* font) const noexcept { TTF_CloseFont(font); } };
139 struct PresentationFace
140 {
141 std::unique_ptr<TTF_Font, CloseFont> font;
142 int size{}, weight{};
143 bool italic{}, underline{}, strikeOut{};
144 std::uint64_t lastUsed{};
145 };
146 void clearPresentationFaces() noexcept;
147 [[nodiscard]] std::expected<data::LegacyBitmapRGBA8, Error> renderFace(
149 std::array<PresentationFace, PresentationFaceLimit> presentationFaces_;
150 std::uint64_t presentationClock_{};
151 bool ttfInitialized_{};
152 TTF_Font* font_{};
153 Settings settings_;
154 std::array<std::optional<Settings>, SlotCount> slots_{};
155 };
156
157 // Retail startup first tries Arial.ttf beside the executable, then the
158 // Windows font directory. The caller supplies those roots explicitly so
159 // non-Windows ports never gain a hidden platform-specific fallback.
160 [[nodiscard]] std::expected<std::filesystem::path, Error>
161 resolveRetailArial(std::span<const std::filesystem::path> roots);
162}
std::string_view text
fonts::Runtime & font
bool enabled
Definition Engine.cpp:170
PlayerNumber slot
std::uint32_t width
unsigned index
std::array< data::DataTag, 3 > roots
std::string path
std::expected< void, Error > setFont(const std::filesystem::path &path, std::string familyName={})
Runtime & operator=(const Runtime &)=delete
std::size_t presentationFaceCount() const noexcept
const Settings * savedSettings(std::size_t slot) const noexcept
std::expected< Metrics, Error > measure(std::string_view utf8) const
std::expected< data::LegacyBitmapRGBA8, Error > renderPresentation(std::string_view utf8, std::uint32_t colorRef, int size, int weight, bool italic, bool underline=false, bool strikeOut=false, bool antialiased=true)
static constexpr std::size_t PresentationFaceLimit
const Settings & settings() const noexcept
std::expected< data::LegacyBitmapRGBA8, Error > render(std::string_view utf8, std::uint32_t colorRef, bool antialiased=false) const
static constexpr std::size_t SlotCount
void setWeight(int weight)
void setUnderline(bool enabled)
std::expected< void, Error > setSize(int points)
Runtime(const Runtime &)=delete
std::expected< void, Error > saveSettings(std::size_t slot)
std::expected< data::LegacyBitmapRGBA8, Error > renderClipped(std::string_view utf8, std::uint32_t colorRef, ClipRect clip, bool antialiased=false) const
bool ready() const noexcept
std::expected< std::vector< std::string >, Error > wrap(std::string_view utf8, int width) const
std::expected< void, Error > restoreSettings(std::size_t slot)
void setStrikeOut(bool enabled)
void setItalic(bool enabled)
std::expected< void, Error > blitText(data::LegacyBitmapRGBA8 &destination, std::string_view utf8, int x, int y, std::uint32_t colorRef) const
std::expected< std::string, Error > transcodeUtf8(std::u16string_view text)
std::expected< std::filesystem::path, Error > resolveRetailArial(std::span< const std::filesystem::path > roots)
std::filesystem::path path
std::filesystem::path fontPath
auto operator<=>(const Settings &) const =default