Blender V4.5
overlay_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
8
9#pragma once
10
11#include "BKE_vfont.hh"
12#include "BLI_math_matrix.hh"
13
14#include "overlay_base.hh"
15
16namespace blender::draw::overlay {
17
22class Text : Overlay {
23
24 private:
25 PassSimple ps_ = {"TextEdit"};
26 PassSimple::Sub *selection_ps_ = nullptr;
27 PassSimple::Sub *selection_highlight_ps_ = nullptr;
28 PassSimple::Sub *cursor_ps_ = nullptr;
29
30 View view_edit_text = {"view_edit_text"};
31
32 LinePrimitiveBuf box_line_buf_;
33
35 gpu::Batch *quad = nullptr;
37 gpu::Batch *quad_wire = nullptr;
38
39 public:
40 Text(SelectionType selection_type) : box_line_buf_(selection_type, "box_line_buf_") {}
41
42 void begin_sync(Resources &res, const State &state) final
43 {
44 enabled_ = state.is_space_v3d();
45 box_line_buf_.clear();
46
47 if (!enabled_) {
48 return;
49 }
50
51 quad = res.shapes.quad_solid.get();
52 quad_wire = res.shapes.quad_wire.get();
53
54 ps_.init();
55 ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
56 ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
57 res.select_bind(ps_);
58 {
61
62 /* Selection Boxes. */
63 {
64 auto &sub = ps_.sub("text_selection");
65 sub.state_set(default_state, state.clipping_plane_count);
66 sub.shader_set(res.shaders->uniform_color.get());
69 sub.push_constant("ucolor", color);
70 selection_ps_ = ⊂
71 }
72
73 /* Highlight text within selection boxes. */
74 {
75 auto &sub = ps_.sub("highlight_text_selection");
78 state.clipping_plane_count);
79 sub.shader_set(res.shaders->uniform_color.get());
82 sub.push_constant("ucolor", color);
83 selection_highlight_ps_ = ⊂
84 }
85
86 /* Cursor (text caret). */
87 {
88 auto &sub = ps_.sub("text_cursor");
89 sub.state_set(default_state, state.clipping_plane_count);
90 sub.shader_set(res.shaders->uniform_color.get());
91 sub.state_set(default_state, state.clipping_plane_count);
94 sub.push_constant("ucolor", color);
95 cursor_ps_ = ⊂
96 }
97 }
98 }
99
101 const ObjectRef &ob_ref,
102 Resources &res,
103 const State & /*state*/) final
104 {
105 if (!enabled_) {
106 return;
107 }
108
109 const Curve &cu = DRW_object_get_data_for_drawing<Curve>(*ob_ref.object);
110 add_select(manager, cu, ob_ref.object->object_to_world());
111 add_cursor(manager, cu, ob_ref.object->object_to_world());
112 add_boxes(res, cu, ob_ref.object->object_to_world());
113 }
114
115 void end_sync(Resources &res, const State &state) final
116 {
117 if (!enabled_) {
118 return;
119 }
120
121 /* Text boxes. */
122 {
123 auto &sub_pass = ps_.sub("text_boxes");
124 sub_pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
126 state.clipping_plane_count);
127 sub_pass.shader_set(res.shaders->extra_wire.get());
128 box_line_buf_.end_sync(sub_pass);
129 }
130 }
131
132 void draw(Framebuffer &framebuffer, Manager &manager, View &view) final
133 {
134 if (!enabled_) {
135 return;
136 }
137
138 View::OffsetData offset;
139 view_edit_text.sync(view.viewmat(), offset.winmat_polygon_offset(view.winmat(), -5.0f));
140
141 GPU_framebuffer_bind(framebuffer);
142 manager.submit(ps_, view_edit_text);
143 }
144
145 private:
146 /* Use 2D quad corners to create a matrix that set
147 * a [-1..1] quad at the right position. */
148 static void v2_quad_corners_to_mat4(const float4x2 &corners, float4x4 &r_mat)
149 {
150 const float2 &origin = corners[0];
151 const float2 half_size_x = (float2(corners[1]) - float2(corners[0])) * 0.5f;
152 const float2 half_size_y = (float2(corners[3]) - float2(corners[0])) * 0.5f;
153
154 r_mat = float4x4(float4(half_size_x, 0.0f, 0.0f),
155 float4(half_size_y, 0.0f, 0.0f),
156 float4(0.0f, 0.0f, 1.0f, 0.0f),
157 float4(origin + half_size_x + half_size_y, 0.0f, 1.0f));
158 }
159
160 void add_select(Manager &manager, const Curve &cu, const float4x4 &ob_to_world)
161 {
162 EditFont *ef = cu.editfont;
163 for (const int i : IndexRange(ef->selboxes_len)) {
164 EditFontSelBox *sb = &ef->selboxes[i];
165
166 float selboxw;
167 if (i + 1 != ef->selboxes_len) {
168 if (ef->selboxes[i + 1].y == sb->y) {
169 selboxw = ef->selboxes[i + 1].x - sb->x;
170 }
171 else {
172 selboxw = sb->w;
173 }
174 }
175 else {
176 selboxw = sb->w;
177 }
178 float4x2 box;
179 /* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */
180 if (sb->rot == 0.0f) {
181 box[0] = float2(sb->x, sb->y);
182 box[1] = float2(sb->x + selboxw, sb->y);
183 box[3] = float2(sb->x, sb->y + sb->h);
184 }
185 else {
187 box[0] = float2(sb->x, sb->y);
188 box[1] = mat[0] * selboxw + float2(&sb->x);
189 box[3] = mat[1] * sb->h + float2(&sb->x);
190 }
191 float4x4 mat;
192 v2_quad_corners_to_mat4(box, mat);
193 ResourceHandle res_handle = manager.resource_handle(ob_to_world * mat);
194 selection_ps_->draw(quad, res_handle);
195 selection_highlight_ps_->draw(quad, res_handle);
196 }
197 }
198
199 void add_cursor(Manager &manager, const Curve &cu, const float4x4 &ob_to_world)
200 {
201 EditFont *edit_font = cu.editfont;
202 float4x2 cursor = float4x2(&edit_font->textcurs[0][0]);
203 float4x4 mat;
204 v2_quad_corners_to_mat4(cursor, mat);
205 ResourceHandle res_handle = manager.resource_handle(ob_to_world * mat);
206
207 cursor_ps_->draw(quad, res_handle);
208
209 /* Draw both wire and solid so the cursor is always at least with width of a line,
210 * otherwise it may become invisible, see: #137940. */
211 cursor_ps_->draw(quad_wire, res_handle);
212 }
213
214 void add_boxes(const Resources &res, const Curve &cu, const float4x4 &ob_to_world)
215 {
216 const EditFont *edit_font = cu.editfont;
217 for (const int i : IndexRange(cu.totbox)) {
218 const TextBox &tb = cu.tb[i];
219 const bool is_active = (i == (cu.actbox - 1));
220 const float4 &color = is_active ? res.theme.colors.active_object : res.theme.colors.wire;
221
222 if ((tb.w != 0.0f) || (tb.h != 0.0f)) {
223 const float3 top_left = float3(
224 cu.xof + tb.x, cu.yof + tb.y + edit_font->font_size_eval, 0.001);
225 const float3 w = float3(tb.w, 0.0f, 0.0f);
226 const float3 h = float3(0.0f, tb.h, 0.0f);
227 float4x3 vecs = float4x3(top_left, top_left + w, top_left + w - h, top_left - h);
228
229 for (const int j : IndexRange(4)) {
230 vecs[j] = math::transform_point(ob_to_world, vecs[j]);
231 }
232 for (const int j : IndexRange(4)) {
233 box_line_buf_.append(vecs[j], vecs[(j + 1) % 4], color);
234 }
235 }
236 }
237 }
238};
239} // namespace blender::draw::overlay
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
struct Curve Curve
struct TextBox TextBox
static AppView * view
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
@ 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
ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandleRange handle={0}, uint custom_id=0)
Definition draw_pass.hh:884
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:490
Text(SelectionType selection_type)
void begin_sync(Resources &res, const State &state) final
void draw(Framebuffer &framebuffer, Manager &manager, View &view) final
void edit_object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &res, const State &) final
void end_sync(Resources &res, const State &state) final
Mesh & DRW_object_get_data_for_drawing(const Object &object)
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
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
blender::gpu::Batch * quad
static ulong state[N]
select::SelectionType SelectionType
detail::Pass< command::DrawCommandBuf > PassSimple
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 textcurs[4][2]
Definition BKE_vfont.hh:48
float font_size_eval
Definition BKE_vfont.hh:45
EditFontSelBox * selboxes
Definition BKE_vfont.hh:49
int selboxes_len
Definition BKE_vfont.hh:50
float4x4 winmat_polygon_offset(float4x4 winmat, float offset)
Definition draw_view.hh:197
void append(const float3 &start, const float3 &end, const float4 &color, select::ID select_id=select::SelectMap::select_invalid_id())
i
Definition text_draw.cc:230