# lrib.py
# One of 7 python scripts that implement a simple L system.
# Useage:
# lrib.render(lstring, path_to_output_rib, database)
#
# The database is created by lscriptreader.py.
# The output (archive) rib file should be rendered by a RenderMan Compliant
# renderer. A sample beauty pass rib that can be used to render the geometry
# produced by the lrib module is also included in the collection of L system
# scripts. It is named "archive_tester.rib".
#
# Malcolm Kesson
# 18 Jan 2012, 26 Jan 2012
import os, random
from math import fabs
from lmel import getval
Cs_stack = []
Os_stack = []
def decr_comp(index, delta):
r,g,b = Cs_stack.pop()
temp = [r,g,b]
temp[index] -= delta
if temp[index] < 0.0:
temp[index] = 0.0
Cs_stack.append(temp)
return temp
def incr_comp(index, delta):
r,g,b = Cs_stack.pop()
temp = [r,g,b]
temp[index] += delta
if temp[index] > 1.0:
temp[index] = 1.0
Cs_stack.append(temp)
return temp
# Interpret the L string
def render(lstr, ribfile, database):
rib = []
move_data = database['move']
angle_data = database['angle']
scale_data = database['scale']
curvewidth_data = database['curvewidth']
rgb_delta = database['rgb_delta']
scale_invert_stack = []
scale_invert = False
scale_invert_stack.append(scale_invert)
move_sign = 1
angle_sign = 1
# RenderMan specific attributes
red_sign = 1
green_sign = 1
blue_sign = 1
opaciy_sign = 1
# Lock the random number generator
random.seed(database['seed'])
Cs_stack.append([1.0,1.0,1.0])
Os_stack.append([1,1,1])
for c in lstr:
# Transformations_______________________
if c == '+': move_sign = 1
elif c == '-': move_sign = -1
elif c == '>': angle_sign = 1
elif c == '<': angle_sign = -1
elif c == 'S': scale_invert = (True, False)[scale_invert == True] # toggle True/False
elif c == 'x': rib.append('Rotate %1.3f 1 0 0\n' % (fabs(getval(angle_data)) * angle_sign))
elif c == 'y': rib.append('Rotate %1.3f 0 1 0\n' % (fabs(getval(angle_data)) * angle_sign))
elif c == 'z': rib.append('Rotate %1.3f 0 0 1\n' % (fabs(getval(angle_data)) * angle_sign))
elif c == 's':
scale = getval(scale_data)
scale = (scale, 1.0/scale)[scale_invert == True]
rib.append('Scale %1.3f %1.3f %1.3f\n' % (scale, scale, scale))
elif c == 'X': rib.append('Translate %1.3f 0 0 $tnode;\n' % (fabs(getval(move_data)) * move_sign))
elif c == 'Y': rib.append('Translate 0 %1.3f 0 $tnode;\n' % (fabs(getval(move_data)) * move_sign))
elif c == 'Z': rib.append('Translate 0 0 %1.3f $tnode;\n' % (fabs(getval(move_data)) * move_sign))
# Attribute Stack_______________________
elif c == '{':
cs = Cs_stack[len(Cs_stack) - 1]
Cs_stack.append(cs);
rib.append('AttributeBegin\n')
scale_invert_stack.append(scale_invert)
elif c == '}':
cs = Cs_stack.pop();
rib.append('AttributeEnd\n')
scale_invert = scale_invert_stack.pop()
# Attributes____________________________
elif c == 'r': r,g,b = decr_comp(0, getval(rgb_delta))
elif c == 'g': r,g,b = decr_comp(1, getval(rgb_delta))
elif c == 'b': r,g,b = decr_comp(2, getval(rgb_delta))
elif c == 'R': r,g,b = incr_comp(0, getval(rgb_delta))
elif c == 'G': r,g,b = incr_comp(1, getval(rgb_delta))
elif c == 'B': r,g,b = incr_comp(2, getval(rgb_delta))
# Geometry______________________________
elif c == '4':
r,g,b = Cs_stack[len(Cs_stack) - 1]
rib.append('Color %1.3f %1.3f %1.3f\n' % (r,g,b))
rib.append('Cone 0.25 1 360\n')
rib.append('Translate 0 1 0\n')
elif c == '1':
r,g,b = Cs_stack[len(Cs_stack) - 1]
rib.append('Color %1.3f %1.3f %1.3f\n' % (r,g,b))
rib.append('Curves "linear" [2] "nonperiodic" "P" [0 0 0 0 1 0]\n')
rib.append(' "constantwidth" [%1.3f]\n' % (fabs(getval(curvewidth_data))))
rib.append('Translate 0 1 0\n')
script_path = database['script_path']
# lprocedural does not provide a path to an output rib file
# because it pipes the rib statements to prman directly.
if len(ribfile) == 0:
return ''.join(rib)
else:
# Copy the text from the original script so that it can be put
# into the output rib file as a header comment
script_text = ''
if os.path.exists(script_path) and os.path.isfile(script_path):
f = open(script_path, 'r')
temp = f.readlines()
f.close()
lines = []
for line in temp:
lines.append('# %s' % line)
script_text = ''.join(lines)
f = open(ribfile, 'w')
f.write('# Created by "%s"\n' % script_path)
f.write('%s\n' % script_text)
f.write('AttributeBegin\n')
f.write(''.join(rib))
f.write('AttributeEnd\n')
f.close()