Blender V5.0
overlay_bounds.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_mball.hh"
12
13#include "BLI_bounds_types.hh"
14#include "BLI_utildefines.h"
15
16#include "DNA_rigidbody_types.h"
17
18#include "overlay_base.hh"
19
20namespace blender::draw::overlay {
21
33class Bounds : Overlay {
34 using BoundsInstanceBuf = ShapeInstanceBuf<ExtraInstanceData>;
35
36 private:
37 PassSimple ps_ = {"Bounds"};
38
39 struct CallBuffers {
40 const SelectionType selection_type_;
41
42 BoundsInstanceBuf box = {selection_type_, "bound_box"};
43 BoundsInstanceBuf sphere = {selection_type_, "bound_sphere"};
44 BoundsInstanceBuf cylinder = {selection_type_, "bound_cylinder"};
45 BoundsInstanceBuf cone = {selection_type_, "bound_cone"};
46 BoundsInstanceBuf capsule_body = {selection_type_, "bound_capsule_body"};
47 BoundsInstanceBuf capsule_cap = {selection_type_, "bound_capsule_cap"};
48 } call_buffers_;
49
50 public:
51 Bounds(const SelectionType selection_type) : call_buffers_{selection_type} {}
52
53 void begin_sync(Resources & /*res*/, const State & /*state*/) final
54 {
55 call_buffers_.box.clear();
56 call_buffers_.sphere.clear();
57 call_buffers_.cylinder.clear();
58 call_buffers_.cone.clear();
59 call_buffers_.capsule_body.clear();
60 call_buffers_.capsule_cap.clear();
61 }
62
63 void object_sync(Manager & /*manager*/,
64 const ObjectRef &ob_ref,
65 Resources &res,
66 const State &state) final
67 {
68 const Object *ob = ob_ref.object;
69 const bool from_dupli = is_from_dupli_or_set(ob);
70 const bool has_bounds =
72 (ob->type != OB_MBALL || BKE_mball_is_basis(ob));
73 const bool show_extras = !from_dupli && state.show_extras();
74
75 /* Ignore `show_extras` when the objects draw-type is already bound-box,
76 * otherwise the object would not draw at all. */
77 const bool draw_bounds = has_bounds && ((ob->dt == OB_BOUNDBOX) ||
78 ((ob->dtx & OB_DRAWBOUNDOX) && show_extras));
79 const float4 color = res.object_wire_color(ob_ref, state);
80
81 auto add_bounds_ex = [&](const float3 center, const float3 size, const char bound_type) {
82 const float4x4 object_mat{ob->object_to_world().ptr()};
83 const select::ID select_id = res.select_id(ob_ref);
84 switch (bound_type) {
85 case OB_BOUND_BOX: {
87 scale.location() = center;
88 ExtraInstanceData data(object_mat * scale, color, 1.0f);
89 call_buffers_.box.append(data, select_id);
90 break;
91 }
92 case OB_BOUND_SPHERE: {
94 scale.location() = center;
95 ExtraInstanceData data(object_mat * scale, color, 1.0f);
96 call_buffers_.sphere.append(data, select_id);
97 break;
98 }
99 case OB_BOUND_CYLINDER: {
101 float3(float2(math::max(size.x, size.y)), size.z));
102 scale.location() = center;
103 ExtraInstanceData data(object_mat * scale, color, 1.0f);
104 call_buffers_.cylinder.append(data, select_id);
105 break;
106 }
107 case OB_BOUND_CONE: {
109 float3(float2(math::max(size.x, size.y)), size.z));
110 mat.location() = center;
111 /* Cone batch has base at 0 and is pointing towards +Y. */
112 std::swap(mat[1], mat[2]);
113 mat.location().z -= size.z;
114 ExtraInstanceData data(object_mat * mat, color, 1.0f);
115 call_buffers_.cone.append(data, select_id);
116 break;
117 }
118 case OB_BOUND_CAPSULE: {
120 mat.location() = center;
121 mat.location().z = center.z + std::max(0.0f, size.z - size.x);
122 ExtraInstanceData data(object_mat * mat, color, 1.0f);
123 call_buffers_.capsule_cap.append(data, select_id);
124 mat.z_axis() *= -1;
125 mat.location().z = center.z - std::max(0.0f, size.z - size.x);
126 data.object_to_world = object_mat * mat;
127 call_buffers_.capsule_cap.append(data, select_id);
128 mat.z_axis().z = std::max(0.0f, size.z * 2.0f - size.x * 2.0f);
129 data.object_to_world = object_mat * mat;
130 call_buffers_.capsule_body.append(data, select_id);
131 break;
132 }
133 }
134 };
135
136 auto add_bounds = [&](const bool around_origin, const char bound_type) {
137 const std::optional<blender::Bounds<float3>> bounds_opt =
140 const blender::Bounds<float3> bounds = bounds_opt.value_or(
141 blender::Bounds(float3(-1.0f), float3(1.0f)));
142 const float3 size = (bounds.max - bounds.min) * 0.5f;
143 const float3 center = around_origin ? float3(0) : math::midpoint(bounds.min, bounds.max);
144 add_bounds_ex(center, size, bound_type);
145 };
146
147 /* Bounds */
148 if (draw_bounds) {
149 add_bounds(false, ob->boundtype);
150 }
151
152 /* Rigid Body Shape */
153 if (show_extras && ob->rigidbody_object != nullptr) {
154 switch (ob->rigidbody_object->shape) {
155 case RB_SHAPE_BOX:
156 add_bounds(true, OB_BOUND_BOX);
157 break;
158 case RB_SHAPE_SPHERE:
159 add_bounds(true, OB_BOUND_SPHERE);
160 break;
161 case RB_SHAPE_CONE:
162 add_bounds(true, OB_BOUND_CONE);
163 break;
165 add_bounds(true, OB_BOUND_CYLINDER);
166 break;
167 case RB_SHAPE_CAPSULE:
168 add_bounds(true, OB_BOUND_CAPSULE);
169 break;
170 };
171 }
172
173 /* Texture Space */
174 if (show_extras && (ob->data != nullptr) && (ob->dtx & OB_TEXSPACE)) {
175 switch (GS(static_cast<ID *>(ob->data)->name)) {
176 case ID_ME: {
179 add_bounds_ex(me.texspace_location, me.texspace_size, OB_BOUND_BOX);
180 break;
181 }
182 case ID_CU_LEGACY: {
185 add_bounds_ex(cu.texspace_location, cu.texspace_size, OB_BOUND_BOX);
186 break;
187 }
188 case ID_MB: {
190 add_bounds_ex(mb.texspace_location, mb.texspace_size, OB_BOUND_BOX);
191 break;
192 }
193 case ID_CV:
194 case ID_PT:
195 case ID_VO: {
196 /* No user defined texture space support. */
197 add_bounds(false, OB_BOUND_BOX);
198 break;
199 }
200 default:
202 }
203 }
204 }
205
206 void end_sync(Resources &res, const State &state) final
207 {
208 ps_.init();
210 state.clipping_plane_count);
211 ps_.shader_set(res.shaders->extra_shape.get());
212 ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
213 ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
214 res.select_bind(ps_);
215
216 call_buffers_.box.end_sync(ps_, res.shapes.cube.get());
217 call_buffers_.sphere.end_sync(ps_, res.shapes.empty_sphere.get());
218 call_buffers_.cylinder.end_sync(ps_, res.shapes.cylinder.get());
219 call_buffers_.cone.end_sync(ps_, res.shapes.empty_cone.get());
220 call_buffers_.capsule_body.end_sync(ps_, res.shapes.capsule_body.get());
221 call_buffers_.capsule_cap.end_sync(ps_, res.shapes.capsule_cap.get());
222 }
223
224 void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
225 {
226 GPU_framebuffer_bind(framebuffer);
227 manager.submit(ps_, view);
228 }
229};
230} // namespace blender::draw::overlay
void BKE_curve_texspace_ensure(Curve *cu)
Definition curve.cc:502
bool BKE_mball_is_basis(const Object *ob)
Definition mball.cc:255
void BKE_mesh_texspace_ensure(Mesh *mesh)
std::optional< blender::Bounds< blender::float3 > > BKE_object_evaluated_geometry_bounds(const Object *ob)
std::optional< blender::Bounds< blender::float3 > > BKE_object_boundbox_get(const Object *ob)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define ELEM(...)
@ ID_VO
@ ID_CV
@ ID_CU_LEGACY
@ ID_ME
@ ID_MB
@ ID_PT
@ OB_BOUNDBOX
@ OB_DRAWBOUNDOX
@ OB_TEXSPACE
@ OB_SPEAKER
@ OB_LATTICE
@ OB_MBALL
@ OB_EMPTY
@ OB_CAMERA
@ OB_ARMATURE
@ OB_LAMP
@ OB_LIGHTPROBE
@ OB_BOUND_CAPSULE
@ OB_BOUND_SPHERE
@ OB_BOUND_CONE
@ OB_BOUND_BOX
@ OB_BOUND_CYLINDER
Types and defines for representing Rigid Body entities.
@ RB_SHAPE_CAPSULE
@ RB_SHAPE_BOX
@ RB_SHAPE_SPHERE
@ RB_SHAPE_CYLINDER
@ RB_SHAPE_CONE
T & DRW_object_get_data_for_drawing(const Object &object)
static AppView * view
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void draw_line(Framebuffer &framebuffer, Manager &manager, View &view) final
void begin_sync(Resources &, const State &) final
Bounds(const SelectionType selection_type)
void end_sync(Resources &res, const State &state) final
void object_sync(Manager &, const ObjectRef &ob_ref, Resources &res, const State &state) final
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
@ 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
#define GS(x)
static ulong state[N]
select::SelectionType SelectionType
static bool is_from_dupli_or_set(const Object *ob)
detail::Pass< command::DrawCommandBuf > PassSimple
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
T reduce_max(const VecBase< T, Size > &a)
T midpoint(const T &a, const T &b)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
T max(const T &a, const T &b)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
float texspace_size[3]
float texspace_location[3]
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
float texspace_size[3]
float texspace_location[3]
float texspace_size[3]
float texspace_location[3]
struct RigidBodyOb * rigidbody_object
T center() const