Merge branch 'master' into blender2.8
[blender.git] / intern / cycles / blender / addon / version_update.py
1 #
2 # Copyright 2011-2014 Blender Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16
17 # <pep8 compliant>
18
19 import bpy
20
21 from bpy.app.handlers import persistent
22
23
24 def check_is_new_shading_ntree(node_tree):
25     for node in node_tree.nodes:
26         # If material has any node with ONLY new shading system
27         # compatibility then it's considered a Cycles material
28         # and versioning code would need to perform on it.
29         #
30         # We can not check for whether NEW_SHADING in compatibility
31         # because some nodes could have compatibility with both old
32         # and new shading system and they can't be used for any
33         # decision here.
34         if node.shading_compatibility == {'NEW_SHADING'}:
35             return True
36
37         # If node is only compatible with old shading system
38         # then material can not be Cycles material and we
39         # can stopiterating nodes now.
40         if node.shading_compatibility == {'OLD_SHADING'}:
41             return False
42     return False
43
44
45 def check_is_new_shading_material(material):
46     if not material.node_tree:
47         return False
48     return check_is_new_shading_ntree(material.node_tree)
49
50
51 def check_is_new_shading_world(world):
52     if not world.node_tree:
53         return False
54     return check_is_new_shading_ntree(world.node_tree)
55
56
57 def check_is_new_shading_lamp(lamp):
58     if not lamp.node_tree:
59         return False
60     return check_is_new_shading_ntree(lamp.node_tree)
61
62
63 def foreach_notree_node(nodetree, callback, traversed):
64     if nodetree in traversed:
65         return
66     traversed.add(nodetree)
67     for node in nodetree.nodes:
68         callback(node)
69         if node.bl_idname == 'ShaderNodeGroup':
70             foreach_notree_node(node.node_tree, callback, traversed)
71
72
73 def foreach_cycles_node(callback):
74     traversed = set()
75     for material in bpy.data.materials:
76         if check_is_new_shading_material(material):
77                 foreach_notree_node(material.node_tree,
78                                     callback,
79                                     traversed)
80     for world in bpy.data.worlds:
81         if check_is_new_shading_world(world):
82                 foreach_notree_node(world.node_tree,
83                                     callback,
84                                     traversed)
85     for lamp in bpy.data.lamps:
86         if check_is_new_shading_world(lamp):
87                 foreach_notree_node(lamp.node_tree,
88                                     callback,
89                                     traversed)
90
91
92 def mapping_node_order_flip(node):
93     """
94     Flip euler order of mapping shader node
95     """
96     if node.bl_idname == 'ShaderNodeMapping':
97         rot = node.rotation.copy()
98         rot.order = 'ZYX'
99         quat = rot.to_quaternion()
100         node.rotation = quat.to_euler('XYZ')
101
102
103 def vector_curve_node_remap(node):
104     """
105     Remap values of vector curve node from normalized to absolute values
106     """
107     if node.bl_idname == 'ShaderNodeVectorCurve':
108         node.mapping.use_clip = False
109         for curve in node.mapping.curves:
110             for point in curve.points:
111                 point.location.x = (point.location.x * 2.0) - 1.0
112                 point.location.y = (point.location.y - 0.5) * 2.0
113         node.mapping.update()
114
115
116 def custom_bake_remap(scene):
117     """
118     Remap bake types into the new types and set the flags accordingly
119     """
120     bake_lookup = (
121         'COMBINED',
122         'AO',
123         'SHADOW',
124         'NORMAL',
125         'UV',
126         'EMIT',
127         'ENVIRONMENT',
128         'DIFFUSE_DIRECT',
129         'DIFFUSE_INDIRECT',
130         'DIFFUSE_COLOR',
131         'GLOSSY_DIRECT',
132         'GLOSSY_INDIRECT',
133         'GLOSSY_COLOR',
134         'TRANSMISSION_DIRECT',
135         'TRANSMISSION_INDIRECT',
136         'TRANSMISSION_COLOR',
137         'SUBSURFACE_DIRECT',
138         'SUBSURFACE_INDIRECT',
139         'SUBSURFACE_COLOR')
140
141     diffuse_direct_idx = bake_lookup.index('DIFFUSE_DIRECT')
142
143     cscene = scene.cycles
144
145     # Old bake type
146     bake_type_idx = cscene.get("bake_type")
147
148     if bake_type_idx is None:
149         cscene.bake_type = 'COMBINED'
150         return
151
152     # File doesn't need versioning
153     if bake_type_idx < diffuse_direct_idx:
154         return
155
156     # File needs versioning
157     bake_type = bake_lookup[bake_type_idx]
158     cscene.bake_type, end = bake_type.split('_')
159
160     if end == 'DIRECT':
161         scene.render.bake.use_pass_indirect = False
162         scene.render.bake.use_pass_color = False
163
164     elif end == 'INDIRECT':
165         scene.render.bake.use_pass_direct = False
166         scene.render.bake.use_pass_color = False
167
168     elif end == 'COLOR':
169         scene.render.bake.use_pass_direct = False
170         scene.render.bake.use_pass_indirect = False
171
172
173 @persistent
174 def do_versions(self):
175     if bpy.context.user_preferences.version <= (2, 78, 1):
176         prop = bpy.context.user_preferences.addons[__package__].preferences
177         system = bpy.context.user_preferences.system
178         if not prop.is_property_set("compute_device_type"):
179             # Device might not currently be available so this can fail
180             try:
181                 if system.legacy_compute_device_type == 1:
182                     prop.compute_device_type = 'OPENCL'
183                 elif system.legacy_compute_device_type == 2:
184                     prop.compute_device_type = 'CUDA'
185                 else:
186                     prop.compute_device_type = 'NONE'
187             except:
188                 pass
189
190             # Init device list for UI
191             prop.get_devices()
192
193     # We don't modify startup file because it assumes to
194     # have all the default values only.
195     if not bpy.data.is_saved:
196         return
197
198     # Clamp Direct/Indirect separation in 270
199     if bpy.data.version <= (2, 70, 0):
200         for scene in bpy.data.scenes:
201             cscene = scene.cycles
202             sample_clamp = cscene.get("sample_clamp", False)
203             if (sample_clamp and
204                 not cscene.is_property_set("sample_clamp_direct") and
205                 not cscene.is_property_set("sample_clamp_indirect")):
206
207                 cscene.sample_clamp_direct = sample_clamp
208                 cscene.sample_clamp_indirect = sample_clamp
209
210     # Change of Volume Bounces in 271
211     if bpy.data.version <= (2, 71, 0):
212         for scene in bpy.data.scenes:
213             cscene = scene.cycles
214             if not cscene.is_property_set("volume_bounces"):
215                 cscene.volume_bounces = 1
216
217     # Caustics Reflective/Refractive separation in 272
218     if bpy.data.version <= (2, 72, 0):
219         for scene in bpy.data.scenes:
220             cscene = scene.cycles
221             if (cscene.get("no_caustics", False) and
222                 not cscene.is_property_set("caustics_reflective") and
223                 not cscene.is_property_set("caustics_refractive")):
224
225                 cscene.caustics_reflective = False
226                 cscene.caustics_refractive = False
227
228     # Euler order was ZYX in previous versions.
229     if bpy.data.version <= (2, 73, 4):
230         foreach_cycles_node(mapping_node_order_flip)
231
232     if bpy.data.version <= (2, 76, 5):
233         foreach_cycles_node(vector_curve_node_remap)
234
235     # Baking types changed
236     if bpy.data.version <= (2, 76, 6):
237         for scene in bpy.data.scenes:
238             custom_bake_remap(scene)
239
240     # Several default changes for 2.77
241     if bpy.data.version <= (2, 76, 8):
242         for scene in bpy.data.scenes:
243             cscene = scene.cycles
244
245             # Samples
246             if not cscene.is_property_set("samples"):
247                 cscene.samples = 10
248
249             # Preview Samples
250             if not cscene.is_property_set("preview_samples"):
251                 cscene.preview_samples = 10
252
253             # Filter
254             if not cscene.is_property_set("filter_type"):
255                 cscene.pixel_filter_type = 'GAUSSIAN'
256
257             # Tile Order
258             if not cscene.is_property_set("tile_order"):
259                 cscene.tile_order = 'CENTER'
260
261         for lamp in bpy.data.lamps:
262             clamp = lamp.cycles
263
264             # MIS
265             if not clamp.is_property_set("use_multiple_importance_sampling"):
266                 clamp.use_multiple_importance_sampling = False
267
268         for mat in bpy.data.materials:
269             cmat = mat.cycles
270
271             # Volume Sampling
272             if not cmat.is_property_set("volume_sampling"):
273                 cmat.volume_sampling = 'DISTANCE'
274
275     if bpy.data.version <= (2, 76, 9):
276         for world in bpy.data.worlds:
277             cworld = world.cycles
278
279             # World MIS
280             if not cworld.is_property_set("sample_as_light"):
281                 cworld.sample_as_light = False
282
283             # World MIS Samples
284             if not cworld.is_property_set("samples"):
285                 cworld.samples = 4
286
287             # World MIS Resolution
288             if not cworld.is_property_set("sample_map_resolution"):
289                 cworld.sample_map_resolution = 256
290
291     if bpy.data.version <= (2, 76, 10):
292         for scene in bpy.data.scenes:
293             cscene = scene.cycles
294             if cscene.is_property_set("filter_type"):
295                 if not cscene.is_property_set("pixel_filter_type"):
296                     cscene.pixel_filter_type = cscene.filter_type
297                 if cscene.filter_type == 'BLACKMAN_HARRIS':
298                     cscene.filter_type = 'GAUSSIAN'
299
300     if bpy.data.version <= (2, 78, 2):
301         for scene in bpy.data.scenes:
302             cscene = scene.cycles
303             if not cscene.is_property_set("light_sampling_threshold"):
304                 cscene.light_sampling_threshold = 0.0
305
306     if bpy.data.version <= (2, 79, 0):
307         for scene in bpy.data.scenes:
308             cscene = scene.cycles
309             # Default changes
310             if not cscene.is_property_set("aa_samples"):
311                 cscene.aa_samples = 4
312             if not cscene.is_property_set("preview_aa_samples"):
313                 cscene.preview_aa_samples = 4
314             if not cscene.is_property_set("blur_glossy"):
315                 cscene.blur_glossy = 0.0
316             if not cscene.is_property_set("sample_clamp_indirect"):
317                 cscene.sample_clamp_indirect = 0.0