Blender V4.3
rigidbody_object.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include <cstdlib>
11#include <cstring>
12
13#include "DNA_object_types.h"
14#include "DNA_rigidbody_types.h"
15#include "DNA_scene_types.h"
16
17#include "BLT_translation.hh"
18
19#include "BKE_context.hh"
20#include "BKE_report.hh"
21#include "BKE_rigidbody.h"
22
23#include "DEG_depsgraph.hh"
26
27#include "RNA_access.hh"
28#include "RNA_define.hh"
29#include "RNA_enum_types.hh"
30#include "RNA_prototypes.hh"
31
32#include "WM_api.hh"
33#include "WM_types.hh"
34
35#include "ED_object.hh"
36#include "ED_physics.hh"
37#include "ED_screen.hh"
38
39#include "physics_intern.hh"
40
41/* ********************************************** */
42/* Helper API's for RigidBody Objects Editing */
43
45{
46 if (scene == nullptr || !ID_IS_EDITABLE(scene) || ID_IS_OVERRIDE_LIBRARY(scene) ||
47 (scene->rigidbody_world != nullptr && scene->rigidbody_world->group != nullptr &&
48 (!ID_IS_EDITABLE(scene->rigidbody_world->group) ||
49 ID_IS_OVERRIDE_LIBRARY(scene->rigidbody_world->group))))
50 {
51 return false;
52 }
53 return true;
54}
55
57{
58 Scene *scene = CTX_data_scene(C);
60 return false;
61 }
62
65 return (ob && ob->rigidbody_object);
66 }
67
68 return false;
69}
70
72{
73 Scene *scene = CTX_data_scene(C);
75 return false;
76 }
77
80 return (ob && ob->type == OB_MESH);
81 }
82
83 return false;
84}
85
86/* ----------------- */
87
88bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
89{
90 return BKE_rigidbody_add_object(bmain, scene, ob, type, reports);
91}
92
94{
95 BKE_rigidbody_remove_object(bmain, scene, ob, false);
96}
97
98/* ********************************************** */
99/* Active Object Add/Remove Operators */
100
101/* ************ Add Rigid Body ************** */
102
104{
105 Main *bmain = CTX_data_main(C);
106 Scene *scene = CTX_data_scene(C);
108 int type = RNA_enum_get(op->ptr, "type");
109 bool changed;
110
111 /* apply to active object */
112 changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
113
114 if (changed) {
115 /* send updates */
118
119 /* done */
120 return OPERATOR_FINISHED;
121 }
122 return OPERATOR_CANCELLED;
123}
124
126{
127 /* identifiers */
128 ot->idname = "RIGIDBODY_OT_object_add";
129 ot->name = "Add Rigid Body";
130 ot->description = "Add active object as Rigid Body";
131
132 /* callbacks */
135
136 /* flags */
138
139 /* properties */
141 "type",
144 "Rigid Body Type",
145 "");
146}
147
148/* ************ Remove Rigid Body ************** */
149
151{
152 Main *bmain = CTX_data_main(C);
153 Scene *scene = CTX_data_scene(C);
155 bool changed = false;
156
157 /* apply to active object */
158 if (!ELEM(nullptr, ob, ob->rigidbody_object)) {
159 ED_rigidbody_object_remove(bmain, scene, ob);
160 changed = true;
161 }
162
163 if (changed) {
164 /* send updates */
167
168 /* done */
169 return OPERATOR_FINISHED;
170 }
171
172 BKE_report(op->reports, RPT_ERROR, "Object has no Rigid Body settings to remove");
173 return OPERATOR_CANCELLED;
174}
175
177{
178 /* identifiers */
179 ot->idname = "RIGIDBODY_OT_object_remove";
180 ot->name = "Remove Rigid Body";
181 ot->description = "Remove Rigid Body settings from Object";
182
183 /* callbacks */
186
187 /* flags */
189}
190
191/* ********************************************** */
192/* Selected Object Add/Remove Operators */
193
194/* ************ Add Rigid Bodies ************** */
195
197{
198 Main *bmain = CTX_data_main(C);
199 Scene *scene = CTX_data_scene(C);
200 int type = RNA_enum_get(op->ptr, "type");
201 bool changed = false;
202
203 /* create rigid body objects and add them to the world's group */
204 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
205 changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
206 }
208
209 if (changed) {
210 /* send updates */
213
214 /* done */
215 return OPERATOR_FINISHED;
216 }
217 return OPERATOR_CANCELLED;
218}
219
221{
222 /* identifiers */
223 ot->idname = "RIGIDBODY_OT_objects_add";
224 ot->name = "Add Rigid Bodies";
225 ot->description = "Add selected objects as Rigid Bodies";
226
227 /* callbacks */
230
231 /* flags */
233
234 /* properties */
236 "type",
239 "Rigid Body Type",
240 "");
241}
242
243/* ************ Remove Rigid Bodies ************** */
244
246{
247 Main *bmain = CTX_data_main(C);
248 Scene *scene = CTX_data_scene(C);
249 bool changed = false;
250
251 /* apply this to all selected objects... */
252 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
253 if (ob->rigidbody_object) {
254 ED_rigidbody_object_remove(bmain, scene, ob);
255 changed = true;
256 }
257 }
259
260 if (changed) {
261 /* send updates */
264
265 /* done */
266 return OPERATOR_FINISHED;
267 }
268 return OPERATOR_CANCELLED;
269}
270
272{
273 /* identifiers */
274 ot->idname = "RIGIDBODY_OT_objects_remove";
275 ot->name = "Remove Rigid Bodies";
276 ot->description = "Remove selected objects from Rigid Body simulation";
277
278 /* callbacks */
281
282 /* flags */
284}
285
286/* ********************************************** */
287/* Utility Operators */
288
289/* ************ Change Collision Shapes ************** */
290
292{
293 int shape = RNA_enum_get(op->ptr, "type");
294 bool changed = false;
295
296 /* apply this to all selected objects... */
297 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
298 if (ob->rigidbody_object) {
299 /* use RNA-system to change the property and perform all necessary changes */
300 PointerRNA ptr = RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object);
301 RNA_enum_set(&ptr, "collision_shape", shape);
302
304
305 changed = true;
306 }
307 }
309
310 if (changed) {
311 /* send updates */
314
315 /* done */
316 return OPERATOR_FINISHED;
317 }
318 return OPERATOR_CANCELLED;
319}
320
322{
323 /* identifiers */
324 ot->idname = "RIGIDBODY_OT_shape_change";
325 ot->name = "Change Collision Shape";
326 ot->description = "Change collision shapes for selected Rigid Body Objects";
327
328 /* callbacks */
332
333 /* flags */
335
336 /* properties */
338 "type",
341 "Rigid Body Shape",
342 "");
343}
344
345/* ************ Calculate Mass ************** */
346
347/* Entry in material density table */
349 const char *name; /* Name of material */
350 float density; /* Density (kg/m^3) */
351};
352
353/* Preset density values for materials (kg/m^3)
354 * Selected values obtained from:
355 * 1) http://www.jaredzone.info/2010/09/densities.html
356 * 2) http://www.avlandesign.com/density_construction.htm
357 * 3) http://www.avlandesign.com/density_metal.htm
358 */
360 {N_("Air"), 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
361 {N_("Acrylic"), 1400.0f},
362 {N_("Asphalt (Crushed)"), 721.0f},
363 {N_("Bark"), 240.0f},
364 {N_("Beans (Cocoa)"), 593.0f},
365 {N_("Beans (Soy)"), 721.0f},
366 {N_("Brick (Pressed)"), 2400.0f},
367 {N_("Brick (Common)"), 2000.0f},
368 {N_("Brick (Soft)"), 1600.0f},
369 {N_("Brass"), 8216.0f},
370 {N_("Bronze"), 8860.0f},
371 {N_("Carbon (Solid)"), 2146.0f},
372 {N_("Cardboard"), 689.0f},
373 {N_("Cast Iron"), 7150.0f}, /* {N_("Cement"), 1442.0f}, */
374 {N_("Chalk (Solid)"), 2499.0f}, /* {N_("Coffee (Fresh/Roast)"), ~500}, */
375 {N_("Concrete"), 2320.0f},
376 {N_("Charcoal"), 208.0f},
377 {N_("Cork"), 240.0f},
378 {N_("Copper"), 8933.0f},
379 {N_("Garbage"), 481.0f},
380 {N_("Glass (Broken)"), 1940.0f},
381 {N_("Glass (Solid)"), 2190.0f},
382 {N_("Gold"), 19282.0f},
383 {N_("Granite (Broken)"), 1650.0f},
384 {N_("Granite (Solid)"), 2691.0f},
385 {N_("Gravel"), 2780.0f},
386 {N_("Ice (Crushed)"), 593.0f},
387 {N_("Ice (Solid)"), 919.0f},
388 {N_("Iron"), 7874.0f},
389 {N_("Lead"), 11342.0f},
390 {N_("Limestone (Broken)"), 1554.0f},
391 {N_("Limestone (Solid)"), 2611.0f},
392 {N_("Marble (Broken)"), 1570.0f},
393 {N_("Marble (Solid)"), 2563.0f},
394 {N_("Paper"), 1201.0f},
395 {N_("Peanuts (Shelled)"), 641.0f},
396 {N_("Peanuts (Not Shelled)"), 272.0f},
397 {N_("Plaster"), 849.0f},
398 {N_("Plastic"), 1200.0f},
399 {N_("Polystyrene"), 1050.0f},
400 {N_("Rubber"), 1522.0f},
401 {N_("Silver"), 10501.0f},
402 {N_("Steel"), 7860.0f},
403 {N_("Stone"), 2515.0f},
404 {N_("Stone (Crushed)"), 1602.0f},
405 {N_("Timber"), 610.0f},
406};
408 sizeof(rbMaterialDensityItem);
409
410/* dynamically generate list of items
411 * - Although there is a runtime cost, this has a lower maintenance cost
412 * in the long run than other two-list solutions...
413 */
415 PointerRNA * /*ptr*/,
416 PropertyRNA * /*prop*/,
417 bool *r_free)
418{
419 EnumPropertyItem item_tmp = {0};
420 EnumPropertyItem *item = nullptr;
421 int totitem = 0;
422 int i = 0;
423
424 /* add each preset to the list */
425 for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) {
427
428 item_tmp.identifier = preset->name;
429 item_tmp.name = IFACE_(preset->name);
430 item_tmp.value = i;
431 RNA_enum_item_add(&item, &totitem, &item_tmp);
432 }
433
434 /* add special "custom" entry to the end of the list */
435 {
436 item_tmp.identifier = "Custom";
437 item_tmp.name = IFACE_("Custom");
438 item_tmp.value = -1;
439 RNA_enum_item_add(&item, &totitem, &item_tmp);
440 }
441
442 RNA_enum_item_end(&item, &totitem);
443 *r_free = true;
444
445 return item;
446}
447
448/* ------------------------------------------ */
449
451{
453 int material = RNA_enum_get(op->ptr, "material");
454 float density;
455 bool changed = false;
456
457 /* get density (kg/m^3) to apply */
458 if (material >= 0) {
459 /* get density from table, and store in props for later repeating */
460 if (material >= NUM_RB_MATERIAL_PRESETS) {
461 material = 0;
462 }
463
465 RNA_float_set(op->ptr, "density", density);
466 }
467 else {
468 /* custom - grab from whatever value is set */
469 density = RNA_float_get(op->ptr, "density");
470 }
471
472 /* Apply this to all selected objects (with rigid-bodies). */
473 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
474 if (ob->rigidbody_object) {
475 float volume; /* m^3 */
476 float mass; /* kg */
477
478 /* mass is calculated from the approximate volume of the object,
479 * and the density of the material we're simulating
480 */
482 BKE_rigidbody_calc_volume(ob_eval, &volume);
483 mass = volume * density;
484
485 /* use RNA-system to change the property and perform all necessary changes */
486 PointerRNA ptr = RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object);
487 RNA_float_set(&ptr, "mass", mass);
488
490
491 changed = true;
492 }
493 }
495
496 if (changed) {
497 /* send updates */
499
500 /* done */
501 return OPERATOR_FINISHED;
502 }
503 return OPERATOR_CANCELLED;
504}
505
506static bool mass_calculate_poll_property(const bContext * /*C*/,
507 wmOperator *op,
508 const PropertyRNA *prop)
509{
510 const char *prop_id = RNA_property_identifier(prop);
511
512 /* Disable density input when not using the 'Custom' preset. */
513 if (STREQ(prop_id, "density")) {
514 int material = RNA_enum_get(op->ptr, "material");
515 if (material >= 0) {
517 }
518 else {
520 }
521 }
522
523 return true;
524}
525
527{
528 PropertyRNA *prop;
529
530 /* identifiers */
531 ot->idname = "RIGIDBODY_OT_mass_calculate";
532 ot->name = "Calculate Mass";
533 ot->description = "Automatically calculate mass values for Rigid Body Objects based on volume";
534
535 /* callbacks */
536 ot->invoke = WM_menu_invoke; /* XXX */
540
541 /* flags */
543
544 /* properties */
545 ot->prop = prop = RNA_def_enum(
546 ot->srna,
547 "material",
549 0,
550 "Material Preset",
551 "Type of material that objects are made of (determines material density)");
554
556 "density",
557 1.0,
558 FLT_MIN,
559 FLT_MAX,
560 "Density",
561 "Density value (kg/m^3), allows custom value if the 'Custom' preset is used",
562 1.0f,
563 2500.0f);
564}
565
566/* ********************************************** */
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
API for Blender-side Rigid Body stuff.
void BKE_rigidbody_remove_object(struct Main *bmain, struct Scene *scene, struct Object *ob, bool free_us)
void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol)
bool BKE_rigidbody_add_object(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports)
#define ELEM(...)
#define STREQ(a, b)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
Object is a sort of wrapper for general info.
@ OB_MESH
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
@ RB_SHAPE_TRIMESH
bool ED_operator_object_active_editable(bContext *C)
@ PROP_EDITABLE
Definition RNA_types.hh:207
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:321
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_TRANSFORM
Definition WM_types.hh:423
#define ND_POINTCACHE
Definition WM_types.hh:433
#define ND_SPACE_VIEW3D
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:346
#define NC_SPACE
Definition WM_types.hh:359
Material material
const Depsgraph * depsgraph
Object * context_active_object(const bContext *C)
static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
static const int NUM_RB_MATERIAL_PRESETS
static const EnumPropertyItem * rigidbody_materials_itemf(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
void RIGIDBODY_OT_shape_change(wmOperatorType *ot)
static bool operator_rigidbody_editable_poll(Scene *scene)
static bool ED_operator_rigidbody_active_poll(bContext *C)
static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
void RIGIDBODY_OT_object_add(wmOperatorType *ot)
void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot)
static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
void RIGIDBODY_OT_objects_remove(wmOperatorType *ot)
void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[]
static bool ED_operator_rigidbody_add_poll(bContext *C)
static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
static bool mass_calculate_poll_property(const bContext *, wmOperator *op, const PropertyRNA *prop)
void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
static int rigidbody_objects_remove_exec(bContext *C, wmOperator *)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
const EnumPropertyItem rna_enum_rigidbody_object_type_items[]
const EnumPropertyItem rna_enum_rigidbody_object_shape_items[]
const EnumPropertyItem rna_enum_dummy_DEFAULT_items[]
Definition rna_rna.cc:35
#define FLT_MAX
Definition stdcycles.h:14
const char * identifier
Definition RNA_types.hh:506
const char * name
Definition RNA_types.hh:510
struct RigidBodyOb * rigidbody_object
const char * name
Definition WM_types.hh:990
bool(* poll_property)(const bContext *C, wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1048
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
#define N_(msgid)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)