Cleanup: autopep8 for 3DS i/o
[blender-addons.git] / space_view3d_stored_views / core.py
blob0ad0b902efb4cd3a7c4e902fa45618a9e3b66548
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Authors: nfloyd, Francesco Siddi
5 import logging
6 module_logger = logging.getLogger(__name__)
8 import hashlib
9 import bpy
12 #Utility function get preferences setting for exporters
13 def get_preferences():
14 # replace the key if the add-on name changes
15 addon = bpy.context.preferences.addons[__package__]
16 show_warn = (addon.preferences.show_exporters if addon else False)
18 return show_warn
21 class StoredView():
22 def __init__(self, mode, index=None):
23 self.logger = logging.getLogger('%s.StoredView' % __name__)
24 self.scene = bpy.context.scene
25 self.view3d = bpy.context.space_data
26 self.index = index
27 self.data_store = DataStore(mode=mode)
29 def save(self):
30 if self.index == -1:
31 stored_view, self.index = self.data_store.create()
32 else:
33 stored_view = self.data_store.get(self.index)
34 self.from_v3d(stored_view)
35 self.logger.debug('index: %s name: %s' % (self.data_store.current_index, stored_view.name))
37 def set(self):
38 stored_view = self.data_store.get(self.index)
39 self.update_v3d(stored_view)
40 self.logger.debug('index: %s name: %s' % (self.data_store.current_index, stored_view.name))
42 def from_v3d(self, stored_view):
43 raise NotImplementedError("Subclass must implement abstract method")
45 def update_v3d(self, stored_view):
46 raise NotImplementedError("Subclass must implement abstract method")
48 @staticmethod
49 def is_modified(context, stored_view):
50 raise NotImplementedError("Subclass must implement abstract method")
53 class POV(StoredView):
54 def __init__(self, index=None):
55 super().__init__(mode='POV', index=index)
56 self.logger = logging.getLogger('%s.POV' % __name__)
58 def from_v3d(self, stored_view):
59 view3d = self.view3d
60 region3d = view3d.region_3d
62 stored_view.distance = region3d.view_distance
63 stored_view.location = region3d.view_location
64 stored_view.rotation = region3d.view_rotation
65 stored_view.perspective_matrix_md5 = POV._get_perspective_matrix_md5(region3d)
66 stored_view.perspective = region3d.view_perspective
67 stored_view.lens = view3d.lens
68 stored_view.clip_start = view3d.clip_start
69 stored_view.clip_end = view3d.clip_end
71 if region3d.view_perspective == 'CAMERA':
72 stored_view.camera_type = view3d.camera.type # type : 'CAMERA' or 'MESH'
73 stored_view.camera_name = view3d.camera.name # store string instead of object
74 if view3d.lock_object is not None:
75 stored_view.lock_object_name = view3d.lock_object.name # idem
76 else:
77 stored_view.lock_object_name = ""
78 stored_view.lock_cursor = view3d.lock_cursor
79 stored_view.cursor_location = bpy.context.scene.cursor.location
81 def update_v3d(self, stored_view):
82 view3d = self.view3d
83 region3d = view3d.region_3d
84 region3d.view_distance = stored_view.distance
85 region3d.view_location = stored_view.location
86 region3d.view_rotation = stored_view.rotation
87 region3d.view_perspective = stored_view.perspective
88 view3d.lens = stored_view.lens
89 view3d.clip_start = stored_view.clip_start
90 view3d.clip_end = stored_view.clip_end
91 view3d.lock_cursor = stored_view.lock_cursor
92 if stored_view.lock_cursor is True:
93 # update cursor only if view is locked to cursor
94 self.scene.cursor.location = stored_view.cursor_location
96 if stored_view.perspective == "CAMERA":
98 lock_obj = self._get_object(stored_view.lock_object_name)
99 if lock_obj:
100 view3d.lock_object = lock_obj
101 else:
102 cam = self._get_object(stored_view.camera_name)
103 if cam:
104 view3d.camera = cam
106 @staticmethod
107 def _get_object(name, pointer=None):
108 return bpy.data.objects.get(name)
110 @staticmethod
111 def is_modified(context, stored_view):
112 # TODO: check for others param, currently only perspective
113 # and perspective_matrix are checked
114 POV.logger = logging.getLogger('%s.POV' % __name__)
115 view3d = context.space_data
116 region3d = view3d.region_3d
117 if region3d.view_perspective != stored_view.perspective:
118 POV.logger.debug('view_perspective')
119 return True
121 md5 = POV._get_perspective_matrix_md5(region3d)
122 if (md5 != stored_view.perspective_matrix_md5 and
123 region3d.view_perspective != "CAMERA"):
124 POV.logger.debug('perspective_matrix')
125 return True
127 return False
129 @staticmethod
130 def _get_perspective_matrix_md5(region3d):
131 md5 = hashlib.md5(str(region3d.perspective_matrix).encode('utf-8')).hexdigest()
132 return md5
135 # class Layers(StoredView):
136 # def __init__(self, index=None):
137 # super().__init__(mode='COLLECTIONS', index=index)
138 # self.logger = logging.getLogger('%s.Layers' % __name__)
140 # def from_v3d(self, stored_view):
141 # view3d = self.view3d
142 # stored_view.view_layers = bpy.types.layer.collection
143 # stored_view.scene_layers = self.scene.layers
144 # stored_view.lock_camera = view3d.lock_camera
146 # def update_v3d(self, stored_view):
147 # view3d = self.view3d
148 # view3d.camera = stored_view.camera
149 # if stored_view.camera is True:
150 # self.scene.layers = stored_view.scene_layers
151 # else:
152 # view3d.layers = stored_view.view_layers
154 # @staticmethod
155 # def is_modified(context, stored_view):
156 # Layers.logger = logging.getLogger('%s.Layers' % __name__)
157 # if stored_view.camera != context.space_data.camera:
158 # Layers.logger.debug('lock_camera')
159 # return True
160 # if stored_view.camera is True:
161 # for i in range(20):
162 # if stored_view.scene_layers[i] != context.scene.layers[i]:
163 # Layers.logger.debug('scene_layers[%s]' % (i, ))
164 # return True
165 # else:
166 # for i in range(20):
167 # if stored_view.view_layers[i] != context.space_data.view3d.layers[i]:
168 # return True
169 # return False
172 # class Display(StoredView):
173 # def __init__(self, index=None):
174 # super().__init__(mode='DISPLAY', index=index)
175 # self.logger = logging.getLogger('%s.Display' % __name__)
177 # def from_v3d(self, stored_view):
178 # view3d = self.view3d
179 # stored_view.viewport_shade = view3d.viewport_shade
180 # stored_view.show_only_render = view3d.show_only_render
181 # stored_view.show_outline_selected = view3d.show_outline_selected
182 # stored_view.show_all_objects_origin = view3d.show_all_objects_origin
183 # stored_view.show_relationship_lines = view3d.show_relationship_lines
184 # stored_view.show_floor = view3d.show_floor
185 # stored_view.show_axis_x = view3d.show_axis_x
186 # stored_view.show_axis_y = view3d.show_axis_y
187 # stored_view.show_axis_z = view3d.show_axis_z
188 # stored_view.grid_lines = view3d.grid_lines
189 # stored_view.grid_scale = view3d.grid_scale
190 # stored_view.grid_subdivisions = view3d.grid_subdivisions
191 # stored_view.material_mode = self.scene.game_settings.material_mode
192 # stored_view.show_textured_solid = view3d.show_textured_solid
194 # def update_v3d(self, stored_view):
195 # view3d = self.view3d
196 # view3d.viewport_shade = stored_view.viewport_shade
197 # view3d.show_only_render = stored_view.show_only_render
198 # view3d.show_outline_selected = stored_view.show_outline_selected
199 # view3d.show_all_objects_origin = stored_view.show_all_objects_origin
200 # view3d.show_relationship_lines = stored_view.show_relationship_lines
201 # view3d.show_floor = stored_view.show_floor
202 # view3d.show_axis_x = stored_view.show_axis_x
203 # view3d.show_axis_y = stored_view.show_axis_y
204 # view3d.show_axis_z = stored_view.show_axis_z
205 # view3d.grid_lines = stored_view.grid_lines
206 # view3d.grid_scale = stored_view.grid_scale
207 # view3d.grid_subdivisions = stored_view.grid_subdivisions
208 # self.scene.game_settings.material_mode = stored_view.material_mode
209 # view3d.show_textured_solid = stored_view.show_textured_solid
211 # @staticmethod
212 # def is_modified(context, stored_view):
213 # Display.logger = logging.getLogger('%s.Display' % __name__)
214 # view3d = context.space_data
215 # excludes = ["material_mode", "quad_view", "lock_rotation", "show_sync_view", "use_box_clip", "name"]
216 # for k, v in stored_view.items():
217 # if k not in excludes:
218 # if getattr(view3d, k) != getattr(stored_view, k):
219 # return True
221 # if stored_view.material_mode != context.scene.game_settings.material_mode:
222 # Display.logger.debug('material_mode')
223 # return True
226 class View(StoredView):
227 def __init__(self, index=None):
228 super().__init__(mode='VIEW', index=index)
229 self.logger = logging.getLogger('%s.View' % __name__)
230 self.pov = POV()
231 # self.layers = Layers()
232 # self.display = Display()
234 def from_v3d(self, stored_view):
235 self.pov.from_v3d(stored_view.pov)
236 # self.layers.from_v3d(stored_view.layers)
237 # self.display.from_v3d(stored_view.display)
239 def update_v3d(self, stored_view):
240 self.pov.update_v3d(stored_view.pov)
241 # self.layers.update_v3d(stored_view.layers)
242 # self.display.update_v3d(stored_view.display)
244 @staticmethod
245 def is_modified(context, stored_view):
246 POV.is_modified(context, stored_view.pov) #or \
247 # Layers.is_modified(context, stored_view.layers) or \
248 # Display.is_modified(context, stored_view.display):
249 return True
250 # return False
253 class DataStore():
254 def __init__(self, scene=None, mode=None):
255 if scene is None:
256 scene = bpy.context.scene
257 stored_views = scene.stored_views
258 self.mode = mode
260 if mode is None:
261 self.mode = stored_views.mode
263 if self.mode == 'VIEW':
264 self.list = stored_views.view_list
265 self.current_index = stored_views.current_indices[0]
266 elif self.mode == 'POV':
267 self.list = stored_views.pov_list
268 self.current_index = stored_views.current_indices[1]
269 elif self.mode == 'LAYERS':
270 self.list = stored_views.layers_list
271 self.current_index = stored_views.current_indices[2]
272 elif self.mode == 'DISPLAY':
273 self.list = stored_views.display_list
274 self.current_index = stored_views.current_indices[3]
276 def create(self):
277 item = self.list.add()
278 item.name = self._generate_name()
279 index = len(self.list) - 1
280 self._set_current_index(index)
281 return item, index
283 def get(self, index):
284 self._set_current_index(index)
285 return self.list[index]
287 def delete(self, index):
288 if self.current_index > index:
289 self._set_current_index(self.current_index - 1)
290 elif self.current_index == index:
291 self._set_current_index(-1)
293 self.list.remove(index)
295 def _set_current_index(self, index):
296 self.current_index = index
297 mode = self.mode
298 stored_views = bpy.context.scene.stored_views
299 if mode == 'VIEW':
300 stored_views.current_indices[0] = index
301 elif mode == 'POV':
302 stored_views.current_indices[1] = index
303 elif mode == 'LAYERS':
304 stored_views.current_indices[2] = index
305 elif mode == 'DISPLAY':
306 stored_views.current_indices[3] = index
308 def _generate_name(self):
309 default_name = str(self.mode)
310 names = []
311 for i in self.list:
312 i_name = i.name
313 if i_name.startswith(default_name):
314 names.append(i_name)
315 names.sort()
316 try:
317 l_name = names[-1]
318 post_fix = l_name.rpartition('.')[2]
319 if post_fix.isnumeric():
320 post_fix = str(int(post_fix) + 1).zfill(3)
321 else:
322 if post_fix == default_name:
323 post_fix = "001"
324 return default_name + "." + post_fix
325 except:
326 return default_name
328 @staticmethod
329 def sanitize_data(scene):
331 def check_objects_references(mode, list):
332 to_remove = []
333 for i, list_item in enumerate(list.items()):
334 key, item = list_item
335 if mode == 'POV' or mode == 'VIEWS':
336 if mode == 'VIEWS':
337 item = item.pov
339 if item.perspective == "CAMERA":
341 camera = bpy.data.objects.get(item.camera_name)
342 if camera is None:
343 try: # pick a default camera TODO: ask to pick?
344 camera = bpy.data.cameras[0]
345 item.camera_name = camera.name
346 except: # couldn't find a camera in the scene
347 pass
349 obj = bpy.data.objects.get(item.lock_object_name)
350 if obj is None and camera is None:
351 to_remove.append(i)
353 for i in reversed(to_remove):
354 list.remove(i)
356 modes = ['POV', 'VIEW', 'DISPLAY', 'LAYERS']
357 for mode in modes:
358 data = DataStore(scene=scene, mode=mode)
359 check_objects_references(mode, data.list)
362 def stored_view_factory(mode, *args, **kwargs):
363 if mode == 'POV':
364 return POV(*args, **kwargs)
365 elif mode == 'LAYERS':
366 return Layers(*args, **kwargs)
367 elif mode == 'DISPLAY':
368 return Display(*args, **kwargs)
369 elif mode == 'VIEW':
370 return View(*args, **kwargs)