-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRenderer.cppm
More file actions
150 lines (122 loc) · 6.2 KB
/
Renderer.cppm
File metadata and controls
150 lines (122 loc) · 6.2 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 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.renderer;
import delta.types;
import std;
export class MuxCanvasRenderer {
private:
SDL_Renderer* ren_ = nullptr;
TTF_Font* font_ = nullptr;
void draw_text_chunk(const std::string& text, float x, float y, style_state style) noexcept {
if (text.empty() || !font_ || !ren_) return;
int ttf_flags = TTF_STYLE_NORMAL;
if (style.bold) ttf_flags |= TTF_STYLE_BOLD;
if (style.italic) ttf_flags |= TTF_STYLE_ITALIC;
TTF_SetFontStyle(font_, ttf_flags);
SDL_Color black = {0, 0, 0, 255};
SDL_Surface* surf = TTF_RenderText_Blended(font_, text.c_str(), text.length(), black);
if (surf) {
SDL_Texture* tex = SDL_CreateTextureFromSurface(ren_, surf);
if (tex) {
SDL_FRect dst = { x, y, static_cast<float>(surf->w), static_cast<float>(surf->h) };
SDL_RenderTexture(ren_, tex, nullptr, &dst);
SDL_DestroyTexture(tex);
}
SDL_DestroySurface(surf);
}
}
public:
MuxCanvasRenderer(SDL_Renderer* renderer, TTF_Font* font) noexcept
: ren_(renderer), font_(font) {}
[[nodiscard]] std::expected<void, DeltaError> render_layout_blueprint(
const std::vector<LayoutLine>& layout,
size_t total_buffer_size,
const selection_span& sel
) noexcept {
if (!ren_ || !font_) return std::unexpected(DeltaError::RendererNullPointer);
SDL_SetRenderDrawColor(ren_, 255, 255, 255, 255);
SDL_RenderClear(ren_);
float current_y = MARGIN_Y;
float cursor_x = MARGIN_X;
float cursor_y = MARGIN_Y;
bool cursor_found = false;
size_t draw_sel_start = sel.start;
size_t draw_sel_end = sel.end;
if (draw_sel_start > draw_sel_end) std::swap(draw_sel_start, draw_sel_end);
for (const auto& line : layout) {
std::string style_chunk_text = "";
style_state active_style{false, false};
float chunk_start_x = MARGIN_X;
float current_x = MARGIN_X;
for (size_t i = 0; i < line.chars.size(); ++i) {
const auto& lc = line.chars[i];
// Trigger a text chunk draw whenever the style state flips!
if (i > 0 && (lc.style.bold != active_style.bold || lc.style.italic != active_style.italic)) {
draw_text_chunk(style_chunk_text, chunk_start_x, current_y, active_style);
chunk_start_x = current_x;
style_chunk_text.clear();
}
active_style = lc.style;
style_chunk_text += lc.character;
// Configure active font styling properties cleanly before sizing layout
int ttf_flags = TTF_STYLE_NORMAL;
if (active_style.bold) ttf_flags |= TTF_STYLE_BOLD;
if (active_style.italic) ttf_flags |= TTF_STYLE_ITALIC;
TTF_SetFontStyle(font_, ttf_flags);
// Look up total string sequence measurement length up to this index
std::string current_line_scan = "";
for (size_t k = 0; k <= i; ++k) {
current_line_scan += line.chars[k].character;
}
int total_w = 0; int total_h = 0;
TTF_GetStringSize(font_, current_line_scan.c_str(), current_line_scan.length(), &total_w, &total_h);
current_x = MARGIN_X + total_w;
// Render selection background highlights
if (lc.raw_buffer_index >= draw_sel_start && lc.raw_buffer_index < draw_sel_end) {
std::string single_g(1, lc.character);
int gw = 0; int gh = 0;
TTF_GetStringSize(font_, single_g.c_str(), 1, &gw, &gh);
SDL_SetRenderDrawBlendMode(ren_, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(ren_, 0, 120, 215, 60);
SDL_FRect highlight_rect = { current_x - gw, current_y + 4.0f, static_cast<float>(gw), 28.0f };
SDL_RenderFillRect(ren_, &highlight_rect);
}
if (lc.raw_buffer_index == sel.start) {
std::string single_g(1, lc.character);
int gw = 0; int gh = 0;
TTF_GetStringSize(font_, single_g.c_str(), 1, &gw, &gh);
cursor_x = current_x - gw; cursor_y = current_y;
cursor_found = true;
} else if (lc.raw_buffer_index + 1 == sel.start) {
cursor_x = current_x; cursor_y = current_y;
cursor_found = true;
}
}
// Flush the remaining text block cluster
draw_text_chunk(style_chunk_text, chunk_start_x, current_y, active_style);
if (!cursor_found && !line.chars.empty() && sel.start > line.chars.back().raw_buffer_index && line.is_hard_newline) {
cursor_x = MARGIN_X; cursor_y = current_y + LINE_SPACING;
}
current_y += LINE_SPACING;
}
if (sel.start == total_buffer_size && !layout.empty() && !layout.back().is_hard_newline) {
float last_y = MARGIN_Y + ((layout.size() - 1) * LINE_SPACING);
std::string full_line_str = "";
for (const auto& lc : layout.back().chars) full_line_str += lc.character;
int tw = 0; int th = 0;
TTF_SetFontStyle(font_, TTF_STYLE_NORMAL); // Default check layout
TTF_GetStringSize(font_, full_line_str.c_str(), full_line_str.length(), &tw, &th);
cursor_x = MARGIN_X + tw; cursor_y = last_y;
}
TTF_SetFontStyle(font_, TTF_STYLE_NORMAL);
if ((SDL_GetTicks() / 500) % 2 == 0 && sel.start == sel.end) {
SDL_SetRenderDrawColor(ren_, 0, 0, 0, 255);
SDL_FRect cursor_rect = { cursor_x + 1.0f, cursor_y + 4.0f, 2.0f, 26.0f };
SDL_RenderFillRect(ren_, &cursor_rect);
}
return {};
}
};