Merge branch 'blender2.7'
[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
37 #include "DNA_object_types.h"
38 #include "DNA_rigidbody_types.h"
39 #include "DNA_scene_types.h"
40
41 #include "BLI_blenlib.h"
42
43 #include "BLT_translation.h"
44
45 #include "BKE_collection.h"
46 #include "BKE_context.h"
47 #include "BKE_library.h"
48 #include "BKE_main.h"
49 #include "BKE_report.h"
50 #include "BKE_rigidbody.h"
51
52 #include "DEG_depsgraph.h"
53 #include "DEG_depsgraph_build.h"
54 #include "DEG_depsgraph_query.h"
55
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58 #include "RNA_enum_types.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "ED_object.h"
64 #include "ED_physics.h"
65 #include "ED_screen.h"
66
67 #include "physics_intern.h"
68
69 /* ********************************************** */
70 /* Helper API's for RigidBody Objects Editing */
71
72 static bool ED_operator_rigidbody_active_poll(bContext *C)
73 {
74         if (ED_operator_object_active_editable(C)) {
75                 Object *ob = ED_object_active_context(C);
76                 return (ob && ob->rigidbody_object);
77         }
78         else
79                 return 0;
80 }
81
82 static bool ED_operator_rigidbody_add_poll(bContext *C)
83 {
84         if (ED_operator_object_active_editable(C)) {
85                 Object *ob = ED_object_active_context(C);
86                 return (ob && ob->type == OB_MESH);
87         }
88         else
89                 return 0;
90 }
91
92 /* ----------------- */
93
94 bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
95 {
96         RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
97
98         if (ob->type != OB_MESH) {
99                 BKE_report(reports, RPT_ERROR, "Can't add Rigid Body to non mesh object");
100                 return false;
101         }
102
103         /* Add rigid body world and group if they don't exist for convenience */
104         if (rbw == NULL) {
105                 rbw = BKE_rigidbody_create_world(scene);
106                 if (rbw == NULL) {
107                         BKE_report(reports, RPT_ERROR, "Can't create Rigid Body world");
108                         return false;
109                 }
110                 BKE_rigidbody_validate_sim_world(scene, rbw, false);
111                 scene->rigidbody_world = rbw;
112         }
113         if (rbw->group == NULL) {
114                 rbw->group = BKE_collection_add(bmain, NULL, "RigidBodyWorld");
115                 id_fake_user_set(&rbw->group->id);
116         }
117
118         /* make rigidbody object settings */
119         if (ob->rigidbody_object == NULL) {
120                 ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, type);
121         }
122         ob->rigidbody_object->type = type;
123         ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_VALIDATE;
124
125         /* add object to rigid body group */
126         BKE_collection_object_add(bmain, rbw->group, ob);
127
128         DEG_relations_tag_update(bmain);
129         DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
130         DEG_id_tag_update(&rbw->group->id, ID_RECALC_COPY_ON_WRITE);
131
132         return true;
133 }
134
135 void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
136 {
137         BKE_rigidbody_remove_object(bmain, scene, ob);
138
139         DEG_relations_tag_update(bmain);
140         DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
141 }
142
143 /* ********************************************** */
144 /* Active Object Add/Remove Operators */
145
146 /* ************ Add Rigid Body ************** */
147
148 static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
149 {
150         Main *bmain = CTX_data_main(C);
151         Scene *scene = CTX_data_scene(C);
152         Object *ob = ED_object_active_context(C);
153         int type = RNA_enum_get(op->ptr, "type");
154         bool changed;
155
156         /* apply to active object */
157         changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
158
159         if (changed) {
160                 /* send updates */
161                 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
162                 WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
163
164                 /* done */
165                 return OPERATOR_FINISHED;
166         }
167         else {
168                 return OPERATOR_CANCELLED;
169         }
170 }
171
172 void RIGIDBODY_OT_object_add(wmOperatorType *ot)
173 {
174         /* identifiers */
175         ot->idname = "RIGIDBODY_OT_object_add";
176         ot->name = "Add Rigid Body";
177         ot->description = "Add active object as Rigid Body";
178
179         /* callbacks */
180         ot->exec = rigidbody_object_add_exec;
181         ot->poll = ED_operator_rigidbody_add_poll;
182
183         /* flags */
184         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
185
186         /* properties */
187         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_rigidbody_object_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
188 }
189
190 /* ************ Remove Rigid Body ************** */
191
192 static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
193 {
194         Main *bmain = CTX_data_main(C);
195         Scene *scene = CTX_data_scene(C);
196         Object *ob = ED_object_active_context(C);
197         bool changed = false;
198
199         /* apply to active object */
200         if (!ELEM(NULL, ob, ob->rigidbody_object)) {
201                 ED_rigidbody_object_remove(bmain, scene, ob);
202                 changed = true;
203         }
204
205         if (changed) {
206                 /* send updates */
207                 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
208                 WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
209
210                 /* done */
211                 return OPERATOR_FINISHED;
212         }
213         else {
214                 BKE_report(op->reports, RPT_ERROR, "Object has no Rigid Body settings to remove");
215                 return OPERATOR_CANCELLED;
216         }
217 }
218
219 void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
220 {
221         /* identifiers */
222         ot->idname = "RIGIDBODY_OT_object_remove";
223         ot->name = "Remove Rigid Body";
224         ot->description = "Remove Rigid Body settings from Object";
225
226         /* callbacks */
227         ot->exec = rigidbody_object_remove_exec;
228         ot->poll = ED_operator_rigidbody_active_poll;
229
230         /* flags */
231         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
232 }
233
234 /* ********************************************** */
235 /* Selected Object Add/Remove Operators */
236
237 /* ************ Add Rigid Bodies ************** */
238
239 static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
240 {
241         Main *bmain = CTX_data_main(C);
242         Scene *scene = CTX_data_scene(C);
243         int type = RNA_enum_get(op->ptr, "type");
244         bool changed = false;
245
246         /* create rigid body objects and add them to the world's group */
247         CTX_DATA_BEGIN(C, Object *, ob, selected_objects) {
248                 changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
249         }
250         CTX_DATA_END;
251
252         if (changed) {
253                 /* send updates */
254                 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
255                 WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
256
257                 /* done */
258                 return OPERATOR_FINISHED;
259         }
260         else {
261                 return OPERATOR_CANCELLED;
262         }
263 }
264
265 void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
266 {
267         /* identifiers */
268         ot->idname = "RIGIDBODY_OT_objects_add";
269         ot->name = "Add Rigid Bodies";
270         ot->description = "Add selected objects as Rigid Bodies";
271
272         /* callbacks */
273         ot->exec = rigidbody_objects_add_exec;
274         ot->poll = ED_operator_rigidbody_add_poll;
275
276         /* flags */
277         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
278
279         /* properties */
280         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_rigidbody_object_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
281 }
282
283 /* ************ Remove Rigid Bodies ************** */
284
285 static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
286 {
287         Main *bmain = CTX_data_main(C);
288         Scene *scene = CTX_data_scene(C);
289         bool changed = false;
290
291         /* apply this to all selected objects... */
292         CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
293         {
294                 if (ob->rigidbody_object) {
295                         ED_rigidbody_object_remove(bmain, scene, ob);
296                         changed = true;
297                 }
298         }
299         CTX_DATA_END;
300
301         if (changed) {
302                 /* send updates */
303                 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
304                 WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
305
306                 /* done */
307                 return OPERATOR_FINISHED;
308         }
309         else {
310                 return OPERATOR_CANCELLED;
311         }
312 }
313
314 void RIGIDBODY_OT_objects_remove(wmOperatorType *ot)
315 {
316         /* identifiers */
317         ot->idname = "RIGIDBODY_OT_objects_remove";
318         ot->name = "Remove Rigid Bodies";
319         ot->description = "Remove selected objects from Rigid Body simulation";
320
321         /* callbacks */
322         ot->exec = rigidbody_objects_remove_exec;
323         ot->poll = ED_operator_scene_editable;
324
325         /* flags */
326         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
327 }
328
329 /* ********************************************** */
330 /* Utility Operators */
331
332 /* ************ Change Collision Shapes ************** */
333
334 static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
335 {
336         int shape = RNA_enum_get(op->ptr, "type");
337         bool changed = false;
338
339         /* apply this to all selected objects... */
340         CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
341         {
342                 if (ob->rigidbody_object) {
343                         PointerRNA ptr;
344
345                         /* use RNA-system to change the property and perform all necessary changes */
346                         RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
347                         RNA_enum_set(&ptr, "collision_shape", shape);
348
349                         DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
350
351                         changed = true;
352                 }
353         }
354         CTX_DATA_END;
355
356         if (changed) {
357                 /* send updates */
358                 WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
359                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
360
361                 /* done */
362                 return OPERATOR_FINISHED;
363         }
364         else {
365                 return OPERATOR_CANCELLED;
366         }
367 }
368
369 void RIGIDBODY_OT_shape_change(wmOperatorType *ot)
370 {
371         /* identifiers */
372         ot->idname = "RIGIDBODY_OT_shape_change";
373         ot->name = "Change Collision Shape";
374         ot->description = "Change collision shapes for selected Rigid Body Objects";
375
376         /* callbacks */
377         ot->invoke = WM_menu_invoke;
378         ot->exec = rigidbody_objects_shape_change_exec;
379         ot->poll = ED_operator_scene_editable;
380
381         /* flags */
382         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
383
384         /* properties */
385         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_rigidbody_object_shape_items, RB_SHAPE_TRIMESH, "Rigid Body Shape", "");
386 }
387
388 /* ************ Calculate Mass ************** */
389
390 /* Entry in material density table */
391 typedef struct rbMaterialDensityItem {
392         const char *name;   /* Name of material */
393         float density;      /* Density (kg/m^3) */
394 } rbMaterialDensityItem;
395
396 /* Preset density values for materials (kg/m^3)
397  * Selected values obtained from:
398  * 1) http://www.jaredzone.info/2010/09/densities.html
399  * 2) http://www.avlandesign.com/density_construction.htm
400  * 3) http://www.avlandesign.com/density_metal.htm
401  */
402 static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[] = {
403         {N_("Air"), 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
404         {N_("Acrylic"), 1400.0f},
405         {N_("Asphalt (Crushed)"), 721.0f},
406         {N_("Bark"), 240.0f},
407         {N_("Beans (Cocoa)"), 593.0f},
408         {N_("Beans (Soy)"), 721.0f},
409         {N_("Brick (Pressed)"), 2400.0f},
410         {N_("Brick (Common)"), 2000.0f},
411         {N_("Brick (Soft)"), 1600.0f},
412         {N_("Brass"), 8216.0f},
413         {N_("Bronze"), 8860.0f},
414         {N_("Carbon (Solid)"), 2146.0f},
415         {N_("Cardboard"), 689.0f},
416         {N_("Cast Iron"), 7150.0f},
417         /* {N_("Cement"), 1442.0f}, */
418         {N_("Chalk (Solid)"), 2499.0f},
419         /* {N_("Coffee (Fresh/Roast)"), ~500}, */
420         {N_("Concrete"), 2320.0f},
421         {N_("Charcoal"), 208.0f},
422         {N_("Cork"), 240.0f},
423         {N_("Copper"), 8933.0f},
424         {N_("Garbage"), 481.0f},
425         {N_("Glass (Broken)"), 1940.0f},
426         {N_("Glass (Solid)"), 2190.0f},
427         {N_("Gold"), 19282.0f},
428         {N_("Granite (Broken)"), 1650.0f},
429         {N_("Granite (Solid)"), 2691.0f},
430         {N_("Gravel"), 2780.0f},
431         {N_("Ice (Crushed)"), 593.0f},
432         {N_("Ice (Solid)"), 919.0f},
433         {N_("Iron"), 7874.0f},
434         {N_("Lead"), 11342.0f},
435         {N_("Limestone (Broken)"), 1554.0f},
436         {N_("Limestone (Solid)"), 2611.0f},
437         {N_("Marble (Broken)"), 1570.0f},
438         {N_("Marble (Solid)"), 2563.0f},
439         {N_("Paper"), 1201.0f},
440         {N_("Peanuts (Shelled)"), 641.0f},
441         {N_("Peanuts (Not Shelled)"), 272.0f},
442         {N_("Plaster"), 849.0f},
443         {N_("Plastic"), 1200.0f},
444         {N_("Polystyrene"), 1050.0f},
445         {N_("Rubber"), 1522.0f},
446         {N_("Silver"), 10501.0f},
447         {N_("Steel"), 7860.0f},
448         {N_("Stone"), 2515.0f},
449         {N_("Stone (Crushed)"), 1602.0f},
450         {N_("Timber"), 610.0f}
451 };
452 static const int NUM_RB_MATERIAL_PRESETS = sizeof(RB_MATERIAL_DENSITY_TABLE) / sizeof(rbMaterialDensityItem);
453
454
455 /* dynamically generate list of items
456  * - Although there is a runtime cost, this has a lower maintenance cost
457  *   in the long run than other two-list solutions...
458  */
459 static const EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
460 {
461         EnumPropertyItem item_tmp = {0};
462         EnumPropertyItem *item = NULL;
463         int totitem = 0;
464         int i = 0;
465
466         /* add each preset to the list */
467         for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) {
468                 rbMaterialDensityItem *preset = &RB_MATERIAL_DENSITY_TABLE[i];
469
470                 item_tmp.identifier = preset->name;
471                 item_tmp.name = IFACE_(preset->name);
472                 item_tmp.value = i;
473                 RNA_enum_item_add(&item, &totitem, &item_tmp);
474         }
475
476         /* add special "custom" entry to the end of the list */
477         {
478                 item_tmp.identifier = "Custom";
479                 item_tmp.name = IFACE_("Custom");
480                 item_tmp.value = -1;
481                 RNA_enum_item_add(&item, &totitem, &item_tmp);
482         }
483
484         RNA_enum_item_end(&item, &totitem);
485         *r_free = true;
486
487         return item;
488 }
489
490 /* ------------------------------------------ */
491
492 static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
493 {
494         Depsgraph *depsgraph = CTX_data_depsgraph(C);
495         int material = RNA_enum_get(op->ptr, "material");
496         float density;
497         bool changed = false;
498
499         /* get density (kg/m^3) to apply */
500         if (material >= 0) {
501                 /* get density from table, and store in props for later repeating */
502                 if (material >= NUM_RB_MATERIAL_PRESETS)
503                         material = 0;
504
505                 density = RB_MATERIAL_DENSITY_TABLE[material].density;
506                 RNA_float_set(op->ptr, "density", density);
507         }
508         else {
509                 /* custom - grab from whatever value is set */
510                 density = RNA_float_get(op->ptr, "density");
511         }
512
513         /* apply this to all selected objects (with rigidbodies)... */
514         CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
515         {
516                 if (ob->rigidbody_object) {
517                         PointerRNA ptr;
518
519                         float volume; /* m^3 */
520                         float mass;   /* kg */
521
522                         /* mass is calculated from the approximate volume of the object,
523                          * and the density of the material we're simulating
524                          */
525                         Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
526                         BKE_rigidbody_calc_volume(ob_eval, &volume);
527                         mass = volume * density;
528
529                         /* use RNA-system to change the property and perform all necessary changes */
530                         RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
531                         RNA_float_set(&ptr, "mass", mass);
532
533                         DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
534
535                         changed = true;
536                 }
537         }
538         CTX_DATA_END;
539
540         if (changed) {
541                 /* send updates */
542                 WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
543
544                 /* done */
545                 return OPERATOR_FINISHED;
546         }
547         else {
548                 return OPERATOR_CANCELLED;
549         }
550 }
551
552 void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot)
553 {
554         PropertyRNA *prop;
555
556         /* identifiers */
557         ot->idname = "RIGIDBODY_OT_mass_calculate";
558         ot->name = "Calculate Mass";
559         ot->description = "Automatically calculate mass values for Rigid Body Objects based on volume";
560
561         /* callbacks */
562         ot->invoke = WM_menu_invoke; // XXX
563         ot->exec = rigidbody_objects_calc_mass_exec;
564         ot->poll = ED_operator_scene_editable;
565
566         /* flags */
567         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
568
569         /* properties */
570         ot->prop = prop = RNA_def_enum(ot->srna, "material",
571                                        DummyRNA_DEFAULT_items, 0,
572                                        "Material Preset",
573                                        "Type of material that objects are made of (determines material density)");
574         RNA_def_enum_funcs(prop, rigidbody_materials_itemf);
575         RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
576
577         RNA_def_float(ot->srna, "density", 1.0, FLT_MIN, FLT_MAX,
578                       "Density",
579                       "Custom density value (kg/m^3) to use instead of material preset",
580                       1.0f, 2500.0f);
581 }
582
583 /* ********************************************** */