Blender V4.3
overlay_next_curve.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_attribute.hh"
12#include "BKE_curves.h"
13
14#include "DNA_curves_types.h"
15
16#include "GPU_capabilities.hh"
17
18#include "draw_cache_impl.hh"
19
21
22namespace blender::draw::overlay {
23
24class Curves {
25 private:
26 PassSimple edit_curves_ps_ = {"Curve Edit"};
27 PassSimple::Sub *edit_curves_points_ = nullptr;
28 PassSimple::Sub *edit_curves_lines_ = nullptr;
29 PassSimple::Sub *edit_curves_handles_ = nullptr;
30
31 PassSimple edit_legacy_curve_ps_ = {"Legacy Curve Edit"};
32 PassSimple::Sub *edit_legacy_curve_wires_ = nullptr;
33 PassSimple::Sub *edit_legacy_curve_normals_ = nullptr;
34 PassSimple::Sub *edit_legacy_curve_points_ = nullptr;
35 PassSimple::Sub *edit_legacy_curve_handles_ = nullptr;
36
37 PassSimple edit_legacy_surface_handles_ps = {"Surface Edit"};
38 PassSimple::Sub *edit_legacy_surface_handles_ = nullptr;
39 /* Handles that are below the geometry and are rendered with lower alpha. */
40 PassSimple::Sub *edit_legacy_surface_xray_handles_ = nullptr;
41
42 /* TODO(fclem): This is quite wasteful and expensive, prefer in shader Z modification like the
43 * retopology offset. */
44 View view_edit_cage = {"view_edit_cage"};
45 float view_dist = 0.0f;
46
47 bool enabled_ = false;
48
49 public:
50 void begin_sync(Resources &res, const State &state, const View &view)
51 {
52 enabled_ = state.space_type == SPACE_VIEW3D;
53
54 if (!enabled_) {
55 return;
56 }
57
58 view_dist = state.view_dist_get(view.winmat());
59
60 {
61 auto &pass = edit_curves_ps_;
62 pass.init();
63 {
64 auto &sub = pass.sub("Lines");
67 state.clipping_plane_count);
68 sub.shader_set(res.shaders.curve_edit_line.get());
69 sub.bind_ubo("globalsBlock", &res.globals_buf);
70 sub.bind_texture("weightTex", &res.weight_ramp_tx);
71 sub.push_constant("useWeight", false);
72 sub.push_constant("useGreasePencil", false);
73 edit_curves_lines_ = ⊂
74 }
75 {
76 auto &sub = pass.sub("Handles");
78 sub.shader_set(res.shaders.curve_edit_handles.get());
79 sub.bind_ubo("globalsBlock", &res.globals_buf);
80 sub.push_constant("showCurveHandles", state.overlay.handle_display != CURVE_HANDLE_NONE);
81 sub.push_constant("curveHandleDisplay", int(state.overlay.handle_display));
82 edit_curves_handles_ = ⊂
83 }
84 {
85 auto &sub = pass.sub("Points");
88 state.clipping_plane_count);
89 sub.shader_set(res.shaders.curve_edit_points.get());
90 sub.bind_ubo("globalsBlock", &res.globals_buf);
91 sub.bind_texture("weightTex", &res.weight_ramp_tx);
92 sub.push_constant("useWeight", false);
93 sub.push_constant("useGreasePencil", false);
94 sub.push_constant("doStrokeEndpoints", false);
95 sub.push_constant("curveHandleDisplay", int(state.overlay.handle_display));
96 edit_curves_points_ = ⊂
97 }
98 }
99
100 const bool show_normals = (state.overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS);
101 const bool use_hq_normals = (state.scene->r.perf_flag & SCE_PERF_HQ_NORMALS) ||
103
104 {
105 auto &pass = edit_legacy_curve_ps_;
106 pass.init();
107 {
108 auto &sub = pass.sub("Wires");
110 state.clipping_plane_count);
111 sub.shader_set(res.shaders.legacy_curve_edit_wires.get());
112 sub.bind_ubo("globalsBlock", &res.globals_buf);
113 sub.push_constant("normalSize", 0.0f);
114 edit_legacy_curve_wires_ = ⊂
115 }
116 if (show_normals) {
117 auto &sub = pass.sub("Normals");
119 state.clipping_plane_count);
120 sub.shader_set(res.shaders.legacy_curve_edit_normals.get());
121 sub.bind_ubo("globalsBlock", &res.globals_buf);
122 sub.push_constant("normalSize", state.overlay.normals_length);
123 sub.push_constant("use_hq_normals", use_hq_normals);
124 edit_legacy_curve_normals_ = ⊂
125 }
126 else {
127 edit_legacy_curve_normals_ = nullptr;
128 }
129 {
130 auto &sub = pass.sub("Handles");
131 sub.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA, state.clipping_plane_count);
132 sub.shader_set(res.shaders.legacy_curve_edit_handles.get());
133 sub.bind_ubo("globalsBlock", &res.globals_buf);
134 sub.push_constant("showCurveHandles", state.overlay.handle_display != CURVE_HANDLE_NONE);
135 sub.push_constant("curveHandleDisplay", int(state.overlay.handle_display));
136 sub.push_constant("alpha", 1.0f);
137 edit_legacy_curve_handles_ = ⊂
138 }
139 /* Points need to be rendered after handles. */
140 {
141 auto &sub = pass.sub("Points");
142 sub.state_set(DRW_STATE_WRITE_COLOR, state.clipping_plane_count);
143 sub.shader_set(res.shaders.legacy_curve_edit_points.get());
144 sub.bind_ubo("globalsBlock", &res.globals_buf);
145 sub.push_constant("showCurveHandles", state.overlay.handle_display != CURVE_HANDLE_NONE);
146 sub.push_constant("curveHandleDisplay", int(state.overlay.handle_display));
147 sub.push_constant("useGreasePencil", false);
148 sub.push_constant("doStrokeEndpoints", false);
149 edit_legacy_curve_points_ = ⊂
150 }
151 }
152
153 {
154 auto &pass = edit_legacy_surface_handles_ps;
155 pass.init();
156
157 auto create_sub = [&](const char *name, DRWState drw_state, float alpha) {
158 auto &sub = pass.sub(name);
159 sub.state_set(drw_state, state.clipping_plane_count);
160 sub.shader_set(res.shaders.legacy_curve_edit_handles.get());
161 sub.bind_ubo("globalsBlock", &res.globals_buf);
162 sub.push_constant("showCurveHandles", state.overlay.handle_display != CURVE_HANDLE_NONE);
163 sub.push_constant("curveHandleDisplay", int(state.overlay.handle_display));
164 sub.push_constant("alpha", alpha);
165 return ⊂
166 };
167
170 edit_legacy_surface_xray_handles_ = create_sub("SurfaceXrayHandles", state_xray, 0.2f);
171
174 edit_legacy_surface_handles_ = create_sub("SurfaceHandles", state_front, 1.0f);
175 }
176 }
177
178 void edit_object_sync(Manager &manager, const ObjectRef &ob_ref, Resources & /*res*/)
179 {
180 if (!enabled_) {
181 return;
182 }
183
184 Object *ob = ob_ref.object;
185 ::Curves &curves = *static_cast<::Curves *>(ob->data);
186 const bool show_points = bke::AttrDomain(curves.selection_domain) == bke::AttrDomain::Point;
187
188 if (show_points) {
189 gpu::Batch *geom = DRW_curves_batch_cache_get_edit_points(&curves);
190 edit_curves_points_->draw(geom, manager.unique_handle(ob_ref));
191 }
192 {
193 gpu::Batch *geom = DRW_curves_batch_cache_get_edit_curves_handles(&curves);
194 edit_curves_handles_->draw_expand(geom, GPU_PRIM_TRIS, 8, 1, manager.unique_handle(ob_ref));
195 }
196 {
197 gpu::Batch *geom = DRW_curves_batch_cache_get_edit_curves_lines(&curves);
198 edit_curves_lines_->draw(geom, manager.unique_handle(ob_ref));
199 }
200 }
201
202 /* Used for legacy curves. */
203 void edit_object_sync_legacy(Manager &manager, const ObjectRef &ob_ref, Resources & /*res*/)
204 {
205 if (!enabled_) {
206 return;
207 }
208
209 ResourceHandle res_handle = manager.unique_handle(ob_ref);
210
211 Object *ob = ob_ref.object;
212 ::Curve &curve = *static_cast<::Curve *>(ob->data);
213
214 if (ob->type == OB_CURVES_LEGACY) {
215 gpu::Batch *geom = DRW_cache_curve_edge_wire_get(ob);
216 edit_legacy_curve_wires_->draw(geom, res_handle);
217 }
218 if (edit_legacy_curve_normals_ && (curve.flag & CU_3D)) {
219 gpu::Batch *geom = DRW_cache_curve_edge_normal_get(ob);
220 edit_legacy_curve_normals_->draw_expand(geom, GPU_PRIM_LINES, 2, 1, res_handle);
221 }
222 {
223 gpu::Batch *geom = DRW_cache_curve_edge_overlay_get(ob);
224 if (ob->type == OB_CURVES_LEGACY) {
225 edit_legacy_curve_handles_->draw_expand(geom, GPU_PRIM_TRIS, 8, 1, res_handle);
226 }
227 else {
228 edit_legacy_surface_xray_handles_->draw_expand(geom, GPU_PRIM_TRIS, 8, 1, res_handle);
229 edit_legacy_surface_handles_->draw_expand(geom, GPU_PRIM_TRIS, 8, 1, res_handle);
230 }
231 }
232 {
233 gpu::Batch *geom = DRW_cache_curve_vert_overlay_get(ob);
234 edit_legacy_curve_points_->draw(geom, res_handle);
235 }
236 }
237
238 void draw(Framebuffer &framebuffer, Manager &manager, View &view)
239 {
240 if (!enabled_) {
241 return;
242 }
243
244 view_edit_cage.sync(view.viewmat(), winmat_polygon_offset(view.winmat(), view_dist, 0.5f));
245
246 GPU_framebuffer_bind(framebuffer);
247 manager.submit(edit_legacy_surface_handles_ps, view);
248 }
249
250 void draw_color_only(Framebuffer &framebuffer, Manager &manager, View &view)
251 {
252 if (!enabled_) {
253 return;
254 }
255
256 view_edit_cage.sync(view.viewmat(), winmat_polygon_offset(view.winmat(), view_dist, 0.5f));
257
258 GPU_framebuffer_bind(framebuffer);
259 manager.submit(edit_curves_ps_, view_edit_cage);
260 manager.submit(edit_legacy_curve_ps_, view);
261 }
262};
263
264} // namespace blender::draw::overlay
Low-level operations for curves that cannot be defined in the C++ header yet.
@ CU_3D
@ OB_CURVES_LEGACY
@ SCE_PERF_HQ_NORMALS
@ SPACE_VIEW3D
@ V3D_OVERLAY_EDIT_CU_NORMALS
@ CURVE_HANDLE_NONE
bool GPU_use_hq_normals_workaround()
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
ResourceHandle unique_handle(const ObjectRef &ref)
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
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandle handle={0}, uint custom_id=0)
Definition draw_pass.hh:760
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
void draw_expand(gpu::Batch *batch, GPUPrimType primitive_type, uint primitive_len, uint instance_len, uint vertex_len=-1, uint vertex_first=-1, ResourceHandle handle={0}, uint custom_id=0)
Definition draw_pass.hh:793
void begin_sync(Resources &res, const State &state, const View &view)
void draw_color_only(Framebuffer &framebuffer, Manager &manager, View &view)
void edit_object_sync_legacy(Manager &manager, const ObjectRef &ob_ref, Resources &)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
void edit_object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &)
blender::gpu::Batch * DRW_cache_curve_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_curve_edge_overlay_get(Object *ob)
blender::gpu::Batch * DRW_cache_curve_vert_overlay_get(Object *ob)
blender::gpu::Batch * DRW_cache_curve_edge_normal_get(Object *ob)
DRWState
Definition draw_state.hh:25
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ 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
@ DRW_STATE_DEPTH_GREATER
Definition draw_state.hh:40
static ulong state[N]
static float4x4 winmat_polygon_offset(float4x4 winmat, float view_dist, float offset)
blender::gpu::Batch * DRW_curves_batch_cache_get_edit_points(Curves *curves)
blender::gpu::Batch * DRW_curves_batch_cache_get_edit_curves_handles(Curves *curves)
blender::gpu::Batch * DRW_curves_batch_cache_get_edit_curves_lines(Curves *curves)