Fix for bl_info blender versions, many addons used (2, 6, x) instead of (2, 6x, x...
[blender-addons-contrib.git] / space_view3d_paint_bprojection.py
1 bl_info = {
2     "name": "BProjection",
3     "description": "Help Clone tool",
4     "author": "kgeogeo",
5     "version": (2, 0),
6     "blender": (2, 66, 0),
7     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/bprojection",
8     "tracker_url":"http://projects.blender.org/tracker/index.php?func=detail&aid=30521&group_id=153&atid=468",
9     "category": "Paint"}
10
11 import bpy
12 from bpy.app.handlers import persistent
13 from bpy.types import Panel, Operator
14 from bpy.props import IntProperty, FloatProperty, BoolProperty, IntVectorProperty, StringProperty, FloatVectorProperty, CollectionProperty
15 from bpy_extras import view3d_utils
16 import math
17 from math import *
18 import mathutils
19 from mathutils import *
20
21 BProjection_Empty    = 'Empty for BProjection'
22 BProjection_Material = 'Material for BProjection'
23 BProjection_Texture  = 'Texture for BProjection'
24
25 # Main function for align the plan to view
26 def align_to_view(context):
27     global last_mouse
28     last_mouse = Vector((0,0))
29     ob = context.object
30     em = bpy.data.objects[BProjection_Empty]
31     rotation = em.custom_rotation
32     scale = em.custom_scale
33     z = em.custom_location.z
34     pos = [em.custom_location.x, em.custom_location.y]
35
36     reg = context.region
37     width = reg.width
38     height = reg.height
39
40     sd = context.space_data
41     r3d = sd.region_3d
42     r3d.update()
43     vr = r3d.view_rotation
44     quat = mathutils.Quaternion((0.0, 0.0, 1.0), math.radians(float(rotation)))
45     v = Vector((pos[0],pos[1],z))
46     v.rotate(vr)
47
48     em = bpy.data.objects[BProjection_Empty]
49     img = bpy.data.textures[BProjection_Texture].image
50     if img and img.size[1] != 0:
51         prop = img.size[0]/img.size[1]
52     else: prop = 1
53
54     if em.custom_linkscale:
55         em.scale = Vector((prop*scale[0], scale[0], 1))
56     else:
57         em.scale = Vector((prop*scale[0], scale[1], 1))
58     pos_cur = em.location - sd.cursor_location
59     rot_cur1 = em.rotation_euler.to_quaternion()
60     em.location = v + ob.location
61     em.rotation_euler = Quaternion.to_euler(vr*quat)
62     if em.custom_c3d:
63         if em.custom_old_scale != em.custom_scale:
64             pos_cur = em.location - sd.cursor_location
65         rot_cur2 = em.rotation_euler.to_quaternion()
66         rot_cur1.invert()
67         pos_cur.rotate(rot_cur1)
68         pos_cur.rotate(rot_cur2)
69         v = em.location - pos_cur
70         sd.cursor_location =  v
71
72 def applyimage(context):
73         img = bpy.data.textures[BProjection_Texture].image
74         em = bpy.data.objects[BProjection_Empty]
75         ob = context.object
76
77         face = ob.data.polygons
78         uvdata = ob.data.uv_textures.active.data
79
80         for f,d in zip(face,uvdata):
81             if f.select:
82                 d.image = img
83
84         align_to_view(context)
85         ob.data.update()
86
87 # Function to update the properties
88 def update_Location(self, context):
89     align_to_view(context)
90
91 def find_uv(context):
92     obj = context.object
93     me = obj.data.vertices
94     vg = obj.vertex_groups
95     l=[]
96     index_uv = 0
97     for face in obj.data.polygons:
98         x=len(face.vertices)
99         for vertex in face.vertices:
100             if len(me[vertex].groups)>0:
101                 for g in me[vertex].groups:
102                     if vg[g.group].name == 'texture plane':
103                         x-=1
104
105
106         if x == 0:
107             l.append([index_uv,len(face.vertices)])
108         index_uv += len(face.vertices)
109     return l
110
111 # Function to update the scaleUV
112 def update_UVScale(self, context):
113     ob = context.object
114     em = bpy.data.objects[BProjection_Empty]
115     v = Vector((em.custom_offsetuv[0]/10 + 0.5, em.custom_offsetuv[1]/10 + 0.5))
116     l = Vector((0.0,0.0))
117     s = em.custom_scaleuv
118     os = em.custom_old_scaleuv
119     scale = s - os
120     l = find_uv(context)
121     for i,j in l:
122         for t in range(j):
123             d = context.object.data.uv_layers.active.data[i+t]
124             vres =  v - d.uv
125             d.uv.x = v.x - vres.x/os[0]*s[0]
126             d.uv.y = v.y - vres.y/os[1]*s[1]
127
128     em.custom_old_scaleuv = s
129
130     applyimage(context)
131
132 def update_PropUVScale(self, context):
133     em = bpy.data.objects[BProjection_Empty]
134     if em.custom_linkscaleuv:
135         em.custom_scaleuv = [em.custom_propscaleuv,em.custom_propscaleuv]
136
137 def update_LinkUVScale(self, context):
138     em = bpy.data.objects[BProjection_Empty]
139     if em.custom_linkscaleuv:
140         em.custom_propscaleuv = em.custom_scaleuv.x
141         update_PropUVScale(self, context)
142     else:
143         update_UVScale(self, context)
144
145 # Function to update the offsetUV
146 def update_UVOffset(self, context):
147     ob = context.object
148     em = bpy.data.objects[BProjection_Empty]
149     o = em.custom_offsetuv
150     oo = em.custom_old_offsetuv
151     l = find_uv(context)
152     for i,j in l:
153         for t in range(j):
154             d = context.object.data.uv_layers.active.data[i+t]
155             d.uv = [d.uv[0] - oo[0]/10 + o[0]/10, d.uv[1] - oo[1]/10 + o[1]/10]
156     em.custom_old_offsetuv = o
157
158     applyimage(context)
159
160 # Function to update the flip horizontal
161 def update_FlipUVX(self, context):
162     l = find_uv(context)
163     for i,j in l:
164         for t in range(j):
165             d = context.object.data.uv_layers.active.data[i+t]
166             x = d.uv.x
167             d.uv.x = 1 - x
168
169     applyimage(context)
170
171 # Function to update the flip vertical
172 def update_FlipUVY(self, context):
173     l = find_uv(context)
174     for i,j in l:
175         for t in range(j):
176             d = context.object.data.uv_layers.active.data[i+t]
177             y = d.uv[1]
178             d.uv[1] = 1 - y
179
180     applyimage(context)
181
182 # Function to update
183 def update_Rotation(self, context):
184     ob = context.object
185     em = bpy.data.objects[BProjection_Empty]
186     if em.custom_rotc3d:
187         angle = em.custom_rotation - em.custom_old_rotation
188         sd = context.space_data
189         vr = sd.region_3d.view_rotation.copy()
190         c = sd.cursor_location - ob.location
191         e = bpy.data.objects[BProjection_Empty].location - ob.location
192         vo = Vector((0.0, 0.0, 1.0))
193         vo.rotate(vr)
194         quat = mathutils.Quaternion(vo, math.radians(angle))
195         v = e-c
196         v.rotate(quat)
197         vr.invert()
198         v.rotate(vr)
199         c.rotate(vr)
200         em.custom_location = c + v
201     else:
202         align_to_view(context)
203
204     em.custom_old_rotation = em.custom_rotation
205
206 # Function to update scale
207 def update_Scale(self, context):
208     ob = context.object
209     em = bpy.data.objects[BProjection_Empty]
210
211     if em.custom_scac3d:
212         sd = context.space_data
213         r3d =  sd.region_3d
214         vr = r3d.view_rotation.copy()
215         vr.invert()
216         e = em.location - ob.location
217         c = sd.cursor_location - ob.location
218         ce = e - c
219
220         s = em.custom_scale
221         os = em.custom_old_scale
222         c.rotate(vr)
223         ce.rotate(vr)
224
225         img = bpy.data.textures[BProjection_Texture].image
226         if img and img.size[1] != 0:
227             prop = img.size[0]/img.size[1]
228         else: prop = 1
229
230         v = Vector((s.x*ce.x/os.x, s.y*ce.y/os.y,0.0))
231         em.custom_location = c + v
232
233
234     else:
235         align_to_view(context)
236
237     em.custom_old_scale = em.custom_scale
238
239 def update_PropScale(self, context):
240     em = bpy.data.objects[BProjection_Empty]
241     if em.custom_linkscale:
242         em.custom_scale = [em.custom_propscale,em.custom_propscale]
243
244 def update_LinkScale(self, context):
245     em = bpy.data.objects[BProjection_Empty]
246     if em.custom_linkscale:
247         em.custom_propscale = em.custom_scale.x
248         update_PropScale(self, context)
249     else:
250         update_Scale(self, context)
251
252 def update_activeviewname(self, context):
253     em = bpy.data.objects[BProjection_Empty]
254     if self.custom_active:
255         em.custom_active_view = self.custom_active_view
256
257 def update_style_clone(self, context):
258     km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
259     for kmi in km.keymap_items:
260         if self.custom_style_clone:
261             if kmi.idname == 'paint.image_paint':
262                 kmi.idname = 'paint.bp_paint'
263         else:
264             if kmi.idname == 'paint.bp_paint':
265                 kmi.idname = 'paint.image_paint'
266
267 class custom_props(bpy.types.PropertyGroup):
268     custom_fnlevel = IntProperty(name="Fast navigate level", description="Increase or decrease the SubSurf level, decrease make navigation faster", default=0)
269
270     custom_location = FloatVectorProperty(name="Location", description="Location of the plane",
271                                           default=(1.0,0,-1.0),
272                                           subtype = 'XYZ',
273                                           soft_min = -10,
274                                           soft_max = 10,
275                                           step=0.1,
276                                           size=3)
277
278     custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
279                                     min=-180, max=180, default=0)
280
281     custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
282                                        default=(1.0, 1.0),
283                                        subtype = 'XYZ',
284                                        min = 0.1,
285                                        max = 10,
286                                        soft_min=0.1,
287                                        soft_max=10,
288                                        step=0.1,
289                                        size=2)
290     custom_propscale = FloatProperty(name="PropScale", description="Scale the Plane",
291                                      default=1.0,
292                                      min = 0.1,
293                                      max = 10,
294                                      soft_min=0.1,
295                                      soft_max=10,
296                                      step=0.1)
297
298     custom_linkscale = BoolProperty(name="linkscale", default=True)
299
300     # UV properties
301     custom_scaleuv = FloatVectorProperty(name="ScaleUV", description="Scale the texture's UV",
302                                             default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2)
303     custom_propscaleuv = FloatProperty(name="PropScaleUV", description="Scale the texture's UV",
304                                            default=1.0,min = 0.01)
305     custom_offsetuv = FloatVectorProperty(name="OffsetUV", description="Decal the texture's UV",
306                                             default=(0.0,0.0), subtype = 'XYZ', size=2)
307     custom_linkscaleuv = BoolProperty(name="linkscaleUV", default=True)
308     custom_flipuvx = BoolProperty(name="flipuvx", default=False)
309     custom_flipuvy = BoolProperty(name="flipuvy", default=False)
310
311     # other properties
312     custom_active= BoolProperty(name="custom_active", default=True)
313     custom_expand = BoolProperty(name="expand", default=False)
314     custom_style_clone = BoolProperty(name="custom_style_clone", default=False)
315
316     custom_active_view = StringProperty(name = "custom_active_view",default = "View",update = update_activeviewname)
317
318     custom_image = StringProperty(name = "custom_image",default = "")
319
320     custom_index = IntProperty()
321
322 # Function to create custom properties
323 def createcustomprops(context):
324     Ob = bpy.types.Object
325
326     Ob.custom_fnlevel = IntProperty(name="Fast navigate level", description="Increase or decrease the SubSurf level, decrease make navigation faster", default=0)
327
328     # plane properties
329     Ob.custom_location = FloatVectorProperty(name="Location", description="Location of the plane",
330                                            default  = (1.0, 0, -1.0),
331                                            subtype  = 'XYZ',
332                                            size     = 3,
333                                            step     = 0.5,
334                                            soft_min = -10,
335                                            soft_max = 10,
336                                            update = update_Location)
337
338     Ob.custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
339                                        min=-180, max=180, default=0,update = update_Rotation)
340
341     Ob.custom_old_rotation = FloatProperty(name="old_Rotation", description="Old Rotate the plane",
342                                            min=-180, max=180, default=0)
343
344     Ob.custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
345                                           subtype = 'XYZ',
346                                           default=(1.0, 1.0),
347                                           min = 0.1,
348                                           max = 10,
349                                           soft_min = 0.1,
350                                           soft_max = 10,
351                                           size=2,
352                                           step=0.5,
353                                           update = update_Scale)
354
355     Ob.custom_propscale = FloatProperty(name="PropScale", description="Scale the Plane",
356                                         default  = 1.0,
357                                         min      = 0.1,
358                                         soft_min = 0.1,
359                                         soft_max = 10,
360                                         step     = 0.5,
361                                         update   = update_PropScale)
362
363     Ob.custom_old_scale = FloatVectorProperty(name="old_Scales", description="Old Scale the planes",
364                                           subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2)
365
366     Ob.custom_linkscale = BoolProperty(name="linkscale", default=True, update = update_LinkScale)
367
368
369     Ob.custom_sub = IntProperty(name="Subdivide", description="Number of subdivision of the plane",
370                                      min=0, max=20, default=0)
371
372     # UV properties
373     Ob.custom_scaleuv = FloatVectorProperty(name="ScaleUV", description="Scale the texture's UV",
374                                             default  = (1.0,1.0),
375                                             soft_min = 0.01,
376                                             soft_max = 100,
377                                             min      = 0.01,
378                                             subtype  = 'XYZ',
379                                             size     = 2,
380                                             update   = update_UVScale)
381
382     Ob.custom_propscaleuv = FloatProperty(name="PropScaleUV", description="Scale the texture's UV",
383                                           default    = 1.0,
384                                           soft_min   = 0.01,
385                                           soft_max   = 100,
386                                           min        = 0.01,
387                                           update     = update_PropUVScale)
388
389     Ob.custom_old_scaleuv = FloatVectorProperty(name="old_ScaleUV", description="Scale the texture's UV",
390                                                 default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2)
391     Ob.custom_offsetuv = FloatVectorProperty(name="OffsetUV", description="Decal the texture's UV",
392                                             default=(0.0,0.0), subtype = 'XYZ', size=2,update = update_UVOffset)
393     Ob.custom_old_offsetuv = FloatVectorProperty(name="old_OffsetUV", description="Decal the texture's UV",
394                                                  default=(0.0,0.0), subtype = 'XYZ', size=2)
395     Ob.custom_linkscaleuv = BoolProperty(name="linkscaleUV", default=True, update = update_LinkUVScale)
396     Ob.custom_flipuvx = BoolProperty(name="flipuvx", default=False, update = update_FlipUVX)
397     Ob.custom_flipuvy = BoolProperty(name="flipuvy", default=False, update = update_FlipUVY)
398
399     # other properties
400     Ob.custom_c3d = BoolProperty(name="c3d", default=True)
401     Ob.custom_rotc3d = BoolProperty(name="rotc3d", default=False)
402     Ob.custom_scac3d = BoolProperty(name="scac3d", default=False)
403     Ob.custom_expand = BoolProperty(name="expand", default=True)
404     Ob.custom_style_clone = BoolProperty(name="custom_style_clone", default=False, update = update_style_clone)
405
406     Ob.custom_active_view = StringProperty(name = "custom_active_view",default = "View")
407     try:
408         Ob.custom_active_object = StringProperty(name = "custom_active_object",default = context.object.name)
409     except:
410         Ob.custom_active_object = StringProperty(name = "custom_active_object",default = 'debut')
411     Ob.custom_props = CollectionProperty(type = custom_props)
412
413 # Function to remove custom properties
414 def removecustomprops():
415     list_prop = ['custom_location', 'custom_rotation', 'custom_old_rotation', 'custom_scale', 'custom_old_scale', 'custom_c3d',
416                  'custom_rotc3d', 'custom_scaleuv', 'custom_flipuvx', 'custom_flipuvy', 'custom_linkscale',
417                  'custom_linkscaleuv', 'custom_old_scaleuv', 'custom_offsetuv', 'custom_old_offsetuv', 'custom_scac3d', 'custom_sub',
418                  'custom_expand', 'custom_style_clone', 'custom_active_view', 'custom_propscaleuv', 'custom_props', 'custom_propscale']
419     for prop in list_prop:
420         try:
421             del bpy.data.objects[BProjection_Empty][prop]
422         except:
423             pass
424
425 def clear_props(context):
426     em = bpy.data.objects[BProjection_Empty]
427     em.custom_scale = [1,1]
428     em.custom_rotation = 0
429     em.custom_scaleuv =[1.0,1.0]
430     em.custom_offsetuv =[0.0,0.0]
431     em.custom_propscaleuv = 1.0
432     em.custom_propscale = 1.0
433     if em.custom_flipuvx == True:
434         em.custom_flipuvx = False
435     if em.custom_flipuvy == True:
436         em.custom_flipuvy = False
437
438 # Oprerator Class to create view
439 class CreateView(Operator):
440     bl_idname = "object.create_view"
441     bl_label = "Create a new view"
442
443     def execute(self, context):
444         ob = context.object
445         em = bpy.data.objects[BProjection_Empty]
446         new_props = em.custom_props.add()
447         em.custom_active_view = new_props.custom_active_view
448         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = True
449         bpy.ops.object.shape_key_add(from_mix = False)
450         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].value = 1.0
451         new_props.custom_index = len(em.custom_props)-1
452         bpy.ops.object.active_view(index = new_props.custom_index)
453         return {'FINISHED'}
454
455 # Oprerator Class to copy view
456 class SaveView(Operator):
457     bl_idname = "object.save_view"
458     bl_label = "copy the view"
459
460     index = IntProperty(default = 0)
461
462     def execute(self, context):
463         em = bpy.data.objects[BProjection_Empty]
464         prop = em.custom_props[self.index]
465         prop.custom_rotation =  em.custom_rotation
466         prop.custom_scale =  em.custom_scale
467         prop.custom_linkscale =  em.custom_linkscale
468         prop.custom_scaleuv = em.custom_scaleuv
469         prop.custom_propscale = em.custom_propscale
470         prop.custom_offsetuv =  em.custom_offsetuv
471         prop.custom_linkscaleuv = em.custom_linkscaleuv
472         prop.custom_propscaleuv = em.custom_propscaleuv
473         prop.custom_flipuvx = em.custom_flipuvx
474         prop.custom_flipuvy = em.custom_flipuvy
475         try:
476             prop.custom_image = bpy.data.textures[BProjection_Texture].image.name
477         except:
478             pass
479
480         return {'FINISHED'}
481
482 # Oprerator Class to copy view
483 class PasteView(Operator):
484     bl_idname = "object.paste_view"
485     bl_label = "paste the view"
486
487     index = IntProperty(default = 0)
488
489     def execute(self, context):
490         em = bpy.data.objects[BProjection_Empty]
491         tmp_scac3d = em.custom_scac3d
492         tmp_rotc3d = em.custom_rotc3d
493         em.custom_scac3d = False
494         em.custom_rotc3d = False
495         prop = em.custom_props[self.index]
496         em.custom_linkscale =  prop.custom_linkscale
497         em.custom_offsetuv =  prop.custom_offsetuv
498         em.custom_linkscaleuv = prop.custom_linkscaleuv
499         em.custom_scaleuv = prop.custom_scaleuv
500         em.custom_propscaleuv = prop.custom_propscaleuv
501         em.custom_rotation =  prop.custom_rotation
502         em.custom_scale =  prop.custom_scale
503         em.custom_propscale = prop.custom_propscale
504         if prop.custom_image != '':
505             if bpy.data.textures[BProjection_Texture].image.name != prop.custom_image:
506                 bpy.data.textures[BProjection_Texture].image = bpy.data.images[prop.custom_image]
507                 applyimage(context)
508         if em.custom_flipuvx != prop.custom_flipuvx:
509             em.custom_flipuvx = prop.custom_flipuvx
510         if em.custom_flipuvy != prop.custom_flipuvy:
511             em.custom_flipuvy = prop.custom_flipuvy
512         em.custom_scac3d = tmp_scac3d
513         em.custom_rotc3d = tmp_rotc3d
514         return {'FINISHED'}
515
516 # Oprerator Class to remove view
517 class RemoveView(Operator):
518     bl_idname = "object.remove_view"
519     bl_label = "Rmeove the view"
520
521     index = IntProperty(default = 0)
522
523     def execute(self, context):
524         ob = context.object
525         em = bpy.data.objects[BProjection_Empty]
526
527         ob.active_shape_key_index =  self.index + 1
528         bpy.ops.object.shape_key_remove()
529
530         if  em.custom_props[self.index].custom_active:
531             if len(em.custom_props) > 0:
532                 bpy.ops.object.active_view(index = self.index-1)
533             if self.index == 0 and len(em.custom_props) > 1:
534                 bpy.ops.object.active_view(index = 1)
535
536         em.custom_props.remove(self.index)
537
538         if len(em.custom_props) == 0:
539             clear_props(context)
540
541             bpy.ops.object.create_view()
542
543         i=0
544         for item in em.custom_props:
545             item.custom_index = i
546             i+=1
547
548         for item in (item for item in em.custom_props if item.custom_active):
549                 ob.active_shape_key_index = item.custom_index+1
550
551         return {'FINISHED'}
552
553 # Oprerator Class to copy view
554 class ActiveView(Operator):
555     bl_idname = "object.active_view"
556     bl_label = "Active the view"
557
558     index = IntProperty(default = 0)
559
560     def execute(self, context):
561         ob = context.object
562         em = bpy.data.objects[BProjection_Empty]
563         for item in (item for item in em.custom_props if item.custom_active == True):
564             bpy.ops.object.save_view(index = item.custom_index)
565             item.custom_active = False
566         em.custom_props[self.index].custom_active  = True
567         em.custom_active_view = em.custom_props[self.index].custom_active_view
568         ob.active_shape_key_index =  self.index + 1
569
570         for i in ob.data.shape_keys.key_blocks:
571             i.mute = True
572
573         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = False
574
575         bpy.ops.object.paste_view(index = self.index)
576
577         return {'FINISHED'}
578
579 # Draw Class to show the panel
580 class BProjection(Panel):
581     bl_space_type = 'VIEW_3D'
582     bl_region_type = 'UI'
583     bl_label = "BProjection"
584
585     @classmethod
586     def poll(cls, context):
587         return (context.image_paint_object or context.sculpt_object)
588
589     def draw(self, context):
590         layout = self.layout
591         if  BProjection_Empty in [ob.name for ob in bpy.data.objects]:
592             tex = bpy.data.textures[BProjection_Texture]
593
594             ob = context.object
595             em = bpy.data.objects[BProjection_Empty]
596             if ob == bpy.data.objects[em.custom_active_object]:
597                 col = layout.column(align =True)
598                 col.operator("object.removebprojectionplane", text="Remove BProjection plane")
599
600             try:
601                 matBProjection = bpy.data.materials[BProjection_Material]
602             except:
603                 matBProjection = None
604
605             box = layout.box()
606
607             row = box.row()
608             if not em.custom_expand:
609                 row.prop(em, "custom_expand", text  = "", icon="TRIA_RIGHT", emboss=False)
610                 row.label(text= 'Paint Object: '+ ob.name)
611             else:
612                 row.prop(em, "custom_expand", text = "" , icon="TRIA_DOWN", emboss=False)
613                 row.label(text= 'Paint Object: '+ ob.name)
614
615                 if ob == bpy.data.objects[em.custom_active_object]:
616                     col = box.column(align =True)
617                     col.template_ID(tex, "image", open="image.open")
618                     row  = box.row(align=True)
619                     row.operator('object.applyimage', text="Apply image", icon = 'FILE_TICK')
620                     row.prop(em, "custom_c3d",text="", icon='CURSOR')
621                     row  = box.row(align =True)
622                     row.label(text="Location:")
623                     row  = box.row(align =True)
624                     row.prop(em,'custom_location', text='')
625                     row  = box.row(align =True)
626                     row.prop(em,'custom_rotation')
627                     row.prop(em,'custom_rotc3d',text="",icon='MANIPUL')
628                     row  = box.row(align =True)
629                     row.label(text="Scale:")
630                     row  = box.row(align =True)
631                     if em.custom_linkscale :
632                         row.prop(em, "custom_propscale",text="")
633                         row.prop(em, "custom_linkscale",text="",icon='LINKED')
634                     else:
635                         row.prop(em,'custom_scale',text='')
636                         row.prop(em, "custom_linkscale",text="",icon='UNLINKED')
637                     row.prop(em,'custom_scac3d',text="",icon='MANIPUL')
638                     row  = box.row(align =True)
639                     row.label(text="UV's Offset:")
640                     row  = box.row(align =True)
641                     row.prop(em,'custom_offsetuv',text='')
642                     row.prop(em, "custom_flipuvx",text="",icon='ARROW_LEFTRIGHT')
643                     row.prop(em, "custom_flipuvy",text="",icon='FULLSCREEN_ENTER')
644                     row  = box.row(align =True)
645                     row.label(text="UV's Scale:")
646                     row  = box.row(align =True)
647                     if em.custom_linkscaleuv:
648                         row.prop(em,'custom_propscaleuv',text='')
649                         row.prop(em, "custom_linkscaleuv",text="",icon='LINKED')
650                     else:
651                         row.prop(em,'custom_scaleuv',text='')
652                         row.prop(em, "custom_linkscaleuv",text="",icon='UNLINKED')
653
654                     if matBProjection:
655                         if context.scene.game_settings.material_mode == 'GLSL' and context.space_data.viewport_shade == 'TEXTURED':
656                             row = box.column(align =True)
657                             row.prop(matBProjection,'alpha', slider = True)
658
659                     row = box.column(align =True)
660                     row.prop(ob,"custom_fnlevel")
661                     row = box.column(align =True)
662                     if not em.custom_style_clone:
663                         row.prop(em,"custom_style_clone",text="Style Clone Normal", icon='RENDERLAYERS')
664                     else:
665                         row.prop(em,"custom_style_clone",text="Style Clone New", icon='RENDERLAYERS')
666                     row = box.column(align =True)
667
668                 if ob == bpy.data.objects[em.custom_active_object]:
669                     for item in em.custom_props:
670                         box = layout.box()
671                         row = box.row()
672                         if item.custom_active:
673                             row.operator("object.active_view",text = "", icon='RADIOBUT_ON', emboss = False).index = item.custom_index
674                         else:
675                             row.operator("object.active_view",text = "", icon='RADIOBUT_OFF', emboss = False).index = item.custom_index
676                         row.prop(item, "custom_active_view", text="")
677                         row.operator('object.remove_view', text="", icon = 'PANEL_CLOSE', emboss = False).index = item.custom_index
678                     row = layout.row()
679                     row.operator('object.create_view', text="Create View", icon = 'RENDER_STILL')
680                 else:
681                     col = box.column(align =True)
682                     col.operator("object.change_object", text="Change Object")
683
684         else:
685             ob = context.object
686             col = layout.column(align = True)
687
688             if ob.active_material is None:
689                 col.label(text="Add a material first!", icon="ERROR")
690             elif ob.data.uv_textures.active is None:
691                 col.label(text="Create UVMap first!!", icon="ERROR")
692             else:
693                 col.operator("object.addbprojectionplane", text="Add BProjection plane")
694                 col = layout.column(align = True)
695                 col.prop(ob, "custom_sub",text="Subdivision level")
696
697
698 # Oprerator Class to apply the image to the plane
699 class ApplyImage(Operator):
700     bl_idname = "object.applyimage"
701     bl_label = "Apply image"
702
703     def execute(self, context):
704         applyimage(context)
705
706         return {'FINISHED'}
707
708 # Oprerator Class to make the 4 or 6 point and scale the plan
709 class IntuitiveScale(Operator):
710     bl_idname = "object.intuitivescale"
711     bl_label = "Draw lines"
712
713     def invoke(self, context, event):
714         ob = context.object
715         em = bpy.data.objects[BProjection_Empty]
716         x = event.mouse_region_x
717         y = event.mouse_region_y
718         if len(ob.grease_pencil.layers.active.frames) == 0:
719             bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
720                                                        "is_start":True, "location":(0, 0, 0),
721                                                        "mouse":(x,y), "pressure":1, "time":0}])
722         else:
723             if em.custom_linkscale:
724                 nb_point = 4
725             else:
726                 nb_point = 6
727
728             if len(ob.grease_pencil.layers.active.frames[0].strokes) < nb_point:
729                 bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
730                                                            "is_start":True, "location":(0, 0, 0),
731                                                            "mouse":(x,y), "pressure":1, "time":0}])
732
733             if len(ob.grease_pencil.layers.active.frames[0].strokes) == nb_point:
734                 s = ob.grease_pencil.layers.active.frames[0]
735                 v1 = s.strokes[1].points[0].co - s.strokes[0].points[0].co
736                 if not em.custom_linkscale:
737                     v2 = s.strokes[4].points[0].co - s.strokes[3].points[0].co
738                 else:
739                     v2 = s.strokes[3].points[0].co - s.strokes[2].points[0].co
740                 propx = v1.x/v2.x
741                 em.custom_scale[0] *= abs(propx)
742
743                 if not em.custom_linkscale:
744                     v1 = s.strokes[2].points[0].co - s.strokes[0].points[0].co
745                     v2 = s.strokes[5].points[0].co - s.strokes[3].points[0].co
746                     propy = v1.y/v2.y
747                     em.custom_scale[1] *= abs(propy)
748                 bpy.ops.gpencil.active_frame_delete()
749
750         return {'FINISHED'}
751
752 # Oprerator Class to configure all wath is needed
753 class AddBProjectionPlane(Operator):
754     bl_idname = "object.addbprojectionplane"
755     bl_label = "Configure"
756
757     def creatematerial(self, context):
758         if 'Material for BProjection' not in [mat.name for mat in bpy.data.materials]:
759             bpy.data.textures.new(name='Texture for BProjection',type='IMAGE')
760
761             bpy.data.materials.new(name='Material for BProjection')
762
763             matBProjection = bpy.data.materials['Material for BProjection']
764             matBProjection.texture_slots.add()
765             matBProjection.use_shadeless = True
766             matBProjection.use_transparency = True
767             matBProjection.active_texture = bpy.data.textures['Texture for BProjection']
768
769             index = matBProjection.active_texture_index
770             matBProjection.texture_slots[index].texture_coords = 'UV'
771
772         ob = context.object
773         old_index = ob.active_material_index
774         bpy.ops.object.material_slot_add()
775         index = ob.active_material_index
776         ob.material_slots[index].material = bpy.data.materials['Material for BProjection']
777         bpy.ops.object.material_slot_assign()
778         ob.active_material_index = old_index
779         ob.data.update()
780
781     def execute(self, context):
782         if  BProjection_Empty not in [ob.name for ob in bpy.data.objects]:
783
784             cm = bpy.context.object.mode
785             '''tmp = context.object
786             for ob in (ob for ob in bpy.data.objects if ob.type == 'MESH' and ob.hide == False and context.scene in ob.users_scene):
787                 context.scene.objects.active = ob
788                 bpy.ops.object.mode_set(mode = cm, toggle=False)
789
790             context.scene.objects.active = tmp'''
791             bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
792
793             context.space_data.show_relationship_lines = False
794
795             ob = context.object
796
797             bpy.ops.object.add()
798             em = context.object
799             em.name = BProjection_Empty
800
801             context.scene.objects.active = ob
802             ob.select = True
803
804             bpy.ops.object.editmode_toggle()
805
806             bpy.ops.mesh.primitive_plane_add()
807             bpy.ops.object.vertex_group_assign(new = True)
808             ob.vertex_groups.active.name = 'texture plane'
809             bpy.ops.uv.unwrap()
810
811             bpy.ops.mesh.select_all(action='DESELECT')
812             bpy.ops.object.vertex_group_select()
813
814             bpy.ops.object.editmode_toggle()
815             for i in range(4):
816                 ob.data.edges[len(ob.data.edges)-1-i].crease = 1
817             bpy.ops.object.editmode_toggle()
818
819             em.custom_sub = ob.custom_sub
820             if em.custom_sub > 0:
821                 bpy.ops.mesh.subdivide(number_cuts = em.custom_sub)
822
823             em.select = True
824             bpy.ops.object.hook_add_selob()
825             em.select = False
826             em.hide = True
827
828             self.creatematerial(context)
829
830
831             bpy.ops.gpencil.data_add()
832             ob.grease_pencil.draw_mode = 'VIEW'
833             bpy.ops.gpencil.layer_add()
834             ob.grease_pencil.layers.active.color = [1.0,0,0]
835
836             bpy.ops.object.editmode_toggle()
837
838             bpy.ops.object.shape_key_add(from_mix = False)
839
840             bpy.ops.object.create_view()
841
842             km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
843             l = ['view3d.rotate','view3d.move','view3d.zoom','view3d.viewnumpad','paint.bp_paint','MOUSE','KEYBOARD','LEFT','MIDDLEMOUSE','WHEELINMOUSE','WHEELOUTMOUSE','NUMPAD_1','NUMPAD_3','NUMPAD_7']
844             for kmi in km.keymap_items:
845                 if kmi.idname in l and kmi.map_type in l and kmi.type in l:
846                     try:
847                         p = kmi.properties.delta
848                         if p == -1 or p == 1:
849                             kmi.idname = 'view3d.zoom_view3d'
850                             kmi.properties.delta = p
851                     except:
852                         try:
853                             p = kmi.properties.type
854                             if kmi.shift == False :
855                                 kmi.idname = 'view3d.preset_view3d'
856                                 kmi.properties.view = p
857                         except:
858                             if kmi.idname == 'view3d.rotate':
859                                 kmi.idname = 'view3d.rotate_view3d'
860                             if kmi.idname == 'view3d.move':
861                                 kmi.idname = 'view3d.pan_view3d'
862
863             km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
864
865             kmi = km.keymap_items.new("object.intuitivescale", 'LEFTMOUSE', 'PRESS', shift=True)
866             kmi = km.keymap_items.new("object.bp_grab", 'G', 'PRESS')
867             kmi = km.keymap_items.new("object.bp_rotate", 'R', 'PRESS')
868             kmi = km.keymap_items.new("object.bp_scale", 'S', 'PRESS')
869             kmi = km.keymap_items.new("object.bp_scaleuv", 'U', 'PRESS')
870             kmi = km.keymap_items.new("object.bp_offsetuv", 'Y', 'PRESS')
871             kmi = km.keymap_items.new("object.bp_clear_prop", 'C', 'PRESS')
872             kmi = km.keymap_items.new("object.bp_toggle_alpha", 'Q', 'PRESS')
873             align_to_view(context)
874
875             context.space_data.cursor_location = em.location
876
877             bpy.ops.object.mode_set(mode = cm, toggle=False)
878             bpy.data.objects[BProjection_Empty].custom_active_object = context.object.name
879
880         return {'FINISHED'}
881
882 # Oprerator Class to remove what is no more needed
883 class RemoveBProjectionPlane(Operator):
884     bl_idname = "object.removebprojectionplane"
885     bl_label = "Configure"
886
887     def removematerial(self, context):
888         ob = context.object
889         i = 0
890
891         for ms in ob.material_slots:
892             if ms.name == BProjection_Material:
893                 index = i
894             i+=1
895
896         ob.active_material_index = index
897         bpy.ops.object.material_slot_remove()
898
899     def execute(self, context):
900         try:
901             cm = bpy.context.object.mode
902             bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
903
904             context.space_data.show_relationship_lines = True
905
906             bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
907
908             self.removematerial(context)
909
910             ob = context.object
911
912             bpy.ops.object.editmode_toggle()
913
914             bpy.ops.mesh.reveal()
915
916             bpy.ops.mesh.select_all(action='DESELECT')
917
918             ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
919             bpy.ops.object.vertex_group_select()
920             bpy.ops.mesh.delete()
921             bpy.ops.object.vertex_group_remove()
922
923             bpy.ops.object.editmode_toggle()
924
925             ob.select = False
926
927             em = bpy.data.objects[BProjection_Empty]
928             context.scene.objects.active = em
929             em.hide = False
930             em.select = True
931             bpy.ops.object.delete()
932
933             context.scene.objects.active = ob
934             ob.select = True
935
936             reinitkey()
937
938             '''tmp = context.object
939             for ob in (ob for ob in bpy.data.objects if ob.type == 'MESH' and ob.hide == False and context.scene in ob.users_scene):
940                 context.scene.objects.active = ob
941                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
942
943             context.scene.objects.active = tmp'''
944             ob = context.object
945
946
947             for i in ob.data.shape_keys.key_blocks:
948                 bpy.ops.object.shape_key_remove()
949             bpy.ops.object.shape_key_remove()
950
951             bpy.ops.object.mode_set(mode = cm, toggle=False)
952             removecustomprops()
953
954         except:
955             nothing = 0
956
957         return {'FINISHED'}
958
959 def reinitkey():
960     km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
961     l = ['view3d.zoom_view3d','view3d.preset_view3d','view3d.rotate_view3d','view3d.pan_view3d','MOUSE','KEYBOARD','MIDDLEMOUSE','WHEELINMOUSE','WHEELOUTMOUSE','NUMPAD_1','NUMPAD_3','NUMPAD_7']
962     for kmi in km.keymap_items:
963         if kmi.idname in l and kmi.map_type in l and kmi.type in l:
964             try:
965                 p = kmi.properties.delta
966                 if p == -1 or p == 1:
967                     kmi.idname = 'view3d.zoom'
968                     kmi.properties.delta = p
969             except:
970                 try:
971                     p = kmi.properties.view
972                     if kmi.shift == False :
973                         kmi.idname = 'view3d.viewnumpad'
974                         kmi.properties.type = p
975                 except:
976                     if kmi.idname == 'view3d.rotate_view3d':
977                         kmi.idname = 'view3d.rotate'
978                     if kmi.idname == 'view3d.pan_view3d':
979                         kmi.idname = 'view3d.move'
980
981     km = bpy.context.window_manager.keyconfigs.default.keymaps['Image Paint']
982
983     for kmi in km.keymap_items:
984         if kmi.idname == 'paint.bp_paint':
985             kmi.idname = 'paint.image_paint'
986
987     for kmi in (kmi for kmi in km.keymap_items if kmi.idname in {"object.intuitivescale", "object.bp_grab", "object.bp_rotate", "object.bp_scale", "object.bp_scaleuv", "object.bp_clear_prop", "object.bp_offsetuv","object.bp_toggle_alpha", }):
988             km.keymap_items.remove(kmi)
989
990 # Oprerator Class to remove what is no more needed
991 class ChangeObject(Operator):
992     bl_idname = "object.change_object"
993     bl_label = "Change Object"
994
995     def removematerial(self, context):
996         ob = context.object
997         i = 0
998
999         for ms in ob.material_slots:
1000             if ms.name == BProjection_Material:
1001                 index = i
1002             i+=1
1003
1004         ob.active_material_index = index
1005         bpy.ops.object.material_slot_remove()
1006
1007     def execute(self, context):
1008             new_ob = context.object
1009             em = bpy.data.objects[BProjection_Empty]
1010             context.scene.objects.active = bpy.data.objects[em.custom_active_object]
1011             ob = context.object
1012             if ob != new_ob:
1013                 cm = bpy.context.object.mode
1014                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
1015
1016                 bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
1017
1018                 ob = context.object
1019
1020                 bpy.ops.object.editmode_toggle()
1021
1022                 bpy.ops.mesh.reveal()
1023
1024                 bpy.ops.mesh.select_all(action='DESELECT')
1025                 ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
1026                 bpy.ops.object.vertex_group_select()
1027                 lo_b = [ob for ob in bpy.data.objects if ob.type == 'MESH']
1028                 bpy.ops.mesh.separate(type='SELECTED')
1029                 lo_a = [ob for ob in bpy.data.objects if ob.type == 'MESH']
1030                 bpy.ops.object.vertex_group_remove()
1031
1032                 for i in lo_b:
1033                     lo_a.remove(i)
1034                 bplane = lo_a[0]
1035
1036                 bpy.ops.object.editmode_toggle()
1037
1038                 self.removematerial(context)
1039
1040                 bpy.ops.object.mode_set(mode = cm, toggle=False)
1041
1042                 shape_index = ob.active_shape_key_index
1043
1044                 for i in ob.data.shape_keys.key_blocks:
1045                     bpy.ops.object.shape_key_remove()
1046                 bpy.ops.object.shape_key_remove()
1047
1048                 ob.select = False
1049
1050                 bplane.select = True
1051                 context.scene.objects.active = bplane
1052                 for ms in (ms for ms in bplane.material_slots if ms.name != BProjection_Material):
1053                     bplane.active_material = ms.material
1054                     bpy.ops.object.material_slot_remove()
1055
1056                 for gs in (gs for gs in bplane.vertex_groups if gs.name != 'texture plane'):
1057                     bplane.vertex_groups.active_index = gs.index
1058                     bpy.ops.object.vertex_group_remove()
1059
1060                 context.scene.objects.active = new_ob
1061                 cm = new_ob.mode
1062                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
1063                 bpy.ops.object.join()
1064
1065                 em.hide = False
1066                 em.select = True
1067                 new_ob.select = False
1068                 bpy.ops.object.location_clear()
1069                 bpy.ops.object.rotation_clear()
1070                 bpy.ops.object.scale_clear()
1071                 context.scene.objects.active = new_ob
1072                 bpy.ops.object.editmode_toggle()
1073                 bpy.ops.object.hook_add_selob()
1074                 bpy.ops.object.editmode_toggle()
1075                 em.hide = True
1076                 em.select = False
1077                 new_ob.select = True
1078                 em.custom_active_object = new_ob.name
1079                 tmp = em.custom_c3d
1080                 em.custom_c3d = False
1081                 bpy.ops.object.active_view(index = shape_index-1)
1082                 bpy.ops.object.mode_set(mode = cm, toggle=False)
1083
1084                 sd = context.space_data
1085                 r3d = sd.region_3d
1086                 vr = r3d.view_rotation.copy()
1087                 vr.invert()
1088                 ob_loc = ob.location.copy()
1089                 new_ob_loc = new_ob.location.copy()
1090                 ob_loc.rotate(vr)
1091                 new_ob_loc.rotate(vr)
1092                 em.custom_location += Vector((ob_loc.x - new_ob_loc.x, ob_loc.y - new_ob_loc.y, 0.0))
1093                 em.custom_c3d = tmp
1094
1095             return {'FINISHED'}
1096
1097 #Paint from the bp_plan
1098
1099 last_mouse = Vector((0,0))
1100
1101 def move_bp(self,context,cm,fm):
1102     em = bpy.data.objects['Empty for BProjection']
1103
1104     deltax = cm.x - round(fm.x)
1105     deltay = cm.y - round(fm.y)
1106
1107     sd = context.space_data
1108     l =  sd.region_3d
1109     vr = l.view_rotation.copy()
1110     vr.invert()
1111
1112     v_init = Vector((0.0,0.0,1.0))
1113
1114     pos = [-deltax,-deltay]
1115     v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1116     pos = [0,0]
1117     vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1118     loc = vbl - v
1119
1120     loc.rotate(vr)
1121
1122     em.custom_location -= loc
1123
1124     self.first_mouse = cm
1125
1126 class BP_Paint(bpy.types.Operator):
1127     bl_idname = "paint.bp_paint"
1128     bl_label = "Paint BProjection Plane"
1129     first_mouse = Vector((0,0))
1130
1131     @classmethod
1132     def poll(cls, context):
1133         return 1
1134
1135     def modal(self, context, event):
1136         global last_mouse
1137         em = bpy.data.objects['Empty for BProjection']
1138         sd = context.space_data
1139
1140         center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location)
1141         vec_init = self.first_mouse - center
1142         vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center
1143
1144         if event.type == 'MOUSEMOVE':#'INBETWEEN_MOUSEMOVE':
1145             step_act = Vector((event.mouse_region_x, event.mouse_region_y)) - self.step_prev
1146             if step_act.length >= context.scene.tool_settings.unified_paint_settings.size*bpy.data.brushes['Clone'].spacing/100 or bpy.data.brushes['Clone'].use_airbrush:
1147                 move_bp(self,context,Vector((event.mouse_region_x, event.mouse_region_y)) - self.v_offset,self.first_mouse)
1148
1149                 bpy.ops.paint.image_paint(stroke=[{"name":"", "location":(0, 0, 0), "mouse":(event.mouse_region_x, event.mouse_region_y),
1150                                                        "pressure":1, "pen_flip":False, "time":0, "is_start":False}])
1151                 self.step_prev = Vector((event.mouse_region_x, event.mouse_region_y))
1152
1153         if event.type == 'LEFTMOUSE':
1154             em.custom_c3d = True
1155             bpy.data.materials['Material for BProjection'].alpha = self.alpha
1156             em.custom_location = self.first_location
1157             return {'FINISHED'}
1158
1159         if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
1160             em.custom_c3d = True
1161             bpy.data.materials['Material for BProjection'].alpha = self.alpha
1162             em.custom_location = self.first_location
1163             return {'FINISHED'}
1164
1165         return {'PASS_THROUGH'}
1166
1167     def invoke(self, context, event):
1168         em = bpy.data.objects['Empty for BProjection']
1169         context.window_manager.modal_handler_add(self)
1170         self.first_mouse = Vector((event.mouse_region_x, event.mouse_region_y))
1171
1172         sd = context.space_data
1173         l =  sd.region_3d
1174         v_init = Vector((0.0,0.0,1.0))
1175         context.scene.cursor_location = view3d_utils.region_2d_to_location_3d(context.region, l, [event.mouse_region_x, event.mouse_region_y], v_init)
1176
1177         self.first_location = em.custom_location.copy()
1178
1179         self.v_offset =  Vector((context.region.width, context.region.height)) - Vector((event.mouse_region_x, event.mouse_region_y))
1180         move_bp(self,context,Vector((event.mouse_region_x, event.mouse_region_y)) - self.v_offset,self.first_mouse)
1181
1182         em.custom_c3d = False
1183         self.alpha = bpy.data.materials['Material for BProjection'].alpha
1184
1185         em.custom_location.z = -10
1186
1187         bpy.data.materials['Material for BProjection'].alpha = 0
1188
1189         bpy.ops.paint.image_paint(stroke=[{"name":"", "location":(0, 0, 0), "mouse":(event.mouse_region_x, event.mouse_region_y),
1190                                                    "pressure":1, "pen_flip":False, "time":0, "is_start":False}])
1191         self.step_prev = Vector((event.mouse_region_x, event.mouse_region_y))
1192         return {'RUNNING_MODAL'}
1193
1194 # Oprerator Class toggle the alpha of the plane
1195 temp_alpha = 0
1196 class ApplyImage(Operator):
1197     bl_idname = "object.bp_toggle_alpha"
1198     bl_label = "Toggle Alpha of the BP"
1199
1200     def execute(self, context):
1201         global temp_alpha
1202         if temp_alpha != 0:
1203             bpy.data.materials['Material for BProjection'].alpha = temp_alpha
1204             temp_alpha = 0
1205         else:
1206             temp_alpha = bpy.data.materials['Material for BProjection'].alpha
1207             bpy.data.materials['Material for BProjection'].alpha = 0
1208
1209         return {'FINISHED'}
1210
1211 #reinit the values of the bp_plane
1212 class BP_Clear_Props(Operator):
1213     bl_idname = "object.bp_clear_prop"
1214     bl_label = "Clear Props BProjection Plane"
1215
1216     def execute(self, context):
1217         clear_props(context)
1218
1219         return{'FINISHED'}
1220
1221 #Move the UV of the bp_plane
1222 class BP_OffsetUV(bpy.types.Operator):
1223     bl_idname = "object.bp_offsetuv"
1224     bl_label = "OffsetUV BProjection Plane"
1225
1226     axe_x = True
1227     axe_y = True
1228
1229     first_mouse = Vector((0,0))
1230     first_offsetuv = Vector((0,0))
1231
1232     @classmethod
1233     def poll(cls, context):
1234         return 1
1235
1236     def modal(self, context, event):
1237         em = bpy.data.objects['Empty for BProjection']
1238
1239         if event.shift:
1240             fac = 0.1
1241         else:
1242             fac = 1
1243
1244         if event.type == 'X' and event.value == 'PRESS':
1245             if self.axe_x == True and self.axe_y == True:
1246                 self.axe_y = False
1247             elif self.axe_x == True and self.axe_y == False:
1248                 self.axe_y = True
1249             elif self.axe_x == False and self.axe_y == True:
1250                 self.axe_y = False
1251                 self.axe_x = True
1252
1253         if event.type == 'Y' and event.value == 'PRESS':
1254             if self.axe_x == True and self.axe_y == True:
1255                 self.axe_x = False
1256             elif self.axe_x == False and self.axe_y == True:
1257                 self.axe_x = True
1258             elif self.axe_x == True and self.axe_y == False:
1259                 self.axe_y = True
1260                 self.axe_x = False
1261
1262         deltax = (event.mouse_region_x - self.first_mouse.x)*fac
1263         deltay = (event.mouse_region_y - self.first_mouse.y)*fac
1264
1265         if event.type == 'MOUSEMOVE':
1266
1267             if  not self.axe_y:
1268                 deltay = 0
1269             if not self.axe_x:
1270                 deltax = 0
1271
1272             ouv = em.custom_offsetuv
1273             em.custom_offsetuv = [ouv[0] - deltax/50,ouv[1] - deltay/50]
1274
1275             self.first_mouse.x = event.mouse_region_x
1276             self.first_mouse.y = event.mouse_region_y
1277
1278         if event.type == 'LEFTMOUSE':
1279             return {'FINISHED'}
1280
1281         if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
1282             em.custom_offsetuv = self.first_offsetuv
1283             return {'FINISHED'}
1284
1285         return {'RUNNING_MODAL'}
1286
1287     def invoke(self, context, event):
1288         em = bpy.data.objects['Empty for BProjection']
1289         context.window_manager.modal_handler_add(self)
1290         self.first_mouse.x = event.mouse_region_x
1291         self.first_mouse.y = event.mouse_region_y
1292         self.first_offsetuv = em.custom_offsetuv.copy()
1293
1294         return {'RUNNING_MODAL'}
1295
1296 #Scale the UV of the bp_plane
1297 class BP_ScaleUV(bpy.types.Operator):
1298     bl_idname = "object.bp_scaleuv"
1299     bl_label = "ScaleUV BProjection Plane"
1300
1301     axe_x = True
1302     axe_y = True
1303
1304     first_mouse = Vector((0,0))
1305     first_scaleuv = Vector((0,0))
1306
1307     @classmethod
1308     def poll(cls, context):
1309         return 1
1310
1311     def modal(self, context, event):
1312         em = bpy.data.objects['Empty for BProjection']
1313
1314         if event.shift:
1315             fac = 0.1
1316         else:
1317             fac = 1
1318
1319         if event.type == 'X' and event.value == 'PRESS':
1320             if self.axe_x == True and self.axe_y == True:
1321                 self.axe_y = False
1322             elif self.axe_x == True and self.axe_y == False:
1323                 self.axe_y = True
1324             elif self.axe_x == False and self.axe_y == True:
1325                 self.axe_y = False
1326                 self.axe_x = True
1327
1328         if event.type == 'Y' and event.value == 'PRESS':
1329             if self.axe_x == True and self.axe_y == True:
1330                 self.axe_x = False
1331             elif self.axe_x == False and self.axe_y == True:
1332                 self.axe_x = True
1333             elif self.axe_x == True and self.axe_y == False:
1334                 self.axe_y = True
1335                 self.axe_x = False
1336
1337         deltax = (event.mouse_region_x - self.first_mouse.x)*fac
1338         deltay = (event.mouse_region_y - self.first_mouse.y)*fac
1339
1340         if event.type == 'MOUSEMOVE':
1341
1342             if  not self.axe_y:
1343                 deltay = 0
1344             if not self.axe_x:
1345                 deltax = 0
1346
1347             if self.axe_x and self.axe_y:
1348                 fac = em.custom_scaleuv[1]/em.custom_scaleuv[0]
1349                 deltay = deltax * fac
1350             else:
1351                 em.custom_linkscaleuv = False
1352
1353             s = em.custom_scaleuv
1354             em.custom_scaleuv = [s[0] + deltax/50, s[1] + deltay/50]
1355
1356             self.first_mouse.x = event.mouse_region_x
1357             self.first_mouse.y = event.mouse_region_y
1358
1359         if event.type == 'LEFTMOUSE':
1360             return {'FINISHED'}
1361
1362         if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
1363             em.custom_scaleuv = self.first_scaleuv
1364             return {'FINISHED'}
1365
1366         return {'RUNNING_MODAL'}
1367
1368     def invoke(self, context, event):
1369         em = bpy.data.objects['Empty for BProjection']
1370         context.window_manager.modal_handler_add(self)
1371         self.first_mouse.x = event.mouse_region_x
1372         self.first_mouse.y = event.mouse_region_y
1373         self.first_scaleuv = em.custom_scaleuv.copy()
1374
1375         return {'RUNNING_MODAL'}
1376
1377 #Scale the bp_plane
1378 class BP_Scale(bpy.types.Operator):
1379     bl_idname = "object.bp_scale"
1380     bl_label = "Scale BProjection Plane"
1381
1382     axe_x = True
1383     axe_y = True
1384
1385     first_mouse = Vector((0,0))
1386     first_scale = Vector((0,0,0))
1387
1388     @classmethod
1389     def poll(cls, context):
1390         return 1
1391
1392     def modal(self, context, event):
1393         em = bpy.data.objects['Empty for BProjection']
1394         sd = context.space_data
1395
1396         center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location)
1397         vec_init = self.first_mouse - center
1398         vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center
1399         scale_fac = vec_act.length/vec_init.length
1400
1401         if event.ctrl:
1402             scale_fac = round(scale_fac,1)
1403
1404         if event.type == 'X' and event.value == 'PRESS':
1405             if self.axe_x == True and self.axe_y == True:
1406                 self.axe_y = False
1407             elif self.axe_x == True and self.axe_y == False:
1408                 self.axe_y = True
1409             elif self.axe_x == False and self.axe_y == True:
1410                 self.axe_y = False
1411                 self.axe_x = True
1412
1413         if event.type == 'Y' and event.value == 'PRESS':
1414             if self.axe_x == True and self.axe_y == True:
1415                 self.axe_x = False
1416             elif self.axe_x == False and self.axe_y == True:
1417                 self.axe_x = True
1418             elif self.axe_x == True and self.axe_y == False:
1419                 self.axe_y = True
1420                 self.axe_x = False
1421
1422         if event.type == 'MOUSEMOVE':
1423
1424             if self.axe_x:
1425                 em.custom_scale = [self.first_scale[0]*scale_fac, self.first_scale[1]]
1426             if self.axe_y:
1427                 em.custom_scale = [self.first_scale[0], self.first_scale[1]*scale_fac]
1428
1429             if self.axe_x and self.axe_y:
1430                 em.custom_scale = [self.first_scale[0]*scale_fac, self.first_scale[1]*scale_fac]
1431             else:
1432                 em.custom_linkscale = False
1433
1434         if event.type == 'LEFTMOUSE':
1435             return {'FINISHED'}
1436
1437         if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
1438             em.custom_scale = self.first_scale
1439             return {'FINISHED'}
1440
1441         return {'RUNNING_MODAL'}
1442
1443     def invoke(self, context, event):
1444         em = bpy.data.objects['Empty for BProjection']
1445         context.window_manager.modal_handler_add(self)
1446         self.first_mouse.x = event.mouse_region_x
1447         self.first_mouse.y = event.mouse_region_y
1448         self.first_scale = em.custom_scale.copy()
1449
1450         return {'RUNNING_MODAL'}
1451
1452 #Rotate the bp_plan
1453 class BP_Rotate(bpy.types.Operator):
1454     bl_idname = "object.bp_rotate"
1455     bl_label = "Rotate BProjection Plane"
1456
1457     first_mouse = Vector((0,0))
1458     first_rotation = 0
1459
1460     @classmethod
1461     def poll(cls, context):
1462         return 1
1463
1464     def modal(self, context, event):
1465         em = bpy.data.objects['Empty for BProjection']
1466         sd = context.space_data
1467
1468         center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location if em.custom_rotc3d else context.scene.cursor_location)
1469         vec_init = self.first_mouse - center
1470         vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center
1471         rot = -vec_init.angle_signed(vec_act)*180/pi
1472
1473         if event.shift:
1474             rot = rot
1475         else:
1476             rot = int(rot)
1477
1478         if event.ctrl:
1479             rot = int(rot/5)*5
1480
1481         if event.type == 'MOUSEMOVE':
1482
1483             em.custom_rotation = self.first_rotation + rot
1484
1485         if event.type == 'LEFTMOUSE':
1486             return {'FINISHED'}
1487
1488         if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
1489             em.custom_rotation = self.first_rotation
1490             return {'FINISHED'}
1491
1492         return {'RUNNING_MODAL'}
1493
1494     def invoke(self, context, event):
1495         em = bpy.data.objects['Empty for BProjection']
1496         context.window_manager.modal_handler_add(self)
1497         self.first_mouse.x = event.mouse_region_x
1498         self.first_mouse.y = event.mouse_region_y
1499         self.first_rotation = em.custom_rotation
1500
1501         return {'RUNNING_MODAL'}
1502
1503 # grab the bp_plan
1504 class BP_Grab(bpy.types.Operator):
1505     bl_idname = "object.bp_grab"
1506     bl_label = "Grab BProjection Plane"
1507
1508     axe_x = True
1509     axe_y = True
1510     axe_z = False
1511     first_mouse = Vector((0,0))
1512     first_location = Vector((0,0,0))
1513
1514     @classmethod
1515     def poll(cls, context):
1516         return 1
1517
1518     def modal(self, context, event):
1519         em = bpy.data.objects['Empty for BProjection']
1520
1521         if event.shift:
1522             fac = 0.1
1523         else:
1524             fac = 1
1525
1526         if event.type == 'X' and event.value == 'PRESS':
1527             if self.axe_x == True and self.axe_y == True:
1528                 self.axe_y = False
1529             elif self.axe_x == True and self.axe_y == False:
1530                 self.axe_y = True
1531             elif self.axe_x == False and self.axe_y == True:
1532                 self.axe_y = False
1533                 self.axe_x = True
1534             if self.axe_z == True:
1535                 self.axe_z = False
1536                 self.axe_x = True
1537
1538         if event.type == 'Y' and event.value == 'PRESS':
1539             if self.axe_x == True and self.axe_y == True:
1540                 self.axe_x = False
1541             elif self.axe_x == False and self.axe_y == True:
1542                 self.axe_x = True
1543             elif self.axe_x == True and self.axe_y == False:
1544                 self.axe_y = True
1545                 self.axe_x = False
1546             if self.axe_z == True:
1547                 self.axe_z = False
1548                 self.axe_y = True
1549
1550         if event.type == 'Z' and event.value == 'PRESS':
1551             if self.axe_z == False:
1552                 self.axe_z = True
1553                 self.axe_x = False
1554                 self.axe_y = False
1555             elif self.axe_z == True:
1556                 self.axe_z = False
1557                 self.axe_x = True
1558                 self.axe_y = True
1559
1560         deltax = event.mouse_region_x - round(self.first_mouse.x)
1561         deltay = event.mouse_region_y - round(self.first_mouse.y)
1562
1563         if event.type == 'MOUSEMOVE':
1564             sd = context.space_data
1565             l =  sd.region_3d
1566             vr = l.view_rotation.copy()
1567             vr.invert()
1568
1569             v_init = Vector((0.0,0.0,1.0))
1570
1571             pos = [-deltax,-deltay]
1572             v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1573             pos = [0,0]
1574             vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1575             loc = vbl - v
1576
1577             loc.rotate(vr)
1578             if  not self.axe_y:
1579                 loc.y = loc.z = 0
1580             if not self.axe_x:
1581                 loc.x = loc.z = 0
1582             if self.axe_z:
1583                 loc.z = deltax/10
1584
1585             em.custom_location += loc*fac
1586
1587             self.first_mouse.x = event.mouse_region_x
1588             self.first_mouse.y = event.mouse_region_y
1589
1590         if event.type == 'LEFTMOUSE':
1591             return {'FINISHED'}
1592
1593         if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
1594             em.custom_location = self.first_location
1595             return {'FINISHED'}
1596
1597         return {'RUNNING_MODAL'}
1598
1599     def invoke(self, context, event):
1600         em = bpy.data.objects['Empty for BProjection']
1601         context.window_manager.modal_handler_add(self)
1602         self.first_mouse.x = event.mouse_region_x
1603         self.first_mouse.y = event.mouse_region_y
1604         self.first_location = em.custom_location.copy()
1605
1606         return {'RUNNING_MODAL'}
1607
1608 # Oprerator Class to rotate the view3D
1609 class RotateView3D(Operator):
1610     bl_idname = "view3d.rotate_view3d"
1611     bl_label = "Rotate the View3D"
1612
1613     first_mouse = Vector((0,0))
1614
1615     first_time = True
1616     tmp_level = -1
1617
1618     def vect_sphere(self, context, mx, my):
1619         width = context.region.width
1620         height = context.region.height
1621
1622         if width >= height:
1623             ratio = height/width
1624
1625             x = 2*mx/width
1626             y = 2*ratio*my/height
1627
1628             x = x - 1
1629             y = y - ratio
1630         else:
1631             ratio = width/height
1632
1633             x = 2*ratio*mx/width
1634             y = 2*my/height
1635
1636             x = x - ratio
1637             y = y - 1
1638
1639         z2 = 1 - x * x - y * y
1640         if z2 > 0:
1641             z= sqrt(z2)
1642         else : z=0
1643
1644         p = Vector((x, y, z))
1645         p.normalize()
1646         return p
1647
1648     def tracball(self, context, mx, my, origine):
1649         sd = context.space_data
1650
1651         vr_b = sd.region_3d.view_rotation.copy()
1652         vr_b.invert()
1653         pos_init = sd.region_3d.view_location - origine
1654         sd.region_3d.view_location = origine
1655
1656         v1 = self.vect_sphere(context, self.first_mouse.x, self.first_mouse.y)
1657         v2 = self.vect_sphere(context, mx, my)
1658
1659         axis = Vector.cross(v1,v2);
1660         angle = Vector.angle(v1,v2);
1661
1662         q =  Quaternion(axis,-2*angle)
1663
1664         sd.region_3d.view_rotation *=q
1665         sd.region_3d.update()
1666
1667         vr_a = sd.region_3d.view_rotation.copy()
1668         pos_init.rotate(vr_a*vr_b)
1669         sd.region_3d.view_location =  pos_init + origine
1670
1671         self.first_mouse = Vector((mx, my))
1672
1673     def turnable(self, context, mx, my, origine):
1674         sd = context.space_data
1675
1676         width = context.region.width
1677         height = context.region.height
1678
1679         vr_b = sd.region_3d.view_rotation.copy()
1680         vr_b.invert()
1681         pos_init = sd.region_3d.view_location - origine
1682         sd.region_3d.view_location = origine
1683
1684         vz = Vector((0,0,1))
1685         qz =  Quaternion(vz,-8*(mx-self.first_mouse.x)/width)
1686         sd.region_3d.view_rotation.rotate(qz)
1687         sd.region_3d.update()
1688
1689         vx = Vector((1,0,0))
1690         vx.rotate(sd.region_3d.view_rotation)
1691         qx =  Quaternion(vx,8*(my-self.first_mouse.y)/height)
1692         sd.region_3d.view_rotation.rotate(qx)
1693         sd.region_3d.update()
1694
1695         vr_a = sd.region_3d.view_rotation.copy()
1696         pos_init.rotate(vr_a*vr_b)
1697         sd.region_3d.view_location =  pos_init + origine
1698
1699         self.first_mouse = Vector((mx, my))
1700
1701     def modal(self, context, event):
1702         ob = context.object
1703         em = bpy.data.objects['Empty for BProjection']
1704         reg = context.region
1705
1706         if event.value == 'RELEASE':
1707             if self.tmp_level > -1:
1708                 for sub in context.object.modifiers:
1709                     if sub.type in ['SUBSURF','MULTIRES']:
1710                         sub.levels = self.tmp_level
1711             return {'FINISHED'}
1712
1713         if event.type == 'MOUSEMOVE':
1714             if context.user_preferences.inputs.view_rotate_method == 'TRACKBALL':
1715                 self.tracball(context, event.mouse_region_x, event.mouse_region_y,ob.location)
1716             else:
1717                 self.turnable(context, event.mouse_region_x, event.mouse_region_y,ob.location)
1718             align_to_view(context)
1719             #to unlock the camera
1720             if self.first_time:
1721                 rot_ang = context.user_preferences.view.rotation_angle
1722                 context.user_preferences.view.rotation_angle = 0
1723                 bpy.ops.view3d.view_orbit(type='ORBITLEFT')
1724                 context.user_preferences.view.rotation_angle = rot_ang
1725                 bpy.ops.view3d.view_persportho()
1726                 bpy.ops.view3d.view_persportho()
1727                 self.first_time = False
1728
1729         return {'RUNNING_MODAL'}
1730
1731     def execute(self, context):
1732         align_to_view(context)
1733
1734         return{'FINISHED'}
1735
1736     def invoke(self, context, event):
1737         bpy.data.objects['Empty for BProjection']
1738         context.window_manager.modal_handler_add(self)
1739         self.first_mouse = Vector((event.mouse_region_x,event.mouse_region_y))
1740         self.first_time = True
1741         for sub in context.object.modifiers:
1742             if sub.type in ['SUBSURF', 'MULTIRES']:
1743                 self.tmp_level = sub.levels
1744                 if sub.levels - self.tmp_level <0:
1745                     sub.levels = 0
1746                 else:
1747                     sub.levels += bpy.context.object.custom_fnlevel
1748         return {'RUNNING_MODAL'}
1749
1750 # Oprerator Class to pan the view3D
1751 class PanView3D(bpy.types.Operator):
1752     bl_idname = "view3d.pan_view3d"
1753     bl_label = "Pan View3D"
1754
1755     first_mouse = Vector((0,0))
1756     tmp_level = -1
1757
1758     def modal(self, context, event):
1759         ob = context.object
1760         em = bpy.data.objects[BProjection_Empty]
1761         width = context.region.width
1762         height = context.region.height
1763
1764         deltax = event.mouse_region_x - self.first_mouse.x
1765         deltay = event.mouse_region_y - self.first_mouse.y
1766
1767         sd = context.space_data
1768         r3d =  sd.region_3d
1769         vr = r3d.view_rotation.copy()
1770         vr.invert()
1771
1772         v_init = Vector((0.0,0.0,1.0))
1773
1774         pos = [deltax,deltay]
1775         v = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1776         pos = [0,0]
1777         vbl = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1778         loc = vbl - v
1779         sd.region_3d.view_location += loc
1780         loc.rotate(vr)
1781         if not em.custom_style_clone:
1782             em.custom_location += loc
1783
1784         self.first_mouse.x = event.mouse_region_x
1785         self.first_mouse.y = event.mouse_region_y
1786
1787         if event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
1788             if self.tmp_level > -1:
1789                 for sub in context.object.modifiers:
1790                     if sub.type in ['SUBSURF','MULTIRES']:
1791                         sub.levels = self.tmp_level
1792             return {'FINISHED'}
1793
1794         return {'RUNNING_MODAL'}
1795
1796     def invoke(self, context, event):
1797         bpy.data.objects['Empty for BProjection']
1798         context.window_manager.modal_handler_add(self)
1799         self.first_mouse.x = event.mouse_region_x
1800         self.first_mouse.y = event.mouse_region_y
1801         for sub in context.object.modifiers:
1802             if sub.type in ['SUBSURF', 'MULTIRES']:
1803                 self.tmp_level = sub.levels
1804                 if sub.levels - self.tmp_level <0:
1805                     sub.levels = 0
1806                 else:
1807                     sub.levels += bpy.context.object.custom_fnlevel
1808
1809         return {'RUNNING_MODAL'}
1810
1811     def execute(self, context):
1812         align_to_view(context)
1813
1814         return{'FINISHED'}
1815
1816 # Oprerator Class to zoom the view3D
1817 class ZoomView3D(Operator):
1818     bl_idname = "view3d.zoom_view3d"
1819     bl_label = "Zoom View3D"
1820
1821     delta = FloatProperty(
1822         name="delta",
1823         description="Delta",
1824         min=-1.0, max=1,
1825         default=1.0)
1826
1827     def invoke(self, context, event):
1828         ob = context.object
1829         em = bpy.data.objects[BProjection_Empty]
1830         sd = context.space_data
1831
1832         width = context.region.width
1833         height = context.region.height
1834
1835         r3d =  sd.region_3d
1836         v_init = Vector((0.0,0.0,1.0))
1837
1838         pos = [width,height]
1839         vtr_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1840         pos = [0,0]
1841         vbl_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1842         len_b = vtr_b - vbl_b
1843
1844         bpy.ops.view3d.zoom(delta = self.delta)
1845         r3d.update()
1846
1847         pos = [width,height]
1848         vtr_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1849         pos = [0,0]
1850         vbl_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1851         len_a = vtr_a - vbl_a
1852
1853         fac = len_a.length/len_b.length
1854         r3d.view_location -= ob.location
1855         r3d.view_location *= fac
1856         r3d.view_location += ob.location
1857         vres = Vector((em.custom_location.x*fac,em.custom_location.y*fac,em.custom_location.z))
1858
1859         if not em.custom_style_clone:
1860             em.custom_location = vres
1861
1862
1863         align_to_view(context)
1864
1865         return {'FINISHED'}
1866
1867     def execute(self, context):
1868         align_to_view(context)
1869
1870         return{'FINISHED'}
1871
1872 # Oprerator Class to use numpad shortcut
1873 class PresetView3D(Operator):
1874     bl_idname = "view3d.preset_view3d"
1875     bl_label = "Preset View3D"
1876
1877     view = StringProperty(name="View", description="Select the view", default='TOP')
1878     def invoke(self, context, event):
1879         ob = context.object
1880         em = bpy.data.objects[BProjection_Empty]
1881         origine = ob.location
1882         sd = context.space_data
1883
1884         vr_b = sd.region_3d.view_rotation.copy()
1885         vr_b.invert()
1886         pos_init = sd.region_3d.view_location - origine
1887         sd.region_3d.view_location = origine
1888
1889         tmp = context.user_preferences.view.smooth_view
1890         context.user_preferences.view.smooth_view = 0
1891         bpy.ops.view3d.viewnumpad(type=self.view)
1892         align_to_view(context)
1893         context.user_preferences.view.smooth_view = tmp
1894
1895         vr_a = sd.region_3d.view_rotation.copy()
1896         pos_init.rotate(vr_a*vr_b)
1897         sd.region_3d.view_location =  pos_init + origine
1898
1899         return {'FINISHED'}
1900
1901 @persistent
1902 def load_handler(dummy):
1903     reinitkey()
1904
1905 def register():
1906     bpy.utils.register_module(__name__)
1907     createcustomprops(bpy.context)
1908     bpy.app.handlers.load_post.append(load_handler)
1909
1910 def unregister():
1911     bpy.utils.unregister_module(__name__)
1912
1913 if __name__ == "__main__":
1914     register()