Blender V4.3
overlay_next_edit_text.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#pragma once
10
11#include "BKE_vfont.hh"
12#include "BLI_math_matrix.hh"
13
15
16namespace blender::draw::overlay {
17
18class EditText {
19
20 private:
21 PassSimple ps_ = {"Selection&Cursor"};
22
23 View view_edit_text = {"view_edit_text"};
24 float view_dist = 0.0f;
25
26 StorageVectorBuffer<ObjectMatrices> text_selection_buf;
28 LinePrimitiveBuf box_line_buf_;
29
30 bool enabled_ = false;
31
32 public:
33 EditText(SelectionType selection_type) : box_line_buf_(selection_type, "box_line_buf_") {}
34
35 void begin_sync(const State &state)
36 {
37 enabled_ = state.v3d;
38 text_selection_buf.clear();
39 text_cursor_buf.clear();
40 box_line_buf_.clear();
41 }
42
43 void edit_object_sync(const ObjectRef &ob_ref, const Resources &res)
44 {
45 if (!enabled_) {
46 return;
47 }
48
49 const Curve &cu = *static_cast<Curve *>(ob_ref.object->data);
50 add_select(cu, ob_ref.object->object_to_world());
51 add_cursor(cu, ob_ref.object->object_to_world());
52 add_boxes(res, cu, ob_ref.object->object_to_world());
53 }
54
55 void end_sync(Resources &res, const ShapeCache &shapes, const State &state)
56 {
57 ps_.init();
58 res.select_bind(ps_);
59 {
61 float4 color;
62
63 /* Selection Boxes. */
64 {
65 auto &sub = ps_.sub("text_selection");
66 sub.state_set(default_state, state.clipping_plane_count);
67 sub.shader_set(res.shaders.uniform_color_batch.get());
69 srgb_to_linearrgb_v4(color, color);
70 sub.push_constant("ucolor", color);
71
72 auto &buf = text_selection_buf;
73 buf.push_update();
74 sub.bind_ssbo("matrix_buf", &buf);
75 sub.draw(shapes.quad_solid.get(), buf.size());
76 }
77
78 /* Highlight text within selection boxes. */
79 {
80 auto &sub = ps_.sub("highlight_text_selection");
83 state.clipping_plane_count);
84 sub.shader_set(res.shaders.uniform_color_batch.get());
86 srgb_to_linearrgb_v4(color, color);
87 sub.push_constant("ucolor", color);
88
89 auto &buf = text_selection_buf;
90 buf.push_update();
91 sub.bind_ssbo("matrix_buf", &buf);
92 sub.draw(shapes.quad_solid.get(), buf.size());
93 }
94
95 /* Cursor (text caret). */
96 {
97 auto &sub = ps_.sub("text_cursor");
98 sub.state_set(default_state, state.clipping_plane_count);
99 sub.shader_set(res.shaders.uniform_color_batch.get());
100 sub.state_set(default_state, state.clipping_plane_count);
102 srgb_to_linearrgb_v4(color, color);
103 sub.push_constant("ucolor", color);
104
105 auto &buf = text_cursor_buf;
106 buf.push_update();
107 sub.bind_ssbo("matrix_buf", &buf);
108 sub.draw(shapes.quad_solid.get(), buf.size());
109 }
110
111 /* Text boxes. */
112 {
113 auto &sub_pass = ps_.sub("text_boxes");
116 state.clipping_plane_count);
117 sub_pass.shader_set(res.shaders.extra_wire.get());
118 sub_pass.bind_ubo("globalsBlock", &res.globals_buf);
119 box_line_buf_.end_sync(sub_pass);
120 }
121 }
122 }
123
124 void draw(Framebuffer &framebuffer, Manager &manager, View &view)
125 {
126 if (!enabled_) {
127 return;
128 }
129 view_edit_text.sync(view.viewmat(), winmat_polygon_offset(view.winmat(), view_dist, -5.0f));
130
131 GPU_framebuffer_bind(framebuffer);
132 manager.submit(ps_, view_edit_text);
133 }
134
135 private:
136 /* Use 2D quad corners to create a matrix that set
137 * a [-1..1] quad at the right position. */
138 static void v2_quad_corners_to_mat4(const float4x2 &corners, float4x4 &r_mat)
139 {
140 const float2 &origin = corners[0];
141 const float2 half_size_x = (float2(corners[1]) - float2(corners[0])) * 0.5f;
142 const float2 half_size_y = (float2(corners[3]) - float2(corners[0])) * 0.5f;
143
144 r_mat = float4x4(float4(half_size_x, 0.0f, 0.0f),
145 float4(half_size_y, 0.0f, 0.0f),
146 float4(0.0f, 0.0f, 1.0f, 0.0f),
147 float4(origin + half_size_x + half_size_y, 0.0f, 1.0f));
148 }
149
150 void add_select(const Curve &cu, const float4x4 &ob_to_world)
151 {
152 EditFont *ef = cu.editfont;
153 float4x4 final_mat;
154 float4x2 box;
155
156 for (const int i : IndexRange(ef->selboxes_len)) {
157 EditFontSelBox *sb = &ef->selboxes[i];
158
159 float selboxw;
160 if (i + 1 != ef->selboxes_len) {
161 if (ef->selboxes[i + 1].y == sb->y) {
162 selboxw = ef->selboxes[i + 1].x - sb->x;
163 }
164 else {
165 selboxw = sb->w;
166 }
167 }
168 else {
169 selboxw = sb->w;
170 }
171 /* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */
172 if (sb->rot == 0.0f) {
173 box[0] = float2(sb->x, sb->y);
174 box[1] = float2(sb->x + selboxw, sb->y);
175 box[3] = float2(sb->x, sb->y + sb->h);
176 }
177 else {
179 box[0] = float2(sb->x, sb->y);
180 box[1] = mat[0] * selboxw + float2(&sb->x);
181 box[3] = mat[1] * sb->h + float2(&sb->x);
182 }
183 v2_quad_corners_to_mat4(box, final_mat);
184 final_mat = ob_to_world * final_mat;
185 ObjectMatrices obj_mat;
186 obj_mat.sync(final_mat);
187 text_selection_buf.append(obj_mat);
188 }
189 }
190
191 void add_cursor(const Curve &cu, const float4x4 &ob_to_world)
192 {
193 EditFont *edit_font = cu.editfont;
194 float4x2 cursor = float4x2(&edit_font->textcurs[0][0]);
195 float4x4 mat;
196
197 v2_quad_corners_to_mat4(cursor, mat);
198 ObjectMatrices ob_mat;
199 ob_mat.sync(ob_to_world * mat);
200 text_cursor_buf.append(ob_mat);
201 }
202
203 void add_boxes(const Resources &res, const Curve &cu, const float4x4 &ob_to_world)
204 {
205 for (const int i : IndexRange(cu.totbox)) {
206 const TextBox &tb = cu.tb[i];
207 const bool is_active = (i == (cu.actbox - 1));
208 const float4 &color = is_active ? res.theme_settings.color_active :
209 res.theme_settings.color_wire;
210
211 if ((tb.w != 0.0f) || (tb.h != 0.0f)) {
212 const float3 top_left = float3(cu.xof + tb.x, cu.yof + tb.y + cu.fsize_realtime, 0.001);
213 const float3 w = float3(tb.w, 0.0f, 0.0f);
214 const float3 h = float3(0.0f, tb.h, 0.0f);
215 float4x3 vecs = float4x3(top_left, top_left + w, top_left + w - h, top_left - h);
216
217 for (const int j : IndexRange(4)) {
218 vecs[j] = math::transform_point(ob_to_world, vecs[j]);
219 }
220 for (const int j : IndexRange(4)) {
221 box_line_buf_.append(vecs[j], vecs[(j + 1) % 4], color);
222 }
223 }
224 }
225 }
226};
227} // namespace blender::draw::overlay
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
@ TH_WIDGET_TEXT_HIGHLIGHT
@ TH_WIDGET_TEXT_SELECTION
@ TH_WIDGET_TEXT_CURSOR
void UI_GetThemeColor4fv(int colorid, float col[4])
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void submit(PassSimple &pass, View &view)
void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id=0)
Definition draw_view.cc:20
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:616
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
EditText(SelectionType selection_type)
void end_sync(Resources &res, const ShapeCache &shapes, const State &state)
void edit_object_sync(const ObjectRef &ob_ref, const Resources &res)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
DRWState
Definition draw_state.hh:25
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_DEPTH_GREATER_EQUAL
Definition draw_state.hh:41
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
static ulong state[N]
static float4x4 winmat_polygon_offset(float4x4 winmat, float view_dist, float offset)
MatT from_rotation(const RotationT &rotation)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 2, 2 > float2x2
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
MatBase< float, 4, 2 > float4x2
MatBase< float, 4, 3 > float4x3
VecBase< float, 3 > float3
struct TextBox * tb
struct EditFont * editfont
float fsize_realtime
float textcurs[4][2]
Definition BKE_vfont.hh:40
EditFontSelBox * selboxes
Definition BKE_vfont.hh:41
int selboxes_len
Definition BKE_vfont.hh:42
void append(const float3 &start, const float3 &end, const float4 &color, select::ID select_id=select::SelectMap::select_invalid_id())
void select_bind(PassSimple &pass)