Skip to content
Snippets Groups Projects
space_view3d_paint_bprojection.py 72.7 KiB
Newer Older
  • Learn to ignore specific revisions
  •                 ob.data.edges[len(ob.data.edges) - 1 - i].crease = 1
    
                bpy.ops.object.editmode_toggle()
    
                em.custom_sub = ob.custom_sub
                if em.custom_sub > 0:
    
                    bpy.ops.mesh.subdivide(number_cuts=em.custom_sub)
    
                em.select_set(True)
    
                bpy.ops.object.hook_add_selob()
    
                em.select_set(False)
    
                self.creatematerial(context)
    
                # fix the grease pencil for 2.78
    
                bpy.ops.gpencil.data_add()
    
                bpy.context.scene.tool_settings.grease_pencil_source = 'OBJECT'
    
                bpy.context.tool_settings.gpencil_stroke_placement_view3d = 'VIEW'
    
                bpy.ops.gpencil.layer_add()
    
                bpy.ops.gpencil.palette_add()
    
                palette = bpy.context.active_gpencil_palette
                palette_color = palette.colors.new()
                palette_color.color = (1.0, 0, 0)
    
                bpy.context.space_data.show_grease_pencil = True
    
                bpy.ops.object.editmode_toggle()
    
                bpy.ops.object.shape_key_add(from_mix=False)
    
                bpy.ops.object.create_view()
    
                km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
    
                l = ['view3d.rotate', 'view3d.move', 'view3d.zoom', 'view3d.viewnumpad', 'paint.bp_paint',
                     'MOUSE', 'KEYBOARD', 'LEFT', 'MIDDLEMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE', 'NUMPAD_1',
                     'NUMPAD_3', 'NUMPAD_7']
    
                for kmi in km.keymap_items:
                    if kmi.idname in l and kmi.map_type in l and kmi.type in l:
                        try:
                            p = kmi.properties.delta
                            if p == -1 or p == 1:
                                kmi.idname = 'view3d.zoom_view3d'
                                kmi.properties.delta = p
                        except:
                            try:
                                p = kmi.properties.type
    
                                    kmi.idname = 'view3d.preset_view3d'
                                    kmi.properties.view = p
                            except:
                                if kmi.idname == 'view3d.rotate':
    
                                if kmi.idname == 'view3d.move':
    
                                    kmi.idname = 'view3d.pan_view3d'
    
                km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
    
                kmi = km.keymap_items.new("object.intuitivescale", 'LEFTMOUSE', 'PRESS', shift=True)
                kmi = km.keymap_items.new("object.bp_grab", 'G', 'PRESS')
    
                kmi = km.keymap_items.new("object.bp_rotate", 'R', 'PRESS')
    
                kmi = km.keymap_items.new("object.bp_scale", 'S', 'PRESS', ctrl=True)
    
                kmi = km.keymap_items.new("object.bp_scaleuv", 'U', 'PRESS')
                kmi = km.keymap_items.new("object.bp_offsetuv", 'Y', 'PRESS')
                kmi = km.keymap_items.new("object.bp_clear_prop", 'C', 'PRESS')
    
                kmi = km.keymap_items.new("object.bp_toggle_alpha", 'Q', 'PRESS')
    
                align_to_view(context)
    
                context.space_data.cursor_location = em.location
    
                bpy.ops.object.mode_set(mode=cm, toggle=False)
    
                bpy.data.objects[BProjection_Empty].custom_active_object = context.object.name
    
    
    # Operator Class to remove what is no more needed
    
    class RemoveBProjectionPlane(Operator):
        bl_idname = "object.removebprojectionplane"
        bl_label = "Configure"
    
        def removematerial(self, context):
    
            i = 0
    
            for ms in ob.material_slots:
                if ms.name == BProjection_Material:
                    index = i
    
            ob.active_material_index = index
            bpy.ops.object.material_slot_remove()
    
        def execute(self, context):
    
                cm = bpy.context.object.mode
    
                bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
                context.space_data.show_relationship_lines = True
    
                bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
    
                self.removematerial(context)
    
                ob = context.object
    
                bpy.ops.object.editmode_toggle()
    
                bpy.ops.mesh.reveal()
    
                ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
                bpy.ops.object.vertex_group_select()
                bpy.ops.mesh.delete()
                bpy.ops.object.vertex_group_remove()
    
                bpy.ops.object.editmode_toggle()
    
                ob.select_set(False)
    
                em = bpy.data.objects[BProjection_Empty]
    
                context.view_layer.objects.active = em
    
                em.select_set(True)
    
                bpy.ops.object.delete()
    
                context.view_layer.objects.active = ob
    
                ob.select_set(True)
    
                for i in ob.data.shape_keys.key_blocks:
                    bpy.ops.object.shape_key_remove()
                bpy.ops.object.shape_key_remove()
    
                bpy.ops.object.mode_set(mode=cm, toggle=False)
    
                removecustomprops()
    
    def reinitkey():
        km = bpy.data.window_managers['WinMan'].keyconfigs['Blender'].keymaps['3D View']
    
        l = ['view3d.zoom_view3d', 'view3d.preset_view3d', 'view3d.rotate_view3d',
             'view3d.pan_view3d', 'MOUSE', 'KEYBOARD', 'MIDDLEMOUSE', 'WHEELINMOUSE',
             'WHEELOUTMOUSE', 'NUMPAD_1', 'NUMPAD_3', 'NUMPAD_7']
    
        for kmi in km.keymap_items:
            if kmi.idname in l and kmi.map_type in l and kmi.type in l:
                try:
                    p = kmi.properties.delta
                    if p == -1 or p == 1:
                        kmi.idname = 'view3d.zoom'
                        kmi.properties.delta = p
                except:
                    try:
                        p = kmi.properties.view
    
                            kmi.idname = 'view3d.viewnumpad'
                            kmi.properties.type = p
                    except:
                        if kmi.idname == 'view3d.rotate_view3d':
    
                        if kmi.idname == 'view3d.pan_view3d':
    
        km = bpy.context.window_manager.keyconfigs.default.keymaps['Image Paint']
    
        for kmi in km.keymap_items:
            if kmi.idname == 'paint.bp_paint':
                kmi.idname = 'paint.image_paint'
    
        for kmi in (kmi for kmi in km.keymap_items if kmi.idname in
                    {"object.intuitivescale", "object.bp_grab", "object.bp_rotate",
                     "object.bp_scale", "object.bp_scaleuv", "object.bp_clear_prop",
                     "object.bp_offsetuv", "object.bp_toggle_alpha", }):
    
                km.keymap_items.remove(kmi)
    
    
    
    # Operator Class to remove what is no more needed
    
    class ChangeObject(Operator):
        bl_idname = "object.change_object"
        bl_label = "Change Object"
    
        def removematerial(self, context):
    
            i = 0
    
            for ms in ob.material_slots:
                if ms.name == BProjection_Material:
                    index = i
    
            ob.active_material_index = index
            bpy.ops.object.material_slot_remove()
    
        def execute(self, context):
                new_ob = context.object
    
                context.view_layer.objects.active = bpy.data.objects[em.custom_active_object]
    
                ob = context.object
                if ob != new_ob:
                    cm = bpy.context.object.mode
    
                    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
    
                    bpy.ops.object.modifier_remove(modifier="Hook-Empty for BProjection")
    
    
                    ob = context.object
    
                    bpy.ops.object.editmode_toggle()
    
                    bpy.ops.mesh.reveal()
    
                    ob.vertex_groups.active_index = ob.vertex_groups['texture plane'].index
                    bpy.ops.object.vertex_group_select()
                    lo_b = [ob for ob in bpy.data.objects if ob.type == 'MESH']
                    bpy.ops.mesh.separate(type='SELECTED')
                    lo_a = [ob for ob in bpy.data.objects if ob.type == 'MESH']
                    bpy.ops.object.vertex_group_remove()
    
                    for i in lo_b:
                        lo_a.remove(i)
                    bplane = lo_a[0]
    
                    bpy.ops.object.editmode_toggle()
    
                    self.removematerial(context)
    
                    bpy.ops.object.mode_set(mode=cm, toggle=False)
    
                    shape_index = ob.active_shape_key_index
    
                    for i in ob.data.shape_keys.key_blocks:
                        bpy.ops.object.shape_key_remove()
                    bpy.ops.object.shape_key_remove()
    
                    ob.select_set(False)
    
                    bplane.select_set(True)
    
                    context.view_layer.objects.active = bplane
    
                    for ms in (ms for ms in bplane.material_slots if ms.name != BProjection_Material):
                        bplane.active_material = ms.material
                        bpy.ops.object.material_slot_remove()
    
                    for gs in (gs for gs in bplane.vertex_groups if gs.name != 'texture plane'):
                        bplane.vertex_groups.active_index = gs.index
                        bpy.ops.object.vertex_group_remove()
    
                    context.view_layer.objects.active = new_ob
    
                    bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
                    bpy.ops.object.join()
    
                    em.select_set(True)
                    new_ob.select_set(False)
    
                    bpy.ops.object.location_clear()
                    bpy.ops.object.rotation_clear()
                    bpy.ops.object.scale_clear()
    
                    context.view_layer.objects.active = new_ob
    
                    bpy.ops.object.hook_add_selob()
                    bpy.ops.object.editmode_toggle()
                    em.hide = True
    
                    em.select_set(False)
                    new_ob.select_set(True)
    
                    em.custom_active_object = new_ob.name
                    tmp = em.custom_c3d
                    em.custom_c3d = False
    
                    bpy.ops.object.active_view(index=shape_index - 1)
                    bpy.ops.object.mode_set(mode=cm, toggle=False)
    
                    sd = context.space_data
    
                    vr = r3d.view_rotation.copy()
                    vr.invert()
    
                    ob_loc = ob.location.copy()
                    new_ob_loc = new_ob.location.copy()
    
                    ob_loc.rotate(vr)
                    new_ob_loc.rotate(vr)
                    em.custom_location += Vector((ob_loc.x - new_ob_loc.x, ob_loc.y - new_ob_loc.y, 0.0))
                    em.custom_c3d = tmp
    
                return {'FINISHED'}
    
    # Paint from the bp_plan
    last_mouse = Vector((0, 0))
    
    
    def move_bp(self, context, cm, fm):
    
        em = bpy.data.objects['Empty for BProjection']
    
        deltax = cm.x - round(fm.x)
        deltay = cm.y - round(fm.y)
    
        vr = l.view_rotation.copy()
        vr.invert()
    
        v_init = Vector((0.0, 0.0, 1.0))
    
        v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
    
        vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
        loc = vbl - v
    
    
        em.custom_location -= loc
    
        self.first_mouse = cm
    
        bl_idname = "paint.bp_paint"
        bl_label = "Paint BProjection Plane"
    
        @classmethod
        def poll(cls, context):
            return 1
    
        def modal(self, context, event):
            global last_mouse
    
            if event.type == 'MOUSEMOVE':  # 'INBETWEEN_MOUSEMOVE':
    
                step_act = Vector((event.mouse_region_x, event.mouse_region_y)) - self.step_prev
    
                if (step_act.length >= context.scene.tool_settings.unified_paint_settings.size *
                   bpy.data.brushes['Clone'].spacing / 100 or bpy.data.brushes['Clone'].use_airbrush):
    
                    move_bp(self, context, Vector((event.mouse_region_x, event.mouse_region_y)) - self.v_offset,
                            self.first_mouse)
    
                    bpy.ops.paint.image_paint(stroke=[{"name": "", "location": (0, 0, 0),
                                                      "mouse": (event.mouse_region_x, event.mouse_region_y),
                                                       "pressure": 1, "pen_flip": False, "time": 0, "is_start": False}])
    
                    self.step_prev = Vector((event.mouse_region_x, event.mouse_region_y))
    
            if event.type == 'LEFTMOUSE':
                em.custom_c3d = True
                bpy.data.materials['Material for BProjection'].alpha = self.alpha
                em.custom_location = self.first_location
                return {'FINISHED'}
    
            if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
                em.custom_c3d = True
                bpy.data.materials['Material for BProjection'].alpha = self.alpha
                em.custom_location = self.first_location
                return {'FINISHED'}
    
            return {'PASS_THROUGH'}
    
            em = bpy.data.objects['Empty for BProjection']
            context.window_manager.modal_handler_add(self)
            self.first_mouse = Vector((event.mouse_region_x, event.mouse_region_y))
    
            l = sd.region_3d
            v_init = Vector((0.0, 0.0, 1.0))
            context.scene.cursor_location = view3d_utils.region_2d_to_location_3d(
                                                        context.region, l,
                                                        [event.mouse_region_x,
                                                         event.mouse_region_y], v_init
                                                        )
    
            self.first_location = em.custom_location.copy()
    
            self.v_offset = Vector((context.region.width, context.region.height)) - Vector((event.mouse_region_x,
                                                                                            event.mouse_region_y))
            move_bp(self, context, Vector((event.mouse_region_x, event.mouse_region_y)) - self.v_offset, self.first_mouse)
    
            em.custom_c3d = False
            self.alpha = bpy.data.materials['Material for BProjection'].alpha
    
            em.custom_location.z = -10
    
            bpy.data.materials['Material for BProjection'].alpha = 0
    
            bpy.ops.paint.image_paint(stroke=[{"name": "", "location": (0, 0, 0),
                                               "mouse": (event.mouse_region_x, event.mouse_region_y),
                                               "pressure": 1, "pen_flip": False,
                                               "time": 0, "size": 1,
                                               "is_start": False}])
    
            self.step_prev = Vector((event.mouse_region_x, event.mouse_region_y))
            return {'RUNNING_MODAL'}
    
    
    # Operator Class toggle the alpha of the plane
    
    class ApplyImage(Operator):
        bl_idname = "object.bp_toggle_alpha"
        bl_label = "Toggle Alpha of the BP"
    
            if temp_alpha != 0:
    
                bpy.data.materials['Material for BProjection'].alpha = temp_alpha
    
                temp_alpha = 0
            else:
                temp_alpha = bpy.data.materials['Material for BProjection'].alpha
    
                bpy.data.materials['Material for BProjection'].alpha = 0
    
    
            return {'FINISHED'}
    
    
    # reinit the values of the bp_plane
    
    class BP_Clear_Props(Operator):
        bl_idname = "object.bp_clear_prop"
        bl_label = "Clear Props BProjection Plane"
    
    
            clear_props(context)
    
            return{'FINISHED'}
    
    
    # Move the UV of the bp_plane
    class BP_OffsetUV(Operator):
    
        bl_idname = "object.bp_offsetuv"
        bl_label = "OffsetUV BProjection Plane"
    
        first_mouse = Vector((0, 0))
        first_offsetuv = Vector((0, 0))
    
        @classmethod
        def poll(cls, context):
            return 1
    
        def modal(self, context, event):
    
            if event.shift:
                fac = 0.1
            else:
                fac = 1
    
            if event.type == 'X' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_y = False
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_y = False
    
            if event.type == 'Y' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_x = False
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_x = True
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
                    self.axe_x = False
    
            deltax = (event.mouse_region_x - self.first_mouse.x) * fac
            deltay = (event.mouse_region_y - self.first_mouse.y) * fac
    
    
            if event.type == 'MOUSEMOVE':
    
    
                    deltay = 0
                if not self.axe_x:
    
                ouv = em.custom_offsetuv
    
                em.custom_offsetuv = [ouv[0] - deltax / 50, ouv[1] - deltay / 50]
    
                self.first_mouse.x = event.mouse_region_x
    
    
            if event.type == 'LEFTMOUSE':
                return {'FINISHED'}
    
            if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
                em.custom_offsetuv = self.first_offsetuv
                return {'FINISHED'}
    
            return {'RUNNING_MODAL'}
    
            em = bpy.data.objects['Empty for BProjection']
            context.window_manager.modal_handler_add(self)
            self.first_mouse.x = event.mouse_region_x
            self.first_mouse.y = event.mouse_region_y
            self.first_offsetuv = em.custom_offsetuv.copy()
    
            return {'RUNNING_MODAL'}
    
    
    
    # Scale the UV of the bp_plane
    class BP_ScaleUV(Operator):
    
        bl_idname = "object.bp_scaleuv"
        bl_label = "ScaleUV BProjection Plane"
    
        first_mouse = Vector((0, 0))
        first_scaleuv = Vector((0, 0))
    
        @classmethod
        def poll(cls, context):
            return 1
    
        def modal(self, context, event):
    
            if event.shift:
                fac = 0.1
            else:
                fac = 1
    
            if event.type == 'X' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_y = False
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_y = False
    
            if event.type == 'Y' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_x = False
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_x = True
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
                    self.axe_x = False
    
            deltax = (event.mouse_region_x - self.first_mouse.x) * fac
            deltay = (event.mouse_region_y - self.first_mouse.y) * fac
    
    
            if event.type == 'MOUSEMOVE':
    
    
                    deltay = 0
                if not self.axe_x:
    
                if self.axe_x and self.axe_y:
    
                    fac = em.custom_scaleuv[1] / em.custom_scaleuv[0]
    
                    deltay = deltax * fac
                else:
    
                s = em.custom_scaleuv
    
                em.custom_scaleuv = [s[0] + deltax / 50, s[1] + deltay / 50]
    
                self.first_mouse.x = event.mouse_region_x
    
    
            if event.type == 'LEFTMOUSE':
                return {'FINISHED'}
    
            if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
                em.custom_scaleuv = self.first_scaleuv
                return {'FINISHED'}
    
            return {'RUNNING_MODAL'}
    
            em = bpy.data.objects['Empty for BProjection']
            context.window_manager.modal_handler_add(self)
            self.first_mouse.x = event.mouse_region_x
            self.first_mouse.y = event.mouse_region_y
            self.first_scaleuv = em.custom_scaleuv.copy()
    
            return {'RUNNING_MODAL'}
    
    
    # Scale the bp_plane
    class BP_Scale(Operator):
    
        bl_idname = "object.bp_scale"
        bl_label = "Scale BProjection Plane"
    
        first_mouse = Vector((0, 0))
        first_scale = Vector((0, 0, 0))
    
        @classmethod
        def poll(cls, context):
            return 1
    
        def modal(self, context, event):
    
            em = bpy.data.objects['Empty for BProjection']
    
            sd = context.space_data
    
    
            center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location)
    
            vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center
    
            scale_fac = vec_act.length / vec_init.length
    
                scale_fac = round(scale_fac, 1)
    
    
            if event.type == 'X' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_y = False
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_y = False
    
            if event.type == 'Y' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_x = False
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_x = True
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
                    self.axe_x = False
    
            if event.type == 'MOUSEMOVE':
    
                    em.custom_scale = [self.first_scale[0] * scale_fac, self.first_scale[1]]
    
                    em.custom_scale = [self.first_scale[0], self.first_scale[1] * scale_fac]
    
                if self.axe_x and self.axe_y:
    
                    em.custom_scale = [self.first_scale[0] * scale_fac, self.first_scale[1] * scale_fac]
    
    
            if event.type == 'LEFTMOUSE':
                return {'FINISHED'}
    
            if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
                em.custom_scale = self.first_scale
                return {'FINISHED'}
    
            return {'RUNNING_MODAL'}
    
            em = bpy.data.objects['Empty for BProjection']
            context.window_manager.modal_handler_add(self)
            self.first_mouse.x = event.mouse_region_x
            self.first_mouse.y = event.mouse_region_y
            self.first_scale = em.custom_scale.copy()
    
            return {'RUNNING_MODAL'}
    
    
    # Rotate the bp_plan
    class BP_Rotate(Operator):
    
        bl_idname = "object.bp_rotate"
        bl_label = "Rotate BProjection Plane"
    
        first_rotation = 0
    
        @classmethod
        def poll(cls, context):
            return 1
    
        def modal(self, context, event):
    
            em = bpy.data.objects['Empty for BProjection']
    
            sd = context.space_data
    
            center = view3d_utils.location_3d_to_region_2d(context.region, sd.region_3d, em.location if
                                                           em.custom_rotc3d else context.scene.cursor_location)
    
            vec_act = Vector((event.mouse_region_x, event.mouse_region_y)) - center
    
            rot = -vec_init.angle_signed(vec_act) * 180 / pi
    
            if event.type == 'MOUSEMOVE':
    
                em.custom_rotation = self.first_rotation + rot
    
    
            if event.type == 'LEFTMOUSE':
                return {'FINISHED'}
    
            if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
                em.custom_rotation = self.first_rotation
                return {'FINISHED'}
    
            return {'RUNNING_MODAL'}
    
            em = bpy.data.objects['Empty for BProjection']
            context.window_manager.modal_handler_add(self)
            self.first_mouse.x = event.mouse_region_x
            self.first_mouse.y = event.mouse_region_y
            self.first_rotation = em.custom_rotation
    
    # grab the bp_plan
    
        bl_idname = "object.bp_grab"
        bl_label = "Grab BProjection Plane"
    
        axe_x = True
        axe_y = True
        axe_z = False
    
        first_mouse = Vector((0, 0))
        first_location = Vector((0, 0, 0))
    
        @classmethod
        def poll(cls, context):
            return 1
    
        def modal(self, context, event):
    
            if event.shift:
                fac = 0.1
            else:
                fac = 1
    
            if event.type == 'X' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_y = False
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_y = False
                    self.axe_x = True
    
                    self.axe_z = False
    
            if event.type == 'Y' and event.value == 'PRESS':
    
                if self.axe_x is True and self.axe_y is True:
    
                    self.axe_x = False
    
                elif self.axe_x is False and self.axe_y is True:
    
                    self.axe_x = True
    
                elif self.axe_x is True and self.axe_y is False:
    
                    self.axe_y = True
                    self.axe_x = False
    
                    self.axe_z = False
                    self.axe_y = True
    
            if event.type == 'Z' and event.value == 'PRESS':
    
                    self.axe_z = True
                    self.axe_x = False
                    self.axe_y = False
    
                    self.axe_z = False
                    self.axe_x = True
                    self.axe_y = True
    
            deltax = event.mouse_region_x - round(self.first_mouse.x)
            deltay = event.mouse_region_y - round(self.first_mouse.y)
    
            if event.type == 'MOUSEMOVE':
    
                vr = l.view_rotation.copy()
                vr.invert()
    
                v_init = Vector((0.0, 0.0, 1.0))
    
                v = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
    
                vbl = view3d_utils.region_2d_to_location_3d(context.region, l, pos, v_init)
                loc = vbl - v
    
    
                    loc.y = loc.z = 0
                if not self.axe_x:
                    loc.x = loc.z = 0
                if self.axe_z:
    
                em.custom_location += loc * fac
    
                self.first_mouse.x = event.mouse_region_x
    
    
            if event.type == 'LEFTMOUSE':
                return {'FINISHED'}
    
            if event.type == 'ESC' or event.type == 'RIGHTMOUSE':
                em.custom_location = self.first_location
                return {'FINISHED'}
    
            return {'RUNNING_MODAL'}
    
            em = bpy.data.objects['Empty for BProjection']
            context.window_manager.modal_handler_add(self)
            self.first_mouse.x = event.mouse_region_x
            self.first_mouse.y = event.mouse_region_y
            self.first_location = em.custom_location.copy()
    
    
    # Operator Class to rotate the view3D
    
    Geo Kgeo's avatar
    Geo Kgeo committed
    class RotateView3D(Operator):
        bl_idname = "view3d.rotate_view3d"
        bl_label = "Rotate the View3D"
    
        first_time = True
        tmp_level = -1
    
        def vect_sphere(self, context, mx, my):
            width = context.region.width
            height = context.region.height
    
            if width >= height:
    
                x = 2 * mx / width
                y = 2 * ratio * my / height
    
                x = x - 1
                y = y - ratio
            else:
    
                x = 2 * ratio * mx / width
                y = 2 * my / height
    
                x = x - ratio
                y = y - 1
    
            z2 = 1 - x * x - y * y
            if z2 > 0:
    
            p = Vector((x, y, z))
            p.normalize()
            return p
    
        def tracball(self, context, mx, my, origine):
            sd = context.space_data
    
            vr_b = sd.region_3d.view_rotation.copy()
            vr_b.invert()
            pos_init = sd.region_3d.view_location - origine
            sd.region_3d.view_location = origine
    
            v1 = self.vect_sphere(context, self.first_mouse.x, self.first_mouse.y)
            v2 = self.vect_sphere(context, mx, my)
    
            axis = Vector.cross(v1, v2)
            angle = Vector.angle(v1, v2)
    
            q = Quaternion(axis, -2 * angle)
    
            sd.region_3d.view_rotation *= q
    
            sd.region_3d.update()
    
            pos_init.rotate(vr_a * vr_b)
            sd.region_3d.view_location = pos_init + origine
    
            self.first_mouse = Vector((mx, my))
    
    
        def turnable(self, context, mx, my, origine):
            sd = context.space_data
    
            width = context.region.width
            height = context.region.height
    
            vr_b = sd.region_3d.view_rotation.copy()
            vr_b.invert()
            pos_init = sd.region_3d.view_location - origine
            sd.region_3d.view_location = origine
    
            vz = Vector((0, 0, 1))
            qz = Quaternion(vz, -8 * (mx - self.first_mouse.x) / width)
    
            sd.region_3d.view_rotation.rotate(qz)
            sd.region_3d.update()
    
    
            qx = Quaternion(vx, 8 * (my - self.first_mouse.y) / height)
    
            pos_init.rotate(vr_a * vr_b)
            sd.region_3d.view_location = pos_init + origine
    
            ob = context.object
    
            if event.value == 'RELEASE':
                if self.tmp_level > -1:
                    for sub in context.object.modifiers:
    
                        if sub.type in ['SUBSURF', 'MULTIRES']:
    
                return {'FINISHED'}
    
                if context.preferences.inputs.view_rotate_method == 'TRACKBALL':
    
                    self.tracball(context, event.mouse_region_x, event.mouse_region_y, ob.location)
    
                    self.turnable(context, event.mouse_region_x, event.mouse_region_y, ob.location)
    
                align_to_view(context)
    
                    rot_ang = context.preferences.view.rotation_angle
                    context.preferences.view.rotation_angle = 0
    
                    bpy.ops.view3d.view_orbit(type='ORBITLEFT')
    
                    context.preferences.view.rotation_angle = rot_ang
    
                    bpy.ops.view3d.view_persportho()
                    self.first_time = False
    
    Geo Kgeo's avatar
    Geo Kgeo committed
            return {'RUNNING_MODAL'}
    
            return{'FINISHED'}
    
    Geo Kgeo's avatar
    Geo Kgeo committed
    
        def invoke(self, context, event):
    
            bpy.data.objects['Empty for BProjection']
    
            context.window_manager.modal_handler_add(self)
    
            self.first_mouse = Vector((event.mouse_region_x, event.mouse_region_y))
    
            self.first_time = True
            for sub in context.object.modifiers:
                if sub.type in ['SUBSURF', 'MULTIRES']:
                    self.tmp_level = sub.levels
    
                    if sub.levels - self.tmp_level < 0:
    
                        sub.levels = 0
                    else:
                        sub.levels += bpy.context.object.custom_fnlevel
            return {'RUNNING_MODAL'}
    
    
    
    # Operator Class to pan the view3D
    class PanView3D(Operator):
    
        bl_idname = "view3d.pan_view3d"
        bl_label = "Pan View3D"
    
        tmp_level = -1
    
        def modal(self, context, event):
            em = bpy.data.objects[BProjection_Empty]
            deltax = event.mouse_region_x - self.first_mouse.x
    
            deltay = event.mouse_region_y - self.first_mouse.y
    
            sd = context.space_data
    
            vr = r3d.view_rotation.copy()
            vr.invert()
    
            v_init = Vector((0.0, 0.0, 1.0))
    
            v = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
    
            vbl = view3d_utils.region_2d_to_location_3d(context.region, r3d, pos, v_init)
            loc = vbl - v
            sd.region_3d.view_location += loc
    
            if not em.custom_style_clone:
                em.custom_location += loc
    
    Geo Kgeo's avatar
    Geo Kgeo committed
    
    
            self.first_mouse.x = event.mouse_region_x
            self.first_mouse.y = event.mouse_region_y
    
            if event.type == 'MIDDLEMOUSE'and event.value == 'RELEASE':
                if self.tmp_level > -1:
                    for sub in context.object.modifiers:
    
                        if sub.type in ['SUBSURF', 'MULTIRES']: