# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# <pep8 compliant>

import bpy
from mathutils import Vector
from bpy.types import Operator
from bpy.props import (
        IntProperty,
        BoolProperty,
        FloatProperty,
        EnumProperty,
        )
import os
import bmesh
import time
import blf
from bpy_extras.view3d_utils import location_3d_to_region_2d
from random import uniform

C = bpy.context
D = bpy.data


# -----------------------------RECONST---------------------------

def defReconst(self, OFFSET):
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    bpy.context.tool_settings.mesh_select_mode = (True, True, True)
    ob = bpy.context.active_object
    bm = bmesh.from_edit_mesh(ob.data)
    bm.select_flush(False)
    for vertice in bm.verts[:]:
        if abs(vertice.co[0]) < OFFSET:
            vertice.co[0] = 0
    for vertice in bm.verts[:]:
        if vertice.co[0] < 0:
            bm.verts.remove(vertice)
            bmesh.update_edit_mesh(ob.data)
    mod = ob.modifiers.new("Mirror", "MIRROR")
    uv = ob.data.uv_textures.new(name="SYMMETRICAL")
    for v in bm.faces:
        v.select = 1
    bmesh.update_edit_mesh(ob.data)
    ob.data.uv_textures.active = ob.data.uv_textures['SYMMETRICAL']
    bpy.ops.uv.unwrap(
        method='ANGLE_BASED',
        fill_holes=True,
        correct_aspect=False,
        use_subsurf_data=0)
    bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Mirror")
    bpy.ops.object.mode_set(mode="EDIT", toggle=False)
    bm = bmesh.from_edit_mesh(ob.data)
    bm.select_flush(0)
    uv = ob.data.uv_textures.new(name="ASYMMETRICAL")
    ob.data.uv_textures.active = ob.data.uv_textures['ASYMMETRICAL']
    bpy.ops.uv.unwrap(
        method='ANGLE_BASED',
        fill_holes=True,
        correct_aspect=False,
        use_subsurf_data=0)


class reConst(Operator):
    """Erase vertices bellow cero X position value and rebuilds the symmetry. """
    """It also creates two uv channels, one symmetrical and one asymmetrical"""
    bl_idname = "mesh.reconst_osc"
    bl_label = "ReConst Mesh"
    bl_options = {"REGISTER", "UNDO"}

    OFFSET = FloatProperty(
            name="Offset",
            default=0.001,
            min=-0,
            max=0.1
            )

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH')

    def execute(self, context):
        defReconst(self, self.OFFSET)
        return {'FINISHED'}


# -----------------------------------SELECT LEFT---------------------

def side(self, nombre, offset):

    bpy.ops.object.mode_set(mode="EDIT", toggle=0)
    OBJECT = bpy.context.active_object
    ODATA = bmesh.from_edit_mesh(OBJECT.data)
    bpy.context.tool_settings.mesh_select_mode = (True, False, False)
    for VERTICE in ODATA.verts[:]:
        VERTICE.select = False
    if nombre is False:
        for VERTICES in ODATA.verts[:]:
            if VERTICES.co[0] < (offset):
                VERTICES.select = 1
    else:
        for VERTICES in ODATA.verts[:]:
            if VERTICES.co[0] > (offset):
                VERTICES.select = 1
    ODATA.select_flush(False)
    bpy.ops.object.mode_set(mode="EDIT", toggle=0)


class SelectMenor(Operator):
    """Selects the vetex with an N position value on the X axis"""
    bl_idname = "mesh.select_side_osc"
    bl_label = "Select Side"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH')

    side = BoolProperty(
            name="Greater than zero",
            default=False
            )
    offset = FloatProperty(
            name="Offset",
            default=0
            )

    def execute(self, context):

        side(self, self.side, self.offset)

        return {'FINISHED'}


# -------------------------RESYM VG----------------------------------


class rvg(Operator):
    bl_idname = "mesh.resym_vertex_weights_osc"
    bl_label = "Resym Vertex Weights"
    bl_description = ("Copies the symetrical weight value of the vertices on the X axys\n"
                      "(It needs the XML map and the Active Object is not in Edit mode)")
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return obj is not None and obj.mode != "EDIT"

    def execute(self, context):
        ob = bpy.context.object
        actgr = ob.vertex_groups.active if ob else None
        if not actgr:
            self.report({'WARNING'},
                        "Object doesn't have active Vertex groups. Operation Cancelled")
            return {"CANCELLED"}

        with open("%s_%s_SYM_TEMPLATE.xml" % (os.path.join(os.path.dirname(bpy.data.filepath),
                                              bpy.context.scene.name), bpy.context.object.name)) as file:
            actind = ob.vertex_groups.active_index
            ls = eval(file.read())
            wdict = {left: actgr.weight(right) for left, right in ls.items()
                     for group in ob.data.vertices[right].groups if group.group == actind}
            actgr.remove(
                [vert.index for vert in ob.data.vertices if vert.co[0] <= 0])
            for ind, weight in wdict.items():
                actgr.add([ind], weight, 'REPLACE')
            bpy.context.object.data.update()

        return {'FINISHED'}


