synched with trunk at revision 30597
[blender.git] / release / scripts / 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
22 narrowui = bpy.context.user_preferences.view.properties_width_check
23
24
25 class PhysicsButtonsPanel(bpy.types.Panel):
26     bl_space_type = 'PROPERTIES'
27     bl_region_type = 'WINDOW'
28     bl_context = "physics"
29
30     def poll(self, context):
31         ob = context.active_object
32         rd = context.scene.render
33         return ob and ob.game and (rd.engine in self.COMPAT_ENGINES)
34
35
36 class PHYSICS_PT_game_physics(PhysicsButtonsPanel):
37     bl_label = "Physics"
38     COMPAT_ENGINES = {'BLENDER_GAME'}
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         wide_ui = context.region.width > narrowui
47
48         if wide_ui:
49             layout.prop(game, "physics_type")
50         else:
51             layout.prop(game, "physics_type", text="")
52         layout.separator()
53
54         #if game.physics_type == 'DYNAMIC':
55         if game.physics_type in ('DYNAMIC', 'RIGID_BODY'):
56             split = layout.split()
57
58             col = split.column()
59             col.prop(game, "actor")
60             col.prop(game, "ghost")
61             col.prop(ob, "hide_render", text="Invisible") # out of place but useful
62
63             if wide_ui:
64                 col = split.column()
65             col.prop(game, "material_physics")
66             col.prop(game, "rotate_from_normal")
67             col.prop(game, "no_sleeping")
68
69             layout.separator()
70
71             split = layout.split()
72
73             col = split.column()
74             col.label(text="Attributes:")
75             col.prop(game, "mass")
76             col.prop(game, "radius")
77             col.prop(game, "form_factor")
78
79             if wide_ui:
80                 col = split.column()
81             sub = col.column()
82             sub.active = (game.physics_type == 'RIGID_BODY')
83             sub.prop(game, "anisotropic_friction")
84             subsub = sub.column()
85             subsub.active = game.anisotropic_friction
86             subsub.prop(game, "friction_coefficients", text="", slider=True)
87
88             split = layout.split()
89
90             col = split.column()
91             col.label(text="Velocity:")
92             sub = col.column(align=True)
93             sub.prop(game, "minimum_velocity", text="Minimum")
94             sub.prop(game, "maximum_velocity", text="Maximum")
95
96             if wide_ui:
97                 col = split.column()
98             col.label(text="Damping:")
99             sub = col.column(align=True)
100             sub.prop(game, "damping", text="Translation", slider=True)
101             sub.prop(game, "rotation_damping", text="Rotation", slider=True)
102
103             layout.separator()
104
105             split = layout.split()
106
107             col = split.column()
108             col.label(text="Lock Translation:")
109             col.prop(game, "lock_x_axis", text="X")
110             col.prop(game, "lock_y_axis", text="Y")
111             col.prop(game, "lock_z_axis", text="Z")
112
113             col = split.column()
114             col.label(text="Lock Rotation:")
115             col.prop(game, "lock_x_rot_axis", text="X")
116             col.prop(game, "lock_y_rot_axis", text="Y")
117             col.prop(game, "lock_z_rot_axis", text="Z")
118
119         elif game.physics_type == 'SOFT_BODY':
120             col = layout.column()
121             col.prop(game, "actor")
122             col.prop(game, "ghost")
123             col.prop(ob, "hide_render", text="Invisible")
124
125             layout.separator()
126
127             split = layout.split()
128
129             col = split.column()
130             col.label(text="Attributes:")
131             col.prop(game, "mass")
132             col.prop(soft, "welding")
133             col.prop(soft, "position_iterations")
134             col.prop(soft, "linstiff", slider=True)
135             col.prop(soft, "dynamic_friction", slider=True)
136             col.prop(soft, "margin", slider=True)
137             col.prop(soft, "bending_const", text="Bending Constraints")
138
139             if wide_ui:
140                 col = split.column()
141             col.prop(soft, "shape_match")
142             sub = col.column()
143             sub.active = soft.shape_match
144             sub.prop(soft, "threshold", slider=True)
145
146             col.separator()
147
148             col.label(text="Cluster Collision:")
149             col.prop(soft, "cluster_rigid_to_softbody")
150             col.prop(soft, "cluster_soft_to_softbody")
151             sub = col.column()
152             sub.active = (soft.cluster_rigid_to_softbody or soft.cluster_soft_to_softbody)
153             sub.prop(soft, "cluster_iterations", text="Iterations")
154
155         elif game.physics_type == 'STATIC':
156             col = layout.column()
157             col.prop(game, "actor")
158             col.prop(game, "ghost")
159             col.prop(ob, "hide_render", text="Invisible")
160
161         elif game.physics_type in ('SENSOR', 'INVISIBLE', 'NO_COLLISION', 'OCCLUDE'):
162             layout.prop(ob, "hide_render", text="Invisible")
163
164
165 class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel):
166     bl_label = "Collision Bounds"
167     COMPAT_ENGINES = {'BLENDER_GAME'}
168
169     def poll(self, context):
170         game = context.object.game
171         rd = context.scene.render
172         return (game.physics_type in ('DYNAMIC', 'RIGID_BODY', 'SENSOR', 'SOFT_BODY', 'STATIC')) and (rd.engine in self.COMPAT_ENGINES)
173
174     def draw_header(self, context):
175         game = context.active_object.game
176
177         self.layout.prop(game, "use_collision_bounds", text="")
178
179     def draw(self, context):
180         layout = self.layout
181
182         game = context.active_object.game
183         wide_ui = context.region.width > narrowui
184
185         layout.active = game.use_collision_bounds
186         if wide_ui:
187             layout.prop(game, "collision_bounds", text="Bounds")
188         else:
189             layout.prop(game, "collision_bounds", text="")
190
191         split = layout.split()
192
193         col = split.column()
194         col.prop(game, "collision_margin", text="Margin", slider=True)
195
196         if wide_ui:
197             col = split.column()
198         col.prop(game, "collision_compound", text="Compound")
199                 
200 class PHYSICS_PT_game_obstacles(PhysicsButtonsPanel):
201     bl_label = "Create obstacle"
202
203     def poll(self, 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 == 'BLENDER_GAME')
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         wide_ui = context.region.width > narrowui
218
219         layout.active = game.create_obstacle
220
221         split = layout.split()
222         col = split.column()
223         col.prop(game, "obstacle_radius", text="Radius")
224
225 class RenderButtonsPanel(bpy.types.Panel):
226     bl_space_type = 'PROPERTIES'
227     bl_region_type = 'WINDOW'
228     bl_context = "render"
229
230     def poll(self, context):
231         rd = context.scene.render
232         return (rd.engine in self.COMPAT_ENGINES)
233
234
235 class RENDER_PT_game(RenderButtonsPanel):
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):
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_data
255         wide_ui = context.region.width > narrowui
256
257         layout.prop(gs, "fullscreen")
258
259         split = layout.split()
260
261         col = split.column()
262         col.label(text="Resolution:")
263         sub = col.column(align=True)
264         sub.prop(gs, "resolution_x", slider=False, text="X")
265         sub.prop(gs, "resolution_y", slider=False, text="Y")
266
267         if wide_ui:
268             col = split.column()
269         col.label(text="Quality:")
270         sub = col.column(align=True)
271         sub.prop(gs, "depth", text="Bit Depth", slider=False)
272         sub.prop(gs, "frequency", text="FPS", slider=False)
273
274         # framing:
275         col = layout.column()
276         col.label(text="Framing:")
277         if wide_ui:
278             col.row().prop(gs, "framing_type", expand=True)
279         else:
280             col.prop(gs, "framing_type", text="")
281         if gs.framing_type == 'LETTERBOX':
282             col.prop(gs, "framing_color", text="")
283
284
285 class RENDER_PT_game_stereo(RenderButtonsPanel):
286     bl_label = "Stereo"
287     COMPAT_ENGINES = {'BLENDER_GAME'}
288
289     def draw(self, context):
290         layout = self.layout
291
292         gs = context.scene.game_data
293         stereo_mode = gs.stereo
294         wide_ui = context.region.width > narrowui
295
296         # stereo options:
297         layout.prop(gs, "stereo", expand=True)
298
299         # stereo:
300         if stereo_mode == 'STEREO':
301             layout.prop(gs, "stereo_mode")
302             layout.prop(gs, "eye_separation")
303
304         # dome:
305         elif stereo_mode == 'DOME':
306             if wide_ui:
307                 layout.prop(gs, "dome_mode", text="Dome Type")
308             else:
309                 layout.prop(gs, "dome_mode", text="")
310
311             dome_type = gs.dome_mode
312
313             split = layout.split()
314
315             if dome_type == 'FISHEYE' or \
316                dome_type == 'TRUNCATED_REAR' or \
317                dome_type == 'TRUNCATED_FRONT':
318
319                 col = split.column()
320                 col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True)
321                 col.prop(gs, "dome_angle", slider=True)
322
323                 if wide_ui:
324                     col = split.column()
325                 col.prop(gs, "dome_tesselation", text="Tesselation")
326                 col.prop(gs, "dome_tilt")
327
328             elif dome_type == 'PANORAM_SPH':
329                 col = split.column()
330
331                 col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True)
332                 if wide_ui:
333                     col = split.column()
334                 col.prop(gs, "dome_tesselation", text="Tesselation")
335
336             else: # cube map
337                 col = split.column()
338                 col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True)
339                 if wide_ui:
340                     col = split.column()
341
342             layout.prop(gs, "dome_text")
343
344
345 class RENDER_PT_game_shading(RenderButtonsPanel):
346     bl_label = "Shading"
347     COMPAT_ENGINES = {'BLENDER_GAME'}
348
349     def draw(self, context):
350         layout = self.layout
351
352         gs = context.scene.game_data
353         wide_ui = context.region.width > narrowui
354
355         if wide_ui:
356             layout.prop(gs, "material_mode", expand=True)
357         else:
358             layout.prop(gs, "material_mode", text="")
359
360         if gs.material_mode == 'GLSL':
361             split = layout.split()
362
363             col = split.column()
364             col.prop(gs, "glsl_lights", text="Lights")
365             col.prop(gs, "glsl_shaders", text="Shaders")
366             col.prop(gs, "glsl_shadows", text="Shadows")
367
368             col = split.column()
369             col.prop(gs, "glsl_ramps", text="Ramps")
370             col.prop(gs, "glsl_nodes", text="Nodes")
371             col.prop(gs, "glsl_extra_textures", text="Extra Textures")
372
373
374 class RENDER_PT_game_performance(RenderButtonsPanel):
375     bl_label = "Performance"
376     COMPAT_ENGINES = {'BLENDER_GAME'}
377
378     def draw(self, context):
379         layout = self.layout
380
381         gs = context.scene.game_data
382         wide_ui = context.region.width > narrowui
383
384         split = layout.split()
385
386         col = split.column()
387         col.label(text="Show:")
388         col.prop(gs, "show_debug_properties", text="Debug Properties")
389         col.prop(gs, "show_framerate_profile", text="Framerate and Profile")
390         col.prop(gs, "show_physics_visualization", text="Physics Visualization")
391         col.prop(gs, "use_deprecation_warnings")
392
393         if wide_ui:
394             col = split.column()
395         col.label(text="Render:")
396         col.prop(gs, "use_frame_rate")
397         col.prop(gs, "use_display_lists")
398
399
400 class RENDER_PT_game_sound(RenderButtonsPanel):
401     bl_label = "Sound"
402     COMPAT_ENGINES = {'BLENDER_GAME'}
403
404     def draw(self, context):
405         layout = self.layout
406
407         scene = context.scene
408         wide_ui = context.region.width > narrowui
409
410         if wide_ui:
411             layout.prop(scene, "distance_model")
412         else:
413             layout.prop(scene, "distance_model", text="")
414         layout.prop(scene, "speed_of_sound", text="Speed")
415         layout.prop(scene, "doppler_factor")
416
417
418 class WorldButtonsPanel(bpy.types.Panel):
419     bl_space_type = 'PROPERTIES'
420     bl_region_type = 'WINDOW'
421     bl_context = "world"
422
423     def poll(self, context):
424         scene = context.scene
425         return (scene.render.engine in self.COMPAT_ENGINES) and (scene.world is not None)
426
427
428 class WORLD_PT_game_context_world(WorldButtonsPanel):
429     bl_label = ""
430     bl_show_header = False
431     COMPAT_ENGINES = {'BLENDER_GAME'}
432
433     def poll(self, context):
434         rd = context.scene.render
435         return (context.scene) and (rd.use_game_engine)
436
437     def draw(self, context):
438         layout = self.layout
439
440         scene = context.scene
441         world = context.world
442         space = context.space_data
443         wide_ui = context.region.width > narrowui
444
445         if wide_ui:
446             split = layout.split(percentage=0.65)
447             if scene:
448                 split.template_ID(scene, "world", new="world.new")
449             elif world:
450                 split.template_ID(space, "pin_id")
451         else:
452             if scene:
453                 layout.template_ID(scene, "world", new="world.new")
454             elif world:
455                 layout.template_ID(space, "pin_id")
456
457
458 class WORLD_PT_game_world(WorldButtonsPanel):
459     bl_label = "World"
460     COMPAT_ENGINES = {'BLENDER_GAME'}
461
462     def draw(self, context):
463         layout = self.layout
464
465         world = context.world
466         wide_ui = context.region.width > narrowui
467
468         split = layout.split()
469
470         col = split.column()
471         col.prop(world, "horizon_color")
472
473         if wide_ui:
474             col = split.column()
475         col.prop(world, "ambient_color")
476
477
478 class WORLD_PT_game_mist(WorldButtonsPanel):
479     bl_label = "Mist"
480     COMPAT_ENGINES = {'BLENDER_GAME'}
481
482     def draw_header(self, context):
483         world = context.world
484
485         self.layout.prop(world.mist, "use_mist", text="")
486
487     def draw(self, context):
488         layout = self.layout
489
490         world = context.world
491         wide_ui = context.region.width > narrowui
492
493         layout.active = world.mist.use_mist
494         split = layout.split()
495
496         col = split.column()
497         col.prop(world.mist, "start")
498
499         if wide_ui:
500             col = split.column()
501         col.prop(world.mist, "depth")
502
503
504 class WORLD_PT_game_physics(WorldButtonsPanel):
505     bl_label = "Physics"
506     COMPAT_ENGINES = {'BLENDER_GAME'}
507
508     def draw(self, context):
509         layout = self.layout
510
511         gs = context.scene.game_data
512         wide_ui = context.region.width > narrowui
513
514         layout.prop(gs, "physics_engine")
515         if gs.physics_engine != 'NONE':
516             layout.prop(gs, "physics_gravity", text="Gravity")
517
518             split = layout.split()
519
520             col = split.column()
521             col.label(text="Physics Steps:")
522             sub = col.column(align=True)
523             sub.prop(gs, "physics_step_max", text="Max")
524             sub.prop(gs, "physics_step_sub", text="Substeps")
525             col.prop(gs, "fps", text="FPS")
526
527             if wide_ui:
528                 col = split.column()
529             col.label(text="Logic Steps:")
530             col.prop(gs, "logic_step_max", text="Max")
531
532             col = layout.column()
533             col.prop(gs, "use_occlusion_culling", text="Occlusion Culling")
534             sub = col.column()
535             sub.active = gs.use_occlusion_culling
536             sub.prop(gs, "occlusion_culling_resolution", text="Resolution")
537
538         else:
539             split = layout.split()
540
541             col = split.column()
542             col.label(text="Physics Steps:")
543             col.prop(gs, "fps", text="FPS")
544
545             col = split.column()
546             col.label(text="Logic Steps:")
547             col.prop(gs, "logic_step_max", text="Max")
548
549 class WORLD_PT_game_physics_obstacles(WorldButtonsPanel):
550     bl_label = "Obstacle simulation"
551     COMPAT_ENGINES = {'BLENDER_GAME'}
552
553     def draw(self, context):
554         layout = self.layout
555
556         gs = context.scene.game_data
557         wide_ui = context.region.width > narrowui
558
559         layout.prop(gs, "obstacle_simulation", text = "Type")
560         if gs.obstacle_simulation != 'None':
561             layout.prop(gs, "level_height")
562             layout.prop(gs, "show_obstacle_simulation")
563                         
564
565 classes = [
566     PHYSICS_PT_game_physics,
567     PHYSICS_PT_game_collision_bounds,
568     PHYSICS_PT_game_obstacles,
569
570     RENDER_PT_game,
571     RENDER_PT_game_player,
572     RENDER_PT_game_stereo,
573     RENDER_PT_game_shading,
574     RENDER_PT_game_performance,
575     RENDER_PT_game_sound,
576
577     WORLD_PT_game_context_world,
578     WORLD_PT_game_world,
579     WORLD_PT_game_mist,
580     WORLD_PT_game_physics,
581     WORLD_PT_game_physics_obstacles]
582
583
584 def register():
585     register = bpy.types.register
586     for cls in classes:
587         register(cls)
588
589
590 def unregister():
591     unregister = bpy.types.unregister
592     for cls in classes:
593         unregister(cls)
594
595 if __name__ == "__main__":
596     register()