Blender V4.5
overlay_armature.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstdlib>
11#include <cstring>
12
13#include "DNA_armature_types.h"
15#include "DNA_mesh_types.h"
16#include "DNA_object_types.h"
17#include "DNA_scene_types.h"
18
19#include "DRW_render.hh"
20
22#include "BLI_math_color.h"
23#include "BLI_math_matrix.h"
25#include "BLI_math_rotation.h"
26#include "BLI_math_vector.h"
27#include "BLI_utildefines.h"
28
29#include "BKE_action.hh"
30#include "BKE_armature.hh"
31#include "BKE_deform.hh"
32#include "BKE_object.hh"
33
35
36#include "ED_armature.hh"
37#include "ED_view3d.hh"
38
39#include "ANIM_armature.hh"
40#include "ANIM_bonecolor.hh"
41
42#include "UI_resources.hh"
43
44#include "draw_cache.hh"
46#include "draw_manager_text.hh"
47
48#include "overlay_armature.hh"
49
50#include "draw_cache_impl.hh"
51
52#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
53
54using namespace blender::draw::overlay;
55
60 private:
61 union {
64 };
65 bool is_editbone_; /* Discriminator for the above union. */
66
67 public:
70
71 UnifiedBonePtr(EditBone *eBone) : eBone_(eBone), is_editbone_(true) {}
72 UnifiedBonePtr(bPoseChannel *pchan) : pchan_(pchan), is_editbone_(false) {}
73
74 const char *name() const
75 {
76 return is_editbone_ ? eBone_->name : pchan_->name;
77 }
78
79 const EditBone *as_editbone() const
80 {
81 BLI_assert_msg(is_editbone_,
82 "conversion to EditBone* only possible when "
83 "UnifiedBonePtr contains an edit bone");
84 return eBone_;
85 }
87 {
88 BLI_assert_msg(is_editbone_,
89 "conversion to EditBone* only possible when "
90 "UnifiedBonePtr contains an edit bone");
91 return eBone_;
92 }
93
95 {
96 BLI_assert_msg(!is_editbone_,
97 "conversion to bPoseChannel* only possible when "
98 "UnifiedBonePtr contains a pose channel");
99 return pchan_;
100 }
102 {
103 BLI_assert_msg(!is_editbone_,
104 "conversion to bPoseChannel* only possible when "
105 "UnifiedBonePtr contains a pose channel");
106 return pchan_;
107 }
108
109 bool is_editbone() const
110 {
111 return is_editbone_;
112 };
113 bool is_posebone() const
114 {
115 return !is_editbone();
116 };
117
118 void get(const EditBone **eBone, const bPoseChannel **pchan) const
119 {
120 *eBone = eBone_;
121 *pchan = pchan_;
122 }
123 void get(EditBone **eBone, bPoseChannel **pchan)
124 {
125 *eBone = eBone_;
126 *pchan = pchan_;
127 }
128
130 {
131 return static_cast<eBone_Flag>(is_editbone_ ? eBone_->flag : pchan_->bone->flag);
132 }
133
136 {
137 return ePchan_ConstFlag(is_editbone_ ? 0 : pchan_->constflag);
138 }
139
140 bool has_parent() const
141 {
142 return is_editbone_ ? eBone_->parent != nullptr : pchan_->bone->parent != nullptr;
143 }
144
145 using f44 = float[4][4];
146 const f44 &disp_mat() const
147 {
148 return is_editbone_ ? eBone_->disp_mat : pchan_->disp_mat;
149 }
151 {
152 return is_editbone_ ? eBone_->disp_mat : pchan_->disp_mat;
153 }
154
155 const f44 &disp_tail_mat() const
156 {
157 return is_editbone_ ? eBone_->disp_tail_mat : pchan_->disp_tail_mat;
158 }
159
161 {
162 return is_editbone_ ? eBone_->disp_tail_mat : pchan_->disp_tail_mat;
163 }
164
165 /* For some, to me unknown, reason, the drawing code passes these around as pointers. This is the
166 * reason that these are returned as references. I'll leave refactoring that for another time. */
167 const float &rad_head() const
168 {
169 return is_editbone_ ? eBone_->rad_head : pchan_->bone->rad_head;
170 }
171
172 const float &rad_tail() const
173 {
174 return is_editbone_ ? eBone_->rad_tail : pchan_->bone->rad_tail;
175 }
176
178 {
179 if (is_editbone_) {
180 return eBone_->color.wrap();
181 }
182
183 if (pchan_->color.palette_index == 0) {
184 /* If the pchan has the 'default' color, treat it as a signal to use the underlying bone
185 * color. */
186 return pchan_->bone->color.wrap();
187 }
188 return pchan_->color.wrap();
189 }
190};
191
192/* -------------------------------------------------------------------- */
195
196/* Stick */
198 const float (*bone_mat)[4],
199 const float col_wire[4],
200 const float col_bone[4],
201 const float col_head[4],
202 const float col_tail[4],
203 const int select_id)
204{
205 float4x4 bmat = float4x4(bone_mat);
206 float3 head = math::transform_point(ctx->ob->object_to_world(), bmat.location());
207 float3 tail = math::transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
208
209 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id);
210
211 ctx->bone_buf->stick_buf.append({head,
212 tail,
213 *(float4 *)col_wire,
214 *(float4 *)col_bone,
215 *(float4 *)col_head,
216 *(float4 *)col_tail},
217 sel_id);
218}
219
220/* Envelope */
222 const float (*bone_mat)[4],
223 const float *radius_head,
224 const float *radius_tail,
225 const float *distance)
226{
227 if (ctx->draw_envelope_distance) {
228 float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
229 float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
230 /* Still less operation than m4 multiplication. */
231 mul_m4_v4(bone_mat, head_sph);
232 mul_m4_v4(bone_mat, tail_sph);
233 mul_m4_v4(bone_mat, xaxis);
234 mul_m4_v4(ctx->ob->object_to_world().ptr(), head_sph);
235 mul_m4_v4(ctx->ob->object_to_world().ptr(), tail_sph);
236 mul_m4_v4(ctx->ob->object_to_world().ptr(), xaxis);
237 sub_v3_v3(xaxis, head_sph);
238 float obscale = mat4_to_scale(ctx->ob->object_to_world().ptr());
239 head_sph[3] = *radius_head * obscale;
240 head_sph[3] += *distance * obscale;
241 tail_sph[3] = *radius_tail * obscale;
242 tail_sph[3] += *distance * obscale;
243 /* TODO(fclem): Cleanup these casts when Overlay Next is shipped. */
244 ctx->bone_buf->envelope_distance_buf.append(
245 {*(float4 *)head_sph, *(float4 *)tail_sph, *(float3 *)xaxis},
247 }
248}
249
251 const float (*bone_mat)[4],
252 const float bone_col[4],
253 const float hint_col[4],
254 const float outline_col[4],
255 const float *radius_head,
256 const float *radius_tail,
257 const int select_id)
258{
259 float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
260 float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
261 /* Still less operation than m4 multiplication. */
262 mul_m4_v4(bone_mat, head_sph);
263 mul_m4_v4(bone_mat, tail_sph);
264 mul_m4_v4(bone_mat, xaxis);
265 mul_m4_v4(ctx->ob->object_to_world().ptr(), head_sph);
266 mul_m4_v4(ctx->ob->object_to_world().ptr(), tail_sph);
267 mul_m4_v4(ctx->ob->object_to_world().ptr(), xaxis);
268 float obscale = mat4_to_scale(ctx->ob->object_to_world().ptr());
269 head_sph[3] = *radius_head * obscale;
270 tail_sph[3] = *radius_tail * obscale;
271
272 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id) :
274
275 if (head_sph[3] < 0.0f || tail_sph[3] < 0.0f) {
277 if (head_sph[3] < 0.0f) {
278 /* Draw Tail only */
279 scale_m4_fl(inst_data.mat, tail_sph[3] / PT_DEFAULT_RAD);
280 copy_v3_v3(inst_data.mat[3], tail_sph);
281 }
282 else {
283 /* Draw Head only */
284 scale_m4_fl(inst_data.mat, head_sph[3] / PT_DEFAULT_RAD);
285 copy_v3_v3(inst_data.mat[3], head_sph);
286 }
287
288 if (ctx->is_filled) {
289 ctx->bone_buf->sphere_fill_buf.append({inst_data.mat44, bone_col, hint_col}, sel_id);
290 }
291 if (outline_col[3] > 0.0f) {
292 ctx->bone_buf->sphere_outline_buf.append({inst_data.mat44, outline_col}, sel_id);
293 }
294 }
295 else {
296 /* Draw Body */
297 float tmp_sph[4];
298 float len = len_v3v3(tail_sph, head_sph);
299 float fac_head = (len - head_sph[3]) / len;
300 float fac_tail = (len - tail_sph[3]) / len;
301 /* Small epsilon to avoid problem with float precision in shader. */
302 if (len > (tail_sph[3] + head_sph[3]) + 1e-8f) {
303 copy_v4_v4(tmp_sph, head_sph);
304 interp_v4_v4v4(head_sph, tail_sph, head_sph, fac_head);
305 interp_v4_v4v4(tail_sph, tmp_sph, tail_sph, fac_tail);
306
307 if (ctx->is_filled) {
308 /* TODO(fclem): Cleanup these casts when Overlay Next is shipped. */
309 ctx->bone_buf->envelope_fill_buf.append({*(float4 *)head_sph,
310 *(float4 *)tail_sph,
311 *(float3 *)bone_col,
312 *(float3 *)hint_col,
313 *(float3 *)xaxis},
314 sel_id);
315 }
316 if (outline_col[3] > 0.0f) {
317 ctx->bone_buf->envelope_outline_buf.append(
318 {*(float4 *)head_sph, *(float4 *)tail_sph, *(float4 *)outline_col, *(float3 *)xaxis},
319 sel_id);
320 }
321 }
322 else {
323 /* Distance between endpoints is too small for a capsule. Draw a Sphere instead. */
324 float fac = max_ff(fac_head, 1.0f - fac_tail);
325 interp_v4_v4v4(tmp_sph, tail_sph, head_sph, clamp_f(fac, 0.0f, 1.0f));
326
328 scale_m4_fl(inst_data.mat, tmp_sph[3] / PT_DEFAULT_RAD);
329 copy_v3_v3(inst_data.mat[3], tmp_sph);
330
331 if (ctx->is_filled) {
332 ctx->bone_buf->sphere_fill_buf.append({inst_data.mat44, bone_col, hint_col}, sel_id);
333 }
334 if (outline_col[3] > 0.0f) {
335 ctx->bone_buf->sphere_outline_buf.append({inst_data.mat44, outline_col}, sel_id);
336 }
337 }
338 }
339}
340
341/* Custom (geometry) */
342
344 Mesh &mesh,
345 const float (*bone_mat)[4],
346 const float bone_color[4],
347 const float hint_color[4],
348 const float outline_color[4],
349 const float wire_width,
350 const draw::select::ID select_id,
351 Object &custom)
352{
353 using namespace blender::draw;
354 /* TODO(fclem): arg... less than ideal but we never iter on this object
355 * to assure batch cache is valid. */
357
358 blender::gpu::Batch *surf = DRW_mesh_batch_cache_get_surface(mesh);
359 blender::gpu::Batch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, nullptr);
360 blender::gpu::Batch *loose_edges = DRW_mesh_batch_cache_get_loose_edges(mesh);
362
363 if (surf || edges || loose_edges) {
364 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
365 }
366
367 if (surf) {
368 inst_data.set_hint_color(hint_color);
369 inst_data.set_color(bone_color);
370 if (ctx->is_filled) {
371 ctx->bone_buf->custom_shape_fill_get_buffer(surf).append(inst_data, select_id);
372 }
373 }
374
375 if (edges) {
376 inst_data.set_color(outline_color);
377 ctx->bone_buf->custom_shape_outline_get_buffer(edges).append(inst_data, select_id);
378 }
379
380 if (loose_edges) {
381 inst_data.set_hint_color(outline_color);
382 inst_data.set_color(float4(UNPACK3(outline_color), wire_width / WIRE_WIDTH_COMPRESSION));
383 ctx->bone_buf->custom_shape_wire_get_buffer(loose_edges).append(inst_data, select_id);
384 }
385
386 /* TODO(fclem): needs to be moved elsewhere. */
388}
389
391 Mesh &mesh,
392 const float (*bone_mat)[4],
393 const float color[4],
394 const float wire_width,
395 const draw::select::ID select_id,
396 Object &custom)
397{
398 using namespace blender::draw;
399 /* TODO(fclem): arg... less than ideal but we never iter on this object
400 * to assure batch cache is valid. */
402
403 blender::gpu::Batch *geom = DRW_mesh_batch_cache_get_all_edges(mesh);
404 if (geom) {
406 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
407 inst_data.set_hint_color(color);
408 inst_data.set_color(float4(UNPACK3(color), wire_width / WIRE_WIDTH_COMPRESSION));
409
410 ctx->bone_buf->custom_shape_wire_get_buffer(geom).append(inst_data, select_id);
411 }
412
413 /* TODO(fclem): needs to be moved elsewhere. */
415}
416
418 Curve *curve,
419 const float (*bone_mat)[4],
420 const float outline_color[4],
421 const float wire_width,
422 const draw::select::ID select_id,
423 Object *custom)
424{
425 using namespace blender::draw;
426 /* TODO(fclem): arg... less than ideal but we never iter on this object
427 * to assure batch cache is valid. */
429
430 /* This only handles curves without any surface. The other curve types should have been converted
431 * to meshes and rendered in the mesh drawing function. */
432 blender::gpu::Batch *loose_edges = nullptr;
433 if (custom->type == OB_FONT) {
434 loose_edges = DRW_cache_text_edge_wire_get(custom);
435 }
436 else {
437 loose_edges = DRW_cache_curve_edge_wire_get(custom);
438 }
439
440 if (loose_edges) {
442 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat);
443 inst_data.set_hint_color(outline_color);
444 inst_data.set_color(float4(UNPACK3(outline_color), wire_width / WIRE_WIDTH_COMPRESSION));
445
446 ctx->bone_buf->custom_shape_wire_get_buffer(loose_edges).append(inst_data, select_id);
447 }
448
449 /* TODO(fclem): needs to be moved elsewhere. */
451}
452
454 const float (*bone_mat)[4],
455 const float bone_color[4],
456 const float hint_color[4],
457 const float outline_color[4],
458 const float wire_width,
459 const draw::select::ID select_id,
460 Object *custom)
461{
462 /* The custom object is not an evaluated object, so its object->data field hasn't been replaced
463 * by #data_eval. This is bad since it gives preference to an object's evaluated mesh over any
464 * other data type, but supporting all evaluated geometry components would require a much
465 * larger refactor of this area. */
467 if (mesh != nullptr) {
469 *mesh,
470 bone_mat,
471 bone_color,
472 hint_color,
473 outline_color,
474 wire_width,
475 select_id,
476 *custom);
477 return;
478 }
479
480 if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
483 bone_mat,
484 outline_color,
485 wire_width,
486 select_id,
487 custom);
488 }
489}
490
492 const float (*bone_mat)[4],
493 const float color[4],
494 const float wire_width,
495 const draw::select::ID select_id,
496 Object *custom)
497{
498 /* See comments in #drw_shgroup_bone_custom_solid. */
500 if (mesh != nullptr) {
501 drw_shgroup_bone_custom_mesh_wire(ctx, *mesh, bone_mat, color, wire_width, select_id, *custom);
502 return;
503 }
504
505 if (ELEM(custom->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
508 bone_mat,
509 color,
510 wire_width,
511 select_id,
512 custom);
513 }
514}
515
517 const float (*bone_mat)[4],
518 const float color[4],
519 const float wire_width,
520 const draw::select::ID select_id,
521 Object *custom)
522{
523 using namespace blender::draw;
524
525 gpu::Batch *geom = nullptr;
526 switch (custom->empty_drawtype) {
527 case OB_PLAINAXES:
528 geom = ctx->res->shapes.plain_axes.get();
529 break;
530 case OB_SINGLE_ARROW:
531 geom = ctx->res->shapes.single_arrow.get();
532 break;
533 case OB_CUBE:
534 geom = ctx->res->shapes.cube.get();
535 break;
536 case OB_CIRCLE:
537 geom = ctx->res->shapes.circle.get();
538 break;
539 case OB_EMPTY_SPHERE:
540 geom = ctx->res->shapes.empty_sphere.get();
541 break;
542 case OB_EMPTY_CONE:
543 geom = ctx->res->shapes.empty_cone.get();
544 break;
545 case OB_ARROWS:
546 geom = ctx->res->shapes.arrows.get();
547 break;
548 case OB_EMPTY_IMAGE:
549 /* Not supported. */
550 return;
551 }
552 BLI_assert(geom);
553
554 const float4 final_color(UNPACK3(color), 1.0f);
555
557 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(bone_mat) *
559 inst_data.set_hint_color(final_color);
560 inst_data.set_color(float4(UNPACK3(final_color), wire_width / WIRE_WIDTH_COMPRESSION));
561
562 ctx->bone_buf->custom_shape_wire_get_buffer(geom).append(inst_data, select_id);
563}
564
565/* Head and tail sphere */
567 const float (*bone_mat)[4],
568 const float bone_color[4],
569 const float hint_color[4],
570 const float outline_color[4],
571 const int select_id)
572{
573 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id) :
575 float4x4 mat = ctx->ob->object_to_world() * float4x4(bone_mat);
576
577 if (ctx->is_filled) {
578 ctx->bone_buf->sphere_fill_buf.append({mat, bone_color, hint_color}, sel_id);
579 }
580 if (outline_color[3] > 0.0f) {
581 ctx->bone_buf->sphere_outline_buf.append({mat, outline_color}, sel_id);
582 }
583}
584
585/* Axes */
587 const float (*bone_mat)[4],
588 const float color[4])
589{
590 float4x4 mat = ctx->ob->object_to_world() * float4x4(bone_mat);
591 /* Move to bone tail. */
592 mat[3] += mat[1];
593 ExtraInstanceData data(mat, color, 0.25f);
594 /* NOTE: Axes are not drawn in bone selection (pose or edit mode).
595 * They are only drawn and selectable in object mode. So only load the object select ID. */
596 ctx->bone_buf->arrows_buf.append(data, ctx->res->select_id(*ctx->ob_ref));
597}
598
599/* Relationship lines */
601 const float start[3],
602 const float end[3],
603 const float color[4])
604{
605 float3 start_pt = math::transform_point(ctx->ob->object_to_world(), float3(start));
606 float3 end_pt = math::transform_point(ctx->ob->object_to_world(), float3(end));
607
608 /* Reverse order to have less stipple overlap. */
609 ctx->bone_buf->relations_buf.append(end_pt, start_pt, float4(color));
610}
611
613 const float start[3],
614 const float end[3])
615{
616 const UniformData &theme = ctx->res->theme;
617 drw_shgroup_bone_relationship_lines_ex(ctx, start, end, theme.colors.wire);
618}
619
621 const float start[3],
622 const float end[3])
623{
624 const UniformData &theme = ctx->res->theme;
626}
627
629 const float start[3],
630 const float end[3])
631{
632 const UniformData &theme = ctx->res->theme;
634}
635
637 const float start[3],
638 const float end[3])
639{
640 const UniformData &theme = ctx->res->theme;
642}
643
645
646/* -------------------------------------------------------------------- */
652
653/* This function sets the color-set for coloring a certain bone */
655{
657
658 if ((arm.flag & ARM_COL_CUSTOM) == 0) {
659 /* Only set a custom color if that's enabled on this armature. */
660 ctx->bcolor = nullptr;
661 return;
662 }
663
664 const blender::animrig::BoneColor &bone_color = bone.effective_bonecolor();
665 ctx->bcolor = bone_color.effective_color();
666}
667
668/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
669static void cp_shade_color3ub(uchar cp[3], const int offset)
670{
671 int r, g, b;
672
673 r = offset + int(cp[0]);
674 CLAMP(r, 0, 255);
675 g = offset + int(cp[1]);
676 CLAMP(g, 0, 255);
677 b = offset + int(cp[2]);
678 CLAMP(b, 0, 255);
679
680 cp[0] = r;
681 cp[1] = g;
682 cp[2] = b;
683}
684
690static void use_bone_color(float *r_color, const uint8_t *color_from_theme, const int shade_offset)
691{
692 uint8_t srgb_color[4] = {255, 255, 255, 255};
693 /* Only copy RGB, not alpha. The "alpha" channel in the bone theme colors is
694 * essentially just padding, and should be ignored. */
695 copy_v3_v3_uchar(srgb_color, color_from_theme);
696 if (shade_offset != 0) {
697 cp_shade_color3ub(srgb_color, shade_offset);
698 }
699 rgba_uchar_to_float(r_color, srgb_color);
700 /* Meh, hardcoded srgb transform here. */
701 srgb_to_linearrgb_v4(r_color, r_color);
702};
703
704static void get_pchan_color_wire(const UniformData &theme,
705 const ThemeWireColor *bcolor,
706 const eArmatureDrawMode draw_mode,
707 const eBone_Flag boneflag,
708 float r_color[4])
709{
710 const bool draw_active = boneflag & BONE_DRAW_ACTIVE;
711 const bool draw_selected = boneflag & BONE_SELECTED;
712 const bool is_edit = draw_mode == ARM_DRAW_MODE_EDIT;
713 float4 wire_color;
714
715 if (bcolor) {
716 if (draw_active && draw_selected) {
717 use_bone_color(r_color, bcolor->active, 0);
718 }
719 else if (draw_active) {
720 use_bone_color(r_color, bcolor->active, -80);
721 }
722 else if (draw_selected) {
723 use_bone_color(r_color, bcolor->select, 0);
724 }
725 else {
726 use_bone_color(r_color, bcolor->solid, -50);
727 }
728 }
729 else {
730 if (draw_active && draw_selected) {
731 wire_color = is_edit ? theme.colors.bone_active : theme.colors.bone_pose_active;
732 }
733 else if (draw_active) {
734 wire_color = is_edit ? theme.colors.bone_active_unsel : theme.colors.bone_pose_active_unsel;
735 }
736 else if (draw_selected) {
737 wire_color = is_edit ? theme.colors.bone_select : theme.colors.bone_pose;
738 }
739 else {
740 wire_color = is_edit ? theme.colors.wire_edit : theme.colors.wire;
741 }
742 copy_v4_v4(r_color, wire_color);
743 }
744}
745
746static void get_pchan_color_solid(const UniformData &theme,
747 const ThemeWireColor *bcolor,
748 float r_color[4])
749{
750
751 if (bcolor) {
752 use_bone_color(r_color, bcolor->solid, 0);
753 }
754 else {
755 copy_v4_v4(r_color, theme.colors.bone_solid);
756 }
757}
758
760 const ThemeWireColor *bcolor,
761 const UnifiedBonePtr bone,
762 float r_color[4])
763{
764 const ePchan_ConstFlag constflag = bone.constflag();
765 /* Not all flags should result in a different bone color. */
768 if ((constflag & flags_to_color) == 0 ||
769 (bcolor && (bcolor->flag & TH_WIRECOLOR_CONSTCOLS) == 0))
770 {
771 get_pchan_color_solid(theme, bcolor, r_color);
772 return;
773 }
774
775 /* The constraint color needs to be blended with the solid color. */
776 float solid_color[4];
777 get_pchan_color_solid(theme, bcolor, solid_color);
778
779 float4 constraint_color;
780 if (constflag & PCHAN_HAS_NO_TARGET) {
781 constraint_color = theme.colors.bone_pose_no_target;
782 }
783 else if (constflag & PCHAN_HAS_IK) {
784 constraint_color = theme.colors.bone_pose_ik;
785 }
786 else if (constflag & PCHAN_HAS_SPLINEIK) {
787 constraint_color = theme.colors.bone_pose_spline_ik;
788 }
789 else if (constflag & PCHAN_HAS_CONST) {
790 constraint_color = theme.colors.bone_pose_constraint;
791 }
792 interp_v4_v4v4(r_color, solid_color, constraint_color, 0.5f);
793}
794
796
797/* -------------------------------------------------------------------- */
800
801static void bone_locked_color_shade(const UniformData &theme, float color[4])
802{
803 const float *locked_color = theme.colors.bone_locked;
804
805 interp_v3_v3v3(color, color, locked_color, locked_color[3]);
806}
807
808static const float *get_bone_solid_color(const Armatures::DrawContext *ctx,
809 const eBone_Flag boneflag)
810{
811 const UniformData &theme = ctx->res->theme;
812 if (ctx->const_color) {
813 return theme.colors.bone_solid;
814 }
815
816 static float disp_color[4];
817 get_pchan_color_solid(theme, ctx->bcolor, disp_color);
818
819 if (ctx->draw_mode == ARM_DRAW_MODE_POSE && (boneflag & BONE_DRAW_LOCKED_WEIGHT)) {
820 bone_locked_color_shade(theme, disp_color);
821 }
822
823 return disp_color;
824}
825
827 const UnifiedBonePtr bone,
828 const eBone_Flag boneflag)
829{
830 const UniformData &theme = ctx->res->theme;
831 if (ctx->const_color) {
832 return theme.colors.bone_solid;
833 }
834
835 const float *col = get_bone_solid_color(ctx, boneflag);
836
837 if (ctx->draw_mode != ARM_DRAW_MODE_POSE || (boneflag & BONE_DRAW_LOCKED_WEIGHT)) {
838 return col;
839 }
840
841 static float consts_color[4];
842 get_pchan_color_constraint(theme, ctx->bcolor, bone, consts_color);
843 return consts_color;
844}
845
846static float get_bone_wire_thickness(const Armatures::DrawContext *ctx, int boneflag)
847{
848 if (ctx->const_color) {
849 return ctx->const_wire;
850 }
851 if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) {
852 return 2.0f;
853 }
854
855 return 1.0f;
856}
857
858static const float *get_bone_wire_color(const Armatures::DrawContext *ctx,
859 const eBone_Flag boneflag)
860{
861 static float disp_color[4];
862
863 if (ctx->const_color) {
864 copy_v3_v3(disp_color, ctx->const_color);
865 }
866 else {
867 const UniformData &theme = ctx->res->theme;
868 switch (ctx->draw_mode) {
870 get_pchan_color_wire(theme, ctx->bcolor, ctx->draw_mode, boneflag, disp_color);
871 break;
873 get_pchan_color_wire(theme, ctx->bcolor, ctx->draw_mode, boneflag, disp_color);
874
875 if (boneflag & BONE_DRAW_LOCKED_WEIGHT) {
876 bone_locked_color_shade(theme, disp_color);
877 }
878 break;
880 copy_v3_v3(disp_color, theme.colors.vert);
881 break;
882 }
883 }
884
885 disp_color[3] = get_bone_wire_thickness(ctx, boneflag);
886
887 return disp_color;
888}
889
890static void bone_hint_color_shade(float hint_color[4], const float color[4])
891{
892 /* Increase contrast. */
893 mul_v3_v3v3(hint_color, color, color);
894 /* Decrease value to add mode shading to the shape. */
895 mul_v3_fl(hint_color, 0.1f);
896 hint_color[3] = 1.0f;
897}
898
899static const float *get_bone_hint_color(const Armatures::DrawContext *ctx,
900 const eBone_Flag boneflag)
901{
902 static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
903
904 if (ctx->const_color) {
905 bone_hint_color_shade(hint_color, ctx->res->theme.colors.bone_solid);
906 }
907 else {
908 const float *wire_color = get_bone_wire_color(ctx, boneflag);
909 bone_hint_color_shade(hint_color, wire_color);
910 }
911
912 return hint_color;
913}
914
916
917/* -------------------------------------------------------------------- */
920
922{
923 if (pchan->draw_data != nullptr) {
924 if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
925 MEM_SAFE_FREE(pchan->draw_data);
926 }
927 }
928
929 if (pchan->draw_data == nullptr) {
930 pchan->draw_data = static_cast<bPoseChannelDrawData *>(
931 MEM_mallocN(sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__));
932 pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
933 }
934}
935
937{
938 float ebmat[4][4];
939 float bone_scale[3];
940 float(*bone_mat)[4];
941 float(*disp_mat)[4] = bone.disp_mat();
942 float(*disp_tail_mat)[4] = bone.disp_tail_mat();
943
944 /* TODO: This should be moved to depsgraph or armature refresh
945 * and not be tied to the draw pass creation.
946 * This would refresh armature without invalidating the draw cache */
947 if (bone.is_posebone()) {
948 bPoseChannel *pchan = bone.as_posebone();
949 bone_mat = pchan->pose_mat;
950 copy_v3_fl(bone_scale, pchan->bone->length);
951 }
952 else {
953 EditBone *eBone = bone.as_editbone();
954 eBone->length = len_v3v3(eBone->tail, eBone->head);
955 ED_armature_ebone_to_mat4(eBone, ebmat);
956
957 copy_v3_fl(bone_scale, eBone->length);
958 bone_mat = ebmat;
959 }
960
961 copy_m4_m4(disp_mat, bone_mat);
962 rescale_m4(disp_mat, bone_scale);
963 copy_m4_m4(disp_tail_mat, disp_mat);
964 translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
965}
966
968{
969 float bone_scale[3];
970 float(*bone_mat)[4];
971 float(*disp_mat)[4];
972 float(*disp_tail_mat)[4];
973 float rot_mat[3][3];
974
975 /* Custom bone shapes are only supported in pose mode for now. */
976 bPoseChannel *pchan = bone.as_posebone();
977
978 /* TODO: This should be moved to depsgraph or armature refresh
979 * and not be tied to the draw pass creation.
980 * This would refresh armature without invalidating the draw cache. */
981 mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(pchan));
982 bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
983 disp_mat = bone.disp_mat();
984 disp_tail_mat = pchan->disp_tail_mat;
985
987
988 copy_m4_m4(disp_mat, bone_mat);
989 translate_m4(disp_mat,
990 pchan->custom_translation[0],
991 pchan->custom_translation[1],
992 pchan->custom_translation[2]);
993 mul_m4_m4m3(disp_mat, disp_mat, rot_mat);
994 rescale_m4(disp_mat, bone_scale);
995 copy_m4_m4(disp_tail_mat, disp_mat);
996 translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
997}
998
999/* compute connected child pointer for B-Bone drawing */
1001{
1002 LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
1003 eBone->bbone_child = nullptr;
1004 }
1005
1006 LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
1007 if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
1008 eBone->parent->bbone_child = eBone;
1009 }
1010 }
1011}
1012
1013/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */
1014static void ebone_spline_preview(EditBone *ebone, const float result_array[MAX_BBONE_SUBDIV][4][4])
1015{
1017 EditBone *prev, *next;
1018 float imat[4][4], bonemat[4][4];
1019 float tmp[3];
1020
1021 memset(&param, 0, sizeof(param));
1022
1023 param.segments = ebone->segments;
1024 param.length = ebone->length;
1025
1026 /* Get "next" and "prev" bones - these are used for handle calculations. */
1027 if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
1028 /* Use connected parent. */
1029 if (ebone->flag & BONE_CONNECTED) {
1030 prev = ebone->parent;
1031 }
1032 else {
1033 prev = nullptr;
1034 }
1035 }
1036 else {
1037 prev = ebone->bbone_prev;
1038 }
1039
1040 if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
1041 /* Use connected child. */
1042 next = ebone->bbone_child;
1043 }
1044 else {
1045 next = ebone->bbone_next;
1046 }
1047
1048 /* compute handles from connected bones */
1049 if (prev || next) {
1050 ED_armature_ebone_to_mat4(ebone, imat);
1051 invert_m4(imat);
1052
1053 if (prev) {
1054 param.use_prev = true;
1055
1056 if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
1057 zero_v3(param.prev_h);
1058 }
1059 else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
1060 sub_v3_v3v3(tmp, prev->tail, prev->head);
1061 sub_v3_v3v3(tmp, ebone->head, tmp);
1062 mul_v3_m4v3(param.prev_h, imat, tmp);
1063 }
1064 else {
1065 param.prev_bbone = (prev->segments > 1);
1066
1067 mul_v3_m4v3(param.prev_h, imat, prev->head);
1068 }
1069
1070 if (!param.prev_bbone) {
1071 ED_armature_ebone_to_mat4(prev, bonemat);
1072 mul_m4_m4m4(param.prev_mat, imat, bonemat);
1073 }
1074 }
1075
1076 if (next) {
1077 param.use_next = true;
1078
1079 if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
1080 copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
1081 }
1082 else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
1083 sub_v3_v3v3(tmp, next->tail, next->head);
1084 add_v3_v3v3(tmp, ebone->tail, tmp);
1085 mul_v3_m4v3(param.next_h, imat, tmp);
1086 }
1087 else {
1088 param.next_bbone = (next->segments > 1);
1089
1090 mul_v3_m4v3(param.next_h, imat, next->tail);
1091 }
1092
1094 mul_m4_m4m4(param.next_mat, imat, bonemat);
1095 }
1096 }
1097
1098 param.ease1 = ebone->ease1;
1099 param.ease2 = ebone->ease2;
1100 param.roll1 = ebone->roll1;
1101 param.roll2 = ebone->roll2;
1102
1103 if (prev && (ebone->bbone_flag & BBONE_ADD_PARENT_END_ROLL)) {
1104 param.roll1 += prev->roll2;
1105 }
1106
1107 copy_v3_v3(param.scale_in, ebone->scale_in);
1108 copy_v3_v3(param.scale_out, ebone->scale_out);
1109
1110 param.curve_in_x = ebone->curve_in_x;
1111 param.curve_in_z = ebone->curve_in_z;
1112
1113 param.curve_out_x = ebone->curve_out_x;
1114 param.curve_out_z = ebone->curve_out_z;
1115
1116 if (ebone->bbone_flag & BBONE_SCALE_EASING) {
1117 param.ease1 *= param.scale_in[1];
1118 param.curve_in_x *= param.scale_in[1];
1119 param.curve_in_z *= param.scale_in[1];
1120
1121 param.ease2 *= param.scale_out[1];
1122 param.curve_out_x *= param.scale_out[1];
1123 param.curve_out_z *= param.scale_out[1];
1124 }
1125
1126 ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
1127}
1128
1129/* This function is used for both B-Bone and Wire matrix updates. */
1131{
1132 float s[4][4], ebmat[4][4];
1133 float length, xwidth, zwidth;
1134 float(*bone_mat)[4];
1135 short bbone_segments;
1136
1137 /* TODO: This should be moved to depsgraph or armature refresh
1138 * and not be tied to the draw pass creation.
1139 * This would refresh armature without invalidating the draw cache. */
1140 if (bone.is_posebone()) {
1141 bPoseChannel *pchan = bone.as_posebone();
1142 length = pchan->bone->length;
1143 xwidth = pchan->bone->xwidth;
1144 zwidth = pchan->bone->zwidth;
1145 bone_mat = pchan->pose_mat;
1146 bbone_segments = pchan->bone->segments;
1147 }
1148 else {
1149 EditBone *eBone = bone.as_editbone();
1150 eBone->length = len_v3v3(eBone->tail, eBone->head);
1151 ED_armature_ebone_to_mat4(eBone, ebmat);
1152
1153 length = eBone->length;
1154 xwidth = eBone->xwidth;
1155 zwidth = eBone->zwidth;
1156 bone_mat = ebmat;
1157 bbone_segments = eBone->segments;
1158 }
1159
1160 const float3 size_vec = {xwidth, length / bbone_segments, zwidth};
1161 size_to_mat4(s, size_vec);
1162
1163 /* Compute BBones segment matrices... */
1164 /* Note that we need this even for one-segment bones, because box drawing need specific weirdo
1165 * matrix for the box, that we cannot use to draw end points & co. */
1166 if (bone.is_posebone()) {
1167 bPoseChannel *pchan = bone.as_posebone();
1168 Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
1169 if (bbone_segments > 1) {
1170 BKE_pchan_bbone_spline_setup(pchan, false, false, bbones_mat);
1171
1172 for (int i = bbone_segments; i--; bbones_mat++) {
1173 mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
1174 mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
1175 }
1176 }
1177 else {
1178 mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
1179 }
1180 }
1181 else {
1182 EditBone *eBone = bone.as_editbone();
1183 float(*bbones_mat)[4][4] = eBone->disp_bbone_mat;
1184
1185 if (bbone_segments > 1) {
1186 ebone_spline_preview(eBone, bbones_mat);
1187
1188 for (int i = bbone_segments; i--; bbones_mat++) {
1189 mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
1190 mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
1191 }
1192 }
1193 else {
1194 mul_m4_m4m4(*bbones_mat, bone_mat, s);
1195 }
1196 }
1197
1198 /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
1200}
1201
1202static void draw_axes(const Armatures::DrawContext *ctx,
1203 const UnifiedBonePtr bone,
1204 const bArmature &arm)
1205{
1206 float final_col[4];
1207 const float *col = (ctx->const_color) ? ctx->const_color :
1208 (bone.flag() & BONE_SELECTED) ? &ctx->res->theme.colors.text_hi.x :
1209 &ctx->res->theme.colors.text.x;
1210 copy_v4_v4(final_col, col);
1211 /* Mix with axes color. */
1212 final_col[3] = (ctx->const_color) ? 1.0 : (bone.flag() & BONE_SELECTED) ? 0.1 : 0.65;
1213
1214 if (bone.is_posebone() && bone.as_posebone()->custom && !(arm.flag & ARM_NO_CUSTOM)) {
1215 const bPoseChannel *pchan = bone.as_posebone();
1216 /* Special case: Custom bones can have different scale than the bone.
1217 * Recompute display matrix without the custom scaling applied. (#65640). */
1218 float axis_mat[4][4];
1219 float length = pchan->bone->length;
1220 copy_m4_m4(axis_mat, pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat);
1221 const float3 length_vec = {length, length, length};
1222 rescale_m4(axis_mat, length_vec);
1223 translate_m4(axis_mat, 0.0, arm.axes_position - 1.0, 0.0);
1224
1225 drw_shgroup_bone_axes(ctx, axis_mat, final_col);
1226 }
1227 else {
1228 float disp_mat[4][4];
1229 copy_m4_m4(disp_mat, bone.disp_mat());
1230 translate_m4(disp_mat, 0.0, arm.axes_position - 1.0, 0.0);
1231 drw_shgroup_bone_axes(ctx, disp_mat, final_col);
1232 }
1233}
1234
1236 const UnifiedBonePtr bone,
1237 const eBone_Flag boneflag,
1238 const float col_solid[4],
1239 const int select_id)
1240{
1241 float col_wire_root[4], col_wire_tail[4];
1242 float col_hint_root[4], col_hint_tail[4];
1243
1244 const UniformData &theme = ctx->res->theme;
1245
1246 copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : &theme.colors.vert.x);
1247 copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : &theme.colors.vert.x);
1248
1249 const bool is_envelope_draw = (ctx->drawtype == ARM_DRAW_TYPE_ENVELOPE);
1250 const float envelope_ignore = -1.0f;
1251
1252 col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(ctx, boneflag);
1253
1254 /* Edit bone points can be selected */
1255 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
1256 const EditBone *eBone = bone.as_editbone();
1257 if (eBone->flag & BONE_ROOTSEL) {
1258 copy_v3_v3(col_wire_root, theme.colors.vert_select);
1259 }
1260 if (eBone->flag & BONE_TIPSEL) {
1261 copy_v3_v3(col_wire_tail, theme.colors.vert_select);
1262 }
1263 }
1264 else if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
1265 const float *wire_color = get_bone_wire_color(ctx, boneflag);
1266 copy_v4_v4(col_wire_tail, wire_color);
1267 copy_v4_v4(col_wire_root, wire_color);
1268 }
1269
1270 const float *hint_color_shade_root = (ctx->const_color) ?
1271 (const float *)theme.colors.bone_solid :
1272 col_wire_root;
1273 const float *hint_color_shade_tail = (ctx->const_color) ?
1274 (const float *)theme.colors.bone_solid :
1275 col_wire_tail;
1276 bone_hint_color_shade(col_hint_root, hint_color_shade_root);
1277 bone_hint_color_shade(col_hint_tail, hint_color_shade_tail);
1278
1279 /* Draw root point if we are not connected to our parent */
1280
1281 if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
1282 if (is_envelope_draw) {
1284 bone.disp_mat(),
1285 col_solid,
1286 col_hint_root,
1287 col_wire_root,
1288 &bone.rad_head(),
1289 &envelope_ignore,
1290 select_id | BONESEL_ROOT);
1291 }
1292 else {
1294 ctx, bone.disp_mat(), col_solid, col_hint_root, col_wire_root, select_id | BONESEL_ROOT);
1295 }
1296 }
1297
1298 /* Draw tip point */
1299 if (is_envelope_draw) {
1301 bone.disp_mat(),
1302 col_solid,
1303 col_hint_tail,
1304 col_wire_tail,
1305 &envelope_ignore,
1306 &bone.rad_tail(),
1307 select_id | BONESEL_TIP);
1308 }
1309 else {
1311 bone.disp_tail_mat(),
1312 col_solid,
1313 col_hint_tail,
1314 col_wire_tail,
1315 select_id | BONESEL_TIP);
1316 }
1317}
1318
1320 const UnifiedBonePtr bone,
1321 const eBone_Flag boneflag,
1322 const int select_id)
1323{
1324 const float *col_solid = get_bone_solid_color(ctx, boneflag);
1325 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1326 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1327 const float(*disp_mat)[4] = bone.disp_mat();
1328
1329 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
1330
1331 /* Custom bone shapes are only supported in pose mode for now. */
1332 const bPoseChannel *pchan = bone.as_posebone();
1333 Object *custom_shape_ob = pchan->custom;
1334
1335 if (custom_shape_ob->type == OB_EMPTY) {
1336 if (custom_shape_ob->empty_drawtype != OB_EMPTY_IMAGE) {
1338 ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
1339 }
1340 }
1341 else if (boneflag & (BONE_DRAWWIRE | BONE_DRAW_LOCKED_WEIGHT)) {
1343 ctx, disp_mat, col_wire, pchan->custom_shape_wire_width, sel_id, pchan->custom);
1344 }
1345 else {
1347 disp_mat,
1348 col_solid,
1349 col_hint,
1350 col_wire,
1352 sel_id,
1353 pchan->custom);
1354 }
1355}
1356
1358 const UnifiedBonePtr bone,
1359 const eBone_Flag boneflag,
1360 const int select_id)
1361{
1362 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1363 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1364 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1365
1366 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
1367 float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(bone.disp_mat());
1368
1369 if (ctx->is_filled) {
1370 ctx->bone_buf->octahedral_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
1371 }
1372 if (col_wire[3] > 0.0f) {
1373 ctx->bone_buf->octahedral_outline_buf.append({bone_mat, col_wire}, sel_id);
1374 }
1375
1376 draw_points(ctx, bone, boneflag, col_solid, select_id);
1377}
1378
1380 const UnifiedBonePtr bone,
1381 const eBone_Flag boneflag,
1382 const int select_id)
1383{
1384 const float *col_bone = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1385 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1386 const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1387 const float *col_head = no_display;
1388 const float *col_tail = col_bone;
1389
1390 if (ctx->const_color != nullptr) {
1391 col_wire = no_display; /* actually shrink the display. */
1392 col_bone = col_head = col_tail = ctx->const_color;
1393 }
1394 else {
1395 const UniformData &theme = ctx->res->theme;
1396
1397 if (bone.is_editbone() && bone.flag() & BONE_TIPSEL) {
1398 col_tail = &theme.colors.vert_select.x;
1399 }
1400
1401 /* Draw root point if we are not connected to our parent. */
1402 if (!(bone.has_parent() && (boneflag & BONE_CONNECTED))) {
1403
1404 if (bone.is_editbone()) {
1405 col_head = (bone.flag() & BONE_ROOTSEL) ? &theme.colors.vert_select.x : col_bone;
1406 }
1407 else {
1408 col_head = col_bone;
1409 }
1410 }
1411 }
1412
1413 if (select_id == -1) {
1414 /* Not in bone selection mode (can still be object select mode), draw everything at once.
1415 */
1417 ctx, bone.disp_mat(), col_wire, col_bone, col_head, col_tail, select_id);
1418 }
1419 else {
1420 /* In selection mode, draw bone, root and tip separately. */
1422 bone.disp_mat(),
1423 col_wire,
1424 col_bone,
1425 no_display,
1426 no_display,
1427 select_id | BONESEL_BONE);
1428
1429 if (col_head[3] > 0.0f) {
1431 bone.disp_mat(),
1432 col_wire,
1433 no_display,
1434 col_head,
1435 no_display,
1436 select_id | BONESEL_ROOT);
1437 }
1438
1440 ctx, bone.disp_mat(), col_wire, no_display, no_display, col_tail, select_id | BONESEL_TIP);
1441 }
1442}
1443
1445 const UnifiedBonePtr bone,
1446 const eBone_Flag boneflag,
1447 const int select_id)
1448{
1449 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1450 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1451 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1452
1453 /* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
1454 * This would require a deeper refactor. */
1455 Span<Mat4> bbone_matrices;
1456 if (bone.is_posebone()) {
1457 bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
1458 bone.as_posebone()->bone->segments};
1459 }
1460 else {
1461 bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
1462 }
1463
1464 auto sel_id = ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE);
1465
1466 for (const Mat4 &in_bone_mat : bbone_matrices) {
1467 float4x4 bone_mat = ctx->ob->object_to_world() * float4x4(in_bone_mat.mat);
1468
1469 if (ctx->is_filled) {
1470 ctx->bone_buf->bbones_fill_buf.append({bone_mat, col_solid, col_hint}, sel_id);
1471 }
1472 if (col_wire[3] > 0.0f) {
1473 ctx->bone_buf->bbones_outline_buf.append({bone_mat, col_wire}, sel_id);
1474 }
1475 }
1476
1477 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
1478 draw_points(ctx, bone, boneflag, col_solid, select_id);
1479 }
1480}
1481
1483 const UnifiedBonePtr bone,
1484 const eBone_Flag boneflag,
1485 const int select_id)
1486{
1487 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1488 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1489 const float *col_hint = get_bone_hint_color(ctx, boneflag);
1490
1491 const float *rad_head, *rad_tail, *distance;
1492 if (bone.is_editbone()) {
1493 const EditBone *eBone = bone.as_editbone();
1494 rad_tail = &eBone->rad_tail;
1495 distance = &eBone->dist;
1496 rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
1497 &eBone->rad_head;
1498 }
1499 else {
1500 const bPoseChannel *pchan = bone.as_posebone();
1501 rad_tail = &pchan->bone->rad_tail;
1502 distance = &pchan->bone->dist;
1503 rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
1504 &pchan->bone->rad_head;
1505 }
1506
1507 if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
1508 ((boneflag & BONE_SELECTED) ||
1509 (bone.is_editbone() && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL)))))
1510 {
1511 drw_shgroup_bone_envelope_distance(ctx, bone.disp_mat(), rad_head, rad_tail, distance);
1512 }
1513
1515 bone.disp_mat(),
1516 col_solid,
1517 col_hint,
1518 col_wire,
1519 rad_head,
1520 rad_tail,
1521 select_id | BONESEL_BONE);
1522
1523 draw_points(ctx, bone, boneflag, col_solid, select_id);
1524}
1525
1527 const UnifiedBonePtr bone,
1528 const eBone_Flag boneflag,
1529 const int select_id)
1530{
1531 using namespace blender::math;
1532
1533 const float *col_wire = get_bone_wire_color(ctx, boneflag);
1534
1535 auto sel_id = (ctx->bone_buf) ? ctx->res->select_id(*ctx->ob_ref, select_id | BONESEL_BONE) :
1537
1538 /* NOTE: Cannot reinterpret as float4x4 because of alignment requirement of float4x4.
1539 * This would require a deeper refactor. */
1540 Span<Mat4> bbone_matrices;
1541 if (bone.is_posebone()) {
1542 bbone_matrices = {(Mat4 *)bone.as_posebone()->draw_data->bbone_matrix,
1543 bone.as_posebone()->bone->segments};
1544 }
1545 else {
1546 bbone_matrices = {(Mat4 *)bone.as_editbone()->disp_bbone_mat, bone.as_editbone()->segments};
1547 }
1548
1549 for (const Mat4 &in_bone_mat : bbone_matrices) {
1550 float4x4 bmat = float4x4(in_bone_mat.mat);
1551 float3 head = transform_point(ctx->ob->object_to_world(), bmat.location());
1552 float3 tail = transform_point(ctx->ob->object_to_world(), bmat.location() + bmat.y_axis());
1553
1554 ctx->bone_buf->wire_buf.append(head, tail, float4(col_wire), sel_id);
1555 }
1556
1557 if (bone.is_editbone()) {
1558 const float *col_solid = get_bone_solid_with_consts_color(ctx, bone, boneflag);
1559 draw_points(ctx, bone, boneflag, col_solid, select_id);
1560 }
1561}
1562
1563static void bone_draw(const eArmature_Drawtype drawtype,
1564 const bool use_custom_shape,
1565 const Armatures::DrawContext *ctx,
1566 const UnifiedBonePtr bone,
1567 const eBone_Flag boneflag,
1568 const int select_id)
1569{
1570 if (use_custom_shape) {
1571 bone_draw_custom_shape(ctx, bone, boneflag, select_id);
1572 return;
1573 }
1574
1575 switch (drawtype) {
1576 case ARM_DRAW_TYPE_OCTA:
1577 bone_draw_octa(ctx, bone, boneflag, select_id);
1578 break;
1580 bone_draw_line(ctx, bone, boneflag, select_id);
1581 break;
1583 bone_draw_b_bone(ctx, bone, boneflag, select_id);
1584 break;
1586 bone_draw_envelope(ctx, bone, boneflag, select_id);
1587 break;
1588 case ARM_DRAW_TYPE_WIRE:
1589 bone_draw_wire(ctx, bone, boneflag, select_id);
1590 break;
1591 default:
1593 break;
1594 }
1595}
1596
1598
1599/* -------------------------------------------------------------------- */
1602
1604 const bPoseChannel *pchan)
1605{
1607 float tmp[4][4], posetrans[4][4];
1608 float xminmax[2], zminmax[2];
1609
1610 /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
1611 xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
1612 xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
1613 zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
1614 zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
1615
1616 unit_m4(posetrans);
1617 translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
1618 /* In parent-bone pose space... */
1619 if (pchan->parent) {
1620 copy_m4_m4(tmp, pchan->parent->pose_mat);
1621 zero_v3(tmp[3]);
1622 mul_m4_m4m4(posetrans, posetrans, tmp);
1623 }
1624 /* ... but its own rest-space. */
1625 mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
1626
1627 float scale = pchan->bone->length * pchan->scale[1];
1628 scale_m4_fl(tmp, scale);
1629 tmp[1][1] = -tmp[1][1];
1630 mul_m4_m4m4(posetrans, posetrans, tmp);
1631
1632 /* into world space. */
1633 inst_data.mat44 = ctx->ob->object_to_world() * float4x4(posetrans);
1634
1635 /* Not selectable. */
1637
1638 if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) {
1640 inst_data.mat44, float4(0.25f), xminmax[0], zminmax[0], xminmax[1], zminmax[1]);
1641
1642 ctx->bone_buf->degrees_of_freedom_fill_buf.append(data, sel_id);
1643 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data.with_color({0.0f, 0.0f, 0.0f, 1.0f}),
1644 sel_id);
1645 }
1646 if (pchan->ikflag & BONE_IK_XLIMIT) {
1648 inst_data.mat44, float4(1.0f, 0.0f, 0.0f, 1.0f), xminmax[0], 0.0f, xminmax[1], 0.0f);
1649 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data, sel_id);
1650 }
1651 if (pchan->ikflag & BONE_IK_ZLIMIT) {
1653 inst_data.mat44, float4(0.0f, 0.0f, 1.0f, 1.0f), 0.0f, zminmax[0], 0.0f, zminmax[1]);
1654 ctx->bone_buf->degrees_of_freedom_wire_buf.append(data, sel_id);
1655 }
1656}
1657
1659
1660/* -------------------------------------------------------------------- */
1663
1665static bool should_draw_relation_to_parent(const UnifiedBonePtr bone, const eBone_Flag boneflag)
1666{
1667 const bool has_parent = bone.has_parent();
1668
1669 if (bone.is_editbone() && has_parent) {
1670 /* Always draw for unconnected bones, regardless of selection,
1671 * since riggers will want to know about the links between bones
1672 */
1673 return (boneflag & BONE_CONNECTED) == 0;
1674 }
1675
1676 if (bone.is_posebone() && has_parent) {
1677 /* Only draw between unconnected bones. */
1678 if (boneflag & BONE_CONNECTED) {
1679 return false;
1680 }
1681
1682 /* Only draw if bone or its parent is selected - reduces viewport
1683 * complexity with complex rigs */
1684 const bPoseChannel *pchan = bone.as_posebone();
1685 return (boneflag & BONE_SELECTED) ||
1686 (pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED));
1687 }
1688
1689 return false;
1690}
1691
1693 const bPoseChannel *pchan,
1694 const bool only_temp)
1695{
1696 const bPoseChannel *parchan;
1697 const float *line_start = nullptr, *line_end = nullptr;
1698 const ePchan_ConstFlag constflag = ePchan_ConstFlag(pchan->constflag);
1699
1700 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
1701 if (con->enforce == 0.0f) {
1702 continue;
1703 }
1704
1705 switch (con->type) {
1708 int segcount = 0;
1709
1710 /* if only_temp, only draw if it is a temporary ik-chain */
1711 if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP)) {
1712 continue;
1713 }
1714
1715 /* exclude tip from chain? */
1716 parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
1717 line_start = parchan->pose_tail;
1718
1719 /* Find the chain's root */
1720 while (parchan->parent) {
1721 segcount++;
1722 if (segcount == data->rootbone || segcount > 255) {
1723 break; /* 255 is weak */
1724 }
1725 parchan = parchan->parent;
1726 }
1727
1728 if (parchan) {
1729 line_end = parchan->pose_head;
1730
1731 if (constflag & PCHAN_HAS_NO_TARGET) {
1732 drw_shgroup_bone_ik_no_target_lines(ctx, line_start, line_end);
1733 }
1734 else {
1735 drw_shgroup_bone_ik_lines(ctx, line_start, line_end);
1736 }
1737 }
1738 break;
1739 }
1742 int segcount = 0;
1743
1744 /* don't draw if only_temp, as Spline IK chains cannot be temporary */
1745 if (only_temp) {
1746 continue;
1747 }
1748
1749 parchan = pchan;
1750 line_start = parchan->pose_tail;
1751
1752 /* Find the chain's root */
1753 while (parchan->parent) {
1754 segcount++;
1755 /* FIXME: revise the breaking conditions */
1756 if (segcount == data->chainlen || segcount > 255) {
1757 break; /* 255 is weak */
1758 }
1759 parchan = parchan->parent;
1760 }
1761 /* Only draw line in case our chain is more than one bone long! */
1762 if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
1763 line_end = parchan->pose_head;
1764 drw_shgroup_bone_ik_spline_lines(ctx, line_start, line_end);
1765 }
1766 break;
1767 }
1768 }
1769 }
1770}
1771
1773 const float bone_head[3],
1774 const float parent_head[3],
1775 const float parent_tail[3])
1776{
1777 if (ctx->draw_relation_from_head) {
1778 drw_shgroup_bone_relationship_lines(ctx, bone_head, parent_head);
1779 }
1780 else {
1781 drw_shgroup_bone_relationship_lines(ctx, bone_head, parent_tail);
1782 }
1783}
1784
1786 const UnifiedBonePtr bone,
1787 const eBone_Flag boneflag)
1788{
1789 if (ctx->draw_mode == ARM_DRAW_MODE_EDIT) {
1790 const EditBone *ebone = bone.as_editbone();
1791 if (ebone->parent) {
1792 if (ctx->do_relations && should_draw_relation_to_parent(bone, boneflag)) {
1794 ctx, ebone->head, ebone->parent->head, ebone->parent->tail);
1795 }
1796 }
1797 }
1798 else {
1799 const bPoseChannel *pchan = bone.as_posebone();
1800 if (pchan->parent) {
1801 if (ctx->do_relations && should_draw_relation_to_parent(bone, boneflag)) {
1803 ctx, pchan->pose_head, pchan->parent->pose_head, pchan->parent->pose_tail);
1804 }
1805
1806 /* Draw a line to IK root bone if bone is selected. */
1807 if (ctx->draw_mode == ARM_DRAW_MODE_POSE) {
1808 if (pchan->constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
1809 if (boneflag & BONE_SELECTED) {
1810 pchan_draw_ik_lines(ctx, pchan, !ctx->do_relations);
1811 }
1812 }
1813 }
1814 }
1815 }
1816}
1817
1819 const UnifiedBonePtr bone,
1820 const eBone_Flag boneflag)
1821{
1822 uchar color[4];
1823 float vec[3];
1824
1825 const bool is_pose = bone.is_posebone();
1826 const EditBone *eBone = nullptr;
1827 const bPoseChannel *pchan = nullptr;
1828 bone.get(&eBone, &pchan);
1829
1830 /* TODO: make this look at `boneflag` only. */
1831 bool highlight = (is_pose && ctx->draw_mode == ARM_DRAW_MODE_POSE &&
1832 (boneflag & BONE_SELECTED)) ||
1833 (!is_pose && (eBone->flag & BONE_SELECTED));
1834
1835 /* Color Management: Exception here as texts are drawn in sRGB space directly. */
1837
1838 const float *head = is_pose ? pchan->pose_head : eBone->head;
1839 const float *tail = is_pose ? pchan->pose_tail : eBone->tail;
1840 mid_v3_v3v3(vec, head, tail);
1841 mul_m4_v3(ctx->ob->object_to_world().ptr(), vec);
1842
1844 vec,
1845 is_pose ? pchan->name : eBone->name,
1846 is_pose ? strlen(pchan->name) : strlen(eBone->name),
1847 10,
1848 0,
1850 color,
1851 true);
1852}
1853
1855
1856/* -------------------------------------------------------------------- */
1859
1861 const bool use_custom_shape,
1862 UnifiedBonePtr bone)
1863{
1864 if (use_custom_shape) {
1866 }
1867 else if (ELEM(drawtype, ARM_DRAW_TYPE_B_BONE, ARM_DRAW_TYPE_WIRE)) {
1869 }
1870 else {
1872 }
1873}
1874
1876{
1877 Object *ob = ctx->ob;
1878 EditBone *eBone;
1879 int index;
1880 const bool is_select = ctx->res->is_selection();
1881 const bool show_text = ctx->show_text;
1882
1883 const Object *ob_orig = DEG_get_original(ob);
1884 /* FIXME(@ideasman42): We should be able to use the evaluated object,
1885 * however the active bone isn't updated. Long term solution is an 'EditArmature' struct.
1886 * for now we can draw from the original armature. See: #66773. */
1887 // bArmature *arm = ob->data;
1889
1891
1892 const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
1893
1894 for (eBone = static_cast<EditBone *>(arm.edbo->first),
1895 /* Note: Selection Next handles the object id merging later. */
1896 index = ctx->bone_buf ? 0x0 : ob_orig->runtime->select_id;
1897 eBone;
1898 eBone = eBone->next, index += 0x10000)
1899 {
1901 continue;
1902 }
1903
1904 const int select_id = is_select ? index : uint(-1);
1905
1906 /* catch exception for bone with hidden parent */
1907 eBone_Flag boneflag = eBone_Flag(eBone->flag);
1908 if ((eBone->parent) && !blender::animrig::bone_is_visible_editbone(&arm, eBone->parent)) {
1909 boneflag &= ~BONE_CONNECTED;
1910 }
1911
1912 /* set temporary flag for drawing bone as active, but only if selected */
1913 if (eBone == arm.act_edbone) {
1914 boneflag |= BONE_DRAW_ACTIVE;
1915 }
1916
1917 boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
1918
1919 UnifiedBonePtr bone = eBone;
1920 if (!ctx->const_color) {
1921 set_ctx_bcolor(ctx, bone);
1922 }
1923
1924 if (!is_select) {
1925 draw_bone_relations(ctx, bone, boneflag);
1926 }
1927
1929 arm_drawtype :
1931 bone_draw_update_display_matrix(drawtype, false, bone);
1932 bone_draw(drawtype, false, ctx, bone, boneflag, select_id);
1933
1934 if (!is_select) {
1935 if (show_text && (arm.flag & ARM_DRAWNAMES)) {
1936 draw_bone_name(ctx, bone, boneflag);
1937 }
1938
1939 if (arm.flag & ARM_DRAWAXES) {
1940 draw_axes(ctx, bone, arm);
1941 }
1942 }
1943 }
1944}
1945
1947{
1948 Object *ob = ctx->ob;
1949 const DRWContext *draw_ctx = DRW_context_get();
1950 const Scene *scene = draw_ctx->scene;
1952 int index = -1;
1953 const bool show_text = ctx->show_text;
1954 bool draw_locked_weights = false;
1955
1956 /* We can't safely draw non-updated pose, might contain nullptr bone pointers... */
1957 if (ob->pose->flag & POSE_RECALC) {
1958 return;
1959 }
1960
1961 ctx->draw_mode = ARM_DRAW_MODE_OBJECT; /* Will likely be set to ARM_DRAW_MODE_POSE below. */
1962
1963 bool is_pose_select = false;
1964 /* Object can be edited in the scene. */
1965 if (!is_from_dupli_or_set(ob)) {
1966 if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
1968 }
1969 is_pose_select =
1970 /* If we're in pose-mode or object-mode with the ability to enter pose mode. */
1971 (
1972 /* Draw as if in pose mode (when selection is possible). */
1973 (ctx->draw_mode == ARM_DRAW_MODE_POSE) ||
1974 /* When we're in object mode, which may select bones. */
1975 ((ob->mode & OB_MODE_POSE) &&
1976 (
1977 /* Switch from object mode when object lock is disabled. */
1978 ((draw_ctx->object_mode == OB_MODE_OBJECT) &&
1979 (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
1980 /* Allow selection when in weight-paint mode
1981 * (selection code ensures this won't become active). */
1982 ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) &&
1983 (draw_ctx->object_pose != nullptr))))) &&
1984 ctx->res->is_selection();
1985
1986 if (is_pose_select) {
1987 const Object *ob_orig = DEG_get_original(ob);
1988 /* Note: Selection Next handles the object id merging later. */
1989 index = ctx->bone_buf ? 0x0 : ob_orig->runtime->select_id;
1990 }
1991 }
1992
1993 /* In weight paint mode retrieve the vertex group lock status. */
1994 if ((draw_ctx->object_mode & OB_MODE_ALL_WEIGHT_PAINT) && (draw_ctx->object_pose == ob) &&
1995 (draw_ctx->obact != nullptr))
1996 {
1997 draw_locked_weights = true;
1998
2000 pchan->bone->flag &= ~BONE_DRAW_LOCKED_WEIGHT;
2001 }
2002
2003 const Object *obact_orig = DEG_get_original(draw_ctx->obact);
2004
2005 const ListBase *defbase = BKE_object_defgroup_list(obact_orig);
2006 for (const bDeformGroup *dg : ConstListBaseWrapper<bDeformGroup>(defbase)) {
2007 if ((dg->flag & DG_LOCK_WEIGHT) == 0) {
2008 continue;
2009 }
2010
2011 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, dg->name);
2012 if (!pchan) {
2013 continue;
2014 }
2015
2017 }
2018 }
2019
2020 const eArmature_Drawtype arm_drawtype = eArmature_Drawtype(arm.drawtype);
2021
2022 for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first); pchan;
2023 pchan = pchan->next, index += 0x10000)
2024 {
2025 Bone *bone = pchan->bone;
2026 if (!blender::animrig::bone_is_visible(&arm, bone)) {
2027 continue;
2028 }
2029
2030 const bool draw_dofs = !is_pose_select && ctx->show_relations &&
2031 (ctx->draw_mode == ARM_DRAW_MODE_POSE) &&
2032 (bone->flag & BONE_SELECTED) &&
2033 ((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
2034 (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT));
2035 const int select_id = is_pose_select ? index : uint(-1);
2036
2037 pchan_draw_data_init(pchan);
2038
2039 UnifiedBonePtr bone_ptr = pchan;
2040 if (!ctx->const_color) {
2041 set_ctx_bcolor(ctx, bone_ptr);
2042 }
2043
2044 eBone_Flag boneflag = eBone_Flag(bone->flag);
2045 if (bone->parent && !blender::animrig::bone_is_visible(&arm, bone->parent)) {
2046 /* Avoid drawing connection line to hidden parent. */
2047 boneflag &= ~BONE_CONNECTED;
2048 }
2049 if (bone == arm.act_bone) {
2050 /* Draw bone as active, but only if selected. */
2051 boneflag |= BONE_DRAW_ACTIVE;
2052 }
2053 if (!draw_locked_weights) {
2054 boneflag &= ~BONE_DRAW_LOCKED_WEIGHT;
2055 }
2056
2057 const bool use_custom_shape = (pchan->custom) && !(arm.flag & ARM_NO_CUSTOM);
2058 if (!is_pose_select) {
2059 draw_bone_relations(ctx, bone_ptr, boneflag);
2060 }
2061
2063 arm_drawtype :
2065 bone_draw_update_display_matrix(drawtype, use_custom_shape, bone_ptr);
2066 bone_draw(drawtype, use_custom_shape, ctx, bone_ptr, boneflag, select_id);
2067
2068 /* Below this point nothing is used for selection queries. */
2069 if (is_pose_select) {
2070 continue;
2071 }
2072
2073 if (draw_dofs) {
2074 draw_bone_degrees_of_freedom(ctx, pchan);
2075 }
2076 if (show_text && (arm.flag & ARM_DRAWNAMES)) {
2077 draw_bone_name(ctx, bone_ptr, boneflag);
2078 }
2079 if (arm.flag & ARM_DRAWAXES) {
2080 draw_axes(ctx, bone_ptr, arm);
2081 }
2082 }
2083}
2084
Functions to deal with Armatures.
C++ part of the BoneColor DNA struct.
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan, bool rest, bool for_deform, Mat4 *result_array)
Definition armature.cc:1365
#define MAX_BBONE_SUBDIV
int BKE_pchan_bbone_spline_compute(BBoneSplineParameters *param, bool for_deform, Mat4 *result_array)
Definition armature.cc:1537
support for deformation groups and hooks.
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:574
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh_no_subsurf_unchecked(const Object *object)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
float mat4_to_scale(const float mat[4][4])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void rescale_m4(float mat[4][4], const float scale[3])
void size_to_mat4(float R[4][4], const float size[3])
void mul_m4_v3(const float M[4][4], float r[3])
void scale_m4_fl(float R[4][4], float scale)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
void mul_m4_v4(const float mat[4][4], float r[4])
bool invert_m4(float mat[4][4])
void unit_m4(float m[4][4])
void eulO_to_mat3(float M[3][3], const float e[3], short order)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t)
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define UNPACK3(a)
#define ELEM(...)
T * DEG_get_original(T *id)
#define PCHAN_CUSTOM_BONE_LENGTH(pchan)
@ ROT_MODE_XYZ
@ BONE_IK_ZLIMIT
@ BONE_IK_XLIMIT
ePchan_ConstFlag
@ PCHAN_HAS_CONST
@ PCHAN_HAS_NO_TARGET
@ PCHAN_HAS_IK
@ PCHAN_HAS_SPLINEIK
@ POSE_RECALC
@ BBONE_HANDLE_AUTO
@ BBONE_HANDLE_TANGENT
@ BBONE_HANDLE_RELATIVE
@ BONE_DRAW_LOCKED_WEIGHT
@ BONE_ROOTSEL
@ BONE_DRAWWIRE
@ BONE_SELECTED
@ BONE_DRAW_ACTIVE
@ BONE_TIPSEL
@ BONE_NO_DEFORM
@ BONE_CONNECTED
@ ARM_NO_CUSTOM
@ ARM_COL_CUSTOM
@ ARM_DRAWNAMES
@ ARM_DRAWAXES
eArmature_Drawtype
@ ARM_DRAW_TYPE_ENVELOPE
@ ARM_DRAW_TYPE_STICK
@ ARM_DRAW_TYPE_B_BONE
@ ARM_DRAW_TYPE_WIRE
@ ARM_DRAW_TYPE_ARMATURE_DEFINED
@ ARM_DRAW_TYPE_OCTA
@ BBONE_ADD_PARENT_END_ROLL
@ BBONE_SCALE_EASING
@ CONSTRAINT_IK_TEMP
@ CONSTRAINT_IK_TIP
@ CONSTRAINT_TYPE_SPLINEIK
@ CONSTRAINT_TYPE_KINEMATIC
@ BASE_FROM_DUPLI
#define OB_MODE_ALL_WEIGHT_PAINT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ OB_EMPTY_CONE
@ OB_SINGLE_ARROW
@ OB_PLAINAXES
@ OB_ARROWS
@ OB_CIRCLE
@ OB_CUBE
@ OB_EMPTY_IMAGE
@ OB_EMPTY_SPHERE
@ OB_EMPTY
@ OB_SURF
@ OB_FONT
@ OB_CURVES_LEGACY
@ DG_LOCK_WEIGHT
@ SCE_OBJECT_MODE_LOCK
@ TH_WIRECOLOR_CONSTCOLS
#define BONESEL_ROOT
#define BONESEL_TIP
#define BONESEL_BONE
@ TH_TEXT
@ TH_TEXT_HI
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
void ED_armature_ebone_to_mat4(EditBone *ebone, float r_mat[4][4])
BMesh const char void * data
return true
bPoseChannel * pchan_
const f44 & disp_tail_mat() const
ePchan_ConstFlag constflag() const
UnifiedBonePtr(EditBone *eBone)
bPoseChannel * as_posebone()
bool is_posebone() const
bool is_editbone() const
void get(EditBone **eBone, bPoseChannel **pchan)
const f44 & disp_mat() const
void get(const EditBone **eBone, const bPoseChannel **pchan) const
const EditBone * as_editbone() const
UnifiedBonePtr(const UnifiedBonePtr &ptr)=default
UnifiedBonePtr(bPoseChannel *pchan)
const float & rad_head() const
const float & rad_tail() const
EditBone * as_editbone()
const blender::animrig::BoneColor & effective_bonecolor() const
eBone_Flag flag() const
const char * name() const
bool has_parent() const
const bPoseChannel * as_posebone() const
const ThemeWireColor * effective_color() const
Definition bonecolor.cc:32
static void draw_armature_pose(Armatures::DrawContext *ctx)
static void draw_armature_edit(Armatures::DrawContext *ctx)
#define sinf(x)
const DRWContext * DRW_context_get()
Mesh & DRW_object_get_data_for_drawing(const Object &object)
void DRW_text_cache_add(DRWTextStore *dt, const float co[3], const char *str, const int str_len, short xoffs, short yoffs, short flag, const uchar col[4], const bool shadow, const bool align_center)
@ DRW_TEXT_CACHE_GLOBALSPACE
@ DRW_TEXT_CACHE_STRING_PTR
uint col
float length(VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
#define MEM_SAFE_FREE(v)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
static ulong * next
bool bone_is_visible_editbone(const bArmature *armature, const EditBone *ebone)
bool bone_is_visible(const bArmature *armature, const Bone *bone)
static bool is_from_dupli_or_set(const Object *ob)
void DRW_mesh_batch_cache_validate(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_loose_edges(Mesh &mesh)
gpu::Batch * DRW_cache_text_edge_wire_get(Object *ob)
void DRW_curve_batch_cache_validate(Curve *cu)
blender::gpu::Batch * DRW_mesh_batch_cache_get_surface(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_all_edges(Mesh &mesh)
blender::gpu::Batch * DRW_mesh_batch_cache_get_edge_detection(Mesh &mesh, bool *r_is_manifold)
void drw_batch_cache_generate_requested_delayed(Object *ob)
gpu::Batch * DRW_cache_curve_edge_wire_get(Object *ob)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
ListBaseWrapperTemplate< const ListBase, const T > ConstListBaseWrapper
VecBase< float, 4 > float4
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
VecBase< float, 3 > float3
static void drw_shgroup_bone_stick(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float col_wire[4], const float col_bone[4], const float col_head[4], const float col_tail[4], const int select_id)
static const float * get_bone_solid_color(const Armatures::DrawContext *ctx, const eBone_Flag boneflag)
static void draw_bone_update_disp_matrix_custom_shape(UnifiedBonePtr bone)
static void drw_shgroup_bone_relationship_lines_ex(const Armatures::DrawContext *ctx, const float start[3], const float end[3], const float color[4])
static void bone_draw_envelope(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static const float * get_bone_solid_with_consts_color(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void ebone_spline_preview(EditBone *ebone, const float result_array[MAX_BBONE_SUBDIV][4][4])
static void drw_shgroup_bone_envelope_distance(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float *radius_head, const float *radius_tail, const float *distance)
static void drw_shgroup_bone_ik_spline_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void drw_shgroup_bone_custom_empty(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
static void drw_shgroup_bone_envelope(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_col[4], const float hint_col[4], const float outline_col[4], const float *radius_head, const float *radius_tail, const int select_id)
static void draw_bone_relations(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void bone_locked_color_shade(const UniformData &theme, float color[4])
static void drw_shgroup_bone_custom_solid(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
static const float * get_bone_hint_color(const Armatures::DrawContext *ctx, const eBone_Flag boneflag)
static void use_bone_color(float *r_color, const uint8_t *color_from_theme, const int shade_offset)
static bool should_draw_relation_to_parent(const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void draw_bone_bone_relationship_line(const Armatures::DrawContext *ctx, const float bone_head[3], const float parent_head[3], const float parent_tail[3])
static void draw_points(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const float col_solid[4], const int select_id)
static void drw_shgroup_bone_custom_wire(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
static void draw_bone_degrees_of_freedom(const Armatures::DrawContext *ctx, const bPoseChannel *pchan)
static void bone_draw(const eArmature_Drawtype drawtype, const bool use_custom_shape, const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void drw_shgroup_bone_axes(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float color[4])
static void get_pchan_color_solid(const UniformData &theme, const ThemeWireColor *bcolor, float r_color[4])
static void edbo_compute_bbone_child(bArmature *arm)
static void drw_shgroup_bone_ik_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void drw_shgroup_custom_bone_curve(const Armatures::DrawContext *ctx, Curve *curve, const float(*bone_mat)[4], const float outline_color[4], const float wire_width, const draw::select::ID select_id, Object *custom)
static void draw_bone_name(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag)
static void bone_hint_color_shade(float hint_color[4], const float color[4])
static void draw_bone_update_disp_matrix_default(UnifiedBonePtr bone)
static void bone_draw_wire(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void bone_draw_update_display_matrix(const eArmature_Drawtype drawtype, const bool use_custom_shape, UnifiedBonePtr bone)
static void draw_bone_update_disp_matrix_bbone(UnifiedBonePtr bone)
static void get_pchan_color_constraint(const UniformData &theme, const ThemeWireColor *bcolor, const UnifiedBonePtr bone, float r_color[4])
static void bone_draw_custom_shape(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static float get_bone_wire_thickness(const Armatures::DrawContext *ctx, int boneflag)
static void bone_draw_line(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void drw_shgroup_bone_custom_mesh_wire(const Armatures::DrawContext *ctx, Mesh &mesh, const float(*bone_mat)[4], const float color[4], const float wire_width, const draw::select::ID select_id, Object &custom)
static void bone_draw_octa(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void pchan_draw_ik_lines(const Armatures::DrawContext *ctx, const bPoseChannel *pchan, const bool only_temp)
static void draw_axes(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const bArmature &arm)
static void drw_shgroup_bone_custom_solid_mesh(const Armatures::DrawContext *ctx, Mesh &mesh, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4], const float wire_width, const draw::select::ID select_id, Object &custom)
static void pchan_draw_data_init(bPoseChannel *pchan)
static void drw_shgroup_bone_ik_no_target_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void bone_draw_b_bone(const Armatures::DrawContext *ctx, const UnifiedBonePtr bone, const eBone_Flag boneflag, const int select_id)
static void set_ctx_bcolor(Armatures::DrawContext *ctx, const UnifiedBonePtr bone)
static void cp_shade_color3ub(uchar cp[3], const int offset)
static const float * get_bone_wire_color(const Armatures::DrawContext *ctx, const eBone_Flag boneflag)
static void drw_shgroup_bone_relationship_lines(const Armatures::DrawContext *ctx, const float start[3], const float end[3])
static void drw_shgroup_bone_sphere(const Armatures::DrawContext *ctx, const float(*bone_mat)[4], const float bone_color[4], const float hint_color[4], const float outline_color[4], const int select_id)
#define PT_DEFAULT_RAD
static void get_pchan_color_wire(const UniformData &theme, const ThemeWireColor *bcolor, const eArmatureDrawMode draw_mode, const eBone_Flag boneflag, float r_color[4])
#define WIRE_WIDTH_COMPRESSION
int8_t drawtype
struct Bone * parent
float bone_mat[3][3]
Object * obact
Scene * scene
Object * object_pose
eObjectMode object_mode
float curve_out_z
float scale_in[3]
char name[64]
float ease2
float roll1
short segments
float tail[3]
char bbone_prev_type
EditBone * parent
float roll2
float disp_bbone_mat[32][4][4]
float curve_in_x
float zwidth
float curve_in_z
float length
float xwidth
EditBone * next
EditBone * bbone_prev
char bbone_next_type
float rad_tail
EditBone * bbone_next
EditBone * bbone_child
float ease1
float rad_head
float scale_out[3]
float curve_out_x
float head[3]
void * first
float mat[4][4]
short base_flag
struct bPose * pose
ObjectRuntimeHandle * runtime
char empty_drawtype
float empty_drawsize
struct ToolSettings * toolsettings
unsigned char select[4]
unsigned char solid[4]
unsigned char active[4]
struct EditBone * act_edbone
ListBase * edbo
float bbone_matrix[0][4][4]
float custom_scale_xyz[3]
bPoseChannelDrawData * draw_data
float custom_rotation_euler[3]
struct Bone * bone
struct bPoseChannel * parent
struct bPoseChannel * custom_tx
struct Object * custom
struct bPoseChannel * next
float custom_translation[3]
float custom_shape_wire_width
float disp_tail_mat[4][4]
float pose_mat[4][4]
ListBase chanbase
void set_color(const float4 &bone_color)
void set_hint_color(const float4 &hint_color)
void append(const float3 &start, const float3 &end, const float4 &color, select::ID select_id=select::SelectMap::select_invalid_id())
void append(const InstanceDataT &data, select::ID select_id)
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)
i
Definition text_draw.cc:230
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56
uint len
PointerRNA * ptr
Definition wm_files.cc:4226