BProjection: change the version number
[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, 6, 3),
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.types import Panel, Operator
13 from bpy.props import IntProperty, FloatProperty, BoolProperty, IntVectorProperty, StringProperty, FloatVectorProperty, CollectionProperty
14 from bpy_extras import view3d_utils
15 import math
16 from math import *
17 import mathutils
18 from mathutils import *
19
20 # Main function for align the plan to view
21 def align_to_view(context):
22     ob = context.object
23     em = bpy.data.objects['Empty for BProjection']       
24     rotation = em.custom_rotation
25     scale = em.custom_scale
26     z = em.custom_location.z
27     pos = [em.custom_location.x, em.custom_location.y]
28     
29     reg = context.area.regions[4]        
30     width = reg.width
31     height = reg.height 
32     
33     sd = context.space_data    
34     r3d = sd.region_3d     
35     r3d.update()
36     vr = r3d.view_rotation
37     quat = mathutils.Quaternion((0.0, 0.0, 1.0), math.radians(float(rotation)))
38     v = Vector((pos[0],pos[1],z))
39     v.rotate(vr)
40
41     em = bpy.data.objects['Empty for BProjection']
42     img = bpy.data.textures['Texture for BProjection'].image
43     if img and img.size[1] != 0:
44         prop = img.size[0]/img.size[1]
45     else: prop = 1    
46     
47     if em.custom_linkscale:    
48         em.scale = Vector((prop*scale[0], scale[0], 1))
49     else:
50         em.scale = Vector((prop*scale[0], scale[1], 1))
51     pos_cur = em.location - sd.cursor_location
52     rot_cur1 = em.rotation_euler.to_quaternion()
53     em.location = v + ob.location            
54     em.rotation_euler = Quaternion.to_euler(vr*quat)   
55     if em.custom_c3d:
56         if em.custom_old_scale != em.custom_scale:
57             pos_cur = em.location - sd.cursor_location       
58         rot_cur2 = em.rotation_euler.to_quaternion()
59         rot_cur1.invert()
60         pos_cur.rotate(rot_cur1)
61         pos_cur.rotate(rot_cur2)
62         v = em.location - pos_cur
63         sd.cursor_location =  v
64
65 def applyimage(context):        
66         img = bpy.data.textures['Texture for BProjection'].image
67         em = bpy.data.objects['Empty for BProjection']
68         ob = context.object
69                
70         face = ob.data.polygons
71         uvdata = ob.data.uv_textures.active.data 
72             
73         for f,d in zip(face,uvdata):
74             if f.select:
75                 d.image = img
76                
77         align_to_view(context)
78         ob.data.update()
79
80 # Function to update the properties
81 def update_Location(self, context):          
82     align_to_view(context)
83
84 def find_uv(context):
85     obj = context.object
86     me = obj.data.vertices
87     vg = obj.vertex_groups
88     l=[]
89     index_uv = 0      
90     for face in obj.data.polygons:
91         x=len(face.vertices)
92         for vertex in face.vertices:
93             if len(me[vertex].groups)>0:
94                 for g in me[vertex].groups:
95                     if vg[g.group].name == 'texture plane':
96                         x-=1
97         
98                         
99         if x == 0:
100             l.append([index_uv,len(face.vertices)])
101         index_uv += len(face.vertices)
102     return l
103
104 # Function to update the scaleUV
105 def update_UVScale(self, context):
106     ob = context.object
107     em = bpy.data.objects['Empty for BProjection']
108     v = Vector((em.custom_offsetuv[0]/10 + 0.5, em.custom_offsetuv[1]/10 + 0.5))
109     l = Vector((0.0,0.0))
110     s = em.custom_scaleuv
111     os = em.custom_old_scaleuv 
112     scale = s - os
113     l = find_uv(context)
114     for i,j in l:
115         for t in range(j):
116             d = context.object.data.uv_layers.active.data[i+t]
117             vres =  v - d.uv  
118             d.uv.x = v.x - vres.x/os[0]*s[0]
119             d.uv.y = v.y - vres.y/os[1]*s[1]
120
121     em.custom_old_scaleuv = s  
122     
123     applyimage(context)
124
125 def update_PropUVScale(self, context):
126     em = bpy.data.objects['Empty for BProjection']
127     if em.custom_linkscaleuv:
128         em.custom_scaleuv = [em.custom_propscaleuv,em.custom_propscaleuv]
129
130 def update_LinkUVScale(self, context):
131     em = bpy.data.objects['Empty for BProjection']
132     if em.custom_linkscaleuv:
133         em.custom_propscaleuv = em.custom_scaleuv.x
134         update_PropUVScale(self, context)
135     else:
136         update_UVScale(self, context) 
137         
138 # Function to update the offsetUV
139 def update_UVOffset(self, context):
140     ob = context.object
141     em = bpy.data.objects['Empty for BProjection']
142     o = em.custom_offsetuv
143     oo = em.custom_old_offsetuv 
144     l = find_uv(context)
145     for i,j in l:
146         for t in range(j):
147             d = context.object.data.uv_layers.active.data[i+t]
148             d.uv = [d.uv[0] - oo[0]/10 + o[0]/10, d.uv[1] - oo[1]/10 + o[1]/10]   
149     em.custom_old_offsetuv = o
150     
151     applyimage(context)
152
153 # Function to update the flip horizontal
154 def update_FlipUVX(self, context):
155     l = find_uv(context)
156     for i,j in l:
157         for t in range(j):
158             d = context.object.data.uv_layers.active.data[i+t]
159             x = d.uv.x
160             d.uv.x = 1 - x
161     
162     applyimage(context)
163
164 # Function to update the flip vertical
165 def update_FlipUVY(self, context):
166     l = find_uv(context)
167     for i,j in l:
168         for t in range(j):
169             d = context.object.data.uv_layers.active.data[i+t]
170             y = d.uv[1]
171             d.uv[1] = 1 - y
172     
173     applyimage(context)
174
175 # Function to update
176 def update_Rotation(self, context):              
177     ob = context.object
178     em = bpy.data.objects['Empty for BProjection']
179     if em.custom_rotc3d:
180         angle = em.custom_rotation - em.custom_old_rotation
181         sd = context.space_data
182         vr = sd.region_3d.view_rotation.copy()        
183         c = sd.cursor_location - ob.location
184         e = bpy.data.objects['Empty for BProjection'].location - ob.location
185         vo = Vector((0.0, 0.0, 1.0))
186         vo.rotate(vr)
187         quat = mathutils.Quaternion(vo, math.radians(angle))
188         v = e-c
189         v.rotate(quat)
190         vr.invert()
191         v.rotate(vr)
192         c.rotate(vr)
193         em.custom_location = c + v
194     else:        
195         align_to_view(context)
196    
197     em.custom_old_rotation = em.custom_rotation
198
199 # Function to update scale
200 def update_Scale(self, context):              
201     ob = context.object
202     em = bpy.data.objects['Empty for BProjection']
203     
204     if em.custom_scac3d:
205         sd = context.space_data
206         r3d =  sd.region_3d
207         vr = r3d.view_rotation.copy()
208         vr.invert()
209         e = em.location - ob.location
210         c = sd.cursor_location - ob.location
211         ce = e - c
212         
213         s = em.custom_scale
214         os = em.custom_old_scale
215         c.rotate(vr)
216         ce.rotate(vr)
217         
218         img = bpy.data.textures['Texture for BProjection'].image
219         if img and img.size[1] != 0:
220             prop = img.size[0]/img.size[1]
221         else: prop = 1
222         
223         v = Vector((s.x*ce.x/os.x, s.y*ce.y/os.y,0.0))
224         em.custom_location = c + v
225         
226
227     else:          
228         align_to_view(context)
229             
230     
231     em.custom_old_scale = em.custom_scale
232
233 def update_PropScale(self, context):
234     em = bpy.data.objects['Empty for BProjection']
235     if em.custom_linkscale:
236         em.custom_scale = [em.custom_propscale,em.custom_propscale]
237     
238 def update_LinkScale(self, context):
239     em = bpy.data.objects['Empty for BProjection']
240     if em.custom_linkscale:
241         em.custom_propscale = em.custom_scale.x
242         update_PropScale(self, context)
243     else:
244         update_Scale(self, context) 
245
246 def update_activeviewname(self, context):
247     em = bpy.data.objects['Empty for BProjection']
248     if self.custom_active:
249         em.custom_active_view = self.custom_active_view
250
251 class custom_props(bpy.types.PropertyGroup):
252     custom_location = FloatVectorProperty(name="Location", description="Location of the plan",
253                                            default=(0,0,-1.0),
254                                            subtype = 'XYZ', size=3)
255                                            
256     custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
257                                      min=-180, max=180, default=0)
258                                          
259     custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
260                                        subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2)
261     custom_propscale = FloatProperty(name="PropScale", description="Scale the Plan",
262                                            default=1.0,min = 0.1)
263                                                                                     
264     custom_linkscale = BoolProperty(name="linkscale", default=True)
265    
266     # UV properties
267     custom_scaleuv = FloatVectorProperty(name="ScaleUV", description="Scale the texture's UV",
268                                             default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2)
269     custom_propscaleuv = FloatProperty(name="PropScaleUV", description="Scale the texture's UV",
270                                            default=1.0,min = 0.01) 
271     custom_offsetuv = FloatVectorProperty(name="OffsetUV", description="Decal the texture's UV",
272                                             default=(0.0,0.0), subtype = 'XYZ', size=2)       
273     custom_linkscaleuv = BoolProperty(name="linkscaleUV", default=True)
274     custom_flipuvx = BoolProperty(name="flipuvx", default=False)
275     custom_flipuvy = BoolProperty(name="flipuvy", default=False)
276     
277     # other properties
278     custom_active= BoolProperty(name="custom_active", default=True)   
279     custom_expand = BoolProperty(name="expand", default=False)
280     
281     custom_active_view = StringProperty(name = "custom_active_view",default = "View",update = update_activeviewname)
282     
283     custom_image = StringProperty(name = "custom_image",default = "")
284     
285     custom_index = IntProperty()
286
287 # Function to create custom properties
288 def createcustomprops(context):
289     Ob = bpy.types.Object    
290     
291     # plane properties 
292     Ob.custom_location = FloatVectorProperty(name="Location", description="Location of the plan",
293                                            default=(5.0,0.0,-1.0),
294                                            subtype = 'XYZ', size=3, update = update_Location)
295                                            
296     Ob.custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
297                                      min=-180, max=180, default=0,update = update_Rotation)
298                                      
299     Ob.custom_old_rotation = FloatProperty(name="old_Rotation", description="Old Rotate the plane",
300                                          min=-180, max=180, default=0)
301                                          
302     Ob.custom_scale = FloatVectorProperty(name="Scales", description="Scale the planes",
303                                           subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2,update = update_Scale)
304     Ob.custom_propscale = FloatProperty(name="PropScale", description="Scale the Plan",
305                                            default=1.0,min = 0.1,update = update_PropScale)
306     Ob.custom_old_scale = FloatVectorProperty(name="old_Scales", description="Old Scale the planes",
307                                           subtype = 'XYZ', default=(1.0, 1.0),min = 0.1, size=2)
308                                           
309     Ob.custom_linkscale = BoolProperty(name="linkscale", default=True, update = update_LinkScale)
310     
311                                 
312     Ob.custom_sub = IntProperty(name="Subdivide", description="Number of subdivision of the plan",
313                                      min=0, max=20, default=0)                                
314     
315     # UV properties
316     Ob.custom_scaleuv = FloatVectorProperty(name="ScaleUV", description="Scale the texture's UV",
317                                             default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2,update = update_UVScale)
318     Ob.custom_propscaleuv = FloatProperty(name="PropScaleUV", description="Scale the texture's UV",
319                                            default=1.0,min = 0.01,update = update_PropUVScale)    
320     Ob.custom_old_scaleuv = FloatVectorProperty(name="old_ScaleUV", description="Scale the texture's UV",
321                                                 default=(1.0,1.0),min = 0.01, subtype = 'XYZ', size=2)
322     Ob.custom_offsetuv = FloatVectorProperty(name="OffsetUV", description="Decal the texture's UV",
323                                             default=(0.0,0.0), subtype = 'XYZ', size=2,update = update_UVOffset)    
324     Ob.custom_old_offsetuv = FloatVectorProperty(name="old_OffsetUV", description="Decal the texture's UV",
325                                                  default=(0.0,0.0), subtype = 'XYZ', size=2)    
326     Ob.custom_linkscaleuv = BoolProperty(name="linkscaleUV", default=True, update = update_LinkUVScale)
327     Ob.custom_flipuvx = BoolProperty(name="flipuvx", default=False, update = update_FlipUVX)
328     Ob.custom_flipuvy = BoolProperty(name="flipuvy", default=False, update = update_FlipUVY)
329     
330     # other properties    
331     Ob.custom_c3d = BoolProperty(name="c3d", default=True)
332     Ob.custom_rotc3d = BoolProperty(name="rotc3d", default=False)
333     Ob.custom_scac3d = BoolProperty(name="scac3d", default=False)
334     Ob.custom_expand = BoolProperty(name="expand", default=True)
335     Ob.custom_active_view = StringProperty(name = "custom_active_view",default = "View")
336     Ob.custom_active_object = StringProperty(name = "custom_active_object",default = context.object.name)
337     
338     Ob.custom_props = CollectionProperty(type = custom_props)
339
340 # Function to remove custom properties
341 def removecustomprops():    
342     list_prop = ['custom_location', 'custom_rotation', 'custom_old_rotation', 'custom_scale', 'custom_old_scale', 'custom_c3d',
343                  'custom_rotc3d', 'custom_scaleuv', 'custom_flipuvx', 'custom_flipuvy', 'custom_linkscale',
344                  'custom_linkscaleuv', 'custom_old_scaleuv', 'custom_offsetuv', 'custom_old_offsetuv', 'custom_scac3d', 'custom_sub',
345                  'custom_expand', 'custom_active_view', 'custom_propscaleuv', 'custom_props', 'custom_propscale']
346     for prop in list_prop:
347         try:
348             del bpy.data.objects['Empty for BProjection'][prop]
349         except:
350             do = 'nothing'
351 def clear_props(context):
352     em = bpy.data.objects['Empty for BProjection'] 
353     em.custom_scale = [1,1]
354     em.custom_rotation = 0
355     em.custom_scaleuv =[1.0,1.0]
356     em.custom_offsetuv =[0.0,0.0]
357     em.custom_propscaleuv = 1.0
358     em.custom_propscale = 1.0
359     if em.custom_flipuvx == True:
360         em.custom_flipuvx = False
361     if em.custom_flipuvy == True:
362         em.custom_flipuvy = False
363
364 # Oprerator Class to create view            
365 class CreateView(Operator):
366     bl_idname = "object.create_view"
367     bl_label = "Create a new view"
368
369     def execute(self, context):              
370         ob = context.object
371         em = bpy.data.objects['Empty for BProjection']
372         new_props = em.custom_props.add()        
373         em.custom_active_view = new_props.custom_active_view               
374         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = True
375         bpy.ops.object.shape_key_add(from_mix = False)
376         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].value = 1.0
377         new_props.custom_index = len(em.custom_props)-1
378         bpy.ops.object.active_view(index = new_props.custom_index)
379         return {'FINISHED'}
380
381 # Oprerator Class to copy view 
382 class SaveView(Operator):
383     bl_idname = "object.save_view"
384     bl_label = "copy the view"
385     
386     index = IntProperty(default = 0)
387     
388     def execute(self, context):              
389         em = bpy.data.objects['Empty for BProjection']
390         prop = em.custom_props[self.index]                            
391         prop.custom_rotation =  em.custom_rotation                    
392         prop.custom_scale =  em.custom_scale                  
393         prop.custom_linkscale =  em.custom_linkscale                                      
394         prop.custom_scaleuv = em.custom_scaleuv
395         prop.custom_propscale = em.custom_propscale
396         prop.custom_offsetuv =  em.custom_offsetuv  
397         prop.custom_linkscaleuv = em.custom_linkscaleuv
398         prop.custom_propscaleuv = em.custom_propscaleuv
399         prop.custom_flipuvx = em.custom_flipuvx
400         prop.custom_flipuvy = em.custom_flipuvy
401         try:
402             prop.custom_image = bpy.data.textures['Texture for BProjection'].image.name
403         except:
404             do = 'nothing'
405         
406         return {'FINISHED'}
407
408 # Oprerator Class to copy view 
409 class PasteView(Operator):
410     bl_idname = "object.paste_view"
411     bl_label = "paste the view"
412     
413     index = IntProperty(default = 0)
414     
415     def execute(self, context):              
416         em = bpy.data.objects['Empty for BProjection']
417         tmp_scac3d = em.custom_scac3d
418         tmp_rotc3d = em.custom_rotc3d
419         em.custom_scac3d = False
420         em.custom_rotc3d = False
421         prop = em.custom_props[self.index]
422         em.custom_linkscale =  prop.custom_linkscale
423         em.custom_offsetuv =  prop.custom_offsetuv 
424         em.custom_linkscaleuv = prop.custom_linkscaleuv
425         em.custom_scaleuv = prop.custom_scaleuv
426         em.custom_propscaleuv = prop.custom_propscaleuv       
427         em.custom_rotation =  prop.custom_rotation                    
428         em.custom_scale =  prop.custom_scale
429         em.custom_propscale = prop.custom_propscale                     
430         if prop.custom_image != '':
431             if bpy.data.textures['Texture for BProjection'].image.name != prop.custom_image:
432                 bpy.data.textures['Texture for BProjection'].image = bpy.data.images[prop.custom_image]
433                 applyimage(context)
434         if em.custom_flipuvx != prop.custom_flipuvx:
435             em.custom_flipuvx = prop.custom_flipuvx
436         if em.custom_flipuvy != prop.custom_flipuvy:
437             em.custom_flipuvy = prop.custom_flipuvy
438         em.custom_scac3d = tmp_scac3d
439         em.custom_rotc3d = tmp_rotc3d        
440         return {'FINISHED'}
441
442 # Oprerator Class to remove view 
443 class RemoveView(Operator):
444     bl_idname = "object.remove_view"
445     bl_label = "Rmeove the view"
446     
447     index = IntProperty(default = 0)
448     
449     def execute(self, context):              
450         ob = context.object
451         em = bpy.data.objects['Empty for BProjection']
452         
453         ob.active_shape_key_index =  self.index + 1
454         bpy.ops.object.shape_key_remove()
455         
456         if  em.custom_props[self.index].custom_active: 
457             if len(em.custom_props) > 0:
458                 bpy.ops.object.active_view(index = self.index-1)
459             if self.index == 0 and len(em.custom_props) > 1:
460                 bpy.ops.object.active_view(index = 1)            
461                 
462         em.custom_props.remove(self.index)
463                 
464         if len(em.custom_props) == 0:
465             clear_props(context)
466             
467             bpy.ops.object.create_view()            
468                  
469         i=0
470         for item in em.custom_props:
471             item.custom_index = i           
472             i+=1 
473
474         for item in (item for item in em.custom_props if item.custom_active):
475                 ob.active_shape_key_index = item.custom_index+1
476            
477         return {'FINISHED'}
478
479 # Oprerator Class to copy view 
480 class ActiveView(Operator):
481     bl_idname = "object.active_view"
482     bl_label = "Active the view"
483     
484     index = IntProperty(default = 0)
485     
486     def execute(self, context):
487         ob = context.object
488         em = bpy.data.objects['Empty for BProjection']
489         for item in (item for item in em.custom_props if item.custom_active == True):
490             bpy.ops.object.save_view(index = item.custom_index)
491             item.custom_active = False
492         em.custom_props[self.index].custom_active  = True
493         em.custom_active_view = em.custom_props[self.index].custom_active_view 
494         ob.active_shape_key_index =  self.index + 1
495         
496         for i in ob.data.shape_keys.key_blocks:
497             i.mute = True
498         
499         ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = False
500         
501         bpy.ops.object.paste_view(index = self.index)         
502         
503         return {'FINISHED'}
504
505 # Draw Class to show the panel
506 class BProjection(Panel):
507     bl_space_type = 'VIEW_3D'
508     bl_region_type = 'UI'
509     bl_label = "BProjection"
510
511     @classmethod
512     def poll(cls, context):
513         return (context.image_paint_object or context.sculpt_object)
514
515     def draw(self, context):        
516         layout = self.layout
517                 
518         try: 
519             bpy.data.objects['Empty for BProjection']
520             
521             tex = bpy.data.textures['Texture for BProjection']
522             ob = context.object
523             em = bpy.data.objects['Empty for BProjection']
524             if ob == bpy.data.objects[em.custom_active_object]:            
525                 col = layout.column(align =True)
526                 col.operator("object.removebprojectionplane", text="Remove BProjection plane")           
527                 
528             box = layout.box()
529
530             row = box.row()
531             if not em.custom_expand:
532                 row.prop(em, "custom_expand", text  = "", icon="TRIA_RIGHT", emboss=False)
533                 row.label(text= 'Paint Object: '+ ob.name)
534             else:
535                 row.prop(em, "custom_expand", text = "" , icon="TRIA_DOWN", emboss=False)                
536                 row.label(text= 'Paint Object: '+ ob.name)
537                 
538                 if ob == bpy.data.objects[em.custom_active_object]:
539                     col = box.column(align =True)
540                     col.template_ID(tex, "image", open="image.open")
541                     row  = box.row(align=True)
542                     row.operator('object.applyimage', text="Apply image", icon = 'FILE_TICK')
543                     row.prop(em, "custom_c3d",text="", icon='CURSOR')
544                     row  = box.row(align =True)
545                     row.label(text="Location:")
546                     row  = box.row(align =True)
547                     row.prop(em,'custom_location', text='')
548                     row  = box.row(align =True)            
549                     row.prop(em,'custom_rotation')
550                     row.prop(em,'custom_rotc3d',text="",icon='MANIPUL')            
551                     row  = box.row(align =True)
552                     row.label(text="Scale:")
553                     row  = box.row(align =True) 
554                     if em.custom_linkscale :
555                         row.prop(em, "custom_propscale",text="")
556                         row.prop(em, "custom_linkscale",text="",icon='LINKED')
557                     else: 
558                         row.prop(em,'custom_scale',text='')
559                         row.prop(em, "custom_linkscale",text="",icon='UNLINKED')
560                     row.prop(em,'custom_scac3d',text="",icon='MANIPUL')                            
561                     row  = box.row(align =True)
562                     row.label(text="UV's Offset:")
563                     row  = box.row(align =True)
564                     row.prop(em,'custom_offsetuv',text='')
565                     row.prop(em, "custom_flipuvx",text="",icon='ARROW_LEFTRIGHT')   
566                     row.prop(em, "custom_flipuvy",text="",icon='FULLSCREEN_ENTER') 
567                     row  = box.row(align =True)
568                     row.label(text="UV's Scale:")
569                     row  = box.row(align =True)                            
570                     if em.custom_linkscaleuv:
571                         row.prop(em,'custom_propscaleuv',text='')
572                         row.prop(em, "custom_linkscaleuv",text="",icon='LINKED')
573                     else: 
574                         row.prop(em,'custom_scaleuv',text='')
575                         row.prop(em, "custom_linkscaleuv",text="",icon='UNLINKED')            
576                     row = box.column(align =True)
577                     row.prop(ob.material_slots['Material for BProjection'].material,'alpha', slider = True)
578                     row = box.column(align =True)
579     
580                 if ob == bpy.data.objects[em.custom_active_object]:    
581                     for item in em.custom_props:
582                         box = layout.box()
583                         row = box.row()
584                         if item.custom_active:
585                             row.operator("object.active_view",text = "", icon='RADIOBUT_ON', emboss = False).index = item.custom_index 
586                         else:
587                             row.operator("object.active_view",text = "", icon='RADIOBUT_OFF', emboss = False).index = item.custom_index 
588                         row.prop(item, "custom_active_view", text="")        
589                         row.operator('object.remove_view', text="", icon = 'PANEL_CLOSE', emboss = False).index = item.custom_index
590                     row = layout.row()
591                     row.operator('object.create_view', text="Create View", icon = 'RENDER_STILL') 
592                 else:
593                     col = box.column(align =True)
594                     col.operator("object.change_object", text="Change Object")       
595
596         except:
597             ob = context.object
598             col = layout.column(align = True)
599             col.operator("object.addbprojectionplane", text="Add BProjection plan")
600             col = layout.column(align = True)
601             col.prop(ob, "custom_sub",text="Subdivision level")
602                    
603
604 # Oprerator Class to apply the image to the plane             
605 class ApplyImage(Operator):
606     bl_idname = "object.applyimage"
607     bl_label = "Apply image"
608
609     def execute(self, context):        
610         applyimage(context)
611         
612         return {'FINISHED'}
613
614 # Oprerator Class to make the 4 or 6 point and scale the plan
615 class IntuitiveScale(Operator):
616     bl_idname = "object.intuitivescale"
617     bl_label = "Draw lines"
618
619     def invoke(self, context, event):
620         ob = context.object
621         em = bpy.data.objects['Empty for BProjection']
622         x = event.mouse_region_x
623         y = event.mouse_region_y                
624         if len(ob.grease_pencil.layers.active.frames) == 0: 
625             bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
626                                                        "is_start":True, "location":(0, 0, 0),
627                                                        "mouse":(x,y), "pressure":1, "time":0}])
628         else:
629             if em.custom_linkscale:
630                 nb_point = 4
631             else:
632                 nb_point = 6
633                    
634             if len(ob.grease_pencil.layers.active.frames[0].strokes) < nb_point:
635                 bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
636                                                            "is_start":True, "location":(0, 0, 0),
637                                                            "mouse":(x,y), "pressure":1, "time":0}])
638                                                            
639             if len(ob.grease_pencil.layers.active.frames[0].strokes) == nb_point:
640                 s = ob.grease_pencil.layers.active.frames[0]
641                 v1 = s.strokes[1].points[0].co - s.strokes[0].points[0].co
642                 if not em.custom_linkscale:
643                     v2 = s.strokes[4].points[0].co - s.strokes[3].points[0].co
644                 else:
645                     v2 = s.strokes[3].points[0].co - s.strokes[2].points[0].co
646                 propx = v1.x/v2.x                
647                 em.custom_scale[0] *= abs(propx)
648                 
649                 if not em.custom_linkscale:
650                     v1 = s.strokes[2].points[0].co - s.strokes[0].points[0].co
651                     v2 = s.strokes[5].points[0].co - s.strokes[3].points[0].co
652                     propy = v1.y/v2.y
653                     em.custom_scale[1] *= abs(propy)
654                 bpy.ops.gpencil.active_frame_delete()
655         
656         return {'FINISHED'}
657
658 # Oprerator Class to configure all wath is needed
659 class AddBProjectionPlane(Operator):
660     bl_idname = "object.addbprojectionplane"
661     bl_label = "Configure"
662     
663     def creatematerial(self, context):        
664         try:
665             matBProjection = bpy.data.materials['Material for BProjection']
666         except:            
667             bpy.data.textures.new(name='Texture for BProjection',type='IMAGE')
668     
669             bpy.data.materials.new(name='Material for BProjection')
670             
671             matBProjection = bpy.data.materials['Material for BProjection']
672             matBProjection.texture_slots.add()
673             matBProjection.use_shadeless = True
674             matBProjection.use_transparency = True
675             matBProjection.active_texture = bpy.data.textures['Texture for BProjection']
676         
677             index = matBProjection.active_texture_index
678             matBProjection.texture_slots[index].texture_coords = 'UV'
679         
680         ob = context.object 
681         old_index = ob.active_material_index
682         bpy.ops.object.material_slot_add()
683         index = ob.active_material_index
684         ob.material_slots[index].material = bpy.data.materials['Material for BProjection']
685         bpy.ops.object.material_slot_assign()
686         ob.active_material_index = old_index
687         ob.data.update()
688             
689     def execute(self, context):    
690         try:
691             bpy.data.objects['Empty for BProjection']
692
693         except:                 
694             
695             cm = bpy.context.object.mode
696             '''tmp = context.object
697             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):
698                 context.scene.objects.active = ob
699                 bpy.ops.object.mode_set(mode = cm, toggle=False) 
700             
701             context.scene.objects.active = tmp'''
702             bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
703             
704             context.space_data.show_relationship_lines = False
705             
706             ob = context.object
707         
708             bpy.ops.object.add()
709             em = context.object
710             em.name = "Empty for BProjection"
711                         
712             context.scene.objects.active = ob
713             ob.select = True
714     
715             bpy.ops.object.editmode_toggle()
716     
717             bpy.ops.mesh.primitive_plane_add()
718             bpy.ops.object.vertex_group_assign(new = True)
719             ob.vertex_groups.active.name = 'texture plane'   
720             bpy.ops.uv.unwrap()
721             
722             bpy.ops.mesh.select_all(action='DESELECT')                                
723             bpy.ops.object.vertex_group_select()
724             
725             bpy.ops.object.editmode_toggle()
726             for i in range(4):
727                 ob.data.edges[len(ob.data.edges)-1-i].crease = 1
728             bpy.ops.object.editmode_toggle()
729             
730             em.custom_sub = ob.custom_sub
731             if em.custom_sub > 0:
732                 bpy.ops.mesh.subdivide(number_cuts = em.custom_sub)
733     
734             em.select = True
735             bpy.ops.object.hook_add_selob()
736             em.select = False
737             em.hide = True   
738                      
739             self.creatematerial(context)
740   
741           
742             bpy.ops.gpencil.data_add()
743             ob.grease_pencil.draw_mode = 'VIEW'
744             bpy.ops.gpencil.layer_add()
745             ob.grease_pencil.layers.active.color = [1.0,0,0]
746             
747             bpy.ops.object.editmode_toggle()
748             
749             bpy.ops.object.shape_key_add(from_mix = False)
750             
751             bpy.ops.object.create_view()
752             # ----------------------------------------------
753             # XXX, this isnt future proof, DON'T USE INDEX's - campbell                    
754             km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
755             km.keymap_items[3-1].idname = 'view3d.rotate_view3d'
756             km.keymap_items[19-1].idname = 'view3d.zoom_view3d'
757             km.keymap_items[19-1].properties.delta = 1.0
758             km.keymap_items[20-1].idname = 'view3d.zoom_view3d'
759             km.keymap_items[20-1].properties.delta = -1.0
760             km.keymap_items[4-1].idname = 'view3d.pan_view3d'
761             km.keymap_items[28-1].idname = 'view3d.preset_view3d'
762             km.keymap_items[28-1].properties.view = 'FRONT'
763             km.keymap_items[30-1].idname = 'view3d.preset_view3d'
764             km.keymap_items[30-1].properties.view = 'RIGHT'            
765             km.keymap_items[34-1].idname = 'view3d.preset_view3d'
766             km.keymap_items[34-1].properties.view = 'TOP'
767             km.keymap_items[36-1].idname = 'view3d.preset_view3d'
768             km.keymap_items[36-1].properties.view = 'BACK'
769             km.keymap_items[37-1].idname = 'view3d.preset_view3d'
770             km.keymap_items[37-1].properties.view = 'LEFT'            
771             km.keymap_items[38-1].idname = 'view3d.preset_view3d'
772             km.keymap_items[38-1].properties.view = 'BOTTOM'                                   
773             km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
774             kmi = km.keymap_items.new("object.intuitivescale", 'LEFTMOUSE', 'PRESS', shift=True)
775                         
776             align_to_view(context)
777             
778             context.space_data.cursor_location = em.location
779             
780             bpy.ops.object.mode_set(mode = cm, toggle=False)
781             
782         return {'FINISHED'}
783
784 # Oprerator Class to remove what is no more needed    
785 class RemoveBProjectionPlane(Operator):
786     bl_idname = "object.removebprojectionplane"
787     bl_label = "Configure"
788
789     def removematerial(self, context):
790         ob = context.object 
791         i = 0
792
793         for ms in ob.material_slots:
794             if ms.name == 'Material for BProjection':
795                 index = i
796             i+=1
797                 
798         ob.active_material_index = index
799         bpy.ops.object.material_slot_remove()
800     
801     def execute(self, context):
802         try:               
803             cm = bpy.context.object.mode
804             bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
805             
806             context.space_data.show_relationship_lines = True
807             
808             bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
809             
810             self.removematerial(context)
811
812             ob = context.object
813     
814             bpy.ops.object.editmode_toggle()
815     
816             bpy.ops.mesh.reveal()
817                                    
818             bpy.ops.mesh.select_all(action='DESELECT')                    
819             
820             ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
821             bpy.ops.object.vertex_group_select()
822             bpy.ops.mesh.delete()
823             bpy.ops.object.vertex_group_remove()
824     
825             bpy.ops.object.editmode_toggle()
826    
827             ob.select = False
828                 
829             em = bpy.data.objects['Empty for BProjection']
830             context.scene.objects.active = em
831             em.hide = False
832             em.select = True
833             bpy.ops.object.delete()
834     
835             context.scene.objects.active = ob
836             ob.select = True
837             
838             km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
839             # ----------------------------------------------
840             # XXX, this isnt future proof, DON'T USE INDEX's - campbell
841             km.keymap_items[3-1].idname = 'view3d.rotate'
842             km.keymap_items[19-1].idname = 'view3d.zoom'
843             km.keymap_items[19-1].properties.delta = 1.0
844             km.keymap_items[20-1].idname = 'view3d.zoom'
845             km.keymap_items[20-1].properties.delta = -1.0
846             km.keymap_items[4-1].idname = 'view3d.move'
847             km.keymap_items[28-1].idname = 'view3d.viewnumpad'
848             km.keymap_items[28-1].properties.type = 'FRONT'
849             km.keymap_items[30-1].idname = 'view3d.viewnumpad'
850             km.keymap_items[30-1].properties.type = 'RIGHT'            
851             km.keymap_items[34-1].idname = 'view3d.viewnumpad'
852             km.keymap_items[34-1].properties.type = 'TOP'
853             km.keymap_items[36-1].idname = 'view3d.viewnumpad'
854             km.keymap_items[36-1].properties.type = 'BACK'
855             km.keymap_items[37-1].idname = 'view3d.viewnumpad'
856             km.keymap_items[37-1].properties.type = 'LEFT'            
857             km.keymap_items[38-1].idname = 'view3d.viewnumpad'
858             km.keymap_items[38-1].properties.type = 'BOTTOM'            
859             
860             km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
861             #to do
862             for kmi in (kmi for kmi in km.keymap_items if kmi.idname in {"object.intuitivescale", }):
863                     km.keymap_items.remove(kmi)
864             
865             '''tmp = context.object
866             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):
867                 context.scene.objects.active = ob
868                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False) 
869             
870             context.scene.objects.active = tmp'''
871             ob = context.object           
872             
873             
874             for i in ob.data.shape_keys.key_blocks:
875                 bpy.ops.object.shape_key_remove()
876             bpy.ops.object.shape_key_remove()
877                
878             bpy.ops.object.mode_set(mode = cm, toggle=False)
879             removecustomprops()
880                     
881         except:
882             nothing = 0
883         
884         return {'FINISHED'}
885
886 # Oprerator Class to remove what is no more needed    
887 class ChangeObject(Operator):
888     bl_idname = "object.change_object"
889     bl_label = "Change Object"
890
891     def removematerial(self, context):
892         ob = context.object 
893         i = 0
894
895         for ms in ob.material_slots:
896             if ms.name == 'Material for BProjection':
897                 index = i
898             i+=1
899                 
900         ob.active_material_index = index
901         bpy.ops.object.material_slot_remove()
902     
903     def execute(self, context):
904             new_ob = context.object
905             em = bpy.data.objects['Empty for BProjection']              
906             context.scene.objects.active = bpy.data.objects[em.custom_active_object]
907             ob = context.object
908             if ob != new_ob:
909                 cm = bpy.context.object.mode
910                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
911                 
912                 bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection") 
913     
914                 ob = context.object
915         
916                 bpy.ops.object.editmode_toggle()
917         
918                 bpy.ops.mesh.reveal()
919                                        
920                 bpy.ops.mesh.select_all(action='DESELECT')                               
921                 ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
922                 bpy.ops.object.vertex_group_select()
923                 lo_b = [ob for ob in bpy.data.objects if ob.type == 'MESH']
924                 bpy.ops.mesh.separate(type='SELECTED')
925                 lo_a = [ob for ob in bpy.data.objects if ob.type == 'MESH']
926                 bpy.ops.object.vertex_group_remove()
927                 
928                 for i in lo_b:
929                     lo_a.remove(i)
930                 bplane = lo_a[0]
931                 
932                 bpy.ops.object.editmode_toggle()
933                 
934                 self.removematerial(context)
935                 
936                 bpy.ops.object.mode_set(mode = cm, toggle=False)
937                 
938                 shape_index = ob.active_shape_key_index
939                 
940                 for i in ob.data.shape_keys.key_blocks:
941                     bpy.ops.object.shape_key_remove()
942                 bpy.ops.object.shape_key_remove()
943                 
944                 ob.select = False
945                 
946                 bplane.select = True            
947                 context.scene.objects.active = bplane
948                 for ms in (ms for ms in bplane.material_slots if ms.name != 'Material for BProjection'):
949                     bplane.active_material = ms.material
950                     bpy.ops.object.material_slot_remove()
951                 
952                 for gs in (gs for gs in bplane.vertex_groups if gs.name != 'texture plane'):
953                     bplane.vertex_groups.active_index = gs.index
954                     bpy.ops.object.vertex_group_remove()
955               
956                 context.scene.objects.active = new_ob
957                 cm = new_ob.mode
958                 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False) 
959                 bpy.ops.object.join()
960     
961                 em.hide = False
962                 em.select = True
963                 new_ob.select = False
964                 bpy.ops.object.location_clear()
965                 bpy.ops.object.rotation_clear()
966                 bpy.ops.object.scale_clear()
967                 context.scene.objects.active = new_ob
968                 bpy.ops.object.editmode_toggle()            
969                 bpy.ops.object.hook_add_selob()
970                 bpy.ops.object.editmode_toggle()
971                 em.hide = True
972                 em.select = False
973                 new_ob.select = True
974                 em.custom_active_object = new_ob.name
975                 tmp = em.custom_c3d
976                 em.custom_c3d = False
977                 bpy.ops.object.active_view(index = shape_index-1)
978                 bpy.ops.object.mode_set(mode = cm, toggle=False)
979                         
980                 sd = context.space_data
981                 r3d = sd.region_3d 
982                 vr = r3d.view_rotation.copy()
983                 vr.invert()
984                 ob_loc = ob.location.copy()            
985                 new_ob_loc = new_ob.location.copy() 
986                 ob_loc.rotate(vr)
987                 new_ob_loc.rotate(vr)
988                 em.custom_location += Vector((ob_loc.x - new_ob_loc.x, ob_loc.y - new_ob_loc.y, 0.0))
989                 em.custom_c3d = tmp
990                     
991             return {'FINISHED'}
992
993 # Oprerator Class to rotate the view3D
994 class RotateView3D(Operator):
995     bl_idname = "view3d.rotate_view3d"
996     bl_label = "Rotate the View3D"
997     
998     first_mouse = Vector((0,0))
999
1000     pan = Vector((0,0))
1001
1002     key = ['']
1003  
1004     first_time = True
1005     tmp_level = -1
1006     
1007     def vect_sphere(self, context, mx, my):
1008         width = context.area.regions[4].width
1009         height = context.area.regions[4].height
1010            
1011         if width >= height:
1012             ratio = height/width
1013         
1014             x = 2*mx/width
1015             y = 2*ratio*my/height
1016             
1017             x = x - 1
1018             y = y - ratio
1019         else:
1020             ratio = width/height
1021         
1022             x = 2*ratio*mx/width
1023             y = 2*my/height
1024  
1025             x = x - ratio
1026             y = y - 1
1027         
1028         z2 = 1 - x * x - y * y
1029         if z2 > 0:
1030             z= sqrt(z2)
1031         else : z=0
1032             
1033         p = Vector((x, y, z))
1034         p.normalize()
1035         return p
1036     
1037     def tracball(self, context, mx, my, origine):
1038         sd = context.space_data
1039         ob = context.object
1040         em = bpy.data.objects['Empty for BProjection']        
1041             
1042         vr_b = sd.region_3d.view_rotation.copy()
1043         vr_b.invert()
1044         pos_init = sd.region_3d.view_location - origine
1045         sd.region_3d.view_location = origine
1046         
1047         v1 = self.vect_sphere(context, self.first_mouse.x, self.first_mouse.y)
1048         v2 = self.vect_sphere(context, mx, my)
1049                         
1050         axis = Vector.cross(v1,v2);
1051         angle = Vector.angle(v1,v2);
1052             
1053         q =  Quaternion(axis,-2*angle)
1054                         
1055         sd.region_3d.view_rotation *=q
1056         sd.region_3d.update()
1057         
1058         vr_a = sd.region_3d.view_rotation.copy()                           
1059         pos_init.rotate(vr_a*vr_b)            
1060         sd.region_3d.view_location =  pos_init + origine
1061         
1062         self.first_mouse = Vector((mx, my))
1063                 
1064     def modal(self, context, event):                                
1065         ob = context.object
1066         em = bpy.data.objects['Empty for BProjection'] 
1067         reg = context.area.regions[4]        
1068         if event.value == 'PRESS':
1069             self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
1070                     
1071             self.key = [event.type]
1072
1073         if event.value == 'RELEASE':
1074             self.key = [''] 
1075
1076         if event.type == 'MOUSEMOVE':                        
1077             
1078             if '' in self.key:
1079                 self.tracball(context, event.mouse_region_x, event.mouse_region_y,ob.location)
1080                 align_to_view(context)
1081                 if self.first_time:
1082                     rot_ang = context.user_preferences.view.rotation_angle            
1083                     context.user_preferences.view.rotation_angle = 0
1084                     bpy.ops.view3d.view_orbit(type='ORBITLEFT')
1085                     context.user_preferences.view.rotation_angle = rot_ang   
1086                     bpy.ops.view3d.view_persportho()         
1087                     bpy.ops.view3d.view_persportho()
1088                     self.first_time = False
1089           
1090             deltax = event.mouse_region_x - round(self.pan.x)
1091             deltay = event.mouse_region_y - round(self.pan.y)          
1092
1093             if 'G' in self.key:       
1094                 sd = context.space_data              
1095                 l =  sd.region_3d
1096                 vr = l.view_rotation.copy()
1097                 vr.invert()
1098                 
1099                 v_init = Vector((0.0,0.0,1.0))
1100                 
1101                 pos = [-deltax,-deltay]
1102                 v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1103                 pos = [0,0]
1104                 vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)        
1105                 loc = vbl - v            
1106                 loc.rotate(vr)
1107                 em.custom_location += loc              
1108                                    
1109             if 'S' in self.key:                
1110                 s = em.custom_scale
1111                 if em.custom_linkscale:
1112                     em.custom_propscale += deltax/20
1113                 else:
1114                     em.custom_scale = [s[0] + deltax/20, s[1] + deltay/20]
1115                                           
1116             if 'Z' in self.key:                
1117                 em.custom_location.z+=deltax/10
1118                       
1119             if 'R' in self.key:
1120                 em.custom_rotation+=deltax
1121                     
1122             if 'U' in self.key:
1123                 suv = em.custom_scaleuv
1124                 if em.custom_linkscaleuv:    
1125                     em.custom_propscaleuv += deltax/50
1126                 else:
1127                     em.custom_scaleuv= [suv[0] + deltax/50 , suv[1] + deltay/50]               
1128
1129             if 'Y' in self.key:       
1130                 ouv = em.custom_offsetuv
1131                 em.custom_offsetuv = [ouv[0] - deltax/50,ouv[1] - deltay/50] 
1132
1133             self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
1134             self.first_mouse = Vector((event.mouse_region_x, self.first_mouse.y))
1135                         
1136         elif event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
1137             if self.tmp_level > -1:
1138                 for sub in context.object.modifiers:
1139                     if sub.type in ['SUBSURF','MULTIRES']:
1140                         sub.levels = self.tmp_level   
1141             
1142             return {'FINISHED'}
1143         
1144         if 'C' in self.key:
1145             clear_props(context)
1146         
1147         if 'O' in self.key:
1148             bpy.ops.object.change_object()            
1149         return {'RUNNING_MODAL'}
1150     
1151     def execute(self, context):        
1152         align_to_view(context)  
1153         
1154         return{'FINISHED'}
1155
1156     def invoke(self, context, event):
1157         context.window_manager.modal_handler_add(self)
1158         self.first_mouse = Vector((event.mouse_region_x,event.mouse_region_y))
1159         self.first_time = True
1160         for sub in context.object.modifiers:
1161             if sub.type in ['SUBSURF', 'MULTIRES']:
1162                 self.tmp_level = sub.levels
1163                 sub.levels = 0
1164         return {'RUNNING_MODAL'}
1165
1166 # Oprerator Class to pan the view3D
1167 class PanView3D(bpy.types.Operator):
1168     bl_idname = "view3d.pan_view3d"
1169     bl_label = "Pan View3D"
1170     
1171     first_mouse = Vector((0,0))
1172     tmp_level = -1
1173
1174     def modal(self, context, event):
1175         ob = context.object
1176         em = bpy.data.objects['Empty for BProjection']
1177         width = context.area.regions[4].width
1178         height = context.area.regions[4].height
1179
1180         deltax = event.mouse_region_x - self.first_mouse.x
1181         deltay = event.mouse_region_y - self.first_mouse.y                
1182         
1183         sd = context.space_data              
1184         r3d =  sd.region_3d
1185         vr = r3d.view_rotation.copy()
1186         vr.invert()
1187         
1188         v_init = Vector((0.0,0.0,1.0))
1189         
1190         pos = [deltax,deltay]
1191         v = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1192         pos = [0,0]
1193         vbl = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)        
1194         loc = vbl - v       
1195         sd.region_3d.view_location += loc         
1196         loc.rotate(vr)
1197         em.custom_location += loc
1198
1199         self.first_mouse.x = event.mouse_region_x
1200         self.first_mouse.y = event.mouse_region_y
1201
1202         if event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
1203             if self.tmp_level > -1:
1204                 for sub in context.object.modifiers:
1205                     if sub.type in ['SUBSURF','MULTIRES']:
1206                         sub.levels = self.tmp_level
1207             return {'FINISHED'}
1208         
1209         return {'RUNNING_MODAL'}
1210                 
1211     def invoke(self, context, event):
1212         context.window_manager.modal_handler_add(self)
1213         self.first_mouse.x = event.mouse_region_x
1214         self.first_mouse.y = event.mouse_region_y   
1215         for sub in context.object.modifiers:
1216             if sub.type in ['SUBSURF', 'MULTIRES']:
1217                 self.tmp_level = sub.levels
1218                 sub.levels = 0  
1219                       
1220         return {'RUNNING_MODAL'}
1221
1222     def execute(self, context):        
1223         align_to_view(context)  
1224         
1225         return{'FINISHED'}
1226
1227 # Oprerator Class to zoom the view3D
1228 class ZoomView3D(Operator):
1229     bl_idname = "view3d.zoom_view3d"
1230     bl_label = "Zoom View3D"
1231
1232     delta = FloatProperty(
1233         name="delta",
1234         description="Delta",
1235         min=-1.0, max=1,
1236         default=1.0)
1237
1238     def invoke(self, context, event):                   
1239         ob = context.object
1240         em = bpy.data.objects['Empty for BProjection']
1241         sd = context.space_data
1242
1243         width = context.area.regions[4].width
1244         height = context.area.regions[4].height              
1245                     
1246         r3d =  sd.region_3d
1247         v_init = Vector((0.0,0.0,1.0))
1248
1249         pos = [width,height]
1250         vtr_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1251         pos = [0,0]
1252         vbl_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1253         len_b = vtr_b - vbl_b
1254        
1255         bpy.ops.view3d.zoom(delta = self.delta)
1256         r3d.update()
1257
1258         pos = [width,height]
1259         vtr_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1260         pos = [0,0]
1261         vbl_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init) 
1262         len_a = vtr_a - vbl_a
1263         
1264         fac = len_a.length/len_b.length
1265         r3d.view_location -= ob.location
1266         r3d.view_location *= fac
1267         r3d.view_location += ob.location
1268         vres = Vector((em.custom_location.x*fac,em.custom_location.y*fac,em.custom_location.z))
1269         em.custom_location = vres
1270         
1271         
1272         align_to_view(context)
1273         
1274         return {'FINISHED'}
1275
1276     def execute(self, context):        
1277         align_to_view(context)
1278         
1279         return{'FINISHED'}
1280
1281 # Oprerator Class to use numpad shortcut
1282 class PresetView3D(Operator):
1283     bl_idname = "view3d.preset_view3d"
1284     bl_label = "Preset View3D"
1285
1286     view = StringProperty(name="View", description="Select the view", default='TOP')
1287     def invoke(self, context, event):                   
1288         ob = context.object
1289         em = bpy.data.objects['Empty for BProjection']
1290         origine = ob.location
1291         sd = context.space_data
1292
1293         vr_b = sd.region_3d.view_rotation.copy()
1294         vr_b.invert()
1295         pos_init = sd.region_3d.view_location - origine
1296         sd.region_3d.view_location = origine
1297
1298         tmp = context.user_preferences.view.smooth_view
1299         context.user_preferences.view.smooth_view = 0
1300         bpy.ops.view3d.viewnumpad(type=self.view)
1301         align_to_view(context)        
1302         context.user_preferences.view.smooth_view = tmp
1303
1304         vr_a = sd.region_3d.view_rotation.copy()                           
1305         pos_init.rotate(vr_a*vr_b)            
1306         sd.region_3d.view_location =  pos_init + origine              
1307                     
1308         return {'FINISHED'}
1309
1310 def register():
1311     bpy.utils.register_module(__name__)
1312     createcustomprops(bpy.context)
1313
1314 def unregister():
1315     bpy.utils.unregister_module(__name__)
1316
1317 if __name__ == "__main__":
1318     register()