# --------------------------- RESYM MESH-------------------------


def reSymSave(self, quality):

    bpy.ops.object.mode_set(mode='OBJECT')

    object = bpy.context.object

    rdqual = quality
    rd = lambda x: round(x, rdqual)
    absol = lambda x: (abs(x[0]), x[1], x[2])

    inddict = {
            tuple(map(rd, vert.co[:])): vert.index for vert in object.data.vertices[:]
            }
    reldict = {inddict[vert]: inddict.get(absol(vert), inddict[vert])
               for vert in inddict if vert[0] <= 0}

    ENTFILEPATH = "%s_%s_SYM_TEMPLATE.xml" % (
        os.path.join(os.path.dirname(bpy.data.filepath),
                     bpy.context.scene.name),
        bpy.context.object.name)

    with open(ENTFILEPATH, mode="w") as file:
        file.writelines(str(reldict))
        reldict.clear()


def reSymMesh(self, SELECTED, SIDE):
    bpy.ops.object.mode_set(mode='EDIT')
    ENTFILEPATH = "%s_%s_SYM_TEMPLATE.xml" % (
        os.path.join(os.path.dirname(bpy.data.filepath),
                     bpy.context.scene.name),
        bpy.context.object.name)
    with open(ENTFILEPATH, mode="r") as file:
        SYMAP = eval(file.readlines()[0])
        bm = bmesh.from_edit_mesh(bpy.context.object.data)
        object = bpy.context.object

        def MAME(SYMAP):
            bm.verts.ensure_lookup_table()
            if SELECTED:
                for vert in SYMAP:
                    if bm.verts[SYMAP[vert]].select:
                        bm.verts[vert].co = (-1 * bm.verts[SYMAP[vert]].co[0],
                                             bm.verts[SYMAP[vert]].co[1],
                                             bm.verts[SYMAP[vert]].co[2])
            else:
                for vert in SYMAP:
                    bm.verts[vert].co = (-1 * bm.verts[SYMAP[vert]].co[0],
                                         bm.verts[SYMAP[vert]].co[1],
                                         bm.verts[SYMAP[vert]].co[2])
            bmesh.update_edit_mesh(object.data)

        def MEMA(SYMAP):
            bm.verts.ensure_lookup_table()
            if SELECTED:
                for vert in SYMAP:
                    if bm.verts[vert].select:
                        bm.verts[SYMAP[vert]].co = (-1 * bm.verts[vert].co[0],
                                                    bm.verts[vert].co[1],
                                                    bm.verts[vert].co[2])
            else:
                for vert in SYMAP:
                    bm.verts[SYMAP[vert]].co = (-1 * bm.verts[vert].co[0],
                                                bm.verts[vert].co[1],
                                                bm.verts[vert].co[2])
            bmesh.update_edit_mesh(object.data)

        if SIDE == "+-":
            MAME(SYMAP)
        else:
            MEMA(SYMAP)


class OscResymSave(Operator):
    """Creates a file on disk that saves the info of every vertex but in simmetry, """ \
    """this info its going to be later used by “Resym Mesh” and “Resym Vertex Weights”"""
    bl_idname = "mesh.resym_save_map"
    bl_label = "Resym save XML Map"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH')

    quality = IntProperty(
            default=4,
            name="Quality"
            )

    def execute(self, context):
        reSymSave(self, self.quality)
        return {'FINISHED'}


class OscResymMesh(Operator):
    """Copies the symetrical position of the vertices on the X axys. It needs the XML map"""
    bl_idname = "mesh.resym_mesh"
    bl_label = "Resym save Apply XML"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    selected = BoolProperty(
            default=False,
            name="Only Selected"
            )
    side = EnumProperty(
            name="Side:",
            description="Select Side",
            items=(('+-', "+X to -X", "+X to -X"),
                   ('-+', "-X to +X", "-X to +X")),
            default='+-',
            )

    def execute(self, context):
        reSymMesh(self, self.selected, self.side)
        return {'FINISHED'}


# -------------------------- OBJECT TO MESH ------------------------------

