-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathengine.cppm
More file actions
112 lines (91 loc) · 3.81 KB
/
engine.cppm
File metadata and controls
112 lines (91 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// This project is licensed under the GPL-3.0 License. See the LICENSE file for details, or check out <gnu.org>.
// Copyright (C) 2026 mxreal64
module;
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
export module delta.engine;
import delta.types;
import std;
export [[nodiscard]] std::vector<LayoutLine> compute_text_layout(TTF_Font* font, const std::string& buffer) noexcept {
std::vector<LayoutLine> layout;
if (!font) return layout;
const float right_bound = static_cast<float>(WINDOW_WIDTH) - (MARGIN_X * 2.0f);
LayoutLine current_line;
style_state current_style{false, false};
float current_x = 0.0f;
for (size_t i = 0; i < buffer.size(); ++i) {
char c = buffer[i];
if (c == '\x02') { current_style.bold = !current_style.bold; continue; }
if (c == '\x03') { current_style.italic = !current_style.italic; continue; }
if (c == '\n') {
current_line.is_hard_newline = true;
layout.push_back(std::move(current_line));
current_line = LayoutLine();
current_x = 0.0f;
continue;
}
// Apply style to font before measuring geometry bounds
int ttf_flags = TTF_STYLE_NORMAL;
if (current_style.bold) ttf_flags |= TTF_STYLE_BOLD;
if (current_style.italic) ttf_flags |= TTF_STYLE_ITALIC;
TTF_SetFontStyle(font, ttf_flags);
std::string glyph_str(1, c);
int cw = 0; int ch = 0;
TTF_GetStringSize(font, glyph_str.c_str(), 1, &cw, &ch);
// Soft wrap constraint tracking
if (current_x + cw > right_bound && !current_line.chars.empty()) {
layout.push_back(std::move(current_line));
current_line = LayoutLine();
current_x = 0.0f;
}
current_line.chars.push_back({c, i, current_style});
current_x += cw;
}
layout.push_back(std::move(current_line));
TTF_SetFontStyle(font, TTF_STYLE_NORMAL); // Reset to base state cleanly
return layout;
}
export [[nodiscard]] size_t pixel_coords_to_buffer_index(
TTF_Font* font,
const std::vector<LayoutLine>& layout,
const std::string& buffer,
float mx,
float my
) noexcept {
if (layout.empty() || !font) return buffer.size();
float current_y = MARGIN_Y;
for (size_t l = 0; l < layout.size(); ++l) {
const auto& line = layout[l];
// Check if the click coordinates match this line row vertically
if (my >= current_y && my < current_y + LINE_SPACING) {
float current_x = MARGIN_X;
for (const auto& lc : line.chars) {
int ttf_flags = TTF_STYLE_NORMAL;
if (lc.style.bold) ttf_flags |= TTF_STYLE_BOLD;
if (lc.style.italic) ttf_flags |= TTF_STYLE_ITALIC;
TTF_SetFontStyle(font, ttf_flags);
std::string g(1, lc.character);
int cw = 0; int ch = 0;
TTF_GetStringSize(font, g.c_str(), 1, &cw, &ch);
if (mx >= current_x && mx < current_x + (cw / 2.0f)) {
return lc.raw_buffer_index;
}
if (mx >= current_x + (cw / 2.0f) && mx < current_x + cw) {
return lc.raw_buffer_index + 1;
}
current_x += cw;
}
// Clicking past the trailing edge of a line maps to the end of that row
if (!line.chars.empty()) {
return line.chars.back().raw_buffer_index + 1;
}
// Fallback for an empty line row entry block
if (l + 1 < layout.size() && !layout[l+1].chars.empty()) {
return layout[l+1].chars.front().raw_buffer_index;
}
return buffer.size();
}
current_y += LINE_SPACING;
}
return buffer.size();
}