Note that `BKE_library.h`/`library.c` were renamed to `BKE_lib_id.h`/`lib_id.c` to avoid having a too generic name here. Part of T72604.
		
			
				
	
	
		
			579 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			579 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software Foundation,
 | |
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | |
|  *
 | |
|  * The Original Code is Copyright (C) 2013 Blender Foundation
 | |
|  * All rights reserved.
 | |
|  */
 | |
| 
 | |
| /** \file
 | |
|  * \ingroup editor_physics
 | |
|  * \brief Rigid Body object editing operators
 | |
|  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "DNA_object_types.h"
 | |
| #include "DNA_rigidbody_types.h"
 | |
| #include "DNA_scene_types.h"
 | |
| 
 | |
| #include "BLI_blenlib.h"
 | |
| 
 | |
| #include "BLT_translation.h"
 | |
| 
 | |
| #include "BKE_collection.h"
 | |
| #include "BKE_context.h"
 | |
| #include "BKE_lib_id.h"
 | |
| #include "BKE_main.h"
 | |
| #include "BKE_report.h"
 | |
| #include "BKE_rigidbody.h"
 | |
| 
 | |
| #include "DEG_depsgraph.h"
 | |
| #include "DEG_depsgraph_build.h"
 | |
| #include "DEG_depsgraph_query.h"
 | |
| 
 | |
| #include "RNA_access.h"
 | |
| #include "RNA_define.h"
 | |
| #include "RNA_enum_types.h"
 | |
| 
 | |
| #include "WM_api.h"
 | |
| #include "WM_types.h"
 | |
| 
 | |
| #include "ED_object.h"
 | |
| #include "ED_physics.h"
 | |
| #include "ED_screen.h"
 | |
| 
 | |
| #include "physics_intern.h"
 | |
| 
 | |
| /* ********************************************** */
 | |
| /* Helper API's for RigidBody Objects Editing */
 | |
| 
 | |
| static bool ED_operator_rigidbody_active_poll(bContext *C)
 | |
