3 "description": "Help Clone tool",
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",
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
18 from mathutils import *
20 # Main function for align the plan to view
21 def align_to_view(context):
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]
29 reg = context.area.regions[4]
33 sd = context.space_data
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))
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]
47 if em.custom_linkscale:
48 em.scale = Vector((prop*scale[0], scale[0], 1))
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)
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()
60 pos_cur.rotate(rot_cur1)
61 pos_cur.rotate(rot_cur2)
62 v = em.location - pos_cur
63 sd.cursor_location = v
65 def applyimage(context):
66 img = bpy.data.textures['Texture for BProjection'].image
67 em = bpy.data.objects['Empty for BProjection']
70 face = ob.data.polygons
71 uvdata = ob.data.uv_textures.active.data
73 for f,d in zip(face,uvdata):
77 align_to_view(context)
80 # Function to update the properties
81 def update_Location(self, context):
82 align_to_view(context)
86 me = obj.data.vertices
87 vg = obj.vertex_groups
90 for face in obj.data.polygons:
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':
100 l.append([index_uv,len(face.vertices)])
101 index_uv += len(face.vertices)
104 # Function to update the scaleUV
105 def update_UVScale(self, context):
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
116 d = context.object.data.uv_layers.active.data[i+t]
118 d.uv.x = v.x - vres.x/os[0]*s[0]
119 d.uv.y = v.y - vres.y/os[1]*s[1]
121 em.custom_old_scaleuv = s
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]
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)
136 update_UVScale(self, context)
138 # Function to update the offsetUV
139 def update_UVOffset(self, context):
141 em = bpy.data.objects['Empty for BProjection']
142 o = em.custom_offsetuv
143 oo = em.custom_old_offsetuv
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
153 # Function to update the flip horizontal
154 def update_FlipUVX(self, context):
158 d = context.object.data.uv_layers.active.data[i+t]
164 # Function to update the flip vertical
165 def update_FlipUVY(self, context):
169 d = context.object.data.uv_layers.active.data[i+t]
176 def update_Rotation(self, context):
178 em = bpy.data.objects['Empty for BProjection']
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))
187 quat = mathutils.Quaternion(vo, math.radians(angle))
193 em.custom_location = c + v
195 align_to_view(context)
197 em.custom_old_rotation = em.custom_rotation
199 # Function to update scale
200 def update_Scale(self, context):
202 em = bpy.data.objects['Empty for BProjection']
205 sd = context.space_data
207 vr = r3d.view_rotation.copy()
209 e = em.location - ob.location
210 c = sd.cursor_location - ob.location
214 os = em.custom_old_scale
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]
223 v = Vector((s.x*ce.x/os.x, s.y*ce.y/os.y,0.0))
224 em.custom_location = c + v
228 align_to_view(context)
231 em.custom_old_scale = em.custom_scale
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]
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)
244 update_Scale(self, context)
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
251 class custom_props(bpy.types.PropertyGroup):
252 custom_location = FloatVectorProperty(name="Location", description="Location of the plan",
254 subtype = 'XYZ', size=3)
256 custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
257 min=-180, max=180, default=0)
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)
264 custom_linkscale = BoolProperty(name="linkscale", default=True)
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)
278 custom_active= BoolProperty(name="custom_active", default=True)
279 custom_expand = BoolProperty(name="expand", default=False)
281 custom_active_view = StringProperty(name = "custom_active_view",default = "View",update = update_activeviewname)
283 custom_image = StringProperty(name = "custom_image",default = "")
285 custom_index = IntProperty()
287 # Function to create custom properties
288 def createcustomprops(context):
289 Ob = bpy.types.Object
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)
296 Ob.custom_rotation = FloatProperty(name="Rotation", description="Rotate the plane",
297 min=-180, max=180, default=0,update = update_Rotation)
299 Ob.custom_old_rotation = FloatProperty(name="old_Rotation", description="Old Rotate the plane",
300 min=-180, max=180, default=0)
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)
309 Ob.custom_linkscale = BoolProperty(name="linkscale", default=True, update = update_LinkScale)
312 Ob.custom_sub = IntProperty(name="Subdivide", description="Number of subdivision of the plan",
313 min=0, max=20, default=0)
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)
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)
338 Ob.custom_props = CollectionProperty(type = custom_props)
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:
348 del bpy.data.objects['Empty for BProjection'][prop]
352 def clear_props(context):
353 em = bpy.data.objects['Empty for BProjection']
354 em.custom_scale = [1,1]
355 em.custom_rotation = 0
356 em.custom_scaleuv =[1.0,1.0]
357 em.custom_offsetuv =[0.0,0.0]
358 em.custom_propscaleuv = 1.0
359 em.custom_propscale = 1.0
360 if em.custom_flipuvx == True:
361 em.custom_flipuvx = False
362 if em.custom_flipuvy == True:
363 em.custom_flipuvy = False
365 # Oprerator Class to create view
366 class CreateView(Operator):
367 bl_idname = "object.create_view"
368 bl_label = "Create a new view"
370 def execute(self, context):
372 em = bpy.data.objects['Empty for BProjection']
373 new_props = em.custom_props.add()
374 em.custom_active_view = new_props.custom_active_view
375 ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = True
376 bpy.ops.object.shape_key_add(from_mix = False)
377 ob.data.shape_keys.key_blocks[ob.active_shape_key_index].value = 1.0
378 new_props.custom_index = len(em.custom_props)-1
379 bpy.ops.object.active_view(index = new_props.custom_index)
382 # Oprerator Class to copy view
383 class SaveView(Operator):
384 bl_idname = "object.save_view"
385 bl_label = "copy the view"
387 index = IntProperty(default = 0)
389 def execute(self, context):
390 em = bpy.data.objects['Empty for BProjection']
391 prop = em.custom_props[self.index]
392 prop.custom_rotation = em.custom_rotation
393 prop.custom_scale = em.custom_scale
394 prop.custom_linkscale = em.custom_linkscale
395 prop.custom_scaleuv = em.custom_scaleuv
396 prop.custom_propscale = em.custom_propscale
397 prop.custom_offsetuv = em.custom_offsetuv
398 prop.custom_linkscaleuv = em.custom_linkscaleuv
399 prop.custom_propscaleuv = em.custom_propscaleuv
400 prop.custom_flipuvx = em.custom_flipuvx
401 prop.custom_flipuvy = em.custom_flipuvy
403 prop.custom_image = bpy.data.textures['Texture for BProjection'].image.name
409 # Oprerator Class to copy view
410 class PasteView(Operator):
411 bl_idname = "object.paste_view"
412 bl_label = "paste the view"
414 index = IntProperty(default = 0)
416 def execute(self, context):
417 em = bpy.data.objects['Empty for BProjection']
418 tmp_scac3d = em.custom_scac3d
419 tmp_rotc3d = em.custom_rotc3d
420 em.custom_scac3d = False
421 em.custom_rotc3d = False
422 prop = em.custom_props[self.index]
423 em.custom_linkscale = prop.custom_linkscale
424 em.custom_offsetuv = prop.custom_offsetuv
425 em.custom_linkscaleuv = prop.custom_linkscaleuv
426 em.custom_scaleuv = prop.custom_scaleuv
427 em.custom_propscaleuv = prop.custom_propscaleuv
428 em.custom_rotation = prop.custom_rotation
429 em.custom_scale = prop.custom_scale
430 em.custom_propscale = prop.custom_propscale
431 if prop.custom_image != '':
432 if bpy.data.textures['Texture for BProjection'].image.name != prop.custom_image:
433 bpy.data.textures['Texture for BProjection'].image = bpy.data.images[prop.custom_image]
435 if em.custom_flipuvx != prop.custom_flipuvx:
436 em.custom_flipuvx = prop.custom_flipuvx
437 if em.custom_flipuvy != prop.custom_flipuvy:
438 em.custom_flipuvy = prop.custom_flipuvy
439 em.custom_scac3d = tmp_scac3d
440 em.custom_rotc3d = tmp_rotc3d
443 # Oprerator Class to remove view
444 class RemoveView(Operator):
445 bl_idname = "object.remove_view"
446 bl_label = "Rmeove the view"
448 index = IntProperty(default = 0)
450 def execute(self, context):
452 em = bpy.data.objects['Empty for BProjection']
454 ob.active_shape_key_index = self.index + 1
455 bpy.ops.object.shape_key_remove()
457 if em.custom_props[self.index].custom_active:
458 if len(em.custom_props) > 0:
459 bpy.ops.object.active_view(index = self.index-1)
460 if self.index == 0 and len(em.custom_props) > 1:
461 bpy.ops.object.active_view(index = 1)
463 em.custom_props.remove(self.index)
465 if len(em.custom_props) == 0:
468 bpy.ops.object.create_view()
471 for item in em.custom_props:
472 item.custom_index = i
475 for item in (item for item in em.custom_props if item.custom_active):
476 ob.active_shape_key_index = item.custom_index+1
480 # Oprerator Class to copy view
481 class ActiveView(Operator):
482 bl_idname = "object.active_view"
483 bl_label = "Active the view"
485 index = IntProperty(default = 0)
487 def execute(self, context):
489 em = bpy.data.objects['Empty for BProjection']
490 for item in (item for item in em.custom_props if item.custom_active == True):
491 bpy.ops.object.save_view(index = item.custom_index)
492 item.custom_active = False
493 em.custom_props[self.index].custom_active = True
494 em.custom_active_view = em.custom_props[self.index].custom_active_view
495 ob.active_shape_key_index = self.index + 1
497 for i in ob.data.shape_keys.key_blocks:
500 ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = False
502 bpy.ops.object.paste_view(index = self.index)
506 # Draw Class to show the panel
507 class BProjection(Panel):
508 bl_space_type = 'VIEW_3D'
509 bl_region_type = 'UI'
510 bl_label = "BProjection"
513 def poll(cls, context):
514 return (context.image_paint_object or context.sculpt_object)
516 def draw(self, context):
519 if 'Empty for BProjection' in [ob.name for ob in bpy.data.objects]:
522 tex = bpy.data.textures['Texture for BProjection']
524 em = bpy.data.objects['Empty for BProjection']
525 if ob == bpy.data.objects[em.custom_active_object]:
526 col = layout.column(align =True)
527 col.operator("object.removebprojectionplane", text="Remove BProjection plane")
532 if not em.custom_expand:
533 row.prop(em, "custom_expand", text = "", icon="TRIA_RIGHT", emboss=False)
534 row.label(text= 'Paint Object: '+ ob.name)
536 row.prop(em, "custom_expand", text = "" , icon="TRIA_DOWN", emboss=False)
537 row.label(text= 'Paint Object: '+ ob.name)
539 if ob == bpy.data.objects[em.custom_active_object]:
540 col = box.column(align =True)
541 col.template_ID(tex, "image", open="image.open")
542 row = box.row(align=True)
543 row.operator('object.applyimage', text="Apply image", icon = 'FILE_TICK')
544 row.prop(em, "custom_c3d",text="", icon='CURSOR')
545 row = box.row(align =True)
546 row.label(text="Location:")
547 row = box.row(align =True)
548 row.prop(em,'custom_location', text='')
549 row = box.row(align =True)
550 row.prop(em,'custom_rotation')
551 row.prop(em,'custom_rotc3d',text="",icon='MANIPUL')
552 row = box.row(align =True)
553 row.label(text="Scale:")
554 row = box.row(align =True)
555 if em.custom_linkscale :
556 row.prop(em, "custom_propscale",text="")
557 row.prop(em, "custom_linkscale",text="",icon='LINKED')
559 row.prop(em,'custom_scale',text='')
560 row.prop(em, "custom_linkscale",text="",icon='UNLINKED')
561 row.prop(em,'custom_scac3d',text="",icon='MANIPUL')
562 row = box.row(align =True)
563 row.label(text="UV's Offset:")
564 row = box.row(align =True)
565 row.prop(em,'custom_offsetuv',text='')
566 row.prop(em, "custom_flipuvx",text="",icon='ARROW_LEFTRIGHT')
567 row.prop(em, "custom_flipuvy",text="",icon='FULLSCREEN_ENTER')
568 row = box.row(align =True)
569 row.label(text="UV's Scale:")
570 row = box.row(align =True)
571 if em.custom_linkscaleuv:
572 row.prop(em,'custom_propscaleuv',text='')
573 row.prop(em, "custom_linkscaleuv",text="",icon='LINKED')
575 row.prop(em,'custom_scaleuv',text='')
576 row.prop(em, "custom_linkscaleuv",text="",icon='UNLINKED')
577 row = box.column(align =True)
578 row.prop(ob.material_slots['Material for BProjection'].material,'alpha', slider = True)
579 row = box.column(align =True)
581 if ob == bpy.data.objects[em.custom_active_object]:
582 for item in em.custom_props:
585 if item.custom_active:
586 row.operator("object.active_view",text = "", icon='RADIOBUT_ON', emboss = False).index = item.custom_index
588 row.operator("object.active_view",text = "", icon='RADIOBUT_OFF', emboss = False).index = item.custom_index
589 row.prop(item, "custom_active_view", text="")
590 row.operator('object.remove_view', text="", icon = 'PANEL_CLOSE', emboss = False).index = item.custom_index
592 row.operator('object.create_view', text="Create View", icon = 'RENDER_STILL')
594 col = box.column(align =True)
595 col.operator("object.change_object", text="Change Object")
599 col = layout.column(align = True)
600 col.operator("object.addbprojectionplane", text="Add BProjection plan")
601 col = layout.column(align = True)
602 col.prop(ob, "custom_sub",text="Subdivision level")
605 # Oprerator Class to apply the image to the plane
606 class ApplyImage(Operator):
607 bl_idname = "object.applyimage"
608 bl_label = "Apply image"
610 def execute(self, context):
615 # Oprerator Class to make the 4 or 6 point and scale the plan
616 class IntuitiveScale(Operator):
617 bl_idname = "object.intuitivescale"
618 bl_label = "Draw lines"
620 def invoke(self, context, event):
622 em = bpy.data.objects['Empty for BProjection']
623 x = event.mouse_region_x
624 y = event.mouse_region_y
625 if len(ob.grease_pencil.layers.active.frames) == 0:
626 bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
627 "is_start":True, "location":(0, 0, 0),
628 "mouse":(x,y), "pressure":1, "time":0}])
630 if em.custom_linkscale:
635 if len(ob.grease_pencil.layers.active.frames[0].strokes) < nb_point:
636 bpy.ops.gpencil.draw(mode='DRAW', stroke=[{"name":"", "pen_flip":False,
637 "is_start":True, "location":(0, 0, 0),
638 "mouse":(x,y), "pressure":1, "time":0}])
640 if len(ob.grease_pencil.layers.active.frames[0].strokes) == nb_point:
641 s = ob.grease_pencil.layers.active.frames[0]
642 v1 = s.strokes[1].points[0].co - s.strokes[0].points[0].co
643 if not em.custom_linkscale:
644 v2 = s.strokes[4].points[0].co - s.strokes[3].points[0].co
646 v2 = s.strokes[3].points[0].co - s.strokes[2].points[0].co
648 em.custom_scale[0] *= abs(propx)
650 if not em.custom_linkscale:
651 v1 = s.strokes[2].points[0].co - s.strokes[0].points[0].co
652 v2 = s.strokes[5].points[0].co - s.strokes[3].points[0].co
654 em.custom_scale[1] *= abs(propy)
655 bpy.ops.gpencil.active_frame_delete()
659 # Oprerator Class to configure all wath is needed
660 class AddBProjectionPlane(Operator):
661 bl_idname = "object.addbprojectionplane"
662 bl_label = "Configure"
664 def creatematerial(self, context):
665 if 'Material for BProjection' not in [mat.name for mat in bpy.data.materials]:
666 bpy.data.textures.new(name='Texture for BProjection',type='IMAGE')
668 bpy.data.materials.new(name='Material for BProjection')
670 matBProjection = bpy.data.materials['Material for BProjection']
671 matBProjection.texture_slots.add()
672 matBProjection.use_shadeless = True
673 matBProjection.use_transparency = True
674 matBProjection.active_texture = bpy.data.textures['Texture for BProjection']
676 index = matBProjection.active_texture_index
677 matBProjection.texture_slots[index].texture_coords = 'UV'
680 old_index = ob.active_material_index
681 bpy.ops.object.material_slot_add()
682 index = ob.active_material_index
683 ob.material_slots[index].material = bpy.data.materials['Material for BProjection']
684 bpy.ops.object.material_slot_assign()
685 ob.active_material_index = old_index
688 def execute(self, context):
689 if 'Empty for BProjection' not in [ob.name for ob in bpy.data.objects]:
691 cm = bpy.context.object.mode
692 '''tmp = context.object
693 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):
694 context.scene.objects.active = ob
695 bpy.ops.object.mode_set(mode = cm, toggle=False)
697 context.scene.objects.active = tmp'''
698 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
700 context.space_data.show_relationship_lines = False
706 em.name = "Empty for BProjection"
708 context.scene.objects.active = ob
711 bpy.ops.object.editmode_toggle()
713 bpy.ops.mesh.primitive_plane_add()
714 bpy.ops.object.vertex_group_assign(new = True)
715 ob.vertex_groups.active.name = 'texture plane'
718 bpy.ops.mesh.select_all(action='DESELECT')
719 bpy.ops.object.vertex_group_select()
721 bpy.ops.object.editmode_toggle()
723 ob.data.edges[len(ob.data.edges)-1-i].crease = 1
724 bpy.ops.object.editmode_toggle()
726 em.custom_sub = ob.custom_sub
727 if em.custom_sub > 0:
728 bpy.ops.mesh.subdivide(number_cuts = em.custom_sub)
731 bpy.ops.object.hook_add_selob()
735 self.creatematerial(context)
738 bpy.ops.gpencil.data_add()
739 ob.grease_pencil.draw_mode = 'VIEW'
740 bpy.ops.gpencil.layer_add()
741 ob.grease_pencil.layers.active.color = [1.0,0,0]
743 bpy.ops.object.editmode_toggle()
745 bpy.ops.object.shape_key_add(from_mix = False)
747 bpy.ops.object.create_view()
748 # ----------------------------------------------
749 # XXX, this isnt future proof, DON'T USE INDEX's - campbell
750 km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
751 km.keymap_items[3-1].idname = 'view3d.rotate_view3d'
752 km.keymap_items[19-1].idname = 'view3d.zoom_view3d'
753 km.keymap_items[19-1].properties.delta = 1.0
754 km.keymap_items[20-1].idname = 'view3d.zoom_view3d'
755 km.keymap_items[20-1].properties.delta = -1.0
756 km.keymap_items[4-1].idname = 'view3d.pan_view3d'
757 km.keymap_items[28-1].idname = 'view3d.preset_view3d'
758 km.keymap_items[28-1].properties.view = 'FRONT'
759 km.keymap_items[30-1].idname = 'view3d.preset_view3d'
760 km.keymap_items[30-1].properties.view = 'RIGHT'
761 km.keymap_items[34-1].idname = 'view3d.preset_view3d'
762 km.keymap_items[34-1].properties.view = 'TOP'
763 km.keymap_items[36-1].idname = 'view3d.preset_view3d'
764 km.keymap_items[36-1].properties.view = 'BACK'
765 km.keymap_items[37-1].idname = 'view3d.preset_view3d'
766 km.keymap_items[37-1].properties.view = 'LEFT'
767 km.keymap_items[38-1].idname = 'view3d.preset_view3d'
768 km.keymap_items[38-1].properties.view = 'BOTTOM'
769 km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
770 kmi = km.keymap_items.new("object.intuitivescale", 'LEFTMOUSE', 'PRESS', shift=True)
772 align_to_view(context)
774 context.space_data.cursor_location = em.location
776 bpy.ops.object.mode_set(mode = cm, toggle=False)
777 bpy.data.objects['Empty for BProjection'].custom_active_object = context.object.name
781 # Oprerator Class to remove what is no more needed
782 class RemoveBProjectionPlane(Operator):
783 bl_idname = "object.removebprojectionplane"
784 bl_label = "Configure"
786 def removematerial(self, context):
790 for ms in ob.material_slots:
791 if ms.name == 'Material for BProjection':
795 ob.active_material_index = index
796 bpy.ops.object.material_slot_remove()
798 def execute(self, context):
800 cm = bpy.context.object.mode
801 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
803 context.space_data.show_relationship_lines = True
805 bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
807 self.removematerial(context)
811 bpy.ops.object.editmode_toggle()
813 bpy.ops.mesh.reveal()
815 bpy.ops.mesh.select_all(action='DESELECT')
817 ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
818 bpy.ops.object.vertex_group_select()
819 bpy.ops.mesh.delete()
820 bpy.ops.object.vertex_group_remove()
822 bpy.ops.object.editmode_toggle()
826 em = bpy.data.objects['Empty for BProjection']
827 context.scene.objects.active = em
830 bpy.ops.object.delete()
832 context.scene.objects.active = ob
835 km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
836 # ----------------------------------------------
837 # XXX, this isnt future proof, DON'T USE INDEX's - campbell
838 km.keymap_items[3-1].idname = 'view3d.rotate'
839 km.keymap_items[19-1].idname = 'view3d.zoom'
840 km.keymap_items[19-1].properties.delta = 1.0
841 km.keymap_items[20-1].idname = 'view3d.zoom'
842 km.keymap_items[20-1].properties.delta = -1.0
843 km.keymap_items[4-1].idname = 'view3d.move'
844 km.keymap_items[28-1].idname = 'view3d.viewnumpad'
845 km.keymap_items[28-1].properties.type = 'FRONT'
846 km.keymap_items[30-1].idname = 'view3d.viewnumpad'
847 km.keymap_items[30-1].properties.type = 'RIGHT'
848 km.keymap_items[34-1].idname = 'view3d.viewnumpad'
849 km.keymap_items[34-1].properties.type = 'TOP'
850 km.keymap_items[36-1].idname = 'view3d.viewnumpad'
851 km.keymap_items[36-1].properties.type = 'BACK'
852 km.keymap_items[37-1].idname = 'view3d.viewnumpad'
853 km.keymap_items[37-1].properties.type = 'LEFT'
854 km.keymap_items[38-1].idname = 'view3d.viewnumpad'
855 km.keymap_items[38-1].properties.type = 'BOTTOM'
857 km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
859 for kmi in (kmi for kmi in km.keymap_items if kmi.idname in {"object.intuitivescale", }):
860 km.keymap_items.remove(kmi)
862 '''tmp = context.object
863 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):
864 context.scene.objects.active = ob
865 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
867 context.scene.objects.active = tmp'''
871 for i in ob.data.shape_keys.key_blocks:
872 bpy.ops.object.shape_key_remove()
873 bpy.ops.object.shape_key_remove()
875 bpy.ops.object.mode_set(mode = cm, toggle=False)
883 # Oprerator Class to remove what is no more needed
884 class ChangeObject(Operator):
885 bl_idname = "object.change_object"
886 bl_label = "Change Object"
888 def removematerial(self, context):
892 for ms in ob.material_slots:
893 if ms.name == 'Material for BProjection':
897 ob.active_material_index = index
898 bpy.ops.object.material_slot_remove()
900 def execute(self, context):
901 new_ob = context.object
902 em = bpy.data.objects['Empty for BProjection']
903 context.scene.objects.active = bpy.data.objects[em.custom_active_object]
906 cm = bpy.context.object.mode
907 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
909 bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
913 bpy.ops.object.editmode_toggle()
915 bpy.ops.mesh.reveal()
917 bpy.ops.mesh.select_all(action='DESELECT')
918 ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
919 bpy.ops.object.vertex_group_select()
920 lo_b = [ob for ob in bpy.data.objects if ob.type == 'MESH']
921 bpy.ops.mesh.separate(type='SELECTED')
922 lo_a = [ob for ob in bpy.data.objects if ob.type == 'MESH']
923 bpy.ops.object.vertex_group_remove()
929 bpy.ops.object.editmode_toggle()
931 self.removematerial(context)
933 bpy.ops.object.mode_set(mode = cm, toggle=False)
935 shape_index = ob.active_shape_key_index
937 for i in ob.data.shape_keys.key_blocks:
938 bpy.ops.object.shape_key_remove()
939 bpy.ops.object.shape_key_remove()
944 context.scene.objects.active = bplane
945 for ms in (ms for ms in bplane.material_slots if ms.name != 'Material for BProjection'):
946 bplane.active_material = ms.material
947 bpy.ops.object.material_slot_remove()
949 for gs in (gs for gs in bplane.vertex_groups if gs.name != 'texture plane'):
950 bplane.vertex_groups.active_index = gs.index
951 bpy.ops.object.vertex_group_remove()
953 context.scene.objects.active = new_ob
955 bpy.ops.object.mode_set(mode = 'OBJECT', toggle=False)
956 bpy.ops.object.join()
960 new_ob.select = False
961 bpy.ops.object.location_clear()
962 bpy.ops.object.rotation_clear()
963 bpy.ops.object.scale_clear()
964 context.scene.objects.active = new_ob
965 bpy.ops.object.editmode_toggle()
966 bpy.ops.object.hook_add_selob()
967 bpy.ops.object.editmode_toggle()
971 em.custom_active_object = new_ob.name
973 em.custom_c3d = False
974 bpy.ops.object.active_view(index = shape_index-1)
975 bpy.ops.object.mode_set(mode = cm, toggle=False)
977 sd = context.space_data
979 vr = r3d.view_rotation.copy()
981 ob_loc = ob.location.copy()
982 new_ob_loc = new_ob.location.copy()
984 new_ob_loc.rotate(vr)
985 em.custom_location += Vector((ob_loc.x - new_ob_loc.x, ob_loc.y - new_ob_loc.y, 0.0))
990 # Oprerator Class to rotate the view3D
991 class RotateView3D(Operator):
992 bl_idname = "view3d.rotate_view3d"
993 bl_label = "Rotate the View3D"
995 first_mouse = Vector((0,0))
1004 def vect_sphere(self, context, mx, my):
1005 width = context.area.regions[4].width
1006 height = context.area.regions[4].height
1009 ratio = height/width
1012 y = 2*ratio*my/height
1017 ratio = width/height
1019 x = 2*ratio*mx/width
1025 z2 = 1 - x * x - y * y
1030 p = Vector((x, y, z))
1034 def tracball(self, context, mx, my, origine):
1035 sd = context.space_data
1037 em = bpy.data.objects['Empty for BProjection']
1039 vr_b = sd.region_3d.view_rotation.copy()
1041 pos_init = sd.region_3d.view_location - origine
1042 sd.region_3d.view_location = origine
1044 v1 = self.vect_sphere(context, self.first_mouse.x, self.first_mouse.y)
1045 v2 = self.vect_sphere(context, mx, my)
1047 axis = Vector.cross(v1,v2);
1048 angle = Vector.angle(v1,v2);
1050 q = Quaternion(axis,-2*angle)
1052 sd.region_3d.view_rotation *=q
1053 sd.region_3d.update()
1055 vr_a = sd.region_3d.view_rotation.copy()
1056 pos_init.rotate(vr_a*vr_b)
1057 sd.region_3d.view_location = pos_init + origine
1059 self.first_mouse = Vector((mx, my))
1061 def modal(self, context, event):
1063 em = bpy.data.objects['Empty for BProjection']
1064 reg = context.area.regions[4]
1065 if event.value == 'PRESS':
1066 self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
1068 self.key = [event.type]
1070 if event.value == 'RELEASE':
1073 if event.type == 'MOUSEMOVE':
1076 self.tracball(context, event.mouse_region_x, event.mouse_region_y,ob.location)
1077 align_to_view(context)
1079 rot_ang = context.user_preferences.view.rotation_angle
1080 context.user_preferences.view.rotation_angle = 0
1081 bpy.ops.view3d.view_orbit(type='ORBITLEFT')
1082 context.user_preferences.view.rotation_angle = rot_ang
1083 bpy.ops.view3d.view_persportho()
1084 bpy.ops.view3d.view_persportho()
1085 self.first_time = False
1087 deltax = event.mouse_region_x - round(self.pan.x)
1088 deltay = event.mouse_region_y - round(self.pan.y)
1091 sd = context.space_data
1093 vr = l.view_rotation.copy()
1096 v_init = Vector((0.0,0.0,1.0))
1098 pos = [-deltax,-deltay]
1099 v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1101 vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
1104 em.custom_location += loc
1108 if em.custom_linkscale:
1109 em.custom_propscale += deltax/20
1111 em.custom_scale = [s[0] + deltax/20, s[1] + deltay/20]
1114 em.custom_location.z+=deltax/10
1117 em.custom_rotation+=deltax
1120 suv = em.custom_scaleuv
1121 if em.custom_linkscaleuv:
1122 em.custom_propscaleuv += deltax/50
1124 em.custom_scaleuv= [suv[0] + deltax/50 , suv[1] + deltay/50]
1127 ouv = em.custom_offsetuv
1128 em.custom_offsetuv = [ouv[0] - deltax/50,ouv[1] - deltay/50]
1130 self.pan = Vector((event.mouse_region_x, event.mouse_region_y))
1131 self.first_mouse = Vector((event.mouse_region_x, self.first_mouse.y))
1133 elif event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
1134 if self.tmp_level > -1:
1135 for sub in context.object.modifiers:
1136 if sub.type in ['SUBSURF','MULTIRES']:
1137 sub.levels = self.tmp_level
1142 clear_props(context)
1145 bpy.ops.object.change_object()
1146 return {'RUNNING_MODAL'}
1148 def execute(self, context):
1149 align_to_view(context)
1153 def invoke(self, context, event):
1154 self.first_mouse = Vector((event.mouse_region_x,event.mouse_region_y))
1155 self.first_time = True
1156 for sub in context.object.modifiers:
1157 if sub.type in {'SUBSURF', 'MULTIRES'}:
1158 self.tmp_level = sub.levels
1160 context.window_manager.modal_handler_add(self)
1161 return {'RUNNING_MODAL'}
1163 # Oprerator Class to pan the view3D
1164 class PanView3D(bpy.types.Operator):
1165 bl_idname = "view3d.pan_view3d"
1166 bl_label = "Pan View3D"
1168 first_mouse = Vector((0,0))
1171 def modal(self, context, event):
1173 em = bpy.data.objects['Empty for BProjection']
1174 width = context.area.regions[4].width
1175 height = context.area.regions[4].height
1177 deltax = event.mouse_region_x - self.first_mouse.x
1178 deltay = event.mouse_region_y - self.first_mouse.y
1180 sd = context.space_data
1182 vr = r3d.view_rotation.copy()
1185 v_init = Vector((0.0,0.0,1.0))
1187 pos = [deltax,deltay]
1188 v = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1190 vbl = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1192 sd.region_3d.view_location += loc
1194 em.custom_location += loc
1196 self.first_mouse.x = event.mouse_region_x
1197 self.first_mouse.y = event.mouse_region_y
1199 if event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
1200 if self.tmp_level > -1:
1201 for sub in context.object.modifiers:
1202 if sub.type in ['SUBSURF','MULTIRES']:
1203 sub.levels = self.tmp_level
1206 return {'RUNNING_MODAL'}
1208 def invoke(self, context, event):
1209 self.first_mouse.x = event.mouse_region_x
1210 self.first_mouse.y = event.mouse_region_y
1211 for sub in context.object.modifiers:
1212 if sub.type in {'SUBSURF', 'MULTIRES'}:
1213 self.tmp_level = sub.levels
1215 context.window_manager.modal_handler_add(self)
1216 return {'RUNNING_MODAL'}
1218 def execute(self, context):
1219 align_to_view(context)
1223 # Oprerator Class to zoom the view3D
1224 class ZoomView3D(Operator):
1225 bl_idname = "view3d.zoom_view3d"
1226 bl_label = "Zoom View3D"
1228 delta = FloatProperty(
1230 description="Delta",
1234 def invoke(self, context, event):
1236 em = bpy.data.objects['Empty for BProjection']
1237 sd = context.space_data
1239 width = context.area.regions[4].width
1240 height = context.area.regions[4].height
1243 v_init = Vector((0.0,0.0,1.0))
1245 pos = [width,height]
1246 vtr_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1248 vbl_b = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1249 len_b = vtr_b - vbl_b
1251 bpy.ops.view3d.zoom(delta = self.delta)
1254 pos = [width,height]
1255 vtr_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1257 vbl_a = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
1258 len_a = vtr_a - vbl_a
1260 fac = len_a.length/len_b.length
1261 r3d.view_location -= ob.location
1262 r3d.view_location *= fac
1263 r3d.view_location += ob.location
1264 vres = Vector((em.custom_location.x*fac,em.custom_location.y*fac,em.custom_location.z))
1265 em.custom_location = vres
1268 align_to_view(context)
1272 def execute(self, context):
1273 align_to_view(context)
1277 # Oprerator Class to use numpad shortcut
1278 class PresetView3D(Operator):
1279 bl_idname = "view3d.preset_view3d"
1280 bl_label = "Preset View3D"
1282 view = StringProperty(name="View", description="Select the view", default='TOP')
1283 def invoke(self, context, event):
1285 em = bpy.data.objects['Empty for BProjection']
1286 origine = ob.location
1287 sd = context.space_data
1289 vr_b = sd.region_3d.view_rotation.copy()
1291 pos_init = sd.region_3d.view_location - origine
1292 sd.region_3d.view_location = origine
1294 tmp = context.user_preferences.view.smooth_view
1295 context.user_preferences.view.smooth_view = 0
1296 bpy.ops.view3d.viewnumpad(type=self.view)
1297 align_to_view(context)
1298 context.user_preferences.view.smooth_view = tmp
1300 vr_a = sd.region_3d.view_rotation.copy()
1301 pos_init.rotate(vr_a*vr_b)
1302 sd.region_3d.view_location = pos_init + origine
1307 bpy.utils.register_module(__name__)
1308 createcustomprops(bpy.context)
1311 bpy.utils.unregister_module(__name__)
1313 if __name__ == "__main__":