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
21from bpy.types import (
22    Panel,
23)
24from bl_ui.properties_physics_common import (
25    point_cache_ui,
26    effector_weights_ui,
27)
28
29COMPAT_OB_TYPES = {'MESH', 'LATTICE', 'CURVE', 'SURFACE', 'FONT'}
30
31
32def softbody_panel_enabled(md):
33    return (md.point_cache.is_baked is False)
34
35
36class PhysicButtonsPanel:
37    bl_space_type = 'PROPERTIES'
38    bl_region_type = 'WINDOW'
39    bl_context = "physics"
40
41    @classmethod
42    def poll(cls, context):
43        ob = context.object
44        return ob and ob.type in COMPAT_OB_TYPES and context.engine in cls.COMPAT_ENGINES and context.soft_body
45
46
47class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel):
48    bl_label = "Soft Body"
49    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
50
51    def draw(self, context):
52        layout = self.layout
53        layout.use_property_split = True
54
55        md = context.soft_body
56        softbody = md.settings
57
58        layout.prop(softbody, "collision_collection")
59
60
61class PHYSICS_PT_softbody_object(PhysicButtonsPanel, Panel):
62    bl_label = "Object"
63    bl_parent_id = 'PHYSICS_PT_softbody'
64    bl_options = {'DEFAULT_CLOSED'}
65    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
66
67    def draw(self, context):
68        layout = self.layout
69        layout.use_property_split = True
70
71        md = context.soft_body
72        softbody = md.settings
73        ob = context.object
74
75        layout.enabled = softbody_panel_enabled(md)
76        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
77
78        col = flow.column()
79        col.prop(softbody, "friction")
80
81        col.separator()
82
83        col = flow.column()
84        col.prop(softbody, "mass")
85
86        col.prop_search(softbody, "vertex_group_mass", ob, "vertex_groups", text="Control Point")
87
88
89class PHYSICS_PT_softbody_simulation(PhysicButtonsPanel, Panel):
90    bl_label = "Simulation"
91    bl_parent_id = 'PHYSICS_PT_softbody'
92    bl_options = {'DEFAULT_CLOSED'}
93    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
94
95    def draw(self, context):
96        layout = self.layout
97        layout.use_property_split = True
98
99        md = context.soft_body
100        softbody = md.settings
101
102        layout.enabled = softbody_panel_enabled(md)
103
104        layout.prop(softbody, "speed")
105
106
107class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel):
108    bl_label = "Cache"
109    bl_parent_id = 'PHYSICS_PT_softbody'
110    bl_options = {'DEFAULT_CLOSED'}
111    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
112
113    def draw(self, context):
114        md = context.soft_body
115        point_cache_ui(self, md.point_cache, softbody_panel_enabled(md), 'SOFTBODY')
116
117
118class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel):
119    bl_label = "Goal"
120    bl_parent_id = 'PHYSICS_PT_softbody'
121    bl_options = {'DEFAULT_CLOSED'}
122    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
123
124    def draw_header(self, context):
125        softbody = context.soft_body.settings
126
127        self.layout.active = softbody_panel_enabled(context.soft_body)
128        self.layout.prop(softbody, "use_goal", text="")
129
130    def draw(self, context):
131        layout = self.layout
132        layout.use_property_split = True
133
134        md = context.soft_body
135        softbody = md.settings
136        ob = context.object
137
138        layout.active = softbody.use_goal and softbody_panel_enabled(md)
139
140        layout.prop_search(softbody, "vertex_group_goal", ob, "vertex_groups", text="Vertex Group")
141
142
143class PHYSICS_PT_softbody_goal_strengths(PhysicButtonsPanel, Panel):
144    bl_label = "Strengths"
145    bl_parent_id = 'PHYSICS_PT_softbody_goal'
146    bl_options = {'DEFAULT_CLOSED'}
147    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
148
149    def draw(self, context):
150        layout = self.layout
151        layout.use_property_split = True
152
153        md = context.soft_body
154        softbody = md.settings
155
156        layout.active = softbody.use_goal and softbody_panel_enabled(md)
157        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
158
159        col = flow.column()
160        col.prop(softbody, "goal_default", text="Default")
161
162        col.separator()
163
164        col = flow.column(align=True)
165        col.prop(softbody, "goal_min", text="Min")
166        col.prop(softbody, "goal_max", text="Max")
167
168
169class PHYSICS_PT_softbody_goal_settings(PhysicButtonsPanel, Panel):
170    bl_label = "Settings"
171    bl_parent_id = 'PHYSICS_PT_softbody_goal'
172    bl_options = {'DEFAULT_CLOSED'}
173    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
174
175    def draw(self, context):
176        layout = self.layout
177        layout.use_property_split = True
178
179        md = context.soft_body
180        softbody = md.settings
181
182        layout.active = softbody.use_goal and softbody_panel_enabled(md)
183        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
184
185        col = flow.column()
186        col.prop(softbody, "goal_spring", text="Stiffness")
187
188        col = flow.column()
189        col.prop(softbody, "goal_friction", text="Damping")
190
191
192class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel):
193    bl_label = "Edges"
194    bl_parent_id = 'PHYSICS_PT_softbody'
195    bl_options = {'DEFAULT_CLOSED'}
196    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
197
198    def draw_header(self, context):
199        softbody = context.soft_body.settings
200
201        self.layout.active = softbody_panel_enabled(context.soft_body)
202        self.layout.prop(softbody, "use_edges", text="")
203
204    def draw(self, context):
205        layout = self.layout
206        layout.use_property_split = True
207
208        md = context.soft_body
209        softbody = md.settings
210        ob = context.object
211
212        layout.active = softbody.use_edges and softbody_panel_enabled(md)
213        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
214
215        col = flow.column()
216
217        col.prop_search(softbody, "vertex_group_spring", ob, "vertex_groups", text="Springs")
218
219        col.separator()
220
221        col.prop(softbody, "pull")
222        col.prop(softbody, "push")
223
224        col.separator()
225
226        col = flow.column()
227        col.prop(softbody, "damping")
228        col.prop(softbody, "plastic")
229        col.prop(softbody, "bend")
230
231        col.separator()
232
233        col = flow.column()
234        col.prop(softbody, "spring_length", text="Length")
235        col.prop(softbody, "use_edge_collision", text="Collision Edge")
236        col.prop(softbody, "use_face_collision", text="Face")
237
238
239class PHYSICS_PT_softbody_edge_aerodynamics(PhysicButtonsPanel, Panel):
240    bl_label = "Aerodynamics"
241    bl_parent_id = 'PHYSICS_PT_softbody_edge'
242    bl_options = {'DEFAULT_CLOSED'}
243    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
244
245    def draw(self, context):
246        layout = self.layout
247        layout.use_property_split = True
248        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
249
250        md = context.soft_body
251        softbody = md.settings
252
253        flow.active = softbody.use_edges and softbody_panel_enabled(md)
254
255        col = flow.column()
256        col.prop(softbody, "aerodynamics_type", text="Type")
257
258        col = flow.column()
259        col.prop(softbody, "aero", text="Factor")
260
261
262class PHYSICS_PT_softbody_edge_stiffness(PhysicButtonsPanel, Panel):
263    bl_label = "Stiffness"
264    bl_parent_id = 'PHYSICS_PT_softbody_edge'
265    bl_options = {'DEFAULT_CLOSED'}
266    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
267
268    def draw_header(self, context):
269        softbody = context.soft_body.settings
270
271        self.layout.active = softbody_panel_enabled(context.soft_body)
272        self.layout.prop(softbody, "use_stiff_quads", text="")
273
274    def draw(self, context):
275        layout = self.layout
276        layout.use_property_split = True
277
278        md = context.soft_body
279        softbody = md.settings
280
281        layout.active = softbody.use_edges and softbody.use_stiff_quads and softbody_panel_enabled(md)
282
283        layout.prop(softbody, "shear")
284
285
286class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel):
287    bl_label = "Self Collision"
288    bl_parent_id = 'PHYSICS_PT_softbody'
289    bl_options = {'DEFAULT_CLOSED'}
290    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
291
292    def draw_header(self, context):
293        softbody = context.soft_body.settings
294
295        self.layout.active = softbody_panel_enabled(context.soft_body)
296        self.layout.prop(softbody, "use_self_collision", text="")
297
298    def draw(self, context):
299        layout = self.layout
300        layout.use_property_split = True
301
302        md = context.soft_body
303        softbody = md.settings
304
305        layout.active = softbody.use_self_collision and softbody_panel_enabled(md)
306
307        layout.prop(softbody, "collision_type", text="Calculation Type")
308
309        layout.separator()
310
311        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
312
313        col = flow.column()
314        col.prop(softbody, "ball_size", text="Ball Size")
315
316        col = flow.column()
317        col.prop(softbody, "ball_stiff", text="Stiffness")
318        col.prop(softbody, "ball_damp", text="Dampening")
319
320
321class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel):
322    bl_label = "Solver"
323    bl_parent_id = 'PHYSICS_PT_softbody'
324    bl_options = {'DEFAULT_CLOSED'}
325    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
326
327    def draw(self, context):
328        layout = self.layout
329        layout.use_property_split = True
330
331        md = context.soft_body
332        softbody = md.settings
333
334        layout.active = softbody_panel_enabled(md)
335        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
336
337        col = flow.column(align=True)
338        col.prop(softbody, "step_min", text="Step Size Min")
339        col.prop(softbody, "step_max", text="Max")
340
341        col = flow.column()
342        col.prop(softbody, "use_auto_step", text="Auto-Step")
343        col.prop(softbody, "error_threshold")
344
345
346class PHYSICS_PT_softbody_solver_diagnostics(PhysicButtonsPanel, Panel):
347    bl_label = "Diagnostics"
348    bl_parent_id = 'PHYSICS_PT_softbody_solver'
349    bl_options = {'DEFAULT_CLOSED'}
350    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
351
352    def draw(self, context):
353        layout = self.layout
354        layout.use_property_split = True
355
356        md = context.soft_body
357        softbody = md.settings
358
359        layout.active = softbody_panel_enabled(md)
360
361        layout.prop(softbody, "use_diagnose")
362        layout.prop(softbody, "use_estimate_matrix")
363
364
365class PHYSICS_PT_softbody_solver_helpers(PhysicButtonsPanel, Panel):
366    bl_label = "Helpers"
367    bl_parent_id = 'PHYSICS_PT_softbody_solver'
368    bl_options = {'DEFAULT_CLOSED'}
369    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
370
371    def draw(self, context):
372        layout = self.layout
373        layout.use_property_split = True
374
375        md = context.soft_body
376        softbody = md.settings
377
378        layout.active = softbody_panel_enabled(md)
379        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
380
381        col = flow.column()
382        col.prop(softbody, "choke")
383
384        col = flow.column()
385        col.prop(softbody, "fuzzy")
386
387
388class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, Panel):
389    bl_label = "Field Weights"
390    bl_parent_id = 'PHYSICS_PT_softbody'
391    bl_options = {'DEFAULT_CLOSED'}
392    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
393
394    def draw(self, context):
395        md = context.soft_body
396        softbody = md.settings
397
398        effector_weights_ui(self, softbody.effector_weights, 'SOFTBODY')
399
400
401classes = (
402    PHYSICS_PT_softbody,
403    PHYSICS_PT_softbody_object,
404    PHYSICS_PT_softbody_simulation,
405    PHYSICS_PT_softbody_cache,
406    PHYSICS_PT_softbody_goal,
407    PHYSICS_PT_softbody_goal_settings,
408    PHYSICS_PT_softbody_goal_strengths,
409    PHYSICS_PT_softbody_edge,
410    PHYSICS_PT_softbody_edge_aerodynamics,
411    PHYSICS_PT_softbody_edge_stiffness,
412    PHYSICS_PT_softbody_collision,
413    PHYSICS_PT_softbody_solver,
414    PHYSICS_PT_softbody_solver_diagnostics,
415    PHYSICS_PT_softbody_solver_helpers,
416    PHYSICS_PT_softbody_field_weights,
417)
418
419
420if __name__ == "__main__":  # only for live edit.
421    from bpy.utils import register_class
422    for cls in classes:
423        register_class(cls)
424