Blender V5.0
overlay_attribute_viewer.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#pragma once
10
11#include "BKE_curves.hh"
12#include "BKE_geometry_set.hh"
13#include "DNA_curve_types.h"
15
16#include "draw_cache.hh"
17#include "draw_cache_impl.hh"
18#include "overlay_base.hh"
19
20namespace blender::draw::overlay {
21
27 private:
28 PassMain ps_ = {"attribute_viewer_ps_"};
29
30 PassMain::Sub *mesh_sub_ = nullptr;
31 PassMain::Sub *pointcloud_sub_ = nullptr;
32 PassMain::Sub *curve_sub_ = nullptr;
33 PassMain::Sub *curves_sub_ = nullptr;
34 PassMain::Sub *instance_sub_ = nullptr;
35
36 public:
37 void begin_sync(Resources &res, const State &state) final
38 {
39 ps_.init();
40 enabled_ = state.is_space_v3d() && !res.is_selection() && state.show_attribute_viewer();
41 if (!enabled_) {
42 return;
43 };
44 ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
45 ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
47 state.clipping_plane_count);
48
49 auto create_sub = [&](const char *name, gpu::Shader *shader) {
50 auto &sub = ps_.sub(name);
51 sub.shader_set(shader);
52 return ⊂
53 };
54
55 mesh_sub_ = create_sub("mesh", res.shaders->attribute_viewer_mesh.get());
56 pointcloud_sub_ = create_sub("pointcloud", res.shaders->attribute_viewer_pointcloud.get());
57 curve_sub_ = create_sub("curve", res.shaders->attribute_viewer_curve.get());
58 curves_sub_ = create_sub("curves", res.shaders->attribute_viewer_curves.get());
59 instance_sub_ = create_sub("instance", res.shaders->uniform_color.get());
60 }
61
62 void object_sync(Manager &manager,
63 const ObjectRef &ob_ref,
64 Resources & /*res*/,
65 const State &state) final
66 {
67 const bool is_preview = ob_ref.preview_base_geometry() != nullptr;
68 if (!enabled_ || !is_preview) {
69 return;
70 }
71
72 if (ob_ref.preview_instance_index() >= 0) {
73 const auto &instances =
74 *ob_ref.preview_base_geometry()->get_component<blender::bke::InstancesComponent>();
75 if (const std::optional<blender::bke::AttributeMetaData> meta_data =
76 instances.attributes()->lookup_meta_data(".viewer"))
77 {
78 if (attribute_type_supports_viewer_overlay(meta_data->data_type)) {
79 populate_for_instance(ob_ref, state, manager);
80 return;
81 }
82 }
83 }
84 populate_for_geometry(ob_ref, state, manager);
85 }
86
87 void pre_draw(Manager &manager, View &view) final
88 {
89 if (!enabled_) {
90 return;
91 }
92
93 manager.generate_commands(ps_, view);
94 }
95
96 void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
97 {
98 if (!enabled_) {
99 return;
100 }
101
102 GPU_framebuffer_bind(framebuffer);
103 manager.submit_only(ps_, view);
104 }
105
106 private:
107 void populate_for_instance(const ObjectRef &ob_ref, const State &state, Manager &manager)
108 {
109 Object &object = *ob_ref.object;
110 const bke::GeometrySet &base_geometry = *ob_ref.preview_base_geometry();
111 const bke::InstancesComponent &instances =
112 *base_geometry.get_component<bke::InstancesComponent>();
113 const bke::AttributeAccessor instance_attributes = *instances.attributes();
114 const VArray attribute = *instance_attributes.lookup<ColorGeometry4f>(".viewer");
115 if (!attribute) {
116 return;
117 }
118 ColorGeometry4f color = attribute.get(ob_ref.preview_instance_index());
119 color.a *= state.overlay.viewer_attribute_opacity;
120 switch (object.type) {
121 case OB_MESH: {
122 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
123
124 {
125 gpu::Batch *batch = DRW_cache_mesh_surface_get(&object);
126 auto &sub = *instance_sub_;
127 sub.push_constant("ucolor", float4(color));
128 sub.draw(batch, res_handle);
129 }
130 if (gpu::Batch *batch = DRW_cache_mesh_loose_edges_get(&object)) {
131 auto &sub = *instance_sub_;
132 sub.push_constant("ucolor", float4(color));
133 sub.draw(batch, res_handle);
134 }
135
136 break;
137 }
138 case OB_POINTCLOUD: {
139 auto &sub = *pointcloud_sub_;
140 gpu::Batch *batch = pointcloud_sub_pass_setup(sub, &object, nullptr);
141 sub.push_constant("ucolor", float4(color));
142 sub.draw(batch, manager.unique_handle(ob_ref));
143 break;
144 }
145 case OB_CURVES_LEGACY: {
146 gpu::Batch *batch = DRW_cache_curve_edge_wire_get(&object);
147 auto &sub = *instance_sub_;
148 sub.push_constant("ucolor", float4(color));
149 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
150 sub.draw(batch, res_handle);
151 break;
152 }
153 case OB_CURVES: {
154 /* Not supported yet because instances of this type are currently drawn as legacy curves.
155 */
156 break;
157 }
158 }
159 }
160
161 static bool attribute_type_supports_viewer_overlay(const bke::AttrType data_type)
162 {
164 }
165
166 void populate_for_geometry(const ObjectRef &ob_ref, const State &state, Manager &manager)
167 {
168 const float opacity = state.overlay.viewer_attribute_opacity;
169 Object &object = *ob_ref.object;
170 switch (object.type) {
171 case OB_MESH: {
173 if (const std::optional<bke::AttributeMetaData> meta_data =
174 mesh.attributes().lookup_meta_data(".viewer"))
175 {
176 if (attribute_type_supports_viewer_overlay(meta_data->data_type)) {
178 auto &sub = *mesh_sub_;
179 sub.push_constant("opacity", opacity);
180 sub.draw(batch, manager.unique_handle(ob_ref));
181 }
182 }
183 break;
184 }
185 case OB_POINTCLOUD: {
187 if (const std::optional<bke::AttributeMetaData> meta_data =
188 pointcloud.attributes().lookup_meta_data(".viewer"))
189 {
190 if (attribute_type_supports_viewer_overlay(meta_data->data_type)) {
191 gpu::VertBuf **vertbuf = DRW_pointcloud_evaluated_attribute(&pointcloud, ".viewer");
192 /* Avoid trying to bind an empty `vertbuf` which causes assert / undefined behavior. */
193 if (pointcloud.totpoint > 0 && vertbuf != nullptr) {
194 auto &sub = *pointcloud_sub_;
195 gpu::Batch *batch = pointcloud_sub_pass_setup(sub, &object, nullptr);
196 sub.push_constant("opacity", opacity);
197 sub.bind_texture("attribute_tx", vertbuf);
198 sub.draw(batch, manager.unique_handle(ob_ref));
199 }
200 }
201 }
202 break;
203 }
204 case OB_CURVES_LEGACY: {
206 if (curve.curve_eval) {
207 const bke::CurvesGeometry &curves = curve.curve_eval->geometry.wrap();
208 if (const std::optional<bke::AttributeMetaData> meta_data =
209 curves.attributes().lookup_meta_data(".viewer"))
210 {
211 if (attribute_type_supports_viewer_overlay(meta_data->data_type)) {
213 auto &sub = *curve_sub_;
214 sub.push_constant("opacity", opacity);
215 ResourceHandleRange res_handle = manager.unique_handle(ob_ref);
216 sub.draw(batch, res_handle);
217 }
218 }
219 }
220 break;
221 }
222 case OB_CURVES: {
224 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
225 if (const std::optional<bke::AttributeMetaData> meta_data =
226 curves.attributes().lookup_meta_data(".viewer"))
227 {
228 if (attribute_type_supports_viewer_overlay(meta_data->data_type)) {
229 bool is_point_domain;
230 bool is_valid;
232 &curves_id, ".viewer", is_point_domain, is_valid);
233 if (is_valid) {
234 auto &sub = *curves_sub_;
235 const char *error = nullptr;
236 /* The error string will always have been printed by the engine already.
237 * No need to display it twice. */
238 gpu::Batch *batch = curves_sub_pass_setup(sub, state.scene, ob_ref.object, error);
239 sub.push_constant("opacity", opacity);
240 sub.push_constant("is_point_domain", is_point_domain);
241 sub.bind_texture("color_tx", texture);
242 sub.draw(batch, manager.unique_handle(ob_ref));
243 }
244 }
245 }
246 break;
247 }
248 }
249 }
250};
251} // namespace blender::draw::overlay
Low-level operations for curves.
#define ELEM(...)
struct Curve Curve
struct Curves Curves
struct Mesh Mesh
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES_LEGACY
@ OB_CURVES
struct Object Object
struct PointCloud PointCloud
T & DRW_object_get_data_for_drawing(const Object &object)
static AppView * view
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
AttributeSet attributes
T get(const int64_t index) const
std::optional< AttributeAccessor > attributes() const final
ResourceHandleRange unique_handle(const ObjectRef &ref)
int preview_instance_index() const
const blender::bke::GeometrySet * preview_base_geometry() const
void push_constant(const char *name, const float &data)
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:499
void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
void begin_sync(Resources &res, const State &state) final
void object_sync(Manager &manager, const ObjectRef &ob_ref, Resources &, const State &state) final
void pre_draw(Manager &manager, View &view) final
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
@ DRW_STATE_BLEND_ALPHA
Definition draw_state.hh:55
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
static ulong state[N]
static void error(const char *str)
gpu::Batch * DRW_cache_curve_edge_wire_viewer_attribute_get(Object *ob)
detail::Pass< command::DrawMultiBuf > PassMain
gpu::Batch * DRW_cache_mesh_loose_edges_get(Object *ob)
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, const char *&r_error, GPUMaterial *gpu_material=nullptr)
gpu::Batch * pointcloud_sub_pass_setup(PassMain::Sub &sub_ps, Object *object, GPUMaterial *gpu_material=nullptr)
gpu::Batch * DRW_cache_mesh_surface_viewer_attribute_get(Object *ob)
gpu::VertBuf ** DRW_pointcloud_evaluated_attribute(PointCloud *pointcloud, StringRef name)
gpu::Batch * DRW_cache_curve_edge_wire_get(Object *ob)
gpu::Batch * DRW_cache_mesh_surface_get(Object *ob)
blender::gpu::VertBufPtr & DRW_curves_texture_for_evaluated_attribute(Curves *curves, StringRef name, bool &r_is_point_domain, bool &r_valid_attribute)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
VecBase< float, 4 > float4
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
const char * name
const struct Curves * curve_eval
CurvesGeometry geometry
const GeometryComponent * get_component(GeometryComponent::Type component_type) const