Skip to content
Snippets Groups Projects
io_import_gimp_image_to_scene.py 24.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • # ##### 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 #####
    
    
    bl_info = {
    
        "name": "Import GIMP Image to Scene (.xcf/.xjt)",
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        "author": "Daniel Salazar (ZanQdo)",
    
        "version": (2, 0, 1),
        "blender": (2, 73, 0),
    
        "location": "File > Import > GIMP Image to Scene(.xcf/.xjt)",
        "description": "Imports GIMP multilayer image files as a series of multiple planes",
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        "warning": "XCF import requires xcftools installed",
    
        "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
    
                    "Scripts/Import-Export/GIMPImageToScene",
    
        "category": "Import-Export",
    }
    
    
    """
    This script imports GIMP layered image files into 3D Scenes (.xcf, .xjt)
    """
    
    
    def main(report, File, Path, LayerViewers, MixerViewers, LayerOffset,
    
             LayerScale, OpacityMode, AlphaMode, ShadelessMats,
    
             SetCamera, SetupCompo, GroupUntagged, Ext):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        #-------------------------------------------------
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        #Folder = '['+File.rstrip(Ext)+']'+'_images/'
        Folder = 'images_'+'['+File.rstrip(Ext)+']/'
    
        if not bpy.data.is_saved:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            PathSaveRaw = Path+Folder
            PathSave = PathSaveRaw.replace(' ', '\ ')
            try: os.mkdir(PathSaveRaw)
            except: pass
        else:
            PathSave = bpy.data.filepath
            RSlash = PathSave.rfind('/')
            PathSaveRaw = PathSave[:RSlash+1]+Folder
            PathSave = PathSaveRaw.replace(' ', '\ ')
            try: os.mkdir(PathSaveRaw)
            except: pass
            PathSaveRaw = bpy.path.relpath(PathSaveRaw)+'/'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        PathRaw = Path
        Path = Path.replace(' ', '\ ')
        if Ext == '.xjt':
            ExtSave = '.jpg'
            #-------------------------------------------------
            # EXTRACT XJT
            import tarfile
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            IMG = tarfile.open ('%s%s' % (PathRaw, File))
            PRP = IMG.extractfile('PRP')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Members = IMG.getmembers()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for Member in Members:
                Name = Member.name
                if Name.startswith('l') and Name.endswith('.jpg'):
                    IMG.extract(Name, path=PathSaveRaw)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            #-------------------------------------------------
            # INFO XJT
            IMGs = []
            for Line in PRP.readlines():
                Line = str(Line)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                if Line.startswith("b'GIMP_XJ_IMAGE"):
                    for Segment in Line.split():
                        if Segment.startswith('w/h:'):
                            ResX, ResY = map (int, Segment[4:].split(','))
    
                    """The "nice" method to check if layer has alpha channel
    
                    sadly GIMP sometimes decides not to export an alpha channel
    
                    if it's pure white so we are not completly sure here yet"""
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    if Line.startswith("b'L"): HasAlpha = True
                    else: HasAlpha = False
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    md = None
                    op = 1
                    ox, oy = 0,0
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    for Segment in Line.split():
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        if Segment.startswith("b'"):
                            imageFile = 'l' + Segment[3:] + '.jpg'
                            imageFileAlpha ='la'+Segment[3:]+'.jpg'
    
                            """Phisically double checking if alpha image exists
                            now we can be sure! (damn GIMP)"""
    
                            if HasAlpha:
                                if not os.path.isfile(PathSaveRaw+imageFileAlpha): HasAlpha = False
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                            # Get Widht and Height from images
                            data = open(PathSaveRaw+imageFile, "rb").read()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                            hexList = []
                            for ch in data:
                                byt = "%02X" % ch
                                hexList.append(byt)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                            for k in range(len(hexList)-1):
                                if hexList[k] == 'FF' and (hexList[k+1] == 'C0' or hexList[k+1] == 'C2'):
                                    ow = int(hexList[k+7],16)*256 + int(hexList[k+8],16)
                                    oh = int(hexList[k+5],16)*256 + int(hexList[k+6],16)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        elif Segment.startswith('md:'): # mode
                            md = Segment[3:]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        elif Segment.startswith('op:'): # opacity
                            op = float(Segment[3:])*.01
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        elif Segment.startswith('o:'): # origin
                            ox, oy = map(int, Segment[2:].split(','))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        elif Segment.startswith('n:'): # name
                            n = Segment[3:-4]
                            OpenBracket = n.find ('[')
                            CloseBracket = n.find (']')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                            if OpenBracket != -1 and CloseBracket != -1:
                                RenderLayer = n[OpenBracket+1:CloseBracket]
                                NameShort = n[:OpenBracket]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                            else:
                                RenderLayer = n
                                NameShort = n
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                            os.rename(PathSaveRaw+imageFile, PathSaveRaw+NameShort+'.jpg')
                            if HasAlpha: os.rename(PathSaveRaw+imageFileAlpha, PathSaveRaw+NameShort+'_A'+'.jpg')
    
                    IMGs.append({'LayerMode':md, 'LayerOpacity':op,
                                'LayerName':n, 'LayerNameShort':NameShort,
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                                'RenderLayer':RenderLayer, 'LayerCoords':[ow, oh, ox, oy], 'HasAlpha':HasAlpha})
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        else: # Ext == '.xcf':
            ExtSave = '.png'
            #-------------------------------------------------
            # CONFIG
            XCFInfo = 'xcfinfo'
            XCF2PNG = 'xcf2png'
            #-------------------------------------------------
            # INFO XCF
    
    
            try:
                Info = subprocess.check_output((XCFInfo, Path+File))
            except FileNotFoundError as e:
                if XCFInfo in str(e):
                    report({'ERROR'}, "Please install xcftools, xcfinfo seems to be missing (%s)" % str(e))
                    return False
                else:
                    raise e
    
            Info = Info.decode()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            IMGs = []
    
            for Line in Info.split('\n'):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                if Line.startswith ('+'):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Line = Line.split(' ', 4)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    RenderLayer = Line[4]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    OpenBracket = RenderLayer.find ('[')
                    CloseBracket = RenderLayer.find (']')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    if OpenBracket != -1 and CloseBracket != -1:
                        RenderLayer = RenderLayer[OpenBracket+1:CloseBracket]
                        NameShort = Line[4][:OpenBracket]
                    else:
                        NameShort = Line[4].rstrip()
                        if GroupUntagged:
                            RenderLayer = '__Undefined__'
                        else:
                            RenderLayer = NameShort
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    LineThree = Line[3]
                    Slash = LineThree.find('/')
                    if Slash == -1:
                        Mode = LineThree
                        Opacity = 1
                    else:
                        Mode = LineThree[:Slash]
                        Opacity = float(LineThree[Slash+1:LineThree.find('%')])*.01
    
                    IMGs.append ({
                        'LayerMode': Mode,
                        'LayerOpacity': Opacity,
                        'LayerName': Line[4].rstrip(),
                        'LayerNameShort': NameShort,
                        'LayerCoords': list(map(int, Line[1].replace('x', ' ').replace('+', ' +').replace('-', ' -').split())),
                        'RenderLayer': RenderLayer,
                        'HasAlpha': True,
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        })
                elif Line.startswith('Version'):
                    ResX, ResY = map (int, Line.split()[2].split('x'))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            #-------------------------------------------------
            # EXTRACT XCF
            if OpacityMode == 'BAKE':
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            else:
    
                Opacity = ("--percent", "100")
            xcf_path = Path + File
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for Layer in IMGs:
    
                png_path = "%s%s.png" % (PathSave, Layer['LayerName'].replace(' ', '_'))
                subprocess.call((XCF2PNG, "-C", xcf_path, "-o", png_path, Layer['LayerName']) + Opacity)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        #-------------------------------------------------
        Scene = bpy.context.scene
        #-------------------------------------------------
        # CAMERA
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if SetCamera:
            bpy.ops.object.camera_add(location=(0, 0, 10))
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Camera = bpy.context.active_object.data
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Camera.type = 'ORTHO'
            Camera.ortho_scale = ResX * .01
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        #-------------------------------------------------
        # RENDER SETTINGS
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        Render = Scene.render
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if SetCamera:
            Render.resolution_x = ResX
            Render.resolution_y = ResY
            Render.resolution_percentage = 100
    
        Render.alpha_mode = 'TRANSPARENT'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        #-------------------------------------------------
        # 3D VIEW SETTINGS
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        Scene.game_settings.material_mode = 'GLSL'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        Areas = bpy.context.screen.areas
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for Area in Areas:
            if Area.type == 'VIEW_3D':
    
                Area.spaces.active.viewport_shade = 'TEXTURED'
                Area.spaces.active.show_textured_solid = True
                Area.spaces.active.show_floor = False
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        #-------------------------------------------------
        # 3D LAYERS
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        def Make3DLayer (Name, NameShort, Z, Coords, RenderLayer, LayerMode, LayerOpacity, HasAlpha):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            # RenderLayer
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if SetupCompo:
                if not bpy.context.scene.render.layers.get(RenderLayer):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    bpy.ops.scene.render_layer_add()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    LayerActive = bpy.context.scene.render.layers.active
                    LayerActive.name = RenderLayer
                    LayerActive.use_pass_vector = True
                    LayerActive.use_sky = False
                    LayerActive.use_edge_enhance = False
                    LayerActive.use_strand = False
                    LayerActive.use_halo = False
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    global LayerNum
                    for i in range (0,20):
                        if not i == LayerNum:
                            LayerActive.layers[i] = False
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    bpy.context.scene.layers[LayerNum] = True
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    LayerFlags[RenderLayer] = bpy.context.scene.render.layers.active.layers
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    LayerList.append([RenderLayer, LayerMode, LayerOpacity])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    LayerNum += 1
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            # Object
    
            bpy.ops.mesh.primitive_plane_add(view_align=False,
                                             enter_editmode=False,
    
            bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
    
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Active = bpy.context.active_object
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if SetupCompo:
                Active.layers = LayerFlags[RenderLayer]
    
            Active.location = (
                (float(Coords[2])-(ResX*0.5))*LayerScale,
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                (-float(Coords[3])+(ResY*0.5))*LayerScale, Z)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for Vert in Active.data.vertices:
                Vert.co[0] += 1
                Vert.co[1] += -1
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Active.dimensions = float(Coords[0])*LayerScale, float(Coords[1])*LayerScale, 0
    
            bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Active.show_wire = True
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Active.name = NameShort
            bpy.ops.mesh.uv_texture_add()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            # Material
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            '''if bpy.data.materials.get(NameShort):
                Mat = bpy.data.materials[NameShort]
                if not Active.material_slots:
                    bpy.ops.object.material_slot_add()
                Active.material_slots[0].material = Mat
            else:'''
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Mat = bpy.data.materials.new(NameShort)
            Mat.diffuse_color = (1,1,1)
            Mat.use_raytrace = False
            Mat.use_shadows = False
            Mat.use_cast_buffer_shadows = False
            Mat.use_cast_approximate = False
            if HasAlpha:
                Mat.use_transparency = True
                if OpacityMode == 'MAT': Mat.alpha = LayerOpacity
                else: Mat.alpha = 0
            if ShadelessMats: Mat.use_shadeless = True
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if Ext == '.xcf':
                # Color & Alpha PNG
                Tex = bpy.data.textures.new(NameShort, 'IMAGE')
                Tex.extension = 'CLIP'
                Tex.use_preview_alpha = True
    
                Img = bpy.data.images.new(NameShort, 128, 128)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Img.source = 'FILE'
    
                Img.alpha_mode = AlphaMode
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Img.filepath = '%s%s%s' % (PathSaveRaw, Name, ExtSave)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                UVFace = Active.data.uv_textures[0].data[0]
                UVFace.image = Img
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Tex.image = Img
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Mat.texture_slots.add()
                TexSlot = Mat.texture_slots[0]
                TexSlot.texture = Tex
                TexSlot.use_map_alpha = True
                TexSlot.texture_coords = 'UV'
                if OpacityMode == 'TEX': TexSlot.alpha_factor = LayerOpacity
                elif OpacityMode == 'MAT': TexSlot.blend_type = 'MULTIPLY'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            else: # Ext == '.xjt'
                # Color JPG
                Tex = bpy.data.textures.new(NameShort, 'IMAGE')
                Tex.extension = 'CLIP'
    
                Img = bpy.data.images.new(NameShort, 128, 128)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Img.source = 'FILE'
                Img.filepath = '%s%s%s' % (PathSaveRaw, Name, ExtSave)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                UVFace = Active.data.uv_textures[0].data[0]
                UVFace.image = Img
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Tex.image = Img
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Mat.texture_slots.add()
                TexSlot = Mat.texture_slots[0]
                TexSlot.texture = Tex
                TexSlot.texture_coords = 'UV'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                if HasAlpha:
                    # Alpha JPG
                    Tex = bpy.data.textures.new(NameShort+'_A', 'IMAGE')
                    Tex.extension = 'CLIP'
                    Tex.use_preview_alpha = True
    
                    Img = bpy.data.images.new(NameShort+'_A', 128, 128)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Img.source = 'FILE'
    
                    Img.alpha_mode = AlphaMode
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Img.filepath = '%s%s_A%s' % (PathSaveRaw, Name, ExtSave)
    
                    Img.use_alpha = False
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Tex.image = Img
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Mat.texture_slots.add()
                    TexSlot = Mat.texture_slots[1]
                    TexSlot.texture = Tex
                    TexSlot.use_map_alpha = True
                    TexSlot.use_map_color_diffuse = False
                    TexSlot.texture_coords = 'UV'
                    if OpacityMode == 'TEX': TexSlot.alpha_factor = LayerOpacity
                    elif OpacityMode == 'MAT': TexSlot.blend_type = 'MULTIPLY'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if not Active.material_slots:
                bpy.ops.object.material_slot_add()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Active.material_slots[0].material = Mat
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        Z = 0
        global LayerNum
        LayerNum = 0
        LayerFlags = {}
        LayerList = []
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        for Layer in IMGs:
    
            Make3DLayer(Layer['LayerName'].replace(' ', '_'),
                        Layer['LayerNameShort'].replace(' ', '_'),
                        Z,
                        Layer['LayerCoords'],
                        Layer['RenderLayer'],
                        Layer['LayerMode'],
                        Layer['LayerOpacity'],
                        Layer['HasAlpha'],
                        )
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Z -= LayerOffset
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        if SetupCompo:
            #-------------------------------------------------
            # COMPO NODES
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Scene.use_nodes = True
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Tree = Scene.node_tree
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for i in Tree.nodes:
                Tree.nodes.remove(i)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            LayerList.reverse()
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Offset = 0
            LayerLen = len(LayerList)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for Layer in LayerList:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Offset += 1
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                X_Offset = (500*Offset)
                Y_Offset = (-300*Offset)
    
                Node = Tree.nodes.new('CompositorNodeRLayers')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                Node.location = (-500+X_Offset, 300+Y_Offset)
                Node.name = 'R_'+ str(Offset)
                Node.scene = Scene
                Node.layer = Layer[0]
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                if LayerViewers:
    
                    Node_V = Tree.nodes.new('CompositorNodeViewer')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Node_V.name = Layer[0]
                    Node_V.location = (-200+X_Offset, 200+Y_Offset)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Tree.links.new(Node.outputs[0], Node_V.inputs[0])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                if LayerLen > Offset:
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Mode = LayerList[Offset][1] # has to go one step further
                    LayerOpacity = LayerList[Offset][2]
    
                    if not Mode in {'Normal', '-1'}:
    
                        Node = Tree.nodes.new('CompositorNodeMixRGB')
                        if OpacityMode == 'COMPO': Node.inputs['Fac'].default_value = LayerOpacity
                        else: Node.inputs['Fac'].default_value = 1
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        Node.use_alpha = True
    
                        if Mode in {'Addition', '7'}: Node.blend_type = 'ADD'
                        elif Mode in {'Subtract', '8'}: Node.blend_type = 'SUBTRACT'
                        elif Mode in {'Multiply', '3'}: Node.blend_type = 'MULTIPLY'
                        elif Mode in {'DarkenOnly', '9'}: Node.blend_type = 'DARKEN'
                        elif Mode in {'Dodge', '16'}: Node.blend_type = 'DODGE'
                        elif Mode in {'LightenOnly', '10'}: Node.blend_type = 'LIGHTEN'
                        elif Mode in {'Difference', '6'}: Node.blend_type = 'DIFFERENCE'
                        elif Mode in {'Divide', '15'}: Node.blend_type = 'DIVIDE'
                        elif Mode in {'Overlay', '5'}: Node.blend_type = 'OVERLAY'
                        elif Mode in {'Screen', '4'}: Node.blend_type = 'SCREEN'
                        elif Mode in {'Burn', '17'}: Node.blend_type = 'BURN'
                        elif Mode in {'Color', '13'}: Node.blend_type = 'COLOR'
                        elif Mode in {'Value', '14'}: Node.blend_type = 'VALUE'
                        elif Mode in {'Saturation', '12'}: Node.blend_type = 'SATURATION'
                        elif Mode in {'Hue', '11'}: Node.blend_type = 'HUE'
                        elif Mode in {'Softlight', '19'}: Node.blend_type = 'SOFT_LIGHT'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        else: pass
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    else:
    
                        Node = Tree.nodes.new('CompositorNodeAlphaOver')
                        if OpacityMode == 'COMPO': Node.inputs['Fac'].default_value = LayerOpacity
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Node.name = 'M_' + str(Offset)
                    Node.location = (300+X_Offset, 250+Y_Offset)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    if MixerViewers:
    
                        Node_V = Tree.nodes.new('CompositorNodeViewer')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        Node_V.name = Layer[0]
                        Node_V.location = (500+X_Offset, 350+Y_Offset)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                        Tree.links.new(Node.outputs[0], Node_V.inputs[0])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                else:
    
                    Node = Tree.nodes.new('CompositorNodeComposite')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    Node.name = 'Composite'
                    Node.location = (400+X_Offset, 350+Y_Offset)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Nodes = bpy.context.scene.node_tree.nodes
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            if LayerLen > 1:
    
                for i in range (1, LayerLen + 1):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
                    if i == 1:
                        Tree.links.new(Nodes['R_'+str(i)].outputs[0], Nodes['M_'+str(i)].inputs[1])
                    if 1 < i < LayerLen:
                        Tree.links.new(Nodes['M_'+str(i-1)].outputs[0], Nodes['M_'+str(i)].inputs[1])
                    if 1 < i < LayerLen+1:
                        Tree.links.new(Nodes['R_'+str(i)].outputs[0], Nodes['M_'+str(i-1)].inputs[2])
                    if i == LayerLen:
                        Tree.links.new(Nodes['M_'+str(i-1)].outputs[0], Nodes['Composite'].inputs[0])
            else:
                Tree.links.new(Nodes['R_1'].outputs[0], Nodes['Composite'].inputs[0])
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            for i in Tree.nodes:
                i.location[0] += -250*Offset
                i.location[1] += 150*Offset
    
    #------------------------------------------------------------------------
    
    import bpy
    from bpy.props import *
    from math import pi
    
    # Operator
    class GIMPImageToScene(bpy.types.Operator):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bl_idname = "import.gimp_image_to_scene"
        bl_label = "GIMP Image to Scene"
        bl_description = "Imports GIMP multilayer image files into 3D Scenes"
        bl_options = {'REGISTER', 'UNDO'}
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        filename = StringProperty(name="File Name",
            description="Name of the file")
        directory = StringProperty(name="Directory",
            description="Directory of the file")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        LayerViewers = BoolProperty(name="Layer Viewers",
            description="Add Viewer nodes to each Render Layer node",
            default=True)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        MixerViewers = BoolProperty(name="Mixer Viewers",
            description="Add Viewer nodes to each Mix node",
            default=True)
    
        AlphaMode = EnumProperty(name="Alpha Mode",
            description="Representation of alpha information in the RGBA pixels",
            items=(
                ('STRAIGHT', 'Texture Alpha Factor', 'Transparent RGB and alpha pixels are unmodified'),
                ('PREMUL', 'Material Alpha Value', 'Transparent RGB pixels are multiplied by the alpha channel')),
            default='STRAIGHT')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        ShadelessMats = BoolProperty(name="Shadeless Material",
            description="Set Materials as Shadeless",
            default=True)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        OpacityMode = EnumProperty(name="Opacity Mode",
            description="Layer Opacity management",
            items=(
                ('TEX', 'Texture Alpha Factor', ''),
                ('MAT', 'Material Alpha Value', ''),
                ('COMPO', 'Mixer Node Factor', ''),
                ('BAKE', 'Baked in Image Alpha', '')),
            default='TEX')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        SetCamera = BoolProperty(name="Set Camera",
            description="Create an Ortho Camera matching image resolution",
            default=True)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        SetupCompo = BoolProperty(name="Setup Node Compositing",
            description="Create a compositing node setup (will delete existing nodes)",
            default=False)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        GroupUntagged = BoolProperty(name="Group Untagged",
            description="Layers with no tag go to a single Render Layer",
            default=False)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        LayerOffset = FloatProperty(name="Layer Separation",
            description="Distance between each 3D Layer in the Z axis",
            min=0,
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        LayerScale = FloatProperty(name="Layer Scale",
            description="Scale pixel resolution by Blender units",
            min=0,
            default=0.01)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        def draw(self, context):
            layout = self.layout
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            box = layout.box()
            box.label('3D Layers:', icon='SORTSIZE')
            box.prop(self, 'SetCamera', icon='OUTLINER_DATA_CAMERA')
            box.prop(self, 'OpacityMode', icon='GHOST')
            if self.OpacityMode == 'COMPO' and self.SetupCompo == False:
                box.label('Tip: Enable Node Compositing', icon='INFO')
    
            box.prop(self, 'AlphaMode', icon='IMAGE_RGB_ALPHA')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            box.prop(self, 'ShadelessMats', icon='SOLID')
            box.prop(self, 'LayerOffset')
            box.prop(self, 'LayerScale')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            box = layout.box()
            box.label('Compositing:', icon='RENDERLAYERS')
            box.prop(self, 'SetupCompo', icon='NODETREE')
            if self.SetupCompo:
                box.prop(self, 'GroupUntagged', icon='IMAGE_ZDEPTH')
                box.prop(self, 'LayerViewers', icon='NODE')
                box.prop(self, 'MixerViewers', icon='NODE')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        def execute(self, context):
            # File Path
            filename = self.filename
            directory = self.directory
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            # Settings
            LayerViewers = self.LayerViewers
            MixerViewers = self.MixerViewers
            OpacityMode = self.OpacityMode
    
            AlphaMode = self.AlphaMode
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            ShadelessMats = self.ShadelessMats
            SetCamera = self.SetCamera
            SetupCompo = self.SetupCompo
            GroupUntagged = self.GroupUntagged
            LayerOffset = self.LayerOffset
            LayerScale = self.LayerScale
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            Ext = None
            if filename.endswith('.xcf'): Ext = '.xcf'
            elif filename.endswith('.xjt'): Ext = '.xjt'
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            # Call Main Function
            if Ext:
    
                ret = main(self.report, filename, directory, LayerViewers, MixerViewers, LayerOffset,
                           LayerScale, OpacityMode, AlphaMode, ShadelessMats,
                           SetCamera, SetupCompo, GroupUntagged, Ext)
                if not ret:
                    return {'CANCELLED'}
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            else:
                self.report({'ERROR'},"Selected file wasn't valid, try .xcf or .xjt")
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return {'FINISHED'}
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        def invoke(self, context, event):
            wm = bpy.context.window_manager
            wm.fileselect_add(self)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
            return {'RUNNING_MODAL'}
    
    
    
    # Registering / Unregister
    def menu_func(self, context):
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        self.layout.operator(GIMPImageToScene.bl_idname, text="GIMP Image to Scene (.xcf, .xjt)", icon='PLUGIN')
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpy.types.INFO_MT_file_import.append(menu_func)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        bpy.types.INFO_MT_file_import.remove(menu_func)
    
    Luca Bonavita's avatar
    Luca Bonavita committed
        register()