38ed903a161f0bf3d30b32fdc68b31163fabb77b
[blender.git] / source / blender / editors / physics / rigidbody_object.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung, Sergej Reich
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file rigidbody_object.c
29  *  \ingroup editor_physics
30  *  \brief Rigid Body object editing operators
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "DNA_group_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_rigidbody_types.h"
42 #include "DNA_scene_types.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_math.h"
46
47 #include "BKE_context.h"
48 #include "BKE_depsgraph.h"
49 #include "BKE_group.h"
50 #include "BKE_object.h"
51 #include "BKE_report.h"
52 #include "BKE_rigidbody.h"
53
54 #include "RNA_access.h"
55 #include "RNA_define.h"
56 #include "RNA_enum_types.h"
57
58 #include "WM_api.h"
59 #include "WM_types.h"
60
61 #include "ED_physics.h"
62 #include "ED_screen.h"
63
64 #include "physics_intern.h"
65
66 /* ********************************************** */
67 /* Helper API's for RigidBody Objects Editing */
68
69 static int ED_operator_rigidbody_active_poll(bContext *C)
70 {
71         if (ED_operator_object_active_editable(C)) {
72                 Object *ob = CTX_data_active_object(C);
73                 return (ob && ob->rigidbody_object);
74         }
75         else
76                 return 0;
77 }
78
79 static int ED_operator_rigidbody_add_poll(bContext *C)
80 {
81         if (ED_operator_object_active_editable(C)) {
82                 Object *ob = CTX_data_active_object(C);
83                 return (ob && ob->type == OB_MESH);
84         }
85         else
86                 return 0;
87 }
88
89 /* ----------------- */
90
91 void ED_rigidbody_ob_add(wmOperator *op, Scene *scene, Object *ob, int type)
92 {
93         RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
94
95         /* check that object doesn't already belong to the current simulation */
96         if (ob->rigidbody_object) {
97                 BKE_reportf(op->reports, RPT_INFO, "Object '%s' already has a Rigid Body", ob->id.name + 2);
98                 return;
99         }
100         if (ob->type != OB_MESH) {
101                 BKE_report(op->reports, RPT_ERROR, "Can't add Rigid Body to non mesh object");
102                 return;
103         }
104         if (((Mesh *)ob->data)->totpoly == 0) {
105                 BKE_report(op->reports, RPT_ERROR, "Can't create Rigid Body from mesh with no polygons");
106                 return;
107         }
108
109         /* Add rigid body world and group if they don't exist for convenience */
110         if (rbw == NULL) {
111                 rbw = BKE_rigidbody_create_world(scene);
112                 BKE_rigidbody_validate_sim_world(scene, rbw, false);
113                 scene->rigidbody_world = rbw;
114         }
115         if (rbw->group == NULL) {
116                 rbw->group = add_group("RigidBodyWorld");
117         }
118
119         /* make rigidbody object settings */
120         ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, type);
121         ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_VALIDATE;
122
123         /* add object to rigid body group */
124         add_to_group(rbw->group, ob, scene, NULL);
125 }
126
127 void ED_rigidbody_ob_remove(Scene *scene, Object *ob)
128 {
129         RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
130
131         BKE_rigidbody_remove_object(scene, ob);
132         if (rbw)
133                 rem_from_group(rbw->group, ob, scene, NULL);
134
135         DAG_id_tag_update(&ob->id, OB_RECALC_OB);
136 }
137
138 /* ********************************************** */
139 /* Active Object Add/Remove Operators */
140
141 /* ************ Add Rigid Body ************** */
142
143 static int rigidbody_ob_add_exec(bContext *C, wmOperator *op)
144 {
145         Scene *scene = CTX_data_scene(C);
146         Object *ob = (scene) ? OBACT : NULL;
147         int type = RNA_enum_get(op->ptr, "type");
148
149         /* apply to active object */
150         ED_rigidbody_ob_add(op, scene, ob, type);
151
152         /* send updates */
153         DAG_ids_flush_update(CTX_data_main(C), 0);
154
155         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
156         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
157
158         /* done */
159         return OPERATOR_FINISHED;
160 }
161
162 void RIGIDBODY_OT_object_add(wmOperatorType *ot)
163 {
164         /* identifiers */
165         ot->idname = "RIGIDBODY_OT_object_add";
166         ot->name = "Add Rigid Body";
167         ot->description = "Add active object as Rigid Body";
168
169         /* callbacks */
170         ot->exec = rigidbody_ob_add_exec;
171         ot->poll = ED_operator_rigidbody_add_poll;
172
173         /* flags */
174         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
175
176         /* properties */
177         ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_ob_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
178 }
179
180 /* ************ Remove Rigid Body ************** */
181
182 static int rigidbody_ob_remove_exec(bContext *C, wmOperator *op)
183 {
184         Scene *scene = CTX_data_scene(C);
185         Object *ob = (scene) ? OBACT : NULL;
186
187         /* sanity checks */
188         if (scene == NULL)
189                 return OPERATOR_CANCELLED;
190
191         /* apply to active object */
192         if (ELEM(NULL, ob, ob->rigidbody_object)) {
193                 BKE_report(op->reports, RPT_ERROR, "Object has no Rigid Body settings to remove");
194                 return OPERATOR_CANCELLED;
195         }
196         else
197                 ED_rigidbody_ob_remove(scene, ob);
198
199         /* send updates */
200         DAG_ids_flush_update(CTX_data_main(C), 0);
201
202         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
203         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
204
205         /* done */
206         return OPERATOR_FINISHED;
207 }
208
209 void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
210 {
211         /* identifiers */
212         ot->idname = "RIGIDBODY_OT_object_remove";
213         ot->name = "Remove Rigid Body";
214         ot->description = "Remove Rigid Body settings from Object";
215
216         /* callbacks */
217         ot->exec = rigidbody_ob_remove_exec;
218         ot->poll = ED_operator_rigidbody_active_poll;
219
220         /* flags */
221         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
222 }
223
224 /* ********************************************** */
225 /* Selected Object Add/Remove Operators */
226
227 /* ************ Add Rigid Bodies ************** */
228
229 static int rigidbody_obs_add_exec(bContext *C, wmOperator *op)
230 {
231         Scene *scene = CTX_data_scene(C);
232         int type = RNA_enum_get(op->ptr, "type");
233
234         /* sanity check */
235         if (scene == NULL) {
236                 BKE_report(op->reports, RPT_ERROR, "No Scene to add Rigid Bodies to");
237                 return OPERATOR_CANCELLED;
238         }
239         /* create rigid body objects and add them to the world's group */
240         CTX_DATA_BEGIN(C, Object *, ob, selected_objects) {
241                 ED_rigidbody_ob_add(op, scene, ob, type);
242         }
243         CTX_DATA_END;
244
245         /* send updates */
246         DAG_ids_flush_update(CTX_data_main(C), 0);
247
248         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
249         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
250
251         /* done */
252         return OPERATOR_FINISHED;
253 }
254
255 void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
256 {
257         /* identifiers */
258         ot->idname = "RIGIDBODY_OT_objects_add";
259         ot->name = "Add Rigid Bodies";
260         ot->description = "Add selected objects as Rigid Bodies";
261
262         /* callbacks */
263         ot->exec = rigidbody_obs_add_exec;
264         ot->poll = ED_operator_rigidbody_add_poll;
265
266         /* flags */
267         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
268
269         /* properties */
270         ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_ob_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
271 }
272
273 /* ************ Remove Rigid Bodies ************** */
274
275 static int rigidbody_obs_remove_exec(bContext *C, wmOperator *UNUSED(op))
276 {
277         Scene *scene = CTX_data_scene(C);
278
279         /* sanity checks */
280         if (scene == NULL)
281                 return OPERATOR_CANCELLED;
282
283         /* apply this to all selected objects... */
284         CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
285         {
286                 if (ob->rigidbody_object) {
287                         ED_rigidbody_ob_remove(scene, ob);
288                 }
289         }
290         CTX_DATA_END;
291
292         /* send updates */
293         DAG_ids_flush_update(CTX_data_main(C), 0);
294
295         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
296         WM_event_add_notifier(C, NC_GROUP | NA_EDITED, NULL);
297
298         /* done */
299         return OPERATOR_FINISHED;
300 }
301
302 void RIGIDBODY_OT_objects_remove(wmOperatorType *ot)
303 {
304         /* identifiers */
305         ot->idname = "RIGIDBODY_OT_objects_remove";
306         ot->name = "Remove Rigid Bodies";
307         ot->description = "Remove selected objects from Rigid Body simulation";
308
309         /* callbacks */
310         ot->exec = rigidbody_obs_remove_exec;
311         ot->poll = ED_operator_rigidbody_active_poll;
312
313         /* flags */
314         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
315 }
316
317 /* ********************************************** */
318 /* Utility Operators */
319
320 /* ************ Change Collision Shapes ************** */
321
322 static int rigidbody_obs_shape_change_exec(bContext *C, wmOperator *op)
323 {
324         Scene *scene = CTX_data_scene(C);
325         int shape = RNA_enum_get(op->ptr, "type");
326
327         /* sanity checks */
328         if (scene == NULL)
329                 return OPERATOR_CANCELLED;
330
331         /* apply this to all selected objects... */
332         CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
333         {
334                 if (ob->rigidbody_object) {
335                         PointerRNA ptr;
336
337                         /* use RNA-system to change the property and perform all necessary changes */
338                         RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
339                         RNA_enum_set(&ptr, "collision_shape", shape);
340                 }
341         }
342         CTX_DATA_END;
343
344         /* send updates */
345         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); // XXX: wrong notifiers for now, but these also do the job...
346
347         /* done */
348         return OPERATOR_FINISHED;
349 }
350
351 void RIGIDBODY_OT_shape_change(wmOperatorType *ot)
352 {
353         /* identifiers */
354         ot->idname = "RIGIDBODY_OT_shape_change";
355         ot->name = "Change Collision Shape";
356         ot->description = "Change collision shapes for selected Rigid Body Objects";
357
358         /* callbacks */
359         ot->invoke = WM_menu_invoke;
360         ot->exec = rigidbody_obs_shape_change_exec;
361         ot->poll = ED_operator_rigidbody_active_poll;
362
363         /* flags */
364         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
365
366         /* properties */
367         ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_ob_shape_items, RB_SHAPE_TRIMESH, "Rigid Body Shape", "");
368 }
369
370 /* ************ Calculate Mass ************** */
371
372 /* Entry in material density table */
373 typedef struct rbMaterialDensityItem {
374         const char *name;   /* Name of material */
375         float density;      /* Density (kg/m^3) */
376 } rbMaterialDensityItem;
377
378 /* Preset density values for materials (kg/m^3)
379  * Selected values obtained from:
380  * 1) http://www.jaredzone.info/2010/09/densities.html
381  * 2) http://www.avlandesign.com/density_construction.htm
382  * 3) http://www.avlandesign.com/density_metal.htm
383  */
384 static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[] = {
385         {"Air", 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
386         {"Acrylic", 1400.0f},
387         {"Asphalt (Crushed)", 721.0f},
388         {"Bark", 240.0f},
389         {"Beans (Cocoa)", 593.0f},
390         {"Beans (Soy)", 721.0f},
391         {"Brick (Pressed)", 2400.0f},
392         {"Brick (Common)", 2000.0f},
393         {"Brick (Soft)", 1600.0f},
394         {"Brass", 8216.0f},
395         {"Bronze", 8860.0f},
396         {"Carbon (Solid)", 2146.0f},
397         {"Cardboard", 689.0f},
398         {"Cast Iron", 7150.0f},
399         //{"Cement", 1442.0f},
400         {"Chalk (Solid)", 2499.0f},
401         //{"Coffee (Fresh/Roast)", ~500},
402         {"Concrete", 2320.0f},
403         {"Charcoal", 208.0f},
404         {"Cork", 240.0f},
405         {"Copper", 8933.0f},
406         {"Garbage", 481.0f},
407         {"Glass (Broken)", 1940.0f},
408         {"Glass (Solid)", 2190.0f},
409         {"Gold", 19282.0f},
410         {"Granite (Broken)", 1650.0f},
411         {"Granite (Solid)", 2691.0f},
412         {"Gravel", 2780.0f},
413         {"Ice (Crushed)", 593.0f},
414         {"Ice (Solid)", 919.0f},
415         {"Iron", 7874.0f},
416         {"Lead", 11342.0f},
417         {"Limestone (Broken)", 1554.0f},
418         {"Limestone (Solid)", 2611.0f},
419         {"Marble (Broken)", 1570.0f},
420         {"Marble (Solid)", 2563.0f},
421         {"Paper", 1201.0f},
422         {"Peanuts (Shelled)", 641.0f},
423         {"Peanuts (Not Shelled)", 272.0f},
424         {"Plaster", 849.0f},
425         {"Plastic", 1200.0f},
426         {"Polystyrene", 1050.0f},
427         {"Rubber", 1522.0f},
428         {"Silver", 10501.0f},
429         {"Steel", 7860.0f},
430         {"Stone", 2515.0f},
431         {"Stone (Crushed)", 1602.0f},
432         {"Timber", 610.0f}
433 };
434 static const int NUM_RB_MATERIAL_PRESETS = sizeof(RB_MATERIAL_DENSITY_TABLE) / sizeof(rbMaterialDensityItem);
435
436
437 /* dynamically generate list of items
438  * - Although there is a runtime cost, this has a lower maintenance cost
439  *       in the long run than other two-list solutions...
440  */
441 static EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
442 {
443         EnumPropertyItem item_tmp = {0};
444         EnumPropertyItem *item = NULL;
445         int totitem = 0;
446         int i = 0;
447
448         /* add each preset to the list */
449         for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) {
450                 rbMaterialDensityItem *preset = &RB_MATERIAL_DENSITY_TABLE[i];
451
452                 item_tmp.identifier = item_tmp.name = preset->name;
453                 item_tmp.value = i;
454                 RNA_enum_item_add(&item, &totitem, &item_tmp);
455         }
456
457         /* add special "custom" entry to the end of the list */
458         {
459                 item_tmp.identifier = item_tmp.name = "Custom";
460                 item_tmp.value = -1;
461                 RNA_enum_item_add(&item, &totitem, &item_tmp);
462         }
463
464         RNA_enum_item_end(&item, &totitem);
465         *free = 1;
466
467         return item;
468 }
469
470 /* ------------------------------------------ */
471
472 /* helper function to calculate volume of rigidbody object */
473 // TODO: allow a parameter to specify method used to calculate this?
474 static float calc_rigidbody_ob_volume(Object *ob)
475 {
476         RigidBodyOb *rbo = ob->rigidbody_object;
477
478         float size[3]  = {1.0f, 1.0f, 1.0f};
479         float radius = 1.0f;
480         float height = 1.0f;
481
482         float volume = 0.0f;
483
484         /* if automatically determining dimensions, use the Object's boundbox
485          *      - assume that all quadrics are standing upright on local z-axis
486          *      - assume even distribution of mass around the Object's pivot
487          *        (i.e. Object pivot is centralised in boundbox)
488          *      - boundbox gives full width
489          */
490         // XXX: all dimensions are auto-determined now... later can add stored settings for this
491         BKE_object_dimensions_get(ob, size);
492
493         if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
494                 /* take radius as largest x/y dimension, and height as z-dimension */
495                 radius = MAX2(size[0], size[1]) * 0.5f;
496                 height = size[2];
497         }
498         else if (rbo->shape == RB_SHAPE_SPHERE) {
499                 /* take radius to the the largest dimension to try and encompass everything */
500                 radius = max_fff(size[0], size[1], size[2]) * 0.5f;
501         }
502
503         /* calculate volume as appropriate  */
504         switch (rbo->shape) {
505                 case RB_SHAPE_BOX:
506                         volume = size[0] * size[1] * size[2];
507                         break;
508
509                 case RB_SHAPE_SPHERE:
510                         volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius;
511                         break;
512
513                 /* for now, assume that capsule is close enough to a cylinder... */
514                 case RB_SHAPE_CAPSULE:
515                 case RB_SHAPE_CYLINDER:
516                         volume = (float)M_PI * radius * radius * height;
517                         break;
518
519                 case RB_SHAPE_CONE:
520                         volume = (float)M_PI / 3.0f * radius * radius * height;
521                         break;
522
523                 /* for now, all mesh shapes are just treated as boxes...
524                  * NOTE: this may overestimate the volume, but other methods are overkill
525                  */
526                 case RB_SHAPE_CONVEXH:
527                 case RB_SHAPE_TRIMESH:
528                         volume = size[0] * size[1] * size[2];
529                         break;
530
531 #if 0 // XXX: not defined yet
532                 case RB_SHAPE_COMPOUND:
533                         volume = 0.0f;
534                         break;
535 #endif
536         }
537
538         /* return the volume calculated */
539         return volume;
540 }
541
542 /* ------------------------------------------ */
543
544 static int rigidbody_obs_calc_mass_exec(bContext *C, wmOperator *op)
545 {
546         Scene *scene = CTX_data_scene(C);
547         int material = RNA_enum_get(op->ptr, "material");
548         float density;
549
550         /* sanity checks */
551         if (scene == NULL)
552                 return OPERATOR_CANCELLED;
553
554         /* get density (kg/m^3) to apply */
555         if (material >= 0) {
556                 /* get density from table, and store in props for later repeating */
557                 if (material >= NUM_RB_MATERIAL_PRESETS)
558                         material = 0;
559
560                 density = RB_MATERIAL_DENSITY_TABLE[material].density;
561                 RNA_float_set(op->ptr, "density", density);
562         }
563         else {
564                 /* custom - grab from whatever value is set */
565                 density = RNA_float_get(op->ptr, "density");
566         }
567
568         /* apply this to all selected objects (with rigidbodies)... */
569         CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
570         {
571                 if (ob->rigidbody_object) {
572                         PointerRNA ptr;
573
574                         float volume; /* m^3 */
575                         float mass;   /* kg */
576
577                         /* mass is calculated from the approximate volume of the object,
578                          * and the density of the material we're simulating
579                          */
580                         volume = calc_rigidbody_ob_volume(ob);
581                         mass = volume * density;
582
583                         /* use RNA-system to change the property and perform all necessary changes */
584                         RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
585                         RNA_float_set(&ptr, "mass", mass);
586                 }
587         }
588         CTX_DATA_END;
589
590         /* send updates */
591         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); // XXX: wrong notifiers for now, but these also do the job...
592
593         /* done */
594         return OPERATOR_FINISHED;
595 }
596
597 void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot)
598 {
599         PropertyRNA *prop;
600
601         /* identifiers */
602         ot->idname = "RIGIDBODY_OT_mass_calculate";
603         ot->name = "Calculate Mass";
604         ot->description = "Automatically calculate mass values for Rigid Body Objects based on volume";
605
606         /* callbacks */
607         ot->invoke = WM_menu_invoke; // XXX
608         ot->exec = rigidbody_obs_calc_mass_exec;
609         ot->poll = ED_operator_rigidbody_active_poll;
610
611         /* flags */
612         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
613
614         /* properties */
615         ot->prop = prop = RNA_def_enum(ot->srna, "material",
616                                        DummyRNA_DEFAULT_items, 0,
617                                        "Material Preset",
618                                        "Type of material that objects are made of (determines material density)");
619         RNA_def_enum_funcs(prop, rigidbody_materials_itemf);
620
621         RNA_def_float(ot->srna, "density", 1.0, FLT_MIN, FLT_MAX,
622                       "Density",
623                       "Custom density value (kg/m^3) to use instead of material preset",
624                       1.0f, 2500.0f);
625 }
626
627 /* ********************************************** */