| {
 | |
|   Scene *scene = CTX_data_scene(C);
 | |
|   if (scene == NULL || ID_IS_LINKED(&scene->id) ||
 | |
|       (scene->rigidbody_world != NULL && scene->rigidbody_world->group != NULL &&
 | |
|        ID_IS_LINKED(&scene->rigidbody_world->group->id))) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (ED_operator_object_active_editable(C)) {
 | |
|     Object *ob = ED_object_active_context(C);
 | |
|     return (ob && ob->rigidbody_object);
 | |
|   }
 | |
|   else {
 | |
|     return 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static bool ED_operator_rigidbody_add_poll(bContext *C)
 | |
| {
 | |
|   Scene *scene = CTX_data_scene(C);
 | |
|   if (scene == NULL || ID_IS_LINKED(&scene->id) ||
 | |
|       (scene->rigidbody_world != NULL && scene->rigidbody_world->group != NULL &&
 | |
|        ID_IS_LINKED(&scene->rigidbody_world->group->id))) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (ED_operator_object_active_editable(C)) {
 | |
|     Object *ob = ED_object_active_context(C);
 | |
|     return (ob && ob->type == OB_MESH);
 | |
|   }
 | |
|   else {
 | |
|     return false;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* ----------------- */
 | |
| 
 | |
| bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
 | |
| {
 | |
|   return BKE_rigidbody_add_object(bmain, scene, ob, type, reports);
 | |
| }
 | |
| 
 | |
| void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
 | |
| {
 | |
|   BKE_rigidbody_remove_object(bmain, scene, ob, false);
 | |
| 
 | |
|   DEG_relations_tag_update(bmain);
 | |
|   DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
 | |
| }
 | |
| 
 | |
| /* ********************************************** */
 | |
| /* Active Object Add/Remove Operators */
 | |
| 
 | |
| /* ************ Add Rigid Body ************** */
 | |
| 
 | |
| static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
|   Main *bmain = CTX_data_main(C);
 | |
|   Scene *scene = CTX_data_scene(C);
 | |
|   Object *ob = ED_object_active_context(C);
 | |
|   int type = RNA_enum_get(op->ptr, "type");
 | |
|   bool changed;
 | |
| 
 | |
|   /* apply to active object */
 | |
|   changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
 | |
| 
 | |
|   if (changed) {
 | |
|     /* send updates */
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
 | |
| 
 | |
|     /* done */
 | |
|     return OPERATOR_FINISHED;
 | |
|   }
 | |
|   else {
 | |
|     return OPERATOR_CANCELLED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RIGIDBODY_OT_object_add(wmOperatorType *ot)
 | |
| {
 | |
|   /* identifiers */
 | |
|   ot->idname = "RIGIDBODY_OT_object_add";
 | |
|   ot->name = "Add Rigid Body";
 | |
|   ot->description = "Add active object as Rigid Body";
 | |
| 
 | |
|   /* callbacks */
 | |
|   ot->exec = rigidbody_object_add_exec;
 | |
|   ot->poll = ED_operator_rigidbody_add_poll;
 | |
| 
 | |
|   /* flags */
 | |
|   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 | |
| 
 | |
|   /* properties */
 | |
|   ot->prop = RNA_def_enum(ot->srna,
 | |
|                           "type",
 | |
|                           rna_enum_rigidbody_object_type_items,
 | |
|                           RBO_TYPE_ACTIVE,
 | |
|                           "Rigid Body Type",
 | |
|                           "");
 | |
| }
 | |
| 
 | |
| /* ************ Remove Rigid Body ************** */
 | |
| 
 | |
| static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
|   Main *bmain = CTX_data_main(C);
 | |
|   Scene *scene = CTX_data_scene(C);
 | |
|   Object *ob = ED_object_active_context(C);
 | |
|   bool changed = false;
 | |
| 
 | |
|   /* apply to active object */
 | |
|   if (!ELEM(NULL, ob, ob->rigidbody_object)) {
 | |
|     ED_rigidbody_object_remove(bmain, scene, ob);
 | |
|     changed = true;
 | |
|   }
 | |
| 
 | |
|   if (changed) {
 | |
|     /* send updates */
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
 | |
| 
 | |
|     /* done */
 | |
|     return OPERATOR_FINISHED;
 | |
|   }
 | |
|   else {
 | |
|     BKE_report(op->reports, RPT_ERROR, "Object has no Rigid Body settings to remove");
 | |
|     return OPERATOR_CANCELLED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
 | |
| {
 | |
|   /* identifiers */
 | |
|   ot->idname = "RIGIDBODY_OT_object_remove";
 | |
|   ot->name = "Remove Rigid Body";
 | |
|   ot->description = "Remove Rigid Body settings from Object";
 | |
| 
 | |
|   /* callbacks */
 | |
|   ot->exec = rigidbody_object_remove_exec;
 | |
|   ot->poll = ED_operator_rigidbody_active_poll;
 | |
| 
 | |
|   /* flags */
 | |
|   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 | |
| }
 | |
| 
 | |
| /* ********************************************** */
 | |
| /* Selected Object Add/Remove Operators */
 | |
| 
 | |
| /* ************ Add Rigid Bodies ************** */
 | |
| 
 | |
| static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
|   Main *bmain = CTX_data_main(C);
 | |
|   Scene *scene = CTX_data_scene(C);
 | |
|   int type = RNA_enum_get(op->ptr, "type");
 | |
|   bool changed = false;
 | |
| 
 | |
|   /* create rigid body objects and add them to the world's group */
 | |
|   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
 | |
|     changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
 | |
|   }
 | |
|   CTX_DATA_END;
 | |
| 
 | |
|   if (changed) {
 | |
|     /* send updates */
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
 | |
| 
 | |
|     /* done */
 | |
|     return OPERATOR_FINISHED;
 | |
|   }
 | |
|   else {
 | |
|     return OPERATOR_CANCELLED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
 | |
| {
 | |
|   /* identifiers */
 | |
|   ot->idname = "RIGIDBODY_OT_objects_add";
 | |
|   ot->name = "Add Rigid Bodies";
 | |
|   ot->description = "Add selected objects as Rigid Bodies";
 | |
| 
 | |
|   /* callbacks */
 | |
|   ot->exec = rigidbody_objects_add_exec;
 | |
|   ot->poll = ED_operator_rigidbody_add_poll;
 | |
| 
 | |
|   /* flags */
 | |
|   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 | |
| 
 | |
|   /* properties */
 | |
|   ot->prop = RNA_def_enum(ot->srna,
 | |
|                           "type",
 | |
|                           rna_enum_rigidbody_object_type_items,
 | |
|                           RBO_TYPE_ACTIVE,
 | |
|                           "Rigid Body Type",
 | |
|                           "");
 | |
| }
 | |
| 
 | |
| /* ************ Remove Rigid Bodies ************** */
 | |
| 
 | |
| static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
 | |
| {
 | |
|   Main *bmain = CTX_data_main(C);
 | |
|   Scene *scene = CTX_data_scene(C);
 | |
|   bool changed = false;
 | |
| 
 | |
|   /* apply this to all selected objects... */
 | |
|   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
 | |
|     if (ob->rigidbody_object) {
 | |
|       ED_rigidbody_object_remove(bmain, scene, ob);
 | |
|       changed = true;
 | |
|     }
 | |
|   }
 | |
|   CTX_DATA_END;
 | |
| 
 | |
|   if (changed) {
 | |
|     /* send updates */
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
 | |
| 
 | |
|     /* done */
 | |
|     return OPERATOR_FINISHED;
 | |
|   }
 | |
|   else {
 | |
|     return OPERATOR_CANCELLED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RIGIDBODY_OT_objects_remove(wmOperatorType *ot)
 | |
| {
 | |
|   /* identifiers */
 | |
|   ot->idname = "RIGIDBODY_OT_objects_remove";
 | |
|   ot->name = "Remove Rigid Bodies";
 | |
|   ot->description = "Remove selected objects from Rigid Body simulation";
 | |
| 
 | |
|   /* callbacks */
 | |
|   ot->exec = rigidbody_objects_remove_exec;
 | |
|   ot->poll = ED_operator_rigidbody_active_poll;
 | |
| 
 | |
|   /* flags */
 | |
|   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 | |
| }
 | |
| 
 | |
| /* ********************************************** */
 | |
| /* Utility Operators */
 | |
| 
 | |
| /* ************ Change Collision Shapes ************** */
 | |
| 
 | |
| static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
|   int shape = RNA_enum_get(op->ptr, "type");
 | |
|   bool changed = false;
 | |
| 
 | |
|   /* apply this to all selected objects... */
 | |
|   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
 | |
|     if (ob->rigidbody_object) {
 | |
|       PointerRNA ptr;
 | |
| 
 | |
|       /* use RNA-system to change the property and perform all necessary changes */
 | |
|       RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
 | |
|       RNA_enum_set(&ptr, "collision_shape", shape);
 | |
| 
 | |
|       DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
 | |
| 
 | |
|       changed = true;
 | |
|     }
 | |
|   }
 | |
|   CTX_DATA_END;
 | |
| 
 | |
|   if (changed) {
 | |
|     /* send updates */
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
 | |
|     WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 | |
| 
 | |
|     /* done */
 | |
|     return OPERATOR_FINISHED;
 | |
|   }
 | |
|   else {
 | |
|     return OPERATOR_CANCELLED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RIGIDBODY_OT_shape_change(wmOperatorType *ot)
 | |
| {
 | |
|   /* identifiers */
 | |
|   ot->idname = "RIGIDBODY_OT_shape_change";
 | |
|   ot->name = "Change Collision Shape";
 | |
|   ot->description = "Change collision shapes for selected Rigid Body Objects";
 | |
| 
 | |
|   /* callbacks */
 | |
|   ot->invoke = WM_menu_invoke;
 | |
|   ot->exec = rigidbody_objects_shape_change_exec;
 | |
|   ot->poll = ED_operator_rigidbody_active_poll;
 | |
| 
 | |
|   /* flags */
 | |
|   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 | |
| 
 | |
|   /* properties */
 | |
|   ot->prop = RNA_def_enum(ot->srna,
 | |
|                           "type",
 | |
|                           rna_enum_rigidbody_object_shape_items,
 | |
|                           RB_SHAPE_TRIMESH,
 | |
|                           "Rigid Body Shape",
 | |
|                           "");
 | |
| }
 | |
| 
 | |
| /* ************ Calculate Mass ************** */
 | |
| 
 | |
| /* Entry in material density table */
 | |
| typedef struct rbMaterialDensityItem {
 | |
|   const char *name; /* Name of material */
 | |
|   float density;    /* Density (kg/m^3) */
 | |
| } rbMaterialDensityItem;
 | |
| 
 | |
| /* Preset density values for materials (kg/m^3)
 | |
|  * Selected values obtained from:
 | |
|  * 1) http://www.jaredzone.info/2010/09/densities.html
 | |
|  * 2) http://www.avlandesign.com/density_construction.htm
 | |
|  * 3) http://www.avlandesign.com/density_metal.htm
 | |
|  */
 | |
| static rbMaterialDensityItem RB_MATERIAL_DENSITY_TABLE[] = {
 | |
|     {N_("Air"), 1.0f}, /* not quite; adapted from 1.43 for oxygen for use as default */
 | |
|     {N_("Acrylic"), 1400.0f},
 | |
|     {N_("Asphalt (Crushed)"), 721.0f},
 | |
|     {N_("Bark"), 240.0f},
 | |
|     {N_("Beans (Cocoa)"), 593.0f},
 | |
|     {N_("Beans (Soy)"), 721.0f},
 | |
|     {N_("Brick (Pressed)"), 2400.0f},
 | |
|     {N_("Brick (Common)"), 2000.0f},
 | |
|     {N_("Brick (Soft)"), 1600.0f},
 | |
|     {N_("Brass"), 8216.0f},
 | |
|     {N_("Bronze"), 8860.0f},
 | |
|     {N_("Carbon (Solid)"), 2146.0f},
 | |
|     {N_("Cardboard"), 689.0f},
 | |
|     {N_("Cast Iron"), 7150.0f},
 | |
|     /* {N_("Cement"), 1442.0f}, */
 | |
|     {N_("Chalk (Solid)"), 2499.0f},
 | |
|     /* {N_("Coffee (Fresh/Roast)"), ~500}, */
 | |
|     {N_("Concrete"), 2320.0f},
 | |
|     {N_("Charcoal"), 208.0f},
 | |
|     {N_("Cork"), 240.0f},
 | |
|     {N_("Copper"), 8933.0f},
 | |
|     {N_("Garbage"), 481.0f},
 | |
|     {N_("Glass (Broken)"), 1940.0f},
 | |
|     {N_("Glass (Solid)"), 2190.0f},
 | |
|     {N_("Gold"), 19282.0f},
 | |
|     {N_("Granite (Broken)"), 1650.0f},
 | |
|     {N_("Granite (Solid)"), 2691.0f},
 | |
|     {N_("Gravel"), 2780.0f},
 | |
|     {N_("Ice (Crushed)"), 593.0f},
 | |
|     {N_("Ice (Solid)"), 919.0f},
 | |
|     {N_("Iron"), 7874.0f},
 | |
|     {N_("Lead"), 11342.0f},
 | |
|     {N_("Limestone (Broken)"), 1554.0f},
 | |
|     {N_("Limestone (Solid)"), 2611.0f},
 | |
|     {N_("Marble (Broken)"), 1570.0f},
 | |
|     {N_("Marble (Solid)"), 2563.0f},
 | |
|     {N_("Paper"), 1201.0f},
 | |
|     {N_("Peanuts (Shelled)"), 641.0f},
 | |
|     {N_("Peanuts (Not Shelled)"), 272.0f},
 | |
|     {N_("Plaster"), 849.0f},
 | |
|     {N_("Plastic"), 1200.0f},
 | |
|     {N_("Polystyrene"), 1050.0f},
 | |
|     {N_("Rubber"), 1522.0f},
 | |
|     {N_("Silver"), 10501.0f},
 | |
|     {N_("Steel"), 7860.0f},
 | |
|     {N_("Stone"), 2515.0f},
 | |
|     {N_("Stone (Crushed)"), 1602.0f},
 | |
|     {N_("Timber"), 610.0f},
 | |
| };
 | |
| static const int NUM_RB_MATERIAL_PRESETS = sizeof(RB_MATERIAL_DENSITY_TABLE) /
 | |
|                                            sizeof(rbMaterialDensityItem);
 | |
| 
 | |
| /* dynamically generate list of items
 | |
|  * - Although there is a runtime cost, this has a lower maintenance cost
 | |
|  *   in the long run than other two-list solutions...
 | |
|  */
 | |
| static const EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C),
 | |
|                                                          PointerRNA *UNUSED(ptr),
 | |
|                                                          PropertyRNA *UNUSED(prop),
 | |
|                                                          bool *r_free)
 | |
| {
 | |
|   EnumPropertyItem item_tmp = {0};
 | |
|   EnumPropertyItem *item = NULL;
 | |
|   int totitem = 0;
 | |
|   int i = 0;
 | |
| 
 | |
|   /* add each preset to the list */
 | |
|   for (i = 0; i < NUM_RB_MATERIAL_PRESETS; i++) {
 | |
|     rbMaterialDensityItem *preset = &RB_MATERIAL_DENSITY_TABLE[i];
 | |
| 
 | |
|     item_tmp.identifier = preset->name;
 | |
|     item_tmp.name = IFACE_(preset->name);
 | |
|     item_tmp.value = i;
 | |
|     RNA_enum_item_add(&item, &totitem, &item_tmp);
 | |
|   }
 | |
| 
 | |
|   /* add special "custom" entry to the end of the list */
 | |
|   {
 | |
|     item_tmp.identifier = "Custom";
 | |
|     item_tmp.name = IFACE_("Custom");
 | |
|     item_tmp.value = -1;
 | |
|     RNA_enum_item_add(&item, &totitem, &item_tmp);
 | |
|   }
 | |
| 
 | |
|   RNA_enum_item_end(&item, &totitem);
 | |
|   *r_free = true;
 | |
| 
 | |
|   return item;
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------ */
 | |
| 
 | |
| static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
 | |
| {
 | |
|   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
 | |
|   int material = RNA_enum_get(op->ptr, "material");
 | |
|   float density;
 | |
|   bool changed = false;
 | |
| 
 | |
|   /* get density (kg/m^3) to apply */
 | |
|   if (material >= 0) {
 | |
|     /* get density from table, and store in props for later repeating */
 | |
|     if (material >= NUM_RB_MATERIAL_PRESETS) {
 | |
|       material = 0;
 | |
|     }
 | |
| 
 | |
|     density = RB_MATERIAL_DENSITY_TABLE[material].density;
 | |
|     RNA_float_set(op->ptr, "density", density);
 | |
|   }
 | |
|   else {
 | |
|     /* custom - grab from whatever value is set */
 | |
|     density = RNA_float_get(op->ptr, "density");
 | |
|   }
 | |
| 
 | |
|   /* apply this to all selected objects (with rigidbodies)... */
 | |
|   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
 | |
|     if (ob->rigidbody_object) {
 | |
|       PointerRNA ptr;
 | |
| 
 | |
|       float volume; /* m^3 */
 | |
|       float mass;   /* kg */
 | |
| 
 | |
|       /* mass is calculated from the approximate volume of the object,
 | |
|        * and the density of the material we're simulating
 | |
|        */
 | |
|       Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
 | |
|       BKE_rigidbody_calc_volume(ob_eval, &volume);
 | |
|       mass = volume * density;
 | |
| 
 | |
|       /* use RNA-system to change the property and perform all necessary changes */
 | |
|       RNA_pointer_create(&ob->id, &RNA_RigidBodyObject, ob->rigidbody_object, &ptr);
 | |
|       RNA_float_set(&ptr, "mass", mass);
 | |
| 
 | |
|       DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
 | |
| 
 | |
|       changed = true;
 | |
|     }
 | |
|   }
 | |
|   CTX_DATA_END;
 | |
| 
 | |
|   if (changed) {
 | |
|     /* send updates */
 | |
|     WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
 | |
| 
 | |
|     /* done */
 | |
|     return OPERATOR_FINISHED;
 | |
|   }
 | |
|   else {
 | |
|     return OPERATOR_CANCELLED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RIGIDBODY_OT_mass_calculate(wmOperatorType *ot)
 | |
| {
 | |
|   PropertyRNA *prop;
 | |
| 
 | |
|   /* identifiers */
 | |
|   ot->idname = "RIGIDBODY_OT_mass_calculate";
 | |
|   ot->name = "Calculate Mass";
 | |
|   ot->description = "Automatically calculate mass values for Rigid Body Objects based on volume";
 | |
| 
 | |
|   /* callbacks */
 | |
|   ot->invoke = WM_menu_invoke;  // XXX
 | |
|   ot->exec = rigidbody_objects_calc_mass_exec;
 | |
|   ot->poll = ED_operator_rigidbody_active_poll;
 | |
| 
 | |
|   /* flags */
 | |
|   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 | |
| 
 | |
|   /* properties */
 | |
|   ot->prop = prop = RNA_def_enum(
 | |
|       ot->srna,
 | |
|       "material",
 | |
|       DummyRNA_DEFAULT_items,
 | |
|       0,
 | |
|       "Material Preset",
 | |
|       "Type of material that objects are made of (determines material density)");
 | |
|   RNA_def_enum_funcs(prop, rigidbody_materials_itemf);
 | |
|   RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
 | |
| 
 | |
|   RNA_def_float(ot->srna,
 | |
|                 "density",
 | |
|                 1.0,
 | |
|                 FLT_MIN,
 | |
|                 FLT_MAX,
 | |
|                 "Density",
 | |
|                 "Custom density value (kg/m^3) to use instead of material preset",
 | |
|                 1.0f,
 | |
|                 2500.0f);
 | |
| }
 | |
| 
 | |
| /* ********************************************** */
 |