5
$\begingroup$

Can someone show me an example how I can read the content of an internal text file? Let's say I append a text file from another Blend file with a known internal name ("Environment") and some text data in it. I would like to read an process the content from within an Add-on. I know how to read an external file but I would like to keep this text file internal (after the append) so that it gets saved with the blender file.

I can access the internal file with: bpy.data.texts['Environment']. I tried autocomplete after this and there are lot's of possibilities but I can't figure out how to simply read or write the content of this data block. What is the "best practice" to do this? Thanks for any suggestion.

$\endgroup$
2

1 Answer 1

6
$\begingroup$

Below are a few funtions I had setup in an old script that can provide some insight to reading, writing and working with data from a text datablock.

Sample writing to a data block:

Pass a mesh object to the function to create a new (or overwrite an existing) text datablock in the current blender session based on the name of the object.

def mesh_to_txt(obj):
    txtname = obj.name
    verts = [v.co for v in obj.data.vertices]
    edges = [e for e in obj.data.edges]
    faces = [f for f in obj.data.polygons]
    if txtname not in bpy.data.texts:
        ntxt = bpy.data.texts.new(txtname)
    else:
        ntxt = bpy.data.texts[txtname]
        ntxt.clear()
    # verts
    ntxt.write(f"verts = [\n")
    for v in verts:
        ntxt.write(f"\t{v.to_tuple()},\n")
    ntxt.write(f"\t]\n")
    # edges
    ntxt.write(f"edges = [\n")
    for e in edges:
        ntxt.write(f"\t[")
        for v in e.vertices:
            ntxt.write(f"{v},")
        ntxt.write(f"],\n")
    ntxt.write(f"\t]\n")
    # faces
    ntxt.write(f"faces = [\n")
    for f in faces:
        ntxt.write(f"\t[")
        for v in f.vertices:
            ntxt.write(f"{v},")
        ntxt.write(f"],\n")
    ntxt.write(f"\t]\n")

A new text block will be created based on the name of the selected object and data formated like so:

verts = [
    (1.0, 1.0, 1.0),
    (1.0, 1.0, -1.0),
    (1.0, -1.0, 1.0),
    (1.0, -1.0, -1.0),
    (-1.0, 1.0, 1.0),
    (-1.0, 1.0, -1.0),
    (-1.0, -1.0, 1.0),
    (-1.0, -1.0, -1.0),
    ]
edges = [
    [5,7,],
    [1,5,],
    [0,1,],
    [7,6,],
    [2,3,],
    [4,5,],
    [2,6,],
    [0,2,],
    [7,3,],
    [6,4,],
    [4,0,],
    [3,1,],
    ]
faces = [
    [0,4,6,2,],
    [3,2,6,7,],
    [7,6,4,5,],
    [5,1,3,7,],
    [1,0,2,3,],
    [5,4,0,1,],
    ]

Reading data from a text datablock

Function that when given a string name corresponding to a text datablock reads the above format creating lists to use elsewhere. If the name provided txtname is not found in the currect blend session the return values are empty lists.

def txt_to_mesh(txtname):
    verts = []
    edges = []
    faces = []
    line = 0
    if txtname in bpy.data.texts:
        ntxt = bpy.data.texts[txtname]
    else:
        return verts, edges, faces
    ntxt.cursor_set(line, character=0, select=False)
    rd_line = ntxt.current_line.body
    
    if rd_line.startswith('verts'):
        line += 1
        ntxt.cursor_set(line, character=0, select=False)
        rd_line = ntxt.current_line.body
        while rd_line.startswith('\t('):
            verts.append(mathutils.Vector(eval(rd_line[1:-1])))
            line += 1
            ntxt.cursor_set(line, character=0, select=False)
            rd_line = ntxt.current_line.body
        # skip to edges or faces
        while rd_line.startswith('\t'):
            line += 1
            ntxt.cursor_set(line, character=0, select=False)
            rd_line = ntxt.current_line.body
        
    if rd_line.startswith('edges'):
        line += 1
        ntxt.cursor_set(line, character=0, select=False)
        rd_line = ntxt.current_line.body
        while rd_line.startswith('\t['):
            edges.append(eval(rd_line[1:-1]))
            line += 1
            ntxt.cursor_set(line, character=0, select=False)
            rd_line = ntxt.current_line.body
        # skip to edges or faces
        while rd_line.startswith('\t'):
            line += 1
            ntxt.cursor_set(line, character=0, select=False)
            rd_line = ntxt.current_line.body
            
    if rd_line.startswith('faces'):
        line += 1
        ntxt.cursor_set(line, character=0, select=False)
        rd_line = ntxt.current_line.body
        while rd_line.startswith('\t['):
            faces.append(eval(rd_line[1:-1]))
            line += 1
            ntxt.cursor_set(line, character=0, select=False)
            rd_line = ntxt.current_line.body
        # skip to edges or faces
        while rd_line.startswith('\t'):
            line += 1
            ntxt.cursor_set(line, character=0, select=False)
            rd_line = ntxt.current_line.body
    return verts, edges, faces

Using information read from datablock:

Function to create a mesh object from verts, edges, faces.

def add_mesh(name, verts, faces, edges=None, col_name=""):    
    if edges is None:
        edges = []
    mesh = bpy.data.meshes.new(name)
    obj = bpy.data.objects.new(mesh.name, mesh)
    if bpy.data.collections.get(col_name):
        col = bpy.data.collections.get(col_name)
    else:
        col = bpy.context.scene.collection
    col.objects.link(obj)
    bpy.context.view_layer.objects.active = obj
    mesh.from_pydata(verts, edges, faces)
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .