efe50b6fe2be3d2e71e3ae9867fbea8b1545da60
[blender.git] / release / scripts / startup / bl_ui / properties_game.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 import bpy
21 from bpy.types import Panel
22 from blf import gettext as _
23
24
25 class PhysicsButtonsPanel():
26     bl_space_type = 'PROPERTIES'
27     bl_region_type = 'WINDOW'
28     bl_context = "physics"
29
30
31 class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
32     bl_label = "Physics"
33     COMPAT_ENGINES = {'BLENDER_GAME'}
34
35     @classmethod
36     def poll(cls, context):
37         ob = context.active_object
38         rd = context.scene.render
39         return ob and ob.game and (rd.engine in cls.COMPAT_ENGINES)
40
41     def draw(self, context):
42         layout = self.layout
43
44         ob = context.active_object
45         game = ob.game
46         soft = ob.game.soft_body
47
48         layout.prop(game, "physics_type")
49         layout.separator()
50
51         #if game.physics_type == 'DYNAMIC':
52         if game.physics_type in {'DYNAMIC', 'RIGID_BODY'}:
53             split = layout.split()
54
55             col = split.column()
56             col.prop(game, "use_actor")
57             col.prop(game, "use_ghost")
58             col.prop(ob, "hide_render", text=_("Invisible"))  # out of place but useful
59
60             col = split.column()
61             col.prop(game, "use_material_physics_fh")
62             col.prop(game, "use_rotate_from_normal")
63             col.prop(game, "use_sleep")
64
65             layout.separator()
66
67             split = layout.split()
68
69             col = split.column()
70             col.label(text=_("Attributes:"))
71             col.prop(game, "mass")
72             col.prop(game, "radius")
73             col.prop(game, "form_factor")
74
75             col = split.column()
76             sub = col.column()
77             sub.prop(game, "use_anisotropic_friction")
78             subsub = sub.column()
79             subsub.active = game.use_anisotropic_friction
80             subsub.prop(game, "friction_coefficients", text="", slider=True)
81
82             split = layout.split()
83
84             col = split.column()
85             col.label(text=_("Velocity:"))
86             sub = col.column(align=True)
87             sub.prop(game, "velocity_min", text=_("Minimum"))
88             sub.prop(game, "velocity_max", text=_("Maximum"))
89
90             col = split.column()
91             col.label(text=_("Damping:"))
92             sub = col.column(align=True)
93             sub.prop(game, "damping", text=_("Translation"), slider=True)
94             sub.prop(game, "rotation_damping", text=_("Rotation"), slider=True)
95
96             layout.separator()
97
98             split = layout.split()
99
100             col = split.column()
101             col.label(text=_("Lock Translation:"))
102             col.prop(game, "lock_location_x", text="X")
103             col.prop(game, "lock_location_y", text="Y")
104             col.prop(game, "lock_location_z", text="Z")
105
106             col = split.column()
107             col.label(text=_("Lock Rotation:"))
108             col.prop(game, "lock_rotation_x", text="X")
109             col.prop(game, "lock_rotation_y", text="Y")
110             col.prop(game, "lock_rotation_z", text="Z")
111
112         elif game.physics_type == 'SOFT_BODY':
113             col = layout.column()
114             col.prop(game, "use_actor")
115             col.prop(game, "use_ghost")
116             col.prop(ob, "hide_render", text=_("Invisible"))
117
118             layout.separator()
119
120             split = layout.split()
121
122             col = split.column()
123             col.label(text=_("Attributes:"))
124             col.prop(game, "mass")
125             col.prop(soft, "weld_threshold")
126             col.prop(soft, "location_iterations")
127             col.prop(soft, "linear_stiffness", slider=True)
128             col.prop(soft, "dynamic_friction", slider=True)
129             col.prop(soft, "collision_margin", slider=True)
130             col.prop(soft, "use_bending_constraints", text=_("Bending Constraints"))
131
132             col = split.column()
133             col.prop(soft, "use_shape_match")
134             sub = col.column()
135             sub.active = soft.use_shape_match
136             sub.prop(soft, "shape_threshold", slider=True)
137
138             col.separator()
139
140             col.label(text=_("Cluster Collision:"))
141             col.prop(soft, "use_cluster_rigid_to_softbody")
142             col.prop(soft, "use_cluster_soft_to_softbody")
143             sub = col.column()
144             sub.active = (soft.use_cluster_rigid_to_softbody or soft.use_cluster_soft_to_softbody)
145             sub.prop(soft, "cluster_iterations", text=_("Iterations"))
146
147         elif game.physics_type == 'STATIC':
148             col = layout.column()
149             col.prop(game, "use_actor")
150             col.prop(game, "use_ghost")
151             col.prop(ob, "hide_render", text=_("Invisible"))
152
153             layout.separator()
154
155             split = layout.split()
156
157             col = split.column()
158             col.label(text=_("Attributes:"))
159             col.prop(game, "radius")
160
161             col = split.column()
162             sub = col.column()
163             sub.prop(game, "use_anisotropic_friction")
164             subsub = sub.column()
165             subsub.active = game.use_anisotropic_friction
166             subsub.prop(game, "friction_coefficients", text="", slider=True)
167
168         elif game.physics_type in {'SENSOR', 'INVISIBLE', 'NO_COLLISION', 'OCCLUDE'}:
169             layout.prop(ob, "hide_render", text=_("Invisible"))
170
171
172 class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel):
173     bl_label = "Collision Bounds"
174     COMPAT_ENGINES = {'BLENDER_GAME'}
175
176     @classmethod
177     def poll(cls, context):
178         game = context.object.game
179         rd = context.scene.render
180         return (game.physics_type in {'DYNAMIC', 'RIGID_BODY', 'SENSOR', 'SOFT_BODY', 'STATIC'}) and (rd.engine in cls.COMPAT_ENGINES)
181
182     def draw_header(self, context):
183         game = context.active_object.game
184
185         self.layout.prop(game, "use_collision_bounds", text="")
186
187     def draw(self, context):
188         layout = self.layout
189
190         game = context.active_object.game
191
192         layout.active = game.use_collision_bounds
193         layout.prop(game, "collision_bounds_type", text=_("Bounds"))
194
195         row = layout.row()
196         row.prop(game, "collision_margin", text=_("Margin"), slider=True)
197         row.prop(game, "use_collision_compound", text=_("Compound"))
198
199
200 class PHYSICS_PT_game_obstacles(PhysicsButtonsPanel, Panel):
201     bl_label = "Create Obstacle"
202     COMPAT_ENGINES = {'BLENDER_GAME'}
203
204     @classmethod
205     def poll(cls, context):
206         game = context.object.game
207         rd = context.scene.render
208         return (game.physics_type in ('DYNAMIC', 'RIGID_BODY', 'SENSOR', 'SOFT_BODY', 'STATIC'))  and (rd.engine in cls.COMPAT_ENGINES)
209
210     def draw_header(self, context):
211         game = context.active_object.game
212
213         self.layout.prop(game, "create_obstacle", text="")
214
215     def draw(self, context):
216         layout = self.layout
217
218         game = context.active_object.game
219
220         layout.active = game.create_obstacle
221
222         row = layout.row()
223         row.prop(game, "obstacle_radius", text="Radius")
224         row.label()
225
226
227 class RenderButtonsPanel():
228     bl_space_type = 'PROPERTIES'
229     bl_region_type = 'WINDOW'
230     bl_context = "render"
231
232     @classmethod
233     def poll(cls, context):
234         rd = context.scene.render
235         return (rd.engine in cls.COMPAT_ENGINES)
236
237
238 class RENDER_PT_game(RenderButtonsPanel, Panel):
239     bl_label = "Game"
240     COMPAT_ENGINES = {'BLENDER_GAME'}
241
242     def draw(self, context):
243         layout = self.layout
244
245         row = layout.row()
246         row.operator("view3d.game_start", text=_("Start"))
247         row.label()
248
249
250 class RENDER_PT_game_player(RenderButtonsPanel, Panel):
251     bl_label = "Standalone Player"
252     COMPAT_ENGINES = {'BLENDER_GAME'}
253
254     def draw(self, context):
255         layout = self.layout
256
257         gs = context.scene.game_settings
258
259         layout.prop(gs, "show_fullscreen")
260
261         split = layout.split()
262
263         col = split.column()
264         col.label(text=_("Resolution:"))
265         sub = col.column(align=True)
266         sub.prop(gs, "resolution_x", slider=False, text="X")
267         sub.prop(gs, "resolution_y", slider=False, text="Y")
268
269         col = split.column()
270         col.label(text=_("Quality:"))
271         sub = col.column(align=True)
272         sub.prop(gs, "depth", text=_("Bit Depth"), slider=False)
273         sub.prop(gs, "frequency", text=_("FPS"), slider=False)
274
275         # framing:
276         col = layout.column()
277         col.label(text=_("Framing:"))
278         col.row().prop(gs, "frame_type", expand=True)
279         if gs.frame_type == 'LETTERBOX':
280             col.prop(gs, "frame_color", text="")
281
282
283 class RENDER_PT_game_stereo(RenderButtonsPanel, Panel):
284     bl_label = "Stereo"
285     COMPAT_ENGINES = {'BLENDER_GAME'}
286
287     def draw(self, context):
288         layout = self.layout
289
290         gs = context.scene.game_settings
291         stereo_mode = gs.stereo
292
293         # stereo options:
294         layout.prop(gs, "stereo", expand=True)
295
296         # stereo:
297         if stereo_mode == 'STEREO':
298             layout.prop(gs, "stereo_mode")
299             layout.prop(gs, "stereo_eye_separation")
300
301         # dome:
302         elif stereo_mode == 'DOME':
303             layout.prop(gs, "dome_mode", text=_("Dome Type"))
304
305             dome_type = gs.dome_mode
306
307             split = layout.split()
308
309             if dome_type == 'FISHEYE' or \
310                dome_type == 'TRUNCATED_REAR' or \
311                dome_type == 'TRUNCATED_FRONT':
312
313                 col = split.column()
314                 col.prop(gs, "dome_buffer_resolution", text=_("Resolution"), slider=True)
315                 col.prop(gs, "dome_angle", slider=True)
316
317                 col = split.column()
318                 col.prop(gs, "dome_tesselation", text=_("Tesselation"))
319                 col.prop(gs, "dome_tilt")
320
321             elif dome_type == 'PANORAM_SPH':
322                 col = split.column()
323
324                 col.prop(gs, "dome_buffer_resolution", text=_("Resolution"), slider=True)
325                 col = split.column()
326                 col.prop(gs, "dome_tesselation", text=_("Tesselation"))
327
328             else:  # cube map
329                 col = split.column()
330                 col.prop(gs, "dome_buffer_resolution", text=_("Resolution"), slider=True)
331
332                 col = split.column()
333
334             layout.prop(gs, "dome_text")
335
336
337 class RENDER_PT_game_shading(RenderButtonsPanel, Panel):
338     bl_label = "Shading"
339     COMPAT_ENGINES = {'BLENDER_GAME'}
340
341     def draw(self, context):
342         layout = self.layout
343
344         gs = context.scene.game_settings
345
346         layout.prop(gs, "material_mode", expand=True)
347
348         if gs.material_mode == 'GLSL':
349             split = layout.split()
350
351             col = split.column()
352             col.prop(gs, "use_glsl_lights", text=_("Lights"))
353             col.prop(gs, "use_glsl_shaders", text=_("Shaders"))
354             col.prop(gs, "use_glsl_shadows", text=_("Shadows"))
355             col.prop(gs, "use_glsl_color_management", text=_("Color Management"))
356
357             col = split.column()
358             col.prop(gs, "use_glsl_ramps", text=_("Ramps"))
359             col.prop(gs, "use_glsl_nodes", text=_("Nodes"))
360             col.prop(gs, "use_glsl_extra_textures", text=_("Extra Textures"))
361
362
363 class RENDER_PT_game_performance(RenderButtonsPanel, Panel):
364     bl_label = "Performance"
365     COMPAT_ENGINES = {'BLENDER_GAME'}
366
367     def draw(self, context):
368         layout = self.layout
369
370         gs = context.scene.game_settings
371         col = layout.column()
372         row = col.row()
373         row.prop(gs, "use_frame_rate")
374         row.prop(gs, "use_display_lists")
375
376         col.prop(gs, "restrict_animation_updates")
377
378
379 class RENDER_PT_game_display(RenderButtonsPanel, Panel):
380     bl_label = "Display"
381     COMPAT_ENGINES = {'BLENDER_GAME'}
382
383     def draw(self, context):
384         layout = self.layout
385
386         gs = context.scene.game_settings
387         flow = layout.column_flow()
388         flow.prop(gs, "show_debug_properties", text=_("Debug Properties"))
389         flow.prop(gs, "show_framerate_profile", text=_("Framerate and Profile"))
390         flow.prop(gs, "show_physics_visualization", text=_("Physics Visualization"))
391         flow.prop(gs, "use_deprecation_warnings")
392         flow.prop(gs, "show_mouse", text=_("Mouse Cursor"))
393
394
395 class SceneButtonsPanel():
396     bl_space_type = 'PROPERTIES'
397     bl_region_type = 'WINDOW'
398     bl_context = "scene"
399
400
401 class SCENE_PT_game_navmesh(SceneButtonsPanel, bpy.types.Panel):
402     bl_label = "Navigation mesh"
403     bl_default_closed = True
404     COMPAT_ENGINES = {'BLENDER_GAME'}
405
406     @classmethod
407     def poll(cls, context):
408         scene = context.scene
409         return (scene and scene.render.engine in cls.COMPAT_ENGINES)
410
411     def draw(self, context):
412         layout = self.layout
413
414         rd = context.scene.game_settings.recast_data
415
416         layout.operator("object.create_navmesh", text='Build navigation mesh')
417
418         col = layout.column()
419         col.label(text="Rasterization:")
420         row = col.row()
421         row.prop(rd, "cell_size")
422         row.prop(rd, "cell_height")
423
424         col = layout.column()
425         col.label(text="Agent:")
426         split = col.split()
427
428         col = split.column()
429         col.prop(rd, "agent_height", text="Height")
430         col.prop(rd, "agent_radius", text="Radius")
431
432         col = split.column()
433         col.prop(rd, "max_slope")
434         col.prop(rd, "max_climb")
435
436         col = layout.column()
437         col.label(text="Region:")
438         row = col.row()
439         row.prop(rd, "region_min_size")
440         row.prop(rd, "region_merge_size")
441
442         col = layout.column()
443         col.label(text="Polygonization:")
444         split = col.split()
445
446         col = split.column()
447         col.prop(rd, "edge_max_len")
448         col.prop(rd, "edge_max_error")
449
450         split.prop(rd, "verts_per_poly")
451
452         col = layout.column()
453         col.label(text="Detail Mesh:")
454         row = col.row()
455         row.prop(rd, "sample_dist")
456         row.prop(rd, "sample_max_error")
457
458
459 class WorldButtonsPanel():
460     bl_space_type = 'PROPERTIES'
461     bl_region_type = 'WINDOW'
462     bl_context = "world"
463
464
465 class WORLD_PT_game_context_world(WorldButtonsPanel, Panel):
466     bl_label = ""
467     bl_options = {'HIDE_HEADER'}
468     COMPAT_ENGINES = {'BLENDER_GAME'}
469
470     @classmethod
471     def poll(cls, context):
472         rd = context.scene.render
473         return (context.scene) and (rd.use_game_engine)
474
475     def draw(self, context):
476         layout = self.layout
477
478         scene = context.scene
479         world = context.world
480         space = context.space_data
481
482         split = layout.split(percentage=0.65)
483         if scene:
484             split.template_ID(scene, "world", new="world.new")
485         elif world:
486             split.template_ID(space, "pin_id")
487
488
489 class WORLD_PT_game_world(WorldButtonsPanel, Panel):
490     bl_label = "World"
491     COMPAT_ENGINES = {'BLENDER_GAME'}
492
493     @classmethod
494     def poll(cls, context):
495         scene = context.scene
496         return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
497
498     def draw(self, context):
499         layout = self.layout
500
501         world = context.world
502
503         row = layout.row()
504         row.column().prop(world, "horizon_color")
505         row.column().prop(world, "ambient_color")
506
507
508 class WORLD_PT_game_mist(WorldButtonsPanel, Panel):
509     bl_label = "Mist"
510     COMPAT_ENGINES = {'BLENDER_GAME'}
511
512     @classmethod
513     def poll(cls, context):
514         scene = context.scene
515         return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
516
517     def draw_header(self, context):
518         world = context.world
519
520         self.layout.prop(world.mist_settings, "use_mist", text="")
521
522     def draw(self, context):
523         layout = self.layout
524
525         world = context.world
526
527         layout.active = world.mist_settings.use_mist
528
529         row = layout.row()
530         row.prop(world.mist_settings, "start")
531         row.prop(world.mist_settings, "depth")
532
533
534 class WORLD_PT_game_physics(WorldButtonsPanel, Panel):
535     bl_label = "Physics"
536     COMPAT_ENGINES = {'BLENDER_GAME'}
537
538     @classmethod
539     def poll(cls, context):
540         scene = context.scene
541         return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
542
543     def draw(self, context):
544         layout = self.layout
545
546         gs = context.scene.game_settings
547
548         layout.prop(gs, "physics_engine")
549         if gs.physics_engine != 'NONE':
550             layout.prop(gs, "physics_gravity", text=_("Gravity"))
551
552             split = layout.split()
553
554             col = split.column()
555             col.label(text=_("Physics Steps:"))
556             sub = col.column(align=True)
557             sub.prop(gs, "physics_step_max", text=_("Max"))
558             sub.prop(gs, "physics_step_sub", text=_("Substeps"))
559             col.prop(gs, "fps", text=_("FPS"))
560
561             col = split.column()
562             col.label(text=_("Logic Steps:"))
563             col.prop(gs, "logic_step_max", text=_("Max"))
564
565             col = layout.column()
566             col.prop(gs, "use_occlusion_culling", text=_("Occlusion Culling"))
567             sub = col.column()
568             sub.active = gs.use_occlusion_culling
569             sub.prop(gs, "occlusion_culling_resolution", text=_("Resolution"))
570
571         else:
572             split = layout.split()
573
574             col = split.column()
575             col.label(text=_("Physics Steps:"))
576             col.prop(gs, "fps", text=_("FPS"))
577
578             col = split.column()
579             col.label(text=_("Logic Steps:"))
580             col.prop(gs, "logic_step_max", text=_("Max"))
581
582
583 class WORLD_PT_game_physics_obstacles(WorldButtonsPanel, Panel):
584     bl_label = "Obstacle simulation"
585     COMPAT_ENGINES = {'BLENDER_GAME'}
586
587     @classmethod
588     def poll(cls, context):
589         scene = context.scene
590         return (scene.world and scene.render.engine in cls.COMPAT_ENGINES)
591
592     def draw(self, context):
593         layout = self.layout
594
595         gs = context.scene.game_settings
596
597         layout.prop(gs, "obstacle_simulation", text="Type")
598         if gs.obstacle_simulation != 'NONE':
599             layout.prop(gs, "level_height")
600             layout.prop(gs, "show_obstacle_simulation")
601
602 if __name__ == "__main__":  # only for live edit.
603     bpy.utils.register_module(__name__)