Skip to content
Snippets Groups Projects
space_view3d_paint_bprojection.py 72.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Geo Kgeo's avatar
    Geo Kgeo committed
    bl_info = {
    
        "name": "BProjection",
    
    Geo Kgeo's avatar
    Geo Kgeo committed
        "description": "Help Clone tool",
        "author": "kgeogeo",
    
        "version": (2, 0, 1),
        "blender": (2, 77, 3),
    
        "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/3D_interaction/bprojection",
    
        "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
    
    Geo Kgeo's avatar
    Geo Kgeo committed
        "category": "Paint"}
    
    import bpy
    
    from bpy.app.handlers import persistent
    
    from bpy.types import (
                Panel,
                Operator,
                PropertyGroup,
                AddonPreferences,
                )
    from bpy.props import (
                IntProperty,
                FloatProperty,
                BoolProperty,
                StringProperty,
                FloatVectorProperty,
                CollectionProperty,
               )
    
    Geo Kgeo's avatar
    Geo Kgeo committed
    from bpy_extras import view3d_utils
    
    
    from math import (
                radians,
                sqrt,
                pi,
                )
    
    from mathutils import (
                Quaternion,
                Vector,
                )
    
    BProjection_Empty = 'Empty for BProjection'
    
    BProjection_Material = 'Material for BProjection'
    
    BProjection_Texture = 'Texture for BProjection'
    
    
    
    # Main function for align the plan to view
    def align_to_view(context):
    
        global last_mouse
    
        ob = context.object
    
        rotation = em.custom_rotation
        scale = em.custom_scale
        z = em.custom_location.z
        pos = [em.custom_location.x, em.custom_location.y]
    
        r3d.update()
        vr = r3d.view_rotation
    
        quat = Quaternion((0.0, 0.0, 1.0), radians(float(rotation)))
        v = Vector((pos[0], pos[1], z))
    
        v.rotate(vr)
    
        em = bpy.data.objects[BProjection_Empty]
        img = bpy.data.textures[BProjection_Texture].image
    
        if img and img.size[1] != 0:
    
            prop = img.size[0] / img.size[1]
        else:
            prop = 1
    
            em.scale = Vector((prop * scale[0], scale[0], 1))
    
            em.scale = Vector((prop * scale[0], scale[1], 1))
    
        pos_cur = em.location - sd.cursor_location
        rot_cur1 = em.rotation_euler.to_quaternion()
        em.location = v + ob.location
    
        em.rotation_euler = Quaternion.to_euler(vr * quat)
    
        if em.custom_c3d:
            if em.custom_old_scale != em.custom_scale:
    
                pos_cur = em.location - sd.cursor_location
    
            rot_cur2 = em.rotation_euler.to_quaternion()
            rot_cur1.invert()
            pos_cur.rotate(rot_cur1)
            pos_cur.rotate(rot_cur2)
            v = em.location - pos_cur
    
        img = bpy.data.textures[BProjection_Texture].image
        ob = context.object
    
        face = ob.data.polygons
        uvdata = ob.data.uv_textures.active.data
    
        for f, d in zip(face, uvdata):
            if f.select:
                d.image = img
    
        align_to_view(context)
        ob.data.update()
    
    
    # Function to update the properties
    
        align_to_view(context)
    
    
    def find_uv(context):
        obj = context.object
        me = obj.data.vertices
        vg = obj.vertex_groups
    
        for face in obj.data.polygons:
    
            for vertex in face.vertices:
    
                if (len(me[vertex]. groups) > 0):
    
                    for g in me[vertex].groups:
                        if vg[g.group].name == 'texture plane':
    
                l.append([index_uv, len(face. vertices)])
    
            index_uv += len(face.vertices)
        return l
    
    
    # Function to update the scaleUV
    def update_UVScale(self, context):
        ob = context.object
        em = bpy.data.objects[BProjection_Empty]
    
        v = Vector((em.custom_offsetuv[0] / 10 + 0.5, em.custom_offsetuv[1] / 10 + 0.5))
        l = Vector((0.0, 0.0))
    
        s = em.custom_scaleuv
    
        l = find_uv(context)
    
            for t in range(j):
    
                d = ob.data.uv_layers.active.data[i + t]
                vres = v - d.uv
                d.uv.x = v.x - vres.x / os[0] * s[0]
                d.uv.y = v.y - vres.y / os[1] * s[1]
    
    def update_PropUVScale(self, context):
        em = bpy.data.objects[BProjection_Empty]
        if em.custom_linkscaleuv:
    
            em.custom_scaleuv = [em.custom_propscaleuv, em.custom_propscaleuv]
    
    
    
    def update_LinkUVScale(self, context):
        em = bpy.data.objects[BProjection_Empty]
        if em.custom_linkscaleuv:
            em.custom_propscaleuv = em.custom_scaleuv.x
            update_PropUVScale(self, context)
        else:
    
    # Function to update the offsetUV
    def update_UVOffset(self, context):
        ob = context.object
        em = bpy.data.objects[BProjection_Empty]
        o = em.custom_offsetuv
    
        l = find_uv(context)
    
            for t in range(j):
    
                d = ob.data.uv_layers.active.data[i + t]
                d.uv = [d.uv[0] - oo[0] / 10 + o[0] / 10, d.uv[1] - oo[1] / 10 + o[1] / 10]
    
        em.custom_old_offsetuv = o
    
    # Function to update the flip horizontal
    def update_FlipUVX(self, context):
        l = find_uv(context)
    
            for t in range(j):
    
                d = context.object.data.uv_layers.active.data[i + t]
    
                x = d.uv.x
                d.uv.x = 1 - x
    
    # Function to update the flip vertical
    def update_FlipUVY(self, context):
        l = find_uv(context)
    
            for t in range(j):
    
                d = context.object.data.uv_layers.active.data[i + t]
    
                y = d.uv[1]
                d.uv[1] = 1 - y
    
    # Function to update
    
        ob = context.object
        em = bpy.data.objects[BProjection_Empty]
        if em.custom_rotc3d:
            angle = em.custom_rotation - em.custom_old_rotation
            sd = context.space_data
    
            c = sd.cursor_location - ob.location
            e = bpy.data.objects[BProjection_Empty].location - ob.location
            vo = Vector((0.0, 0.0, 1.0))
            vo.rotate(vr)
    
            quat = Quaternion(vo, radians(angle))
            v = e - c
    
            v.rotate(quat)
            vr.invert()
            v.rotate(vr)
            c.rotate(vr)
            em.custom_location = c + v
    
            align_to_view(context)
    
        em.custom_old_rotation = em.custom_rotation
    
    
    # Function to update scale
    
        ob = context.object
        em = bpy.data.objects[BProjection_Empty]
    
        if em.custom_scac3d:
            sd = context.space_data
    
            vr = r3d.view_rotation.copy()
            vr.invert()
            e = em.location - ob.location
            c = sd.cursor_location - ob.location
            ce = e - c
    
            s = em.custom_scale
            os = em.custom_old_scale
            c.rotate(vr)
            ce.rotate(vr)
    
            v = Vector((s.x * ce.x / os.x, s.y * ce.y / os.y, 0.0))
    
            em.custom_location = c + v
    
    
            align_to_view(context)
    
        em.custom_old_scale = em.custom_scale
    
    
    def update_PropScale(self, context):
        em = bpy.data.objects[BProjection_Empty]
        if em.custom_linkscale:
    
            em.custom_scale = [em.custom_propscale, em.custom_propscale]
    
    
    def update_LinkScale(self, context):
        em = bpy.data.objects[BProjection_Empty]
        if em.custom_linkscale:
            em.custom_propscale = em.custom_scale.x
            update_PropScale(self, context)
        else:
    
    def update_activeviewname(self, context):
        em = bpy.data.objects[BProjection_Empty]
        if self.custom_active:
            em.custom_active_view = self.custom_active_view
    
    
        km = context.window_manager.keyconfigs.default.keymaps['Image Paint']
        for kmi in km.keymap_items:
    
                if kmi.idname == 'paint.image_paint':
                    kmi.idname = 'paint.bp_paint'
            else:
                if kmi.idname == 'paint.bp_paint':
    
    class custom_props(PropertyGroup):
    
        custom_fnlevel: IntProperty(
    
                            name="Fast navigate level",
                            description="Increase or decrease the SubSurf level, decrease make navigation faster",
                            default=0,
                            )
    
        custom_location: FloatVectorProperty(
    
                            name="Location",
                            description="Location of the plane",
                            default=(1.0, 0, -1.0),
                            subtype='XYZ',
                            soft_min=-10,
                            soft_max=10,
                            step=0.1,
                            size=3,
                            )
    
        custom_rotation: FloatProperty(
    
                            name="Rotation",
                            description="Rotate the plane",
                            min=-180, max=180,
                            default=0
                            )
    
        custom_scale: FloatVectorProperty(
    
                            name="Scales",
                            description="Scale the planes",
                            default=(1.0, 1.0),
                            subtype='XYZ',
                            min=0.1,
                            max=10,
                            soft_min=0.1,
                            soft_max=10,
                            step=0.1,
                            size=2,
                            )
    
        custom_propscale: FloatProperty(
    
                            name="PropScale",
                            description="Scale the Plane",
                            default=1.0,
                            min=0.1,
                            max=10,
                            soft_min=0.1,
                            soft_max=10,
                            step=0.1
                            )
    
    
        custom_linkscale: BoolProperty(
    
        custom_scaleuv: FloatVectorProperty(
    
                            name="ScaleUV",
                            description="Scale the texture's UV",
                            default=(1.0, 1.0),
                            min=0.01,
                            subtype='XYZ',
                            size=2
                            )
    
        custom_propscaleuv: FloatProperty(
    
                            name="PropScaleUV",
                            description="Scale the texture's UV",
                            default=1.0,
                            min=0.01
                            )
    
        custom_offsetuv: FloatVectorProperty(
    
                            name="OffsetUV",
                            description="Decal the texture's UV",
                            default=(0.0, 0.0),
                            subtype='XYZ',
                            size=2
                            )
    
        custom_linkscaleuv: BoolProperty(
    
        custom_flipuvx: BoolProperty(
    
        custom_flipuvy: BoolProperty(
    
        # other properties
    
        custom_active: BoolProperty(
    
        custom_expand: BoolProperty(
    
        custom_style_clone: BoolProperty(
    
                            name="custom_style_clone",
                            default=False
                            )
    
        custom_active_view: StringProperty(
    
                            name="custom_active_view",
                            default="View",
                            update=update_activeviewname
                            )
    
        custom_image: StringProperty(
    
        custom_index: IntProperty()
    
    # Function to create custom properties
    def createcustomprops(context):
        Ob = bpy.types.Object
    
        Ob.custom_fnlevel = IntProperty(
                            name="Fast navigate level",
                            description="Increase or decrease the SubSurf level, decrease make navigation faster",
                            default=0
                            )
    
        Ob.custom_location = FloatVectorProperty(
                            name="Location",
                            description="Location of the plane",
                            default=(1.0, 0, -1.0),
                            subtype='XYZ',
                            size=3,
                            step=0.5,
                            soft_min=-10,
                            soft_max=10,
                            update=update_Location
                            )
        Ob.custom_rotation = FloatProperty(
                            name="Rotation",
                            description="Rotate the plane",
                            min=-180,
                            max=180,
                            default=0,
                            update=update_Rotation
                            )
        Ob.custom_old_rotation = FloatProperty(
                            name="old_Rotation",
                            description="Old Rotate the plane",
                            min=-180,
                            max=180,
                            default=0
                            )
        Ob.custom_scale = FloatVectorProperty(
                            name="Scales",
                            description="Scale the planes",
                            subtype='XYZ',
                            default=(1.0, 1.0),
                            min=0.1,
                            max=10,
                            soft_min=0.1,
                            soft_max=10,
                            size=2,
                            step=0.5,
                            update=update_Scale
                            )
        Ob.custom_propscale = FloatProperty(
                            name="PropScale",
                            description="Scale the Plane",
                            default=1.0,
                            min=0.1,
                            soft_min=0.1,
                            soft_max=10,
                            step=0.5,
                            update=update_PropScale
                            )
        Ob.custom_old_scale = FloatVectorProperty(
                            name="old_Scales",
                            description="Old Scale the planes",
                            subtype='XYZ',
                            default=(1.0, 1.0),
                            min=0.1,
                            size=2
                            )
        Ob.custom_linkscale = BoolProperty(
                            name="linkscale",
                            default=True,
                            update=update_LinkScale
                            )
        Ob.custom_sub = IntProperty(
                            name="Subdivide",
                            description="Number of subdivision of the plane",
                            min=0,
                            max=20,
                            default=0
                            )
    
        Ob.custom_scaleuv = FloatVectorProperty(
                            name="ScaleUV",
                            description="Scale the texture's UV",
                            default=(1.0, 1.0),
                            soft_min=0.01,
                            soft_max=100,
                            min=0.01,
                            subtype='XYZ',
                            size=2,
                            update=update_UVScale
                            )
        Ob.custom_propscaleuv = FloatProperty(
                            name="PropScaleUV",
                            description="Scale the texture's UV",
                            default=1.0,
                            soft_min=0.01,
                            soft_max=100,
                            min=0.01,
                            update=update_PropUVScale
                            )
        Ob.custom_old_scaleuv = FloatVectorProperty(
                            name="old_ScaleUV",
                            description="Scale the texture's UV",
                            default=(1.0, 1.0),
                            min=0.01,
                            subtype='XYZ',
                            size=2
                            )
        Ob.custom_offsetuv = FloatVectorProperty(
                            name="OffsetUV",
                            description="Decal the texture's UV",
                            default=(0.0, 0.0),
                            subtype='XYZ',
                            size=2,
                            update=update_UVOffset
                            )
        Ob.custom_old_offsetuv = FloatVectorProperty(
                            name="old_OffsetUV",
                            description="Decal the texture's UV",
                            default=(0.0, 0.0),
                            subtype='XYZ',
                            size=2
                            )
        Ob.custom_linkscaleuv = BoolProperty(
                            name="linkscaleUV",
                            default=True,
                            update=update_LinkUVScale
                            )
        Ob.custom_flipuvx = BoolProperty(
                            name="flipuvx",
                            default=False,
                            update=update_FlipUVX
                            )
        Ob.custom_flipuvy = BoolProperty(
                            name="flipuvy",
                            default=False,
                            update=update_FlipUVY
                            )
    
        Ob.custom_c3d = BoolProperty(
                            name="c3d",
                            default=True
                            )
        Ob.custom_rotc3d = BoolProperty(
                            name="rotc3d",
                            default=False
                            )
        Ob.custom_scac3d = BoolProperty(
                            name="scac3d",
                            default=False
                            )
        Ob.custom_expand = BoolProperty(
                            name="expand",
                            default=True
                            )
        Ob.custom_style_clone = BoolProperty(
                            name="custom_style_clone",
                            default=False,
                            update=update_style_clone
                            )
        Ob.custom_active_view = StringProperty(
                            name="custom_active_view",
                            default="View"
                            )
    
            Ob.custom_active_object = StringProperty(
                            name="custom_active_object",
                            default=context.object.name
                            )
    
            Ob.custom_active_object = StringProperty(
                            name="custom_active_object",
                            default='debut'
                            )
        Ob.custom_props = CollectionProperty(type=custom_props)
    
    
    
    # Function to remove custom properties
    
        list_prop = ['custom_location', 'custom_rotation',
                     'custom_old_rotation', 'custom_scale',
                     'custom_old_scale', 'custom_c3d',
                     'custom_rotc3d', 'custom_scaleuv',
                     'custom_flipuvx', 'custom_flipuvy',
                     'custom_linkscale', 'custom_linkscaleuv',
                     'custom_old_scaleuv', 'custom_offsetuv',
                     'custom_old_offsetuv', 'custom_scac3d',
                     'custom_sub', 'custom_expand',
                     'custom_style_clone', 'custom_active_view',
                     'custom_propscaleuv', 'custom_props', 'custom_propscale']
    
        for prop in list_prop:
            try:
                del bpy.data.objects[BProjection_Empty][prop]
            except:
                pass
    
    def clear_props(context):
    
        em.custom_rotation = 0
    
        em.custom_scaleuv = [1.0, 1.0]
        em.custom_offsetuv = [0.0, 0.0]
    
        em.custom_propscaleuv = 1.0
        em.custom_propscale = 1.0
    
            em.custom_flipuvx = False
    
            em.custom_flipuvy = False
    
    
    class CreateView(Operator):
        bl_idname = "object.create_view"
        bl_label = "Create a new view"
    
    
            ob = context.object
            em = bpy.data.objects[BProjection_Empty]
    
            new_props = em.custom_props.add()
            em.custom_active_view = new_props.custom_active_view
    
            ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = True
    
            bpy.ops.object.shape_key_add(from_mix=False)
    
            ob.data.shape_keys.key_blocks[ob.active_shape_key_index].value = 1.0
    
            new_props.custom_index = len(em.custom_props) - 1
            bpy.ops.object.active_view(index=new_props.custom_index)
    
    
    class SaveView(Operator):
        bl_idname = "object.save_view"
        bl_label = "copy the view"
    
        index: IntProperty(default=0)
    
            em = bpy.data.objects[BProjection_Empty]
    
            prop.custom_rotation = em.custom_rotation
            prop.custom_scale = em.custom_scale
            prop.custom_linkscale = em.custom_linkscale
    
            prop.custom_scaleuv = em.custom_scaleuv
            prop.custom_propscale = em.custom_propscale
    
            prop.custom_offsetuv = em.custom_offsetuv
    
            prop.custom_linkscaleuv = em.custom_linkscaleuv
            prop.custom_propscaleuv = em.custom_propscaleuv
            prop.custom_flipuvx = em.custom_flipuvx
            prop.custom_flipuvy = em.custom_flipuvy
            try:
                prop.custom_image = bpy.data.textures[BProjection_Texture].image.name
            except:
                pass
    
    class PasteView(Operator):
        bl_idname = "object.paste_view"
        bl_label = "paste the view"
    
        index: IntProperty(default=0)
    
            em = bpy.data.objects[BProjection_Empty]
            tmp_scac3d = em.custom_scac3d
            tmp_rotc3d = em.custom_rotc3d
            em.custom_scac3d = False
            em.custom_rotc3d = False
            prop = em.custom_props[self.index]
    
            em.custom_linkscale = prop.custom_linkscale
            em.custom_offsetuv = prop.custom_offsetuv
    
            em.custom_linkscaleuv = prop.custom_linkscaleuv
            em.custom_scaleuv = prop.custom_scaleuv
    
            em.custom_propscaleuv = prop.custom_propscaleuv
    
            em.custom_rotation = prop.custom_rotation
            em.custom_scale = prop.custom_scale
    
            em.custom_propscale = prop.custom_propscale
    
            if prop.custom_image != '':
                if bpy.data.textures[BProjection_Texture].image.name != prop.custom_image:
                    bpy.data.textures[BProjection_Texture].image = bpy.data.images[prop.custom_image]
                    applyimage(context)
            if em.custom_flipuvx != prop.custom_flipuvx:
                em.custom_flipuvx = prop.custom_flipuvx
            if em.custom_flipuvy != prop.custom_flipuvy:
                em.custom_flipuvy = prop.custom_flipuvy
            em.custom_scac3d = tmp_scac3d
    
    class RemoveView(Operator):
        bl_idname = "object.remove_view"
        bl_label = "Rmeove the view"
    
        index: IntProperty(default=0)
    
            ob = context.object
            em = bpy.data.objects[BProjection_Empty]
    
            ob.active_shape_key_index = self.index + 1
    
            bpy.ops.object.shape_key_remove()
    
            if em.custom_props[self.index].custom_active:
    
                if len(em.custom_props) > 0:
    
                    bpy.ops.object.active_view(index=self.index - 1)
    
                if self.index == 0 and len(em.custom_props) > 1:
    
                    bpy.ops.object.active_view(index=1)
    
            em.custom_props.remove(self.index)
    
            if len(em.custom_props) == 0:
                clear_props(context)
    
            for item in em.custom_props:
    
    
            for item in (item for item in em.custom_props if item.custom_active):
    
                    ob.active_shape_key_index = item.custom_index + 1
    
    class ActiveView(Operator):
        bl_idname = "object.active_view"
        bl_label = "Active the view"
    
        index: IntProperty(default=0)
    
        def execute(self, context):
            ob = context.object
            em = bpy.data.objects[BProjection_Empty]
    
            for item in (item for item in em.custom_props if item.custom_active is True):
                bpy.ops.object.save_view(index=item.custom_index)
    
                item.custom_active = False
    
            em.custom_props[self.index].custom_active = True
    
            em.custom_active_view = em.custom_props[self.index].custom_active_view
    
            ob.active_shape_key_index = self.index + 1
    
            for i in ob.data.shape_keys.key_blocks:
                i.mute = True
    
            ob.data.shape_keys.key_blocks[ob.active_shape_key_index].mute = False
    
            bpy.ops.object.paste_view(index=self.index)
    
    # Draw Class to show the panel
    class BProjection(Panel):
        bl_space_type = 'VIEW_3D'
        bl_region_type = 'UI'
        bl_label = "BProjection"
    
        @classmethod
        def poll(cls, context):
            return (context.image_paint_object or context.sculpt_object)
    
        def draw(self, context):
    
            if BProjection_Empty in [ob.name for ob in bpy.data.objects]:
    
                tex = bpy.data.textures[BProjection_Texture]
    
                ob = context.object
                em = bpy.data.objects[BProjection_Empty]
    
                if ob == bpy.data.objects[em.custom_active_object]:
    
                    col = layout.column(align=True)
    
                    col.operator("object.removebprojectionplane", text="Remove BProjection plane")
    
    
                try:
                    matBProjection = bpy.data.materials[BProjection_Material]
                except:
                    matBProjection = None
    
                box = layout.box()
    
                row = box.row()
                if not em.custom_expand:
    
                    row.prop(em, "custom_expand", text="", icon="TRIA_RIGHT", emboss=False)
                    row.label(text='Paint Object: ' + ob.name)
    
                    row.prop(em, "custom_expand", text="", icon="TRIA_DOWN", emboss=False)
                    row.label(text='Paint Object: ' + ob.name)
    
                    if ob == bpy.data.objects[em.custom_active_object]:
    
                        col.template_ID(tex, "image", open="image.open")
    
                        row = box.row(align=True)
                        row.operator('object.applyimage', text="Apply image", icon='FILE_TICK')
    
                        row.prop(em, "custom_c3d", text="", icon='PIVOT_CURSOR')
    
                        row.label(text="Location:")
    
                        row = box.row(align=True)
                        row.prop(em, 'custom_location', text='')
                        row = box.row(align=True)
                        row.prop(em, 'custom_rotation')
                        row.prop(em, 'custom_rotc3d', text="", icon='MANIPUL')
                        row = box.row(align=True)
    
                        row.label(text="Scale:")
    
                        row = box.row(align=True)
                        if em.custom_linkscale:
                            row.prop(em, "custom_propscale", text="")
                            row.prop(em, "custom_linkscale", text="", icon='LINKED')
    
                            row.prop(em, 'custom_scale', text='')
                            row.prop(em, "custom_linkscale", text="", icon='UNLINKED')
                        row.prop(em, 'custom_scac3d', text="", icon='MANIPUL')
                        row = box.row(align=True)
    
                        row.label(text="UV's Offset:")
    
                        row = box.row(align=True)
                        row.prop(em, 'custom_offsetuv', text='')
                        row.prop(em, "custom_flipuvx", text="", icon='ARROW_LEFTRIGHT')
                        row.prop(em, "custom_flipuvy", text="", icon='FULLSCREEN_ENTER')
                        row = box.row(align=True)
    
                        row.label(text="UV's Scale:")
    
                        if em.custom_linkscaleuv:
    
                            row.prop(em, 'custom_propscaleuv', text='')
                            row.prop(em, "custom_linkscaleuv", text="", icon='LINKED')
    
                            row.prop(em, 'custom_scaleuv', text='')
                            row.prop(em, "custom_linkscaleuv", text="", icon='UNLINKED')
    
                        if matBProjection:
    
                            if (context.scene.game_settings.material_mode == 'GLSL' and
                               context.space_data.viewport_shade == 'TEXTURED'):
                                row = box.column(align=True)
                                row.prop(matBProjection, 'alpha', slider=True)
    
                        row = box.column(align=True)
                        row.prop(ob, "custom_fnlevel")
                        row = box.column(align=True)
    
                        if not em.custom_style_clone:
    
                            row.prop(em, "custom_style_clone", text="Style Clone Normal", icon='RENDERLAYERS')
    
                            row.prop(em, "custom_style_clone", text="Style Clone New", icon='RENDERLAYERS')
                        row = box.column(align=True)
    
    
                    if ob == bpy.data.objects[em.custom_active_object]:
    
                        for item in em.custom_props:
                            box = layout.box()
                            row = box.row()
                            if item.custom_active:
    
                                row.operator("object.active_view", text="",
                                             icon='RADIOBUT_ON', emboss=False).index = item.custom_index
    
                                row.operator("object.active_view", text="",
                                             icon='RADIOBUT_OFF', emboss=False).index = item.custom_index
    
                            row.prop(item, "custom_active_view", text="")
    
                            row.operator('object.remove_view', text="",
                                         icon='PANEL_CLOSE', emboss=False).index = item.custom_index
    
                        row = layout.row()
    
                        row.operator('object.create_view', text="Create View", icon='RENDER_STILL')
    
                        col.operator("object.change_object", text="Change Object")
    
    
            else:
                ob = context.object
    
                col = layout.column(align=True)
    
                if ob.active_material is None:
                    col.label(text="Add a material first!", icon="ERROR")
                elif ob.data.uv_textures.active is None:
                    col.label(text="Create UVMap first!!", icon="ERROR")
                else:
                    col.operator("object.addbprojectionplane", text="Add BProjection plane")
    
                    col = layout.column(align=True)
                    col.prop(ob, "custom_sub", text="Subdivision level")
    
    # Operator Class to apply the image to the plane
    class ApplyImageOB(Operator):
    
        bl_idname = "object.applyimage"
        bl_label = "Apply image"
    
    
            applyimage(context)
    
    
    # Operator Class to make the 4 or 6 point and scale the plan
    
    class IntuitiveScale(Operator):
        bl_idname = "object.intuitivescale"
        bl_label = "Draw lines"
    
        def invoke(self, context, event):
            ob = context.object
            em = bpy.data.objects[BProjection_Empty]
            x = event.mouse_region_x
    
            draw_stroke = {"name": "", "pen_flip": False,
                           "is_start": True, "location": (0, 0, 0),
                           "mouse": (x, y), "pressure": 1,
                           "size": 0.5, "time": 0}
    
    
            if len(ob.grease_pencil.layers.active.frames) == 0:
    
                bpy.ops.gpencil.draw(mode='DRAW', stroke=[draw_stroke])
    
            else:
                if em.custom_linkscale:
                    nb_point = 4
                else:
                    nb_point = 6
    
                if len(ob.grease_pencil.layers.active.frames[0].strokes) < nb_point:
    
                    bpy.ops.gpencil.draw(mode='DRAW', stroke=[draw_stroke])
    
                if len(ob.grease_pencil.layers.active.frames[0].strokes) == nb_point:
                    s = ob.grease_pencil.layers.active.frames[0]
                    v1 = s.strokes[1].points[0].co - s.strokes[0].points[0].co
                    if not em.custom_linkscale:
                        v2 = s.strokes[4].points[0].co - s.strokes[3].points[0].co
                    else:
                        v2 = s.strokes[3].points[0].co - s.strokes[2].points[0].co
    
                    if (v1.x and v2.x) != 0:
                        propx = v1.x / v2.x
                        em.custom_scale[0] *= abs(propx)
    
                    if not em.custom_linkscale:
                        v1 = s.strokes[2].points[0].co - s.strokes[0].points[0].co
                        v2 = s.strokes[5].points[0].co - s.strokes[3].points[0].co
    
                        if (v1.y and v2.y) != 0:
                            propy = v1.y / v2.y
                            em.custom_scale[1] *= abs(propy)
    
                    bpy.ops.gpencil.active_frame_delete()
    
    
    # Operator Class to configure all what's needed
    
    class AddBProjectionPlane(Operator):
        bl_idname = "object.addbprojectionplane"
        bl_label = "Configure"
    
    
        def creatematerial(self, context):
            if 'Material for BProjection' not in [mat.name for mat in bpy.data.materials]:
    
                bpy.data.textures.new(name='Texture for BProjection', type='IMAGE')
    
                bpy.data.materials.new(name='Material for BProjection')
    
                matBProjection = bpy.data.materials['Material for BProjection']
                matBProjection.texture_slots.add()
                matBProjection.use_shadeless = True
                matBProjection.use_transparency = True
                matBProjection.active_texture = bpy.data.textures['Texture for BProjection']
    
                index = matBProjection.active_texture_index
                matBProjection.texture_slots[index].texture_coords = 'UV'
    
            old_index = ob.active_material_index
            bpy.ops.object.material_slot_add()
            index = ob.active_material_index
            ob.material_slots[index].material = bpy.data.materials['Material for BProjection']
            bpy.ops.object.material_slot_assign()
            ob.active_material_index = old_index
            ob.data.update()
    
            if BProjection_Empty not in [ob.name for ob in bpy.data.objects]:
    
                cm = bpy.context.object.mode
    
                bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
                context.space_data.show_relationship_lines = False
    
                ob = context.object
    
                bpy.ops.object.add()
                em = context.object
                em.name = BProjection_Empty
    
                context.view_layer.objects.active = ob
    
                ob.select_set(True)
    
                bpy.ops.object.editmode_toggle()
    
                bpy.ops.mesh.primitive_plane_add()
    
    
                # fix the vertex group creation
                bpy.ops.object.vertex_group_assign_new()
    
                ob.vertex_groups.active.name = 'texture plane'
    
                bpy.ops.uv.unwrap()
    
                bpy.ops.object.vertex_group_select()
    
                bpy.ops.object.editmode_toggle()
                for i in range(4):