Skip to content
Snippets Groups Projects
scripting.py 23.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Maurice Raybaud's avatar
    Maurice Raybaud committed
    # ***** 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>
    
    """Support POV Scene Description Language snippets or full includes: import,
    
    load, create or edit"""
    
    import bpy
    from bpy.props import StringProperty, BoolProperty, CollectionProperty
    from bpy_extras.io_utils import ImportHelper
    
    from bpy.utils import register_class, unregister_class
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    from mathutils import Vector
    
    from math import pi, sqrt
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    
    def export_custom_code(file):
        """write all POV user defined custom code to exported file """
        # Write CurrentAnimation Frame for use in Custom POV Code
        file.write("#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current)
        # Change path and uncomment to add an animated include file by hand:
        file.write("//#include \"/home/user/directory/animation_include_file.inc\"\n")
        for txt in bpy.data.texts:
            if txt.pov.custom_code == 'both':
                # Why are the newlines needed?
                file.write("\n")
                file.write(txt.as_string())
                file.write("\n")
    
    
    
    # ----------------------------------- IMPORT
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    
    class ImportPOV(bpy.types.Operator, ImportHelper):
        """Load Povray files"""
    
        bl_idname = "import_scene.pov"
        bl_label = "POV-Ray files (.pov/.inc)"
        bl_options = {'PRESET', 'UNDO'}
        COMPAT_ENGINES = {'POVRAY_RENDER'}
    
        # -----------
        # File props.
        files: CollectionProperty(
            type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}
        )
        directory: StringProperty(maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'})
    
        filename_ext = {".pov", ".inc"}
        filter_glob: StringProperty(default="*.pov;*.inc", options={'HIDDEN'})
    
        import_at_cur: BoolProperty(
            name="Import at Cursor Location", description="Ignore Object Matrix", default=False
        )
    
        def execute(self, context):
            from mathutils import Matrix
    
            verts = []
            faces = []
            materials = []
    
            blend_mats = []  # XXX
            pov_mats = []  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            colors = []
            mat_names = []
            lenverts = None
            lenfaces = None
            suffix = -1
            name = 'Mesh2_%s' % suffix
            name_search = False
            verts_search = False
            faces_search = False
            plane_search = False
            box_search = False
            cylinder_search = False
            sphere_search = False
            cone_search = False
    
            tex_search = False  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            cache = []
            matrixes = {}
            write_matrix = False
            index = None
            value = None
    
            # file_pov = bpy.path.abspath(self.filepath) # was used for single files
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
            def mat_search(cache):
                r = g = b = 0.5
                f = t = 0
                color = None
                for item, value in enumerate(cache):
    
                    # if value == 'texture': # add more later
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                    if value == 'pigment':
    
                        # Todo: create function for all color models.
                        # instead of current pass statements
                        # distinguish srgb from rgb into blend option
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        if cache[item + 2] in {'rgb', 'srgb'}:
                            pass
                        elif cache[item + 2] in {'rgbf', 'srgbf'}:
                            pass
                        elif cache[item + 2] in {'rgbt', 'srgbt'}:
                            try:
                                r, g, b, t = (
                                    float(cache[item + 3]),
                                    float(cache[item + 4]),
                                    float(cache[item + 5]),
                                    float(cache[item + 6]),
                                )
                            except BaseException as e:
                                print(e.__doc__)
                                print('An exception occurred: {}'.format(e))
                                r = g = b = t = float(cache[item + 2])
                            color = (r, g, b, t)
    
                        elif cache[item + 2] in {'rgbft', 'srgbft'}:
                            pass
    
                        else:
                            pass
    
                if colors == [] or (colors != [] and color not in colors):
                    colors.append(color)
                    name = ob.name + "_mat"
                    mat_names.append(name)
                    mat = bpy.data.materials.new(name)
                    mat.diffuse_color = (r, g, b)
                    mat.alpha = 1 - t
                    if mat.alpha != 1:
                        mat.use_transparency = True
                    ob.data.materials.append(mat)
    
                else:
                    for i, value in enumerate(colors):
                        if color == value:
                            ob.data.materials.append(bpy.data.materials[mat_names[i]])
    
            for file in self.files:
                print("Importing file: " + file.name)
                file_pov = self.directory + file.name
                for line in open(file_pov):
                    string = line.replace("{", " ")
                    string = string.replace("}", " ")
                    string = string.replace("<", " ")
                    string = string.replace(">", " ")
                    string = string.replace(",", " ")
                    lw = string.split()
                    # lenwords = len(lw) # Not used... why written?
                    if lw:
                        if lw[0] == "object":
                            write_matrix = True
                        if write_matrix:
                            if lw[0] not in {"object", "matrix"}:
                                index = lw[0]
                            if lw[0] in {"matrix"}:
                                value = [
                                    float(lw[1]),
                                    float(lw[2]),
                                    float(lw[3]),
                                    float(lw[4]),
                                    float(lw[5]),
                                    float(lw[6]),
                                    float(lw[7]),
                                    float(lw[8]),
                                    float(lw[9]),
                                    float(lw[10]),
                                    float(lw[11]),
                                    float(lw[12]),
                                ]
                                matrixes[index] = value
                                write_matrix = False
                for line in open(file_pov):
                    S = line.replace("{", " { ")
                    S = S.replace("}", " } ")
                    S = S.replace(",", " ")
                    S = S.replace("<", "")
                    S = S.replace(">", " ")
                    S = S.replace("=", " = ")
                    S = S.replace(";", " ; ")
                    S = S.split()
                    # lenS = len(S) # Not used... why written?
    
                    for word in enumerate(S):
                        # -------- Primitives Import -------- #
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        if word == 'cone':
                            cone_search = True
                            name_search = False
                        if cone_search:
                            cache.append(word)
                            if cache[-1] == '}':
                                try:
                                    x0 = float(cache[2])
                                    y0 = float(cache[3])
                                    z0 = float(cache[4])
                                    r0 = float(cache[5])
                                    x1 = float(cache[6])
                                    y1 = float(cache[7])
                                    z1 = float(cache[8])
                                    r1 = float(cache[9])
                                    # Y is height in most pov files, not z
                                    bpy.ops.pov.cone_add(base=r0, cap=r1, height=(y1 - y0))
                                    ob = context.object
                                    ob.location = (x0, y0, z0)
                                    # ob.scale = (r,r,r)
                                    mat_search(cache)
                                except ValueError:
                                    pass
                                cache = []
                                cone_search = False
                        if word == 'plane':
                            plane_search = True
                            name_search = False
                        if plane_search:
                            cache.append(word)
                            if cache[-1] == '}':
                                try:
                                    bpy.ops.pov.addplane()
                                    ob = context.object
                                    mat_search(cache)
                                except ValueError:
                                    pass
                                cache = []
                                plane_search = False
                        if word == 'box':
                            box_search = True
                            name_search = False
                        if box_search:
                            cache.append(word)
                            if cache[-1] == '}':
                                try:
                                    x0 = float(cache[2])
                                    y0 = float(cache[3])
                                    z0 = float(cache[4])
                                    x1 = float(cache[5])
                                    y1 = float(cache[6])
                                    z1 = float(cache[7])
                                    # imported_corner_1=(x0, y0, z0)
                                    # imported_corner_2 =(x1, y1, z1)
                                    center = ((x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2)
                                    bpy.ops.pov.addbox()
                                    ob = context.object
                                    ob.location = center
                                    mat_search(cache)
    
                                except ValueError:
                                    pass
                                cache = []
                                box_search = False
                        if word == 'cylinder':
                            cylinder_search = True
                            name_search = False
                        if cylinder_search:
                            cache.append(word)
                            if cache[-1] == '}':
                                try:
                                    x0 = float(cache[2])
                                    y0 = float(cache[3])
                                    z0 = float(cache[4])
                                    x1 = float(cache[5])
                                    y1 = float(cache[6])
                                    z1 = float(cache[7])
                                    imported_cyl_loc = (x0, y0, z0)
                                    imported_cyl_loc_cap = (x1, y1, z1)
    
                                    r = float(cache[8])
    
                                    vec = Vector(imported_cyl_loc_cap) - Vector(imported_cyl_loc)
                                    depth = vec.length
                                    rot = Vector((0, 0, 1)).rotation_difference(
                                        vec
                                    )  # Rotation from Z axis.
                                    trans = rot @ Vector(  # XXX Not used, why written?
                                        (0, 0, depth / 2)
                                    )  # Such that origin is at center of the base of the cylinder.
                                    # center = ((x0 + x1)/2,(y0 + y1)/2,(z0 + z1)/2)
                                    scale_z = sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2 + (z1 - z0) ** 2) / 2
                                    bpy.ops.pov.addcylinder(
                                        R=r,
                                        imported_cyl_loc=imported_cyl_loc,
                                        imported_cyl_loc_cap=imported_cyl_loc_cap,
                                    )
                                    ob = context.object
                                    ob.location = (x0, y0, z0)
                                    ob.rotation_euler = rot.to_euler()
                                    ob.scale = (1, 1, scale_z)
    
                                    # scale data rather than obj?
                                    # bpy.ops.object.mode_set(mode='EDIT')
                                    # bpy.ops.mesh.reveal()
                                    # bpy.ops.mesh.select_all(action='SELECT')
                                    # bpy.ops.transform.resize(value=(1,1,scale_z), orient_type='LOCAL')
                                    # bpy.ops.mesh.hide(unselected=False)
                                    # bpy.ops.object.mode_set(mode='OBJECT')
    
                                    mat_search(cache)
    
                                except ValueError:
                                    pass
                                cache = []
                                cylinder_search = False
                        if word == 'sphere':
                            sphere_search = True
                            name_search = False
                        if sphere_search:
                            cache.append(word)
                            if cache[-1] == '}':
                                x = y = z = r = 0
                                try:
                                    x = float(cache[2])
                                    y = float(cache[3])
                                    z = float(cache[4])
                                    r = float(cache[5])
    
                                except ValueError:
                                    pass
                                except:
                                    x = y = z = float(cache[2])
                                    r = float(cache[3])
                                bpy.ops.pov.addsphere(R=r, imported_loc=(x, y, z))
                                ob = context.object
                                ob.location = (x, y, z)
                                ob.scale = (r, r, r)
                                mat_search(cache)
                                cache = []
                                sphere_search = False
    
                        # -------- End Primitives Import -------- #
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        if word == '#declare':
                            name_search = True
                        if name_search:
                            cache.append(word)
                            if word == 'mesh2':
                                name_search = False
                                if cache[-2] == '=':
                                    name = cache[-3]
                                else:
                                    suffix += 1
                                cache = []
                            if word in {'texture', ';'}:
                                name_search = False
                                cache = []
                        if word == 'vertex_vectors':
                            verts_search = True
                        if verts_search:
                            cache.append(word)
                            if word == '}':
                                verts_search = False
                                lenverts = cache[2]
                                cache.pop()
                                cache.pop(0)
                                cache.pop(0)
                                cache.pop(0)
                                for j in range(int(lenverts)):
                                    x = j * 3
                                    y = (j * 3) + 1
                                    z = (j * 3) + 2
                                    verts.append((float(cache[x]), float(cache[y]), float(cache[z])))
                                cache = []
                        # if word == 'face_indices':
                        # faces_search = True
    
                        if word == 'texture_list':  # XXX
                            tex_search = True  # XXX
                        if tex_search:  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            if (
                                word not in {'texture_list', 'texture', '{', '}', 'face_indices'}
                                and not word.isdigit()
    
                            ):  # XXX
                                pov_mats.append(word)  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                        if word == 'face_indices':
    
                            tex_search = False  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                            faces_search = True
                        if faces_search:
                            cache.append(word)
                            if word == '}':
                                faces_search = False
                                lenfaces = cache[2]
                                cache.pop()
                                cache.pop(0)
                                cache.pop(0)
                                cache.pop(0)
                                lf = int(lenfaces)
                                var = int(len(cache) / lf)
                                for k in range(lf):
                                    if var == 3:
                                        v0 = k * 3
                                        v1 = k * 3 + 1
                                        v2 = k * 3 + 2
                                        faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
                                    if var == 4:
                                        v0 = k * 4
                                        v1 = k * 4 + 1
                                        v2 = k * 4 + 2
                                        m = k * 4 + 3
                                        materials.append((int(cache[m])))
                                        faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
                                    if var == 6:
                                        v0 = k * 6
                                        v1 = k * 6 + 1
                                        v2 = k * 6 + 2
                                        m0 = k * 6 + 3
                                        m1 = k * 6 + 4
                                        m2 = k * 6 + 5
                                        materials.append(
                                            (int(cache[m0]), int(cache[m1]), int(cache[m2]))
                                        )
                                        faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
                                # mesh = pov_define_mesh(None, verts, [], faces, name, hide_geometry=False)
                                # ob = object_utils.object_data_add(context, mesh, operator=None)
    
    
                                me = bpy.data.meshes.new(name)  # XXX
                                ob = bpy.data.objects.new(name, me)  # XXX
                                bpy.context.collection.objects.link(ob)  # XXX
                                me.from_pydata(verts, [], faces)  # XXX
    
                                for mat in bpy.data.materials:  # XXX
                                    blend_mats.append(mat.name)  # XXX
                                for m_name in pov_mats:  # XXX
                                    if m_name not in blend_mats:  # XXX
                                        bpy.data.materials.new(m_name)  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                                        mat_search(cache)
                                    ob.data.materials.append(
                                        bpy.data.materials[m_name]
    
                                    )  # XXX
                                if materials:  # XXX
                                    for idx, val in enumerate(materials):  # XXX
                                        try:  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                                            ob.data.polygons[
    
                                                idx
                                            ].material_index = val  # XXX
                                        except TypeError:  # XXX
                                            ob.data.polygons[idx].material_index = int(
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                                                val[0]
    
                                blend_mats = []  # XXX
                                pov_mats = []  # XXX
                                materials = []  # XXX
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
                                cache = []
                                name_search = True
                                if name in matrixes and not self.import_at_cur:
                                    global_matrix = Matrix.Rotation(pi / 2.0, 4, 'X')
                                    ob = bpy.context.object
                                    matrix = ob.matrix_world
                                    v = matrixes[name]
                                    matrix[0][0] = v[0]
                                    matrix[1][0] = v[1]
                                    matrix[2][0] = v[2]
                                    matrix[0][1] = v[3]
                                    matrix[1][1] = v[4]
                                    matrix[2][1] = v[5]
                                    matrix[0][2] = v[6]
                                    matrix[1][2] = v[7]
                                    matrix[2][2] = v[8]
                                    matrix[0][3] = v[9]
                                    matrix[1][3] = v[10]
                                    matrix[2][3] = v[11]
                                    matrix = global_matrix * ob.matrix_world
                                    ob.matrix_world = matrix
                                verts = []
                                faces = []
    
                        # if word == 'pigment':
                        # try:
                        # #all indices have been incremented once to fit a bad test file
                        # r,g,b,t = float(S[2]),float(S[3]),float(S[4]),float(S[5])
                        # color = (r,g,b,t)
    
                        # except IndexError:
                        # #all indices have been incremented once to fit alternate test file
                        # r,g,b,t = float(S[3]),float(S[4]),float(S[5]),float(S[6])
                        # color = (r,g,b,t)
                        # except UnboundLocalError:
                        # # In case no transmit is specified ? put it to 0
                        # r,g,b,t = float(S[2]),float(S[3]),float(S[4],0)
                        # color = (r,g,b,t)
    
                        # except ValueError:
                        # color = (0.8,0.8,0.8,0)
                        # pass
    
                        # if colors == [] or (colors != [] and color not in colors):
                        # colors.append(color)
                        # name = ob.name+"_mat"
                        # mat_names.append(name)
                        # mat = bpy.data.materials.new(name)
                        # mat.diffuse_color = (r,g,b)
                        # mat.alpha = 1-t
                        # if mat.alpha != 1:
                        # mat.use_transparency=True
                        # ob.data.materials.append(mat)
                        # print (colors)
                        # else:
                        # for m in range(len(colors)):
                        # if color == colors[m]:
                        # ob.data.materials.append(bpy.data.materials[mat_names[m]])
    
    
            # To keep Avogadro Camera angle:
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
            # for obj in bpy.context.view_layer.objects:
            # if obj.type == "CAMERA":
            # track = obj.constraints.new(type = "TRACK_TO")
            # track.target = ob
            # track.track_axis ="TRACK_NEGATIVE_Z"
            # track.up_axis = "UP_Y"
            # obj.location = (0,0,0)
            return {'FINISHED'}
    
    
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    def register():
    
        for cls in classes:
            register_class(cls)
    
    Maurice Raybaud's avatar
    Maurice Raybaud committed
    
    
    def unregister():
    
        for cls in reversed(classes):
            unregister_class(cls)