Blender V4.3
overlay_next_wireframe.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 "DNA_volume_types.h"
12
13#include "draw_common.hh"
14
15#include "overlay_next_mesh.hh"
16
17namespace blender::draw::overlay {
18
19class Wireframe {
20 private:
21 PassMain wireframe_ps_ = {"Wireframe"};
22 struct ColoringPass {
23 PassMain::Sub *curves_ps_ = nullptr;
24 PassMain::Sub *mesh_ps_ = nullptr;
25 PassMain::Sub *pointcloud_ps_ = nullptr;
26 /* Variant for meshes that force drawing all edges. */
27 PassMain::Sub *mesh_all_edges_ps_ = nullptr;
28 } colored, non_colored;
29
30 /* Force display of wireframe on surface objects, regardless of the object display settings. */
31 bool show_wire_ = false;
32
33 bool enabled_ = false;
34
35 public:
36 void begin_sync(Resources &res, const State &state)
37 {
38 enabled_ = (state.space_type == SPACE_VIEW3D) &&
39 (state.is_wireframe_mode || !state.hide_overlays);
40 if (!enabled_) {
41 return;
42 }
43
44 show_wire_ = (state.overlay.flag & V3D_OVERLAY_WIREFRAMES);
45
46 const bool do_smooth_lines = (U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0;
47 const bool is_transform = (G.moving & G_TRANSFORM_OBJ) != 0;
48 const float wire_threshold = wire_discard_threshold_get(state.overlay.wireframe_threshold);
49
50 GPUTexture **depth_tex = (state.xray_enabled) ? &res.depth_tx : &res.dummy_depth_tx;
51
52 {
53 auto &pass = wireframe_ps_;
54 pass.init();
57 state.clipping_plane_count);
58 res.select_bind(pass);
59
60 auto shader_pass =
61 [&](GPUShader *shader, const char *name, bool use_coloring, float wire_threshold) {
62 auto &sub = pass.sub(name);
63 if (res.shaders.wireframe_mesh.get() == shader) {
64 sub.specialize_constant(shader, "use_custom_depth_bias", do_smooth_lines);
65 }
66 sub.shader_set(shader);
67 sub.bind_ubo("globalsBlock", &res.globals_buf);
68 sub.bind_texture("depthTex", depth_tex);
69 sub.push_constant("wireOpacity", state.overlay.wireframe_opacity);
70 sub.push_constant("isTransform", is_transform);
71 sub.push_constant("colorType", state.v3d->shading.wire_color_type);
72 sub.push_constant("useColoring", use_coloring);
73 sub.push_constant("wireStepParam", wire_threshold);
74 sub.push_constant("isHair", false);
75 return ⊂
76 };
77
78 auto coloring_pass = [&](ColoringPass &ps, bool use_color) {
80 ps.mesh_ps_ = shader_pass(sh.wireframe_mesh.get(), "Mesh", use_color, wire_threshold);
81 ps.mesh_all_edges_ps_ = shader_pass(sh.wireframe_mesh.get(), "Wire", use_color, 1.0f);
82 ps.pointcloud_ps_ = shader_pass(sh.wireframe_points.get(), "PtCloud", use_color, 1.0f);
83 ps.curves_ps_ = shader_pass(sh.wireframe_curve.get(), "Curve", use_color, 1.0f);
84 };
85
86 coloring_pass(non_colored, false);
87 coloring_pass(colored, true);
88 }
89 }
90
91 void object_sync(Manager &manager,
92 const ObjectRef &ob_ref,
93 const State &state,
94 Resources &res,
95 const bool in_edit_paint_mode)
96 {
97 if (!enabled_) {
98 return;
99 }
100
101 if (ob_ref.object->dt < OB_WIRE) {
102 return;
103 }
104
105 const bool all_edges = (ob_ref.object->dtx & OB_DRAW_ALL_EDGES) != 0;
106 const bool show_surface_wire = show_wire_ || (ob_ref.object->dtx & OB_DRAWWIRE);
107
108 ColoringPass &coloring = in_edit_paint_mode ? non_colored : colored;
109 switch (ob_ref.object->type) {
110 case OB_CURVES_LEGACY: {
111 gpu::Batch *geom = DRW_cache_curve_edge_wire_get(ob_ref.object);
112 coloring.curves_ps_->draw(
113 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
114 break;
115 }
116 case OB_FONT: {
117 gpu::Batch *geom = DRW_cache_text_edge_wire_get(ob_ref.object);
118 coloring.curves_ps_->draw(
119 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
120 break;
121 }
122 case OB_SURF: {
123 gpu::Batch *geom = DRW_cache_surf_edge_wire_get(ob_ref.object);
124 coloring.curves_ps_->draw(
125 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
126 break;
127 }
128 case OB_CURVES:
129 /* TODO(fclem): Not yet implemented. */
130 break;
131 case OB_GREASE_PENCIL: {
132 if (show_surface_wire) {
133 gpu::Batch *geom = DRW_cache_grease_pencil_face_wireframe_get(state.scene,
134 ob_ref.object);
135 coloring.curves_ps_->draw(
136 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
137 }
138 break;
139 }
140 case OB_MESH:
141 if (show_surface_wire) {
142 gpu::Batch *geom = DRW_cache_mesh_face_wireframe_get(ob_ref.object);
143 (all_edges ? coloring.mesh_all_edges_ps_ : coloring.mesh_ps_)
144 ->draw(geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
145 }
146
147 /* Draw loose geometry. */
148 if (!in_edit_paint_mode || Meshes::mesh_has_edit_cage(ob_ref.object)) {
149 const Mesh *mesh = static_cast<const Mesh *>(ob_ref.object->data);
150 gpu::Batch *geom;
151 if ((mesh->edges_num == 0) && (mesh->verts_num > 0)) {
153 coloring.pointcloud_ps_->draw(
154 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
155 }
156 else if ((geom = DRW_cache_mesh_loose_edges_get(ob_ref.object))) {
157 coloring.mesh_all_edges_ps_->draw(
158 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
159 }
160 }
161 break;
162 case OB_POINTCLOUD: {
163 if (show_surface_wire) {
164 gpu::Batch *geom = DRW_pointcloud_batch_cache_get_dots(ob_ref.object);
165 coloring.pointcloud_ps_->draw(
166 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
167 }
168 break;
169 }
170 case OB_VOLUME: {
171 gpu::Batch *geom = DRW_cache_volume_face_wireframe_get(ob_ref.object);
172 if (static_cast<Volume *>(ob_ref.object->data)->display.wireframe_type ==
174 {
175 coloring.pointcloud_ps_->draw(
176 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
177 }
178 else {
179 coloring.mesh_ps_->draw(
180 geom, manager.unique_handle(ob_ref), res.select_id(ob_ref).get());
181 }
182 break;
183 }
184 default:
185 /* Would be good to have. */
186 // BLI_assert_unreachable();
187 break;
188 }
189 }
190
191 void draw(Framebuffer &framebuffer, Manager &manager, View &view)
192 {
193 if (!enabled_) {
194 return;
195 }
196
197 GPU_framebuffer_bind(framebuffer);
198 manager.submit(wireframe_ps_, view);
199 }
200
201 private:
202 float wire_discard_threshold_get(float threshold)
203 {
204 /* Use `sqrt` since the value stored in the edge is a variation of the cosine, so its square
205 * becomes more proportional with a variation of angle. */
206 threshold = sqrt(abs(threshold));
207 /* The maximum value (255 in the VBO) is used to force hide the edge. */
208 return math::interpolate(0.0f, 1.0f - (1.0f / 255.0f), threshold);
209 }
210};
211
212} // namespace blender::draw::overlay
@ G_TRANSFORM_OBJ
@ OB_WIRE
@ OB_SURF
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_CURVES
@ OB_DRAW_ALL_EDGES
@ OB_DRAWWIRE
@ SPACE_VIEW3D
@ USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE
@ V3D_OVERLAY_WIREFRAMES
@ VOLUME_WIREFRAME_POINTS
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
struct GPUShader GPUShader
unsigned int U
Definition btGjkEpa3.h:78
ResourceHandle unique_handle(const ObjectRef &ref)
void submit(PassSimple &pass, View &view)
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
static bool mesh_has_edit_cage(const Object *ob)
void begin_sync(Resources &res, const State &state)
void object_sync(Manager &manager, const ObjectRef &ob_ref, const State &state, Resources &res, const bool in_edit_paint_mode)
void draw(Framebuffer &framebuffer, Manager &manager, View &view)
blender::gpu::Batch * DRW_cache_curve_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_surf_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_mesh_all_verts_get(Object *ob)
blender::gpu::Batch * DRW_cache_text_edge_wire_get(Object *ob)
blender::gpu::Batch * DRW_cache_mesh_face_wireframe_get(Object *ob)
blender::gpu::Batch * DRW_cache_mesh_loose_edges_get(Object *ob)
@ 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_FIRST_VERTEX_CONVENTION
Definition draw_state.hh:70
static ulong state[N]
#define G(x, y, z)
blender::gpu::Batch * DRW_cache_volume_face_wireframe_get(Object *ob)
blender::gpu::Batch * DRW_cache_grease_pencil_face_wireframe_get(const Scene *scene, Object *ob)
blender::gpu::Batch * DRW_pointcloud_batch_cache_get_dots(Object *ob)
T sqrt(const T &a)
T interpolate(const T &a, const T &b, const FactorT &t)
T abs(const T &a)
VolumeDisplay display
void select_bind(PassSimple &pass)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)