8e99f8019255705990a332bbe931c39afe8da331
[blender-addons-contrib.git] / space_view3d_add_surround_cameras.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 bl_info = {
20     "name": "Surround Projection Tools",
21     "author": "Cole Ingraham",
22     "version": (0, 1, 2),
23     "blender": (2, 75, 0),
24     "location": "View3D > Tool Shelf > Surround Projection panel",
25     "description": "Setup cameras and create rendering scenes for n-screen surround projection.",
26     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/Surround_Projection_Tools",
27     "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
28     "category": "3D View"}
29
30
31 import bpy
32 from bpy.props import IntProperty
33 from bpy.props import BoolProperty
34 from math import pi
35 import re
36
37 CAMERA_ORIGIN_NAME = "CameraOrigin"
38
39 # property for how many screens to add
40 bpy.types.WindowManager.num_surround_screens = IntProperty(
41     name="Number of screens",
42     description="How many screens to add",
43     default=4,
44     min=3)
45
46 # safeguard for removing previous cameras/scenes
47 bpy.types.WindowManager.previous_num_surround_screens = IntProperty(
48     name="Previous number of screens",
49     description="used for removing cameras/scenes",
50     default=-1)
51
52 # used to enable/disable make/remove scenes and cameras
53 bpy.types.WindowManager.surround_screens_init = BoolProperty(
54     name="SurroundScenesInit",
55     default=False)
56
57 # GUI panel
58 class AddSurroundCamerasPanel(bpy.types.Panel):
59     bl_space_type = 'VIEW_3D'
60     bl_region_type = 'TOOLS'
61     bl_label = "Surround Projection"
62     bl_category = 'Tools'
63     bl_options = {'DEFAULT_CLOSED'}
64
65     def draw(self, context):
66         layout = self.layout
67         col = layout.column(align=True)
68
69         row = col.row()
70         row.prop(context.window_manager, "num_surround_screens")
71         row = col.row()
72
73         if context.window_manager.previous_num_surround_screens is not -1:
74              row.operator('objects.remove_surround_cameras', icon='X')
75         else:
76              row.operator('objects.add_surround_cameras', icon='CAMERA_DATA')
77
78         row = col.row()
79
80         if context.window_manager.surround_screens_init is True:
81              row.operator('objects.remove_linked_scenes_for_surround_cameras', icon='X')
82         else:
83              row.operator('scene.add_linked_scenes_for_surround_cameras', icon='SCENE_DATA')
84
85         #col = layout.column(align=True)
86         #row = col.row()
87         #row.operator('objects.remove_surround_cameras', icon='X')
88         #row = col.row()
89         #row.operator('objects.remove_linked_scenes_for_surround_cameras', icon='X')
90
91
92 # operator for adding cameras
93 class AddSurroundCamerasOperator(bpy.types.Operator):
94     bl_idname = 'objects.add_surround_cameras'
95     bl_label = "Add Cameras"
96     bl_description = "Add n cameras"
97     bl_options = {'REGISTER', 'UNDO'}
98
99     @classmethod
100     def poll(cls, context):
101         return context.window_manager.previous_num_surround_screens is -1
102
103     def execute(self, context):
104
105         scene = context.scene
106         view_layer = context.view_layer
107         numScreens = context.window_manager.num_surround_screens
108
109         # add an empty for the camera origin if not already present
110         obj_origin = scene.objects.get(CAMERA_ORIGIN_NAME)
111         if not obj_origin:
112             bpy.ops.object.add()
113             obj_origin = context.active_object
114             obj_origin.name = CAMERA_ORIGIN_NAME
115             obj_origin.location = scene.cursor_location
116
117         for i in range(0,numScreens):
118
119             # add a new camer
120             bpy.ops.object.camera_add()
121
122             # get the current camera
123             cam = context.active_object
124
125             # name the camera
126             cameraName = "Camera" + str(i)
127             cam.name = cameraName
128             cam.data.name = cameraName
129
130             # position camera
131             cam.location = 0,0,0
132             cam.rotation_euler = (pi/2), 0, ((-2*pi)/numScreens) * i
133
134             # set the field of view angle
135             cam.data.angle = (2*pi)/numScreens
136
137             # make the parent of the camera the origin
138             cam.parent = obj_origin
139
140         # sel/activate origin
141         bpy.ops.object.select_all(action='DESELECT')
142         obj_origin.select_set(True)
143         view_layer.objects.active = obj_origin
144
145         context.window_manager.previous_num_surround_screens = numScreens
146         return {'FINISHED'}
147
148
149 # operator for creating new linked scenes for each camera
150 class AddSurroundScenesOperator(bpy.types.Operator):
151     bl_idname = 'scene.add_linked_scenes_for_surround_cameras'
152     bl_label = "Make Scenes"
153     bl_description = "Creates new scenes with linked object data for each camera"
154     bl_options = {'REGISTER', 'UNDO'}
155
156     @classmethod
157     def poll(cls, context):
158         if context.window_manager.previous_num_surround_screens is not -1 and context.window_manager.surround_screens_init is False:
159             return True
160         return False
161
162     def execute(self, context):
163         scene_base = context.scene
164         numScreens = context.window_manager.previous_num_surround_screens
165         sceneName = scene_base.name
166         renderpath = scene_base.render.filepath
167
168         for i in range(0, numScreens):
169
170             thisScene = sceneName + "-Camera" + str(i)
171
172             bpy.ops.scene.new(type='EMPTY')
173             scene_new = context.scene
174             scene_new.name = thisScene
175
176             camera_object = bpy.data.objects["Camera" + str(i)]
177             scene_new.camera = camera_object
178             scene_new.background_set = scene_base
179
180             # not essential but nice to have the camera in the scene
181             scene_new.objects.link(camera_object)
182
183             scene_new.render.filepath = renderpath + thisScene
184
185         context.screen.scene = scene_base
186         context.window_manager.surround_screens_init = True
187         return {'FINISHED'}
188
189
190 # operator for removing the surround scenes
191 class RemoveSurroundScenesOperator(bpy.types.Operator):
192     bl_idname = 'objects.remove_linked_scenes_for_surround_cameras'
193     bl_label = "Remove Scenes"
194     bl_description = "Removes all surround scenes"
195     bl_options = {'REGISTER', 'UNDO'}
196
197     @classmethod
198     def poll(cls, context):
199         return context.window_manager.surround_screens_init is True
200
201     def execute(self, context):
202         numScreens = context.window_manager.previous_num_surround_screens
203
204         for scene in list(bpy.data.scenes):
205             if re.search("-Camera",scene.name):
206                 bpy.data.scenes.remove(scene)
207
208         context.window_manager.surround_screens_init = False
209         return {'FINISHED'}
210
211
212 # operator for removing the surround cameras/scenes
213 class RemoveSurroundCamerasOperator(bpy.types.Operator):
214     bl_idname = 'objects.remove_surround_cameras'
215     bl_label = "Remove Cameras"
216     bl_description = "Removes all surround cameras"
217     bl_options = {'REGISTER', 'UNDO'}
218
219     @classmethod
220     def poll(cls, context):
221         if context.window_manager.previous_num_surround_screens is not -1 and context.window_manager.surround_screens_init is False:
222             return True
223         return False
224
225     def execute(self, context):
226
227         scene = context.scene
228
229         # XXX. shouldnt there be some less general way to do this?
230         # like check if they are the child of origin? - campbell
231         for obj in scene.objects[:]:
232             if obj.type == 'CAMERA':
233                 scene.objects.unlink(obj)
234
235         context.window_manager.previous_num_surround_screens = -1
236         return {'FINISHED'}
237
238
239
240 def register():
241     bpy.utils.register_module(__name__)
242
243
244 def unregister():
245     bpy.utils.unregister_module(__name__)
246
247
248 if __name__ == "__main__":
249     register()