I did it my way.... of(in) course

I am trying to avoid splitting my attention between Cycles and Blender Render.
Attempting to stay with Cycles knowing that I will have little use of any other…

So, here is my solution to the problem, but applied to Cycles.


'''
  Create credits from CVS - file.

  BOOTSTRAP:
import os,sys,bpy;sys.path.append(os.path.dirname(bpy.data.filepath))
import importlib; importlib.reload(texture_painter)
'''

import bpy, sys, os, codecs, csv

from PIL import Image, ImageDraw, ImageFont

PDIR = os.path.dirname( bpy.data.filepath )
TEXDIR = 'textures'

class Props(object):
    """ Args as props utility """
    def __init__(self,data=None,**kv):
        self.__dict__.update(kv)
        if data: self.__dict__.update(data)

    def __call__(self,data=None,**kv):
        clone = Props(kv,**self.__dict__)
        if data: clone.__dict__.update(data)
        return clone

def PPath(*args):
    return os.path.join(PDIR,*args)

def TextureFactory(text, **kv):
    """ Create texture file.

    Arguments:
       text: The text to render

   Keyed arguments (default):
       imgsize  = (512,64)
       fontsize = 32
       out      = 'out.png'
       margin   = (20,20)
    """
    imgsize  = kv.get( 'imgsize',(512,64) )
    fontsize = kv.get( 'fontsize',32 )
    outfile  = PPath( kv.get('out','out.png') )
    pos      = kv.get( 'margin',(20,20) )

    # Initiate an image (w,h)
    img = Image.new( 'RGB', imgsize )
    # Initiate a font (sources?)
    draw = ImageDraw.Draw(img)
    fnt  = ImageFont.truetype( PPath('defconzero.ttf'), fontsize )
    # Use the font to project on the image
    draw.text( pos, text, font=fnt )
    # Save the image
    img.save( outfile )
    return outfile

def BackerIter( cvs_fname ):
    """ Iterate csv - file, skipping the header.

        Yields values as Props(Name=?,Number=?,Country=?)
        Accessible as obj.Name, obj.Country ...
    """
    with codecs.open(PPath(cvs_fname),'r','utf-8-sig') as file:
        rip = csv.reader(file)
        hdr = next(rip)
        for row in rip:
            yield Props(zip(hdr,row))

def get_single_selected():
    if 1 != len(bpy.context.selected_objects):
        raise Exception('Operation only valid with one selected template!')
    return bpy.context.selected_objects[0]

def CloneFactory( templ, offset ):
    bpy.ops.object.select_all(action='DESELECT')
    templ.select=True
    bpy.ops.object.duplicate_move( TRANSFORM_OT_translate={"value":offset })
    new_brick = bpy.context.selected_objects[0]
    new_brick.select = False
    return new_brick


class Layout(Props):
    """ Stateful placement tool

     Keyword arguments
       cols - Number of columns
       xpad - Padding between 'bricks' in x
       ypad - Padding between 'bricks' in y
    """
    def __call__(self, idx):
        row = idx // self.cols
        col = idx % self.cols
        return ( col * (2 + self.xpad), row * (1 + self.ypad), 0 )

def BrickFactory( templ, backer, idx ):
    """ Create brick
    """
    text     = ', '.join( (backer.Name, backer.Country) )
    fname    = PPath(TEXDIR,'%d.png'%idx)
    texture_file = TextureFactory(text, fontsize=42, out=fname, margin=(10,9))
    placer   = Layout(cols=3,xpad=.1,ypad=.1)
    if idx:
        new_brick = CloneFactory(templ=templ, offset=placer(idx))
    else:
        new_brick = templ
    new_mat = templ.material_slots[0].material.copy()
    new_mat.name = 'GeneratedMaterial%d'%idx
    new_img = bpy.data.images.load(texture_file)
    new_mat.node_tree.nodes.get('Image Texture').image = new_img
    new_brick.material_slots[0].material = new_mat

def go():
    templ = get_single_selected()
    for idx, backer in enumerate(BackerIter('backers_10.csv')):
        BrickFactory( templ, backer, idx )

Hopefully this is useful further on…

Privacy & Terms