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