def DefOscObjectToMesh():
    ACTOBJ = bpy.context.object
    MESH = ACTOBJ.to_mesh(
        scene=bpy.context.scene,
        apply_modifiers=True,
        settings="RENDER",
        calc_tessface=True)
    OBJECT = bpy.data.objects.new(("%s_Freeze") % (ACTOBJ.name), MESH)
    bpy.context.scene.objects.link(OBJECT)


class OscObjectToMesh(Operator):
    """It creates a copy of the final state of the object as it being see in the viewport"""
    bl_idname = "mesh.object_to_mesh_osc"
    bl_label = "Object To Mesh"

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type in
                {'MESH', 'META', 'CURVE', 'SURFACE'})

    def execute(self, context):
        print("Active type object is", context.object.type)
        DefOscObjectToMesh()

        return {'FINISHED'}


# ----------------------------- OVERLAP UV -------------------------------


def DefOscOverlapUv(self,offset,rotate):
    me = bpy.context.object.data
    bm = bmesh.from_edit_mesh(me)
    bm.faces.ensure_lookup_table()
    faces = [face for face in bm.faces if face.select]
    uv_layer = bm.loops.layers.uv[bpy.context.object.data.uv_layers.active.name]
    
    faceDict = {}
    faceReverse = []
    bm.select_mode = {'FACE'}
    for face in faces:
        bpy.ops.mesh.select_all(action="DESELECT") 
        face.select = True
        bpy.ops.mesh.select_mirror()
        faceDict[face.index] = [mirrorface for mirrorface in bm.faces if mirrorface.select][0].index
        faceReverse.append([mirrorface for mirrorface in bm.faces if mirrorface.select][0])
        
    

    for selFace,mirrorFace in faceDict.items():   
        for loop,mirrorLoop in zip(bm.faces[selFace].loops,bm.faces[mirrorFace].loops): 
            mirrorLoop.copy_from(loop)   
        if offset:      
            for loop,mirrorLoop in zip(bm.faces[selFace].loops,bm.faces[mirrorFace].loops):    
                mirrorLoop[uv_layer].uv += Vector((1,0))  
   
                       
    #invierto direcciones        
    bmesh.ops.reverse_uvs(bm, faces=[f for f in faceReverse])
    bmesh.ops.rotate_uvs(bm, faces=[f for f in faceReverse]) 
    if rotate:
        bmesh.ops.rotate_uvs(bm, faces=[f for f in faceReverse]) 

    bmesh.update_edit_mesh(me)


class OscOverlapUv(Operator):
    """Overlaps the uvs on one side of the model symmetry plane. """ \
    """Useful to get more detail on fixed resolution bitmaps"""
    bl_idname = "mesh.overlap_uv_faces"
    bl_label = "Overlap Uvs"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH')


    offset = BoolProperty(
            default=True,
            name="Offset"
            )
    rotate = BoolProperty(
            default=False,
            name="Rotate"
            )

    def execute(self, context):
        DefOscOverlapUv(self,self.offset,self.rotate)
        return {'FINISHED'}


# ------------------ PRINT VERTICES ----------------------

def dibuja_callback(self, context):
    font_id = 0
    bm = bmesh.from_edit_mesh(bpy.context.object.data)
    for v in bm.verts:
        cord = location_3d_to_region_2d(
            context.region,
            context.space_data.region_3d,
            self.matr * v.co)
        blf.position(font_id, cord[0], cord[1], 0)
        blf.size(font_id, self.tsize, 72)
        blf.draw(font_id, str(v.index))


class ModalIndexOperator(Operator):
    """Allow to visualize the index number for vertices in the viewport"""
    bl_idname = "view3d.modal_operator"
    bl_label = "Print Vertices"

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH')

    def modal(self, context, event):
        context.area.tag_redraw()
        if event.type == 'MOUSEMOVE':
            self.x = event.mouse_region_x
            self.matr = context.object.matrix_world
        elif event.type == 'LEFTMOUSE':
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'FINISHED'}
        elif event.type == 'PAGE_UP':
            self.tsize += 1
        elif event.type == 'PAGE_DOWN':
            self.tsize -= 1
        elif event.type in {'RIGHTMOUSE', 'ESC', 'TAB'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            context.area.header_text_set()
            return {'CANCELLED'}

        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        if context.area.type == "VIEW_3D":
            context.area.header_text_set("Esc: exit, PageUP/Down: text size")
            bpy.ops.object.mode_set(mode="EDIT")
            self.tsize = 20
            args = (self, context)
            self._handle = bpy.types.SpaceView3D.draw_handler_add(
                dibuja_callback, args, "WINDOW", "POST_PIXEL")
            context.window_manager.modal_handler_add(self)
            return{'RUNNING_MODAL'}
        else:
            self.report({"WARNING"}, "Is not a 3D Space")
            return {'CANCELLED'}


# -------------------------- SELECT DOUBLES

def SelDoubles(self, context):
    bm = bmesh.from_edit_mesh(bpy.context.object.data)

    for v in bm.verts:
        v.select = 0

    dictloc = {}

    rd = lambda x: (round(x[0], 4), round(x[1], 4), round(x[2], 4))

    for vert in bm.verts:
        dictloc.setdefault(rd(vert.co), []).append(vert.index)

    for loc, ind in dictloc.items():
        if len(ind) > 1:
            for v in ind:
                bm.verts[v].select = 1

    bpy.context.scene.objects.active = bpy.context.scene.objects.active


class SelectDoubles(Operator):
    """Selects duplicated vertex without merge them"""
    bl_idname = "mesh.select_doubles"
    bl_label = "Select Doubles"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH' and
                context.active_object.mode == "EDIT")

    def execute(self, context):
        SelDoubles(self, context)
        return {'FINISHED'}


