1c0598fb6dc38e477d87ceb864e555d7dfb6c897
[blender.git] / release / scripts / startup / bl_ui / properties_physics_rigidbody.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 import bpy
22 from bpy.types import (
23     Panel,
24 )
25
26
27 def rigid_body_warning(layout):
28     row = layout.row(align=True)
29     row.alignment = 'RIGHT'
30     row.label(text="Object does not have a Rigid Body")
31
32
33 class PHYSICS_PT_rigidbody_panel:
34     bl_space_type = 'PROPERTIES'
35     bl_region_type = 'WINDOW'
36     bl_context = "physics"
37
38
39 class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
40     bl_label = "Rigid Body"
41     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
42
43     @classmethod
44     def poll(cls, context):
45         obj = context.object
46         return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
47
48     def draw(self, context):
49         layout = self.layout
50         layout.use_property_split = True
51
52         ob = context.object
53         rbo = ob.rigid_body
54
55         if rbo is None:
56             rigid_body_warning(layout)
57             return
58
59         layout.prop(rbo, "type", text="Type")
60
61
62 class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel):
63     bl_label = "Settings"
64     bl_parent_id = 'PHYSICS_PT_rigid_body'
65     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
66
67     @classmethod
68     def poll(cls, context):
69         obj = context.object
70         return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
71
72     def draw(self, context):
73         layout = self.layout
74         layout.use_property_split = True
75
76         ob = context.object
77         rbo = ob.rigid_body
78
79         if rbo is None:
80             rigid_body_warning(layout)
81             return
82
83         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
84         col = flow.column()
85
86         if rbo.type == 'ACTIVE':
87             col.prop(rbo, "mass")
88             col.prop(rbo, "enabled", text="Dynamic")
89
90         col = flow.column()
91         col.prop(rbo, "kinematic", text="Animated")
92
93
94 class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
95     bl_label = "Collisions"
96     bl_parent_id = 'PHYSICS_PT_rigid_body'
97     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
98
99     @classmethod
100     def poll(cls, context):
101         obj = context.object
102         return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
103
104     def draw(self, context):
105         layout = self.layout
106
107         ob = context.object
108         rbo = ob.rigid_body
109         layout.use_property_split = True
110
111         layout.prop(rbo, "collision_shape", text="Shape")
112
113         if rbo.collision_shape in {'MESH', 'CONVEX_HULL'}:
114             layout.prop(rbo, "mesh_source", text="Source")
115
116         if rbo.collision_shape == 'MESH' and rbo.mesh_source == 'DEFORM':
117             layout.prop(rbo, "use_deform", text="Deforming")
118
119
120 class PHYSICS_PT_rigid_body_collisions_surface(PHYSICS_PT_rigidbody_panel, Panel):
121     bl_label = "Surface Response"
122     bl_parent_id = 'PHYSICS_PT_rigid_body_collisions'
123     bl_options = {'DEFAULT_CLOSED'}
124     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
125
126     @classmethod
127     def poll(cls, context):
128         obj = context.object
129         return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
130
131     def draw(self, context):
132         layout = self.layout
133         layout.use_property_split = True
134         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
135
136         ob = context.object
137         rbo = ob.rigid_body
138
139         col = flow.column()
140         col.prop(rbo, "friction")
141
142         col = flow.column()
143         col.prop(rbo, "restitution", text="Bounciness")
144
145
146 class PHYSICS_PT_rigid_body_collisions_sensitivity(PHYSICS_PT_rigidbody_panel, Panel):
147     bl_label = "Sensitivity"
148     bl_parent_id = 'PHYSICS_PT_rigid_body_collisions'
149     bl_options = {'DEFAULT_CLOSED'}
150     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
151
152     @classmethod
153     def poll(cls, context):
154         obj = context.object
155         return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
156
157     def draw(self, context):
158         layout = self.layout
159         layout.use_property_split = True
160
161         ob = context.object
162         rbo = ob.rigid_body
163
164         if rbo.collision_shape in {'MESH', 'CONE'}:
165             col = layout.column()
166             col.prop(rbo, "collision_margin", text="Margin")
167         else:
168             flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
169             col = flow.column()
170             col.prop(rbo, "use_margin")
171
172             col = flow.column()
173             col.active = rbo.use_margin
174             col.prop(rbo, "collision_margin", text="Margin")
175
176
177 class PHYSICS_PT_rigid_body_collisions_collections(PHYSICS_PT_rigidbody_panel, Panel):
178     bl_label = "Collections"
179     bl_parent_id = 'PHYSICS_PT_rigid_body_collisions'
180     bl_options = {'DEFAULT_CLOSED'}
181     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
182
183     @classmethod
184     def poll(cls, context):
185         obj = context.object
186         return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
187
188     def draw(self, context):
189         layout = self.layout
190
191         ob = context.object
192         rbo = ob.rigid_body
193
194         layout.prop(rbo, "collision_collections", text="")
195
196
197 class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
198     bl_label = "Dynamics"
199     bl_parent_id = 'PHYSICS_PT_rigid_body'
200     bl_options = {'DEFAULT_CLOSED'}
201     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
202
203     @classmethod
204     def poll(cls, context):
205         obj = context.object
206         return (obj and obj.rigid_body and obj.rigid_body.type == 'ACTIVE'
207                 and (context.engine in cls.COMPAT_ENGINES))
208
209     def draw(self, context):
210         layout = self.layout
211         layout.use_property_split = True
212         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
213
214         ob = context.object
215         rbo = ob.rigid_body
216
217         # col = layout.column(align=True)
218         # col.label(text="Activation:")
219         # XXX: settings such as activate on collison/etc.
220
221         col = flow.column()
222         col.prop(rbo, "linear_damping", text="Damping Translation")
223
224         col = flow.column()
225         col.prop(rbo, "angular_damping", text="Rotation")
226
227
228 class PHYSICS_PT_rigid_body_dynamics_deactivation(PHYSICS_PT_rigidbody_panel, Panel):
229     bl_label = "Deactivation"
230     bl_parent_id = 'PHYSICS_PT_rigid_body_dynamics'
231     bl_options = {'DEFAULT_CLOSED'}
232     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
233
234     @classmethod
235     def poll(cls, context):
236         obj = context.object
237         return (obj and obj.rigid_body
238                 and obj.rigid_body.type == 'ACTIVE'
239                 and (context.engine in cls.COMPAT_ENGINES))
240
241     def draw_header(self, context):
242         ob = context.object
243         rbo = ob.rigid_body
244         self.layout.prop(rbo, "use_deactivation", text="")
245
246     def draw(self, context):
247         layout = self.layout
248         layout.use_property_split = True
249         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
250
251         ob = context.object
252         rbo = ob.rigid_body
253
254         layout.active = rbo.use_deactivation
255
256         col = flow.column()
257         col.prop(rbo, "use_start_deactivated")
258
259         col = flow.column()
260         col.prop(rbo, "deactivate_linear_velocity", text="Velocity Linear")
261         col.prop(rbo, "deactivate_angular_velocity", text="Angular")
262         # TODO: other params such as time?
263
264
265 classes = (
266     PHYSICS_PT_rigid_body,
267     PHYSICS_PT_rigid_body_settings,
268     PHYSICS_PT_rigid_body_collisions,
269     PHYSICS_PT_rigid_body_collisions_surface,
270     PHYSICS_PT_rigid_body_collisions_sensitivity,
271     PHYSICS_PT_rigid_body_collisions_collections,
272     PHYSICS_PT_rigid_body_dynamics,
273     PHYSICS_PT_rigid_body_dynamics_deactivation,
274 )
275
276
277 if __name__ == "__main__":  # only for live edit.
278     from bpy.utils import register_class
279     for cls in classes:
280         register_class(cls)