# -------------------------- SELECT DOUBLES

def defLatticeMirror(self, context):

    ob = bpy.context.object
    u = ob.data.points_u
    v = ob.data.points_v
    w = ob.data.points_w
    total = u * v * w

    # guardo indices a cada punto
    libIndex = {point: index for point, index in zip(bpy.context.object.data.points, range(0, total))}

    # guardo puntos seleccionados
    selectionPoint = [libIndex[i] for i in ob.data.points if i.select]

    for point in selectionPoint:
        rango = list(range(int(point / u) * u, int(point / u) * u + (u)))
        rango.reverse()
        indPorcion = range(int(point / u) * u, int(point / u) * u + (u)).index(point)
        ob.data.points[rango[indPorcion]].co_deform.x = -ob.data.points[point].co_deform.x
        ob.data.points[rango[indPorcion]].co_deform.y = ob.data.points[point].co_deform.y
        ob.data.points[rango[indPorcion]].co_deform.z = ob.data.points[point].co_deform.z


class LatticeMirror(Operator):
    """Mirror Lattice"""
    bl_idname = "lattice.mirror_selected"
    bl_label = "Mirror Lattice"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'LATTICE' and
                context.active_object.mode == "EDIT")

    def execute(self, context):
        defLatticeMirror(self, context)
        return {'FINISHED'}


# -------------------------- OVERLAP UV ISLANDS

def defCopyUvsIsland(self, context):
    bpy.ops.object.mode_set(mode="OBJECT")
    global obLoop
    global islandFaces
    obLoop = []
    islandFaces = []
    for poly in bpy.context.object.data.polygons:
        if poly.select:
            islandFaces.append(poly.index)
            for li in poly.loop_indices:
                obLoop.append(li)

    bpy.ops.object.mode_set(mode="EDIT")        
    
def defPasteUvsIsland(self, uvOffset, rotateUv,context):
    bpy.ops.object.mode_set(mode="OBJECT")
    selPolys = [poly.index for poly in bpy.context.object.data.polygons if poly.select]
        
    for island in selPolys:
        bpy.ops.object.mode_set(mode="EDIT")      
        bpy.ops.mesh.select_all(action="DESELECT")        
        bpy.ops.object.mode_set(mode="OBJECT")  
        bpy.context.object.data.polygons[island].select = True
        bpy.ops.object.mode_set(mode="EDIT")  
        bpy.ops.mesh.select_linked()
        bpy.ops.object.mode_set(mode="OBJECT") 
        TobLoop = []
        TislandFaces = []
        for poly in bpy.context.object.data.polygons:
            if poly.select:
                TislandFaces.append(poly.index)
                for li in poly.loop_indices:
                    TobLoop.append(li)    

        for source,target in zip(range(min(obLoop),max(obLoop)+1),range(min(TobLoop),max(TobLoop)+1)):
            bpy.context.object.data.uv_layers.active.data[target].uv = bpy.context.object.data.uv_layers.active.data[source].uv + Vector((uvOffset,0))
              
        bpy.ops.object.mode_set(mode="EDIT")   
        
    if rotateUv:
        bpy.ops.object.mode_set(mode="OBJECT") 
        for poly in selPolys:
            bpy.context.object.data.polygons[poly].select = True
        bpy.ops.object.mode_set(mode="EDIT")
        bm = bmesh.from_edit_mesh(bpy.context.object.data)
        bmesh.ops.reverse_uvs(bm, faces=[f for f in bm.faces if f.select])
        bmesh.ops.rotate_uvs(bm, faces=[f for f in bm.faces if f.select]) 
        #bmesh.update_edit_mesh(bpy.context.object.data, tessface=False, destructive=False)



class CopyUvIsland(Operator):
    """Copy Uv Island"""
    bl_idname = "mesh.uv_island_copy"
    bl_label = "Copy Uv Island"
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH' and
                context.active_object.mode == "EDIT")

    def execute(self, context):
        defCopyUvsIsland(self, context)
        return {'FINISHED'}
    
class PasteUvIsland(Operator):
    """Paste Uv Island"""
    bl_idname = "mesh.uv_island_paste"
    bl_label = "Paste Uv Island"
    bl_options = {"REGISTER", "UNDO"}
    
    uvOffset = BoolProperty(
            name="Uv Offset",
            default=False
            )    

    rotateUv = BoolProperty(
            name="Rotate Uv Corner",
            default=False
            )  
    @classmethod
    def poll(cls, context):
        return (context.active_object is not None and
                context.active_object.type == 'MESH' and
                context.active_object.mode == "EDIT")

    def execute(self, context):
        defPasteUvsIsland(self, self.uvOffset, self.rotateUv, context)
        return {'FINISHED'}    
    
    

class createEditMultimesh(Operator):
    """Create Edit Multi Mesh"""
    bl_idname = "mesh.create_edit_multimesh"
    bl_label = "Create edit multimesh"
    bl_options = {"REGISTER", "UNDO"}
    
    
    # creo el merge para editar
    def execute(self,context):    
        global relvert
        global me    
        global ob 
        temp = [[ob , [vert.co for vert in ob.data.vertices]]for ob in bpy.data.groups[bpy.context.scene.multimeshedit].objects]
        vi = 0
        pi = 0
        relvert = {}
        vertlist = []
        polylist = []
        for ob in temp:
            objectMatrix = ob[0].matrix_world.copy()
            for vert in ob[0].data.vertices:
                vertlist.append(objectMatrix*vert.co)
            for poly in ob[0].data.polygons: 
                polylist.append(tuple([vert+vi for vert in poly.vertices[:]]))
            relvert[ob[0]] = {vert.index:vert.index+vi for vert in  ob[0].data.vertices}
            vi += len(ob[0].data.vertices)  
            ob[0].hide = 1
        me = bpy.data.meshes.new("editMesh")
        ob = bpy.data.objects.new("editMesh", me)
        bpy.context.scene.objects.link(ob)
        me.from_pydata(vertlist,[],polylist)
        bpy.ops.object.select_all(action="DESELECT")
        bpy.context.scene.objects.active = ob
        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
        return {'FINISHED'}  


class ApplyEditMultimesh(Operator):
    """Apply Edit Multi Mesh"""
    bl_idname = "mesh.apply_edit_multimesh"
    bl_label = "Apply edit multimesh"
    bl_options = {"REGISTER", "UNDO"}
   
    def execute(self,context):    
        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
        for object,rv in relvert.items():
            objectMatrix = object.matrix_world.inverted().copy()
            for source, target in rv.items():
                object.data.vertices[source].co = objectMatrix * me.vertices[target].co
            object.hide = 0    
        bpy.context.scene.objects.unlink(ob) 
        return {'FINISHED'} 
        
# -------------------------VERTEX COLOR MASK----------------------------------


class resymVertexGroups(Operator):
    bl_idname = "mesh.vertex_color_mask"
    bl_label = "Vertex Color Mask"
    bl_description = ("Create a Vertex Color Mask")
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return obj is not None

    def execute(self, context):
        obj = bpy.context.active_object
        mesh= obj.data

        bpy.ops.object.mode_set(mode='EDIT', toggle=False) 
        bpy.ops.mesh.select_all(action="DESELECT") 

        bm = bmesh.from_edit_mesh(mesh) 
        bm.faces.ensure_lookup_table()

        islands = []
        faces = bm.faces

        try:
            color_layer = bm.loops.layers.color["RGBMask"]
        except:    
            color_layer = bm.loops.layers.color.new("RGBMask")

        while faces:
            faces[0].select_set(True) 
            bpy.ops.mesh.select_linked() 
            islands.append([f for f in faces if f.select])
            bpy.ops.mesh.hide(unselected=False) 
            faces = [f for f in bm.faces if not f.hide] 

        bpy.ops.mesh.reveal()

        for island in islands:
            color = (uniform(0,1),uniform(0,1),uniform(0,1),1) 
            for face in island:
                for loop in face.loops:
                    loop[color_layer] = color    
            
        bpy.ops.object.mode_set(mode="VERTEX_PAINT")

        return {'FINISHED'}           