open_toontown_panda3d/direct/src/leveleditor/LevelStyleManager.py

1568 lines
63 KiB
Python
Executable File

import sys, string, math, types
from pandac.PandaModules import *
import direct.gui.DirectGuiGlobals as DGG
from direct.gui.DirectGui import *
from PieMenu import *
from ScrollMenu import *
dnaDirectory = Filename.expandFrom(base.config.GetString("dna-directory", "$TTMODELS/src/dna"))
# Colors used by all color menus
DEFAULT_COLORS = [
Vec4(1, 1, 1, 1),
Vec4(0.75, 0.75, 0.75, 1.0),
Vec4(0.5, 0.5, 0.5, 1.0),
Vec4(0.25, 0.25, 0.25, 1.0)
]
# The list of items with color attributes
COLOR_TYPES = ['wall_color', 'window_color',
'window_awning_color', 'sign_color', 'door_color',
'door_awning_color', 'cornice_color',
'prop_color']
# The list of dna components maintained in the style attribute dictionary
DNA_TYPES = ['wall', 'window', 'sign', 'door_double', 'door_single', 'cornice', 'toon_landmark',
'prop', 'street']
BUILDING_TYPES = ['10_10', '20', '10_20', '20_10', '10_10_10',
'4_21', '3_22', '4_13_8', '3_13_9', '10',
'12_8', '13_9_8', '4_10_10', '4_10', '4_20',
]
BUILDING_HEIGHTS = [10, 14, 20, 24, 25, 30]
NUM_WALLS = [1, 2, 3]
LANDMARK_SPECIAL_TYPES = ['', 'hq', 'gagshop', 'clotheshop', 'petshop', 'kartshop']
OBJECT_SNAP_POINTS = {
'street_5x20': [(Vec3(5.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_10x20': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x20': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_30x20': [(Vec3(30.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x20': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_80x20': [(Vec3(80.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_5x40': [(Vec3(5.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_10x40': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x40': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x40_15': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_30x40': [(Vec3(30.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x60': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x60': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x40_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_80x40': [(Vec3(80.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_angle_30': [(Vec3(0), Vec3(-30, 0, 0)),
(Vec3(0), Vec3(0))],
'street_angle_45': [(Vec3(0), Vec3(-45, 0, 0)),
(Vec3(0), Vec3(0))],
'street_angle_60': [(Vec3(0), Vec3(-60, 0, 0)),
(Vec3(0), Vec3(0))],
'street_inner_corner': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_outer_corner': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_full_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_tight_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_tight_corner_mirror': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_double_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_curved_corner': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_curved_corner_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_t_intersection': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_y_intersection': [(Vec3(30.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_street_20x20': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_street_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_sidewalk_20x20': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_sidewalk_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_transition': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_40x70': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_transition_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_divided_40x70_15': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_stairs_40x10x5': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_4way_intersection': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_incline_40x40x5': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_square_courtyard': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70_15': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_70_15_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90_15': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_courtyard_90_15_exit': [(Vec3(0.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_50_transition': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_20x50': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_40x50': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_keyboard_10x40': [(Vec3(10.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_keyboard_20x40': [(Vec3(20.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_keyboard_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
'street_sunken_40x40': [(Vec3(40.0, 0, 0), Vec3(0)),
(Vec3(0), Vec3(0))],
}
# Precompute class types for type comparisons
DNA_CORNICE = DNACornice.getClassType()
DNA_DOOR = DNADoor.getClassType()
DNA_FLAT_DOOR = DNAFlatDoor.getClassType()
DNA_FLAT_BUILDING = DNAFlatBuilding.getClassType()
DNA_NODE = DNANode.getClassType()
DNA_GROUP = DNAGroup.getClassType()
DNA_VIS_GROUP = DNAVisGroup.getClassType()
DNA_LANDMARK_BUILDING = DNALandmarkBuilding.getClassType()
DNA_NODE = DNANode.getClassType()
DNA_PROP = DNAProp.getClassType()
DNA_SIGN = DNASign.getClassType()
DNA_SIGN_BASELINE = DNASignBaseline.getClassType()
DNA_SIGN_TEXT = DNASignText.getClassType()
DNA_SIGN_GRAPHIC = DNASignGraphic.getClassType()
DNA_STREET = DNAStreet.getClassType()
DNA_WALL = DNAWall.getClassType()
DNA_WINDOWS = DNAWindows.getClassType()
# DNA Utility functions (possible class extensions?)
def DNARemoveChildren(dnaObject):
""" Utility function to delete all the children of a DNANode """
children = []
for i in range(dnaObject.getNumChildren()):
children.append(dnaObject.at(i))
for child in children:
dnaObject.remove(child)
DNASTORE.removeDNAGroup(child)
def DNARemoveChildOfClass(dnaNode, classType, childNum = 0):
""" Remove the nth object of that type you come across """
childCount = 0
for i in range(dnaNode.getNumChildren()):
child = dnaNode.at(i)
if DNAClassEqual(child, classType):
if childCount == childNum:
dnaNode.remove(child)
DNASTORE.removeDNAGroup(child)
return 1
childCount = childCount + 1
# None found
return 0
def DNARemoveAllChildrenOfClass(dnaNode, classType):
""" Remove the objects of that type """
children = []
for i in range(dnaNode.getNumChildren()):
child=dnaNode.at(i)
if DNAClassEqual(child, classType):
children.append(child)
for child in children:
dnaNode.remove(child)
DNASTORE.removeDNAGroup(child)
def DNAGetChildren(dnaNode, classType=None):
""" Return the objects of that type """
children = []
for i in range(dnaNode.getNumChildren()):
child=dnaNode.at(i)
if ((not classType)
or DNAClassEqual(child, classType)):
children.append(child)
return children
def DNAGetChild(dnaObject, type = DNA_NODE, childNum = 0):
childCount = 0
for i in range(dnaObject.getNumChildren()):
child = dnaObject.at(i)
if DNAClassEqual(child, type):
if childCount == childNum:
return child
childCount = childCount + 1
# Not found
return None
def DNAGetChildRecursive(dnaObject, type = DNA_NODE, childNum = 0):
childCount = 0
for i in range(dnaObject.getNumChildren()):
child = dnaObject.at(i)
if DNAClassEqual(child, type):
if childCount == childNum:
return child
childCount = childCount + 1
else:
child = DNAGetChildRecursive(child, type, childNum-childCount)
if child:
return child
# Not found
return None
def DNAGetChildOfClass(dnaNode, classType):
for i in range(dnaNode.getNumChildren()):
child = dnaNode.at(i)
if DNAClassEqual(child, classType):
return child
# Not found
return None
def DNAGetClassType(dnaObject):
return dnaObject.__class__.getClassType()
def DNAClassEqual(dnaObject, classType):
return DNAGetClassType(dnaObject).eq(classType)
def DNAIsDerivedFrom(dnaObject, classType):
return DNAGetClassType(dnaObject).isDerivedFrom(classType)
def DNAGetWallHeights(aDNAFlatBuilding):
""" Get a list of wall heights for a given flat building """
# Init variables
heightList = []
offsetList = []
offset = 0.0
# Compute wall heights
for i in range(aDNAFlatBuilding.getNumChildren()):
child = aDNAFlatBuilding.at(i)
if DNAClassEqual(child, DNA_WALL):
height = child.getHeight()
heightList.append(height)
offsetList.append(offset)
offset = offset + height
return heightList, offsetList
def DNAGetBaselineString(baseline):
s=""
for i in range(baseline.getNumChildren()):
child = baseline.at(i)
if DNAClassEqual(child, DNA_SIGN_TEXT):
s=s+child.getLetters()
elif DNAClassEqual(child, DNA_SIGN_GRAPHIC):
s=s+'['+child.getCode()+']'
return s
def DNASetBaselineString(baseline, text):
# TODO: Instead of removing all the text and replacing it,
# replace each text item and then add or remove at the end.
# This should allow inlined graphics to stay in place.
# end of todo.
DNARemoveAllChildrenOfClass(baseline, DNA_SIGN_TEXT)
# We can't just blindly iterate through the text, because it might
# be utf-8 encoded, meaning some characters are represented using
# multi-byte sequences. Instead, create a TextNode and use it to
# iterate through the characters of the text.
t = TextNode('')
t.setText(text)
for i in range(t.getNumChars()):
ch = t.getEncodedChar(i)
text=DNASignText("text")
text.setLetters(ch)
baseline.add(text)
class LevelStyleManager:
"""Class which reads in style files and manages class variables"""
def __init__(self, NEIGHBORHOODS = [], NEIGHBORHOOD_CODES = {} ):
self.NEIGHBORHOODS = NEIGHBORHOODS
self.NEIGHBORHOOD_CODES = NEIGHBORHOOD_CODES
# The main dictionary holding all attribute objects
self.attributeDictionary = {}
# Create the style samples
self.createBaselineStyleAttributes()
self.createWallStyleAttributes()
self.createBuildingStyleAttributes()
self.createColorAttributes()
self.createDNAAttributes()
self.createMiscAttributes()
# BASELINE STYLE FUNCTIONS
def createBaselineStyleAttributes(self):
"""
Create a baselineStyle entry in the attribute dictionary
This will be a dictionary of style attributes, one per neighborhood
"""
# First create an empty dictionary
dict = self.attributeDictionary['baseline_style'] = {}
# Create a attribute object for each neighborhood
for neighborhood in self.NEIGHBORHOODS:
attribute = LevelAttribute('baseline_style')
attribute.setDict(
# Create a baseline style dictionary for each neighborhood
self.createBaselineStyleDictionary(neighborhood))
# Using this dictionary, create style pie menus
attribute.setMenu(
self.createBaselineStyleMenu(neighborhood, attribute.getDict()))
dict[neighborhood] = attribute
def createBaselineStyleDictionary(self, neighborhood):
"""
Create a dictionary of baseline styles for a neighborhood
"""
filename = neighborhood + '_baseline_styles.txt'
print 'Loading baseline styles from: ' + filename
styleData = self.getStyleFileData(filename)
return self.initializeBaselineStyleDictionary(styleData, neighborhood)
def initializeBaselineStyleDictionary(self, styleData, neighborhood):
"""
Fill in the baseline style dictionary with data from the style file
"""
styleDictionary = {}
styleCount = 0
code = self.NEIGHBORHOOD_CODES[neighborhood]
while styleData:
l = styleData[0]
if l == 'baselineStyle':
# Start of new style, strip off first line then extract style
style, styleData = self.extractBaselineStyle(styleData)
style.name = code + '_baseline_style_' + `styleCount`
# Store style in dictionary
styleDictionary[style.name] = style
styleCount = styleCount + 1
# Move to next line
styleData = styleData[1:]
return styleDictionary
def extractBaselineStyle(self, styleData):
"""
Pull out one style from a list of style data. Will keep
processing data until endBaselineStyle of end of data is reached.
Returns a baseline style and remaining styleData.
"""
# Create default style
style = DNABaselineStyle()
# Strip off first line
styleData = styleData[1:]
while styleData:
l = styleData[0]
if l == 'endBaselineStyle':
# End of style found, break out of while loop
# Note, endBaselineStyle line is *not* stripped off
return style, styleData
else:
pair = map(string.strip, l.split(':'))
if style.__dict__.has_key(pair[0]):
pair_0 = pair[0]
# Convert some numerical values
if (pair_0 == 'color'
or pair_0 == 'kern'
or pair_0 == 'wiggle'
or pair_0 == 'stumble'
or pair_0 == 'stomp'
or pair_0 == 'curve'
or pair_0 == 'x'
or pair_0 == 'z'
or pair_0 == 'scaleX'
or pair_0 == 'scaleZ'
or pair_0 == 'roll'):
style[pair_0] = eval(pair[1])
else:
style[pair_0] = pair[1]
else:
print 'extractBaselineStyle: Invalid Key'
print pair[0]
styleData = styleData[1:]
# No end of style found, return style data as is
return style, None
def createBaselineStyleMenu(self, neighborhood, dictionary):
"""
Create a baseline style pie menu
"""
numItems = len(dictionary)
newStyleMenu = hidden.attachNewNode(neighborhood + '_style_menu')
radius = 0.7
angle = deg2Rad(360.0/numItems)
keys = dictionary.keys()
keys.sort()
styles = map(lambda x, d = dictionary: d[x], keys)
sf = 0.1
aspectRatio = (base.direct.dr.getWidth()/float(base.direct.dr.getHeight()))
for i in range(numItems):
# Get the node
node = self.createBaselineStyleSample(styles[i])
bounds = node.getBounds()
center = bounds.getCenter()
center = center * sf
# Reposition it
node.setPos((radius * math.cos(i * angle)) - center[0],
0.0,
((radius * aspectRatio * math.sin(i * angle)) -
center[2]))
# Scale it
node.setScale(sf)
# Add it to the styleMenu
node.reparentTo(newStyleMenu)
# Scale the whole shebang down by 0.5
newStyleMenu.setScale(0.5)
# Create and return a pie menu
return PieMenu(newStyleMenu, styles)
def createBaselineStyleSample(self, baselineStyle):
"""
Create a style sample using the DNA info in the style
"""
baseline = DNASignBaseline()
# Set some example text:
DNASetBaselineString(baseline, "Example Text")
baselineStyle.copyTo(baseline)
return baseline.traverse(hidden, DNASTORE, 1)
# WALL STYLE FUNCTIONS
def createWallStyleAttributes(self):
"""
Create a wallStyle entry in the attribute dictionary
This will be a dictionary of style attributes, one per neighborhood
"""
# First create an empty dictionary
dict = self.attributeDictionary['wall_style'] = {}
# Create a attribute object for each neighborhood
for neighborhood in self.NEIGHBORHOODS:
attribute = LevelAttribute('wall_style')
attribute.setDict(
# Create a wall style dictionary for each neighborhood
self.createWallStyleDictionary(neighborhood))
# Using this dictionary, create color pie menus
attribute.setMenu(
self.createWallStyleMenu(neighborhood, attribute.getDict()))
dict[neighborhood] = attribute
def createWallStyleDictionary(self, neighborhood):
"""
Create a dictionary of wall styles for a neighborhood
"""
filename = neighborhood + '_wall_styles.txt'
print 'Loading wall styles from: ' + filename
styleData = self.getStyleFileData(filename)
return self.initializeWallStyleDictionary(styleData, neighborhood)
def initializeWallStyleDictionary(self, styleData, neighborhood):
"""
Fill in the wall style dictionary with data from the style file
"""
styleDictionary = {}
styleCount = 0
code = self.NEIGHBORHOOD_CODES[neighborhood]
while styleData:
l = styleData[0]
if l == 'wallStyle':
# Start of new style, strip off first line then extract style
style, styleData = self.extractWallStyle(styleData)
style.name = code + '_wall_style_' + `styleCount`
# Store style in dictionary
styleDictionary[style.name] = style
styleCount = styleCount + 1
# Move to next line
styleData = styleData[1:]
return styleDictionary
def extractWallStyle(self, styleData):
"""
Pull out one style from a list of style data. Will keep
processing data until endWallStyle of end of data is reached.
Returns a wall style and remaining styleData.
"""
# Create default style
style = DNAWallStyle()
# Strip off first line
styleData = styleData[1:]
while styleData:
l = styleData[0]
if l == 'endWallStyle':
# End of style found, break out of while loop
# Note, endWallStyle line is *not* stripped off
return style, styleData
else:
pair = map(string.strip, l.split(':'))
if style.__dict__.has_key(pair[0]):
# Convert colors and count strings to numerical values
if ((string.find(pair[0],'_color') >= 0) or
(string.find(pair[0],'_count') >= 0)):
style[pair[0]] = eval(pair[1])
else:
style[pair[0]] = pair[1]
else:
print 'getStyleDictionaryFromStyleData: Invalid Key'
print pair[0]
styleData = styleData[1:]
# No end of style found, return style data as is
return style, None
def createWallStyleMenu(self, neighborhood, dictionary):
"""
Create a wall style pie menu
"""
numItems = len(dictionary)
newStyleMenu = hidden.attachNewNode(neighborhood + '_style_menu')
radius = 0.7
angle = deg2Rad(360.0/numItems)
keys = dictionary.keys()
keys.sort()
styles = map(lambda x, d = dictionary: d[x], keys)
sf = 0.03
aspectRatio = (base.direct.dr.getWidth()/float(base.direct.dr.getHeight()))
for i in range(numItems):
# Get the node
node = self.createWallStyleSample(styles[i])
bounds = node.getBounds()
center = bounds.getCenter()
center = center * sf
# Reposition it
node.setPos((radius * math.cos(i * angle)) - center[0],
0.0,
((radius * aspectRatio * math.sin(i * angle)) -
center[2]))
# Scale it
node.setScale(sf)
# Add it to the styleMenu
node.reparentTo(newStyleMenu)
# Scale the whole shebang down by 0.5
newStyleMenu.setScale(0.5)
# Create and return a pie menu
return PieMenu(newStyleMenu, styles)
def createWallStyleSample(self, wallStyle):
"""
Create a style sample using the DNA info in the style
"""
bldg = DNAFlatBuilding()
bldgStyle = DNAFlatBuildingStyle(styleList = [(wallStyle, 10.0)])
self.setDNAFlatBuildingStyle(bldg, bldgStyle, width = 12.0,
name = 'wall_style_sample')
return bldg.traverse(hidden, DNASTORE, 1)
# BUILDING STYLE FUNCTIONS
def createBuildingStyleAttributes(self):
"""
Create a buildingStyle entry in the attribute dictionary
This will be a dictionary of style attributes, one per neighborhood
This information is sorted and stored by num walls, building height,
and building type (e.g. 10_20, or 10_10_10).
"""
# First create an attribute which holds one dictionary per
# neighborhood which stores all of the styles for each neighborhood.
styleDict = self.attributeDictionary['building_style_all'] = {}
# Keep track of all building types
typeDict = {}
masterTypeList = []
for neighborhood in self.NEIGHBORHOODS:
attribute = LevelAttribute('building_style_all')
# Create a building style dictionary for each neighborhood
attribute.setDict(
self.createBuildingStyleDictionary(neighborhood))
# Using this dictionary, create building style pie menus
attribute.setMenu(
self.createBuildingStyleMenu(neighborhood,
attribute.getDict()))
# Store attribute in dictionary keyed by neighborhood
styleDict[neighborhood] = attribute
# Generate a list of building types for this neighborhood
# and a list of building types for all neighborhoods,
# to be used in creating attribute dicts below
typeList = typeDict[neighborhood] = []
for style in attribute.getList():
heightType = string.strip(string.split(style.name, ':')[1])
if heightType not in typeList:
typeList.append(heightType)
if heightType not in masterTypeList:
masterTypeList.append(heightType)
# Now sort styles according to the building type and number of walls
# in the building style. Each of these attributes is also sorted by
# neighborhood
for i in masterTypeList:
typeKey = i + '_styles'
self.attributeDictionary[typeKey] = {}
for i in NUM_WALLS:
numWallKey = `i` + '_wall_styles'
self.attributeDictionary[numWallKey] = {}
# Also sort height lists according to total height of the building
for i in BUILDING_HEIGHTS:
heightKey = `i` + '_ft_wall_heights'
self.attributeDictionary[heightKey] = {}
# Now distribute data for each neighborhood
for neighborhood in self.NEIGHBORHOODS:
# Create temp dicts to accumulate styles and heights for that
# neighborhood
typeAttributes = {}
numWallsAttributes = {}
heightAttributes = {}
# Store atributes for the different categories
# Building type
for i in typeDict[neighborhood]:
typeAttrName = neighborhood + '_' + i + '_styles'
typeAttributes[i] = LevelAttribute(typeAttrName)
# Number of walls
for i in NUM_WALLS:
styleAttrName = neighborhood + '_' + `i` + '_wall_styles'
numWallsAttributes[i] = LevelAttribute(styleAttrName)
# Building height
for i in BUILDING_HEIGHTS:
heightAttrName = neighborhood + '_' + `i` + '_ft_wall_heights'
heightAttributes[i] = LevelAttribute(heightAttrName)
# Sort through the styles and store in separate lists
for style in styleDict[neighborhood].getList():
# Put in code for number of walls into building styles
heightType = string.strip(string.split(style.name, ':')[1])
heightList = map(string.atof, string.split(heightType, '_'))
numWalls = len(heightList)
# This one stores styles sorted by type
typeAttributes[heightType].add(style)
# This one stores styles sorted by number of walls
numWallsAttributes[numWalls].add(style)
# A record of all the unique height lists
height = calcHeight(heightList)
if heightList not in heightAttributes[height].getList():
heightAttributes[height].add(heightList)
# Now store these sorted style and height attributes
# in the appropriate top-level attribute dictionary
for i in typeDict[neighborhood]:
# Styles
typeKey = i + '_styles'
self.attributeDictionary[typeKey][neighborhood] = (
typeAttributes[i])
for i in NUM_WALLS:
# Styles
numWallKey = `i` + '_wall_styles'
self.attributeDictionary[numWallKey][neighborhood] = (
numWallsAttributes[i])
for i in BUILDING_HEIGHTS:
# Heights
heightKey = `i` + '_ft_wall_heights'
self.attributeDictionary[heightKey][neighborhood] = (
heightAttributes[i])
def createBuildingStyleDictionary(self, neighborhood):
"""
Create a dictionary of wall styles for a neighborhood
"""
filename = neighborhood + '_building_styles.txt'
print 'Loading building styles from: ' + filename
styleData = self.getStyleFileData(filename)
return self.initializeBuildingStyleDictionary(styleData, neighborhood)
def initializeBuildingStyleDictionary(self, styleData, neighborhood):
"""
Fill in the building style dictionary with data from the style file
"""
# Create a dictionary of all building styles, this will later be
# split out into a separate dictionary for each building type
# e.g. 20, 10-10, 10-20....
bldgStyleDictionary = {}
styleCount = 0
code = self.NEIGHBORHOOD_CODES[neighborhood]
while styleData:
# Pull out first line
l = styleData[0]
if l[:13] == 'buildingStyle':
# Start with empty style list
bldgStyle = DNAFlatBuildingStyle(styleList = [])
# Extract height information found at end of line
heightCode = string.strip(string.split(l, ':')[1])
heightList = map(string.atof, string.split(heightCode, '_'))
# Construct name for building style. Tack on height code
# to be used later to split styles by heightCode
bldgStyle.name = (
code + '_building_style_' + `styleCount` +
':' + heightCode)
# Increment counter
styleCount = styleCount + 1
# Reset wall counter to zero
wallCount = 0
elif l == 'endBuildingStyle':
# Done, add new style to dictionary
bldgStyleDictionary[bldgStyle.name] = bldgStyle
elif l[:9] == 'wallStyle':
# Beginning of next wall style
wallStyle, styleData = self.extractWallStyle(styleData)
wallStyle.name = bldgStyle.name + '_wall_' + `wallCount`
try:
height = heightList[wallCount]
except IndexError:
height = 10.0
# Add wall style to building style
bldgStyle.add(wallStyle, height)
# Increment wall counter
wallCount = wallCount + 1
# Move to next line
styleData = styleData[1:]
return bldgStyleDictionary
def createBuildingStyleMenu(self, neighborhood, dictionary):
"""
Create a wall style pie menu
"""
numItems = len(dictionary)
newStyleMenu = hidden.attachNewNode(neighborhood + '_style_menu')
radius = 0.7
angle = deg2Rad(360.0/numItems)
keys = dictionary.keys()
keys.sort()
styles = map(lambda x, d = dictionary: d[x], keys)
sf = 0.02
aspectRatio = (base.direct.dr.getWidth()/float(base.direct.dr.getHeight()))
for i in range(numItems):
# Get the node
node = self.createBuildingStyleSample(styles[i])
bounds = node.getBounds()
center = bounds.getCenter()
center = center * sf
# Reposition it
node.setPos((radius * math.cos(i * angle)) - center[0],
0.0,
((radius * aspectRatio * math.sin(i * angle)) -
center[2]))
# Scale it
node.setScale(sf)
# Add it to the styleMenu
node.reparentTo(newStyleMenu)
# Scale the whole shebang down by 0.5
newStyleMenu.setScale(0.5)
# Create and return a pie menu
return PieMenu(newStyleMenu, styles)
def createBuildingStyleSample(self, bldgStyle):
"""
Create a style sample using the DNA info in the style
"""
bldg = DNAFlatBuilding()
self.setDNAFlatBuildingStyle(bldg, bldgStyle, width = 10.0,
name = 'building_style_sample')
return bldg.traverse(hidden, DNASTORE, 1)
def setDNAFlatBuildingStyle(self, fb, bldgStyle, width = 10.0,
heightList = None, name = 'building'):
""" Set DNAFlatBuilding style. """
# Remove flat building's children
DNARemoveChildren(fb)
# Update the name
fb.setName(name)
# Create the walls
styleList = bldgStyle.styleList
# Height list not specified, use styles default heights
if not heightList:
heightList = bldgStyle.heightList
for i in range(len(styleList)):
wallStyle = styleList[i]
# Get Style
if not wallStyle:
# If set to None use default style
wallStyle = DNAWallStyle()
# Try to get height
try:
wallHeight = heightList[i]
except IndexError:
wallHeight = 10.0
# Create wall accordingly
wall = DNAWall()
self.setDNAWallStyle(wall, wallStyle, wallHeight,
width = width)
# Add it to building DNA
fb.add(wall)
# Set the buildings width
fb.setWidth(width)
def setDNAWallStyle(self, wall, style, height = 10.0, width = None):
""" Set DNAWall to input style. """
# Remove wall's children
DNARemoveChildren(wall)
# Update wall attributes
wall.setCode(style['wall_texture'])
wall.setColor(style['wall_color'])
wall.setHeight(height)
# Add windows if necessary
if style['window_texture']:
windows = DNAWindows()
windowCount = style['window_count']
if width:
if (width < 15.0):
windowCount = min(1, windowCount)
windows.setWindowCount(windowCount)
# Set window's attributes
windows.setCode(style['window_texture'])
windows.setColor(style['window_color'])
# Add windows to the wall
wall.add(windows)
# Add a window awning if necessary
if style['window_awning_texture']:
awning = DNAProp()
# Update awning's attributes
awning.setCode(style['window_awning_texture'])
awning.setColor(style['window_awning_color'])
# Add awning to window
windows.add(awning)
# Add a door if necessary
if style['door_texture']:
door = DNAFlatDoor()
# Set the door's attributes
door.setCode(style['door_texture'])
door.setColor(style['door_color'])
# Add door to wall
wall.add(door)
# Add a door awning if necessary
if style['door_awning_texture']:
awning = DNAProp()
awning.setCode(style['door_awning_texture'])
awning.setColor(style['door_awning_color'])
door.add(awning)
# And a cornice if necessary
if style['cornice_texture']:
cornice = DNACornice()
# Set the cornice's attributes
cornice.setCode(style['cornice_texture'])
cornice.setColor(style['cornice_color'])
# Add cornice to wall
wall.add(cornice)
def printFlatBuildingStyle(self, building):
for i in range(building.getNumChildren()):
child = building.at(i)
if DNAClassEqual(child, DNA_WALL):
self.printWallStyle(child)
def printWallStyle(self, wall):
print 'wall_texture: ' + wall.getCode()
color = wall.getColor()
print ('wall_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
(color[0], color[1], color[2]))
for i in range(wall.getNumChildren()):
child = wall.at(i)
if DNAClassEqual(child, DNA_WINDOWS):
print 'window_texture: ' + child.getCode()
color = child.getColor()
print ('window_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
(color[0], color[1], color[2]))
# MRM: Check for awnings here
elif DNAClassEqual(child, DNA_DOOR):
print 'door_texture: ' + child.getCode()
color = child.getColor()
print ('door_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
(color[0], color[1], color[2]))
elif DNAClassEqual(child, DNA_FLAT_DOOR):
print 'door_texture: ' + child.getCode()
color = child.getColor()
print ('door_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
(color[0], color[1], color[2]))
elif DNAClassEqual(child, DNA_CORNICE):
print 'cornice_texture: ' + child.getCode()
color = child.getColor()
print ('cornice_color: Vec4(%.3f, %.3f, %.3f, 1.0)' %
(color[0], color[1], color[2]))
# COLOR PALETTE FUNCTIONS
def createColorAttributes(self):
# First compile color information for each neighborhood
colorDictionary = {}
colorMenuDictionary = {}
for neighborhood in self.NEIGHBORHOODS:
colorDictionary[neighborhood] = (
# Create a wall style dictionary for each neighborhood
self.createColorDictionary(neighborhood))
# Using this dictionary, create color pie menus
colorMenuDictionary[neighborhood] = (
self.createColorMenus(
neighborhood, colorDictionary[neighborhood]))
# Now store this info in the appropriate place in the attribute dict
for colorType in COLOR_TYPES:
neighborhoodDict = self.attributeDictionary[colorType] = {}
for neighborhood in self.NEIGHBORHOODS:
attribute = LevelAttribute(colorType)
dict = {}
# Add colors to attribute dictionary
colorList = colorDictionary[neighborhood][colorType]
for i in range(len(colorList)):
dict[i] = colorList[i]
attribute.setDict(dict)
attribute.setMenu(
colorMenuDictionary[neighborhood][colorType])
neighborhoodDict[neighborhood] = attribute
def createColorDictionary(self, neighborhood):
filename = neighborhood + '_colors.txt'
print 'Loading Color Palettes from: ' + filename
colorData = self.getStyleFileData(filename)
return self.getColorDictionary(colorData)
def getColorDictionary(self, colorData):
# Initialze neighborhod color dictionary
dict = {}
for colorType in COLOR_TYPES:
dict[colorType] = DEFAULT_COLORS[:]
# Add color information to appropriate sub-list
for line in colorData:
pair = map(string.strip, line.split(':'))
key = pair[0]
if dict.has_key(key):
dict[key].append(eval(pair[1]))
else:
print 'LevelStyleManager.getColorDictionary key not found'
return dict
def createColorMenus(self, neighborhood, dictionary):
menuDict = {}
keys = dictionary.keys()
for key in keys:
menuDict[key] = (
self.createColorMenu(neighborhood + key, dictionary[key]))
return menuDict
def createColorMenu(self, menuName, colorList, radius = 0.7, sf = 2.0):
# Create color chips for each color
numItems = len(colorList)
# Attach it to hidden for now
newColorMenu = hidden.attachNewNode(menuName + 'Menu')
# Compute the angle per item
angle = deg2Rad(360.0/float(numItems))
aspectRatio = (base.direct.dr.getWidth() / float(base.direct.dr.getHeight()))
# Attach the color chips to the new menu and adjust sizes
for i in range (numItems):
# Create a text node--just a card, really--of the right color.
tn = TextNode('colorChip')
tn.setFont(DGG.getDefaultFont())
tn.setTransform(Mat4.scaleMat(0.07, 0.07, 0.07 * aspectRatio))
tn.setCardColor(colorList[i])
tn.setCardActual(0, 1.1111, 0, 0.8333)
tn.setText(' ')
# Reposition it
card = tn.getCardTransformed()
center = (card[1] - card[0], card[3] - card[2])
node = newColorMenu.attachNewNode(tn)
node.setScale(sf)
node.setPos(radius * math.cos(i * angle) - center[0], 0.0,
((radius * aspectRatio * math.sin(i * angle)) -
center[1]))
# Scale the whole shebang down by 0.5
newColorMenu.setScale(0.5)
# Create and return resulting pie menu
return PieMenu(newColorMenu, colorList)
# DNA ATTRIBUTES
def createDNAAttributes(self):
# Create the DNA Attribute entries
# Most objects are oriented with graphical menu items
# Street and props aren't oiented and use text menus
for dnaType in DNA_TYPES:
# Create a dictionary of dna types
dict = {}
if ((dnaType == 'street') or (dnaType == 'prop') or
(dnaType == 'toon_landmark')):
dnaList = self.getCatalogCodes(dnaType)
if dnaType == 'prop':
dnaList = dnaList + self.getCatalogCodes('holiday_prop')
elif (dnaType == 'sign'):
dnaList = [''] + self.getCatalogCodes(dnaType)
elif (dnaType == 'wall'):
# Add in suit walls here for now
dnaList = ([None] +
self.getCatalogCodesSuffix(dnaType, '_ur') +
self.getCatalogCodesSuffix('suit_wall', '_ur'))
else:
dnaList = [None] + self.getCatalogCodesSuffix(dnaType, '_ur')
# Add dnaCodes to attribute dictionary
for i in range(len(dnaList)):
dict[i] = dnaList[i]
# Create a LevelAttribute
attribute = LevelAttribute(dnaType + '_texture')
attribute.setDict(dict)
# Prepend None to allow option of no item
if ((dnaType == 'street') or (dnaType == 'prop') or
(dnaType == 'toon_landmark')):
# attribute.setMenu(self.createTextPieMenu(dnaType, dnaList))
attribute.setMenu(self.createScrollMenu(dnaType, dnaList))
attribute.getMenu().createScrolledList()
elif (dnaType == 'wall'):
attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
sf = 0.25))
elif (dnaType == 'sign'):
attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
sf = 0.05))
elif (dnaType == 'door_double'):
attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
sf = 0.035))
elif (dnaType == 'door_single'):
attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
sf = 0.035))
elif (dnaType == 'cornice'):
attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
sf = 0.5))
elif (dnaType == 'window'):
attribute.setMenu(self.createDNAPieMenu(dnaType, dnaList,
sf = 0.125))
else:
print 'unknown attribute'
# Add it to the attributeDictionary
self.attributeDictionary[dnaType + '_texture'] = attribute
def createDNAPieMenu(self, dnaType, dnaList, radius = 0.7, sf = 1.0):
# Get the currently available window options
numItems = len(dnaList)
# Create a top level node to hold the menu
newMenu = hidden.attachNewNode(dnaType + 'Menu')
# Compute angle increment per item
angle = deg2Rad(360.0/numItems)
aspectRatio = base.direct.dr.getWidth() /float(base.direct.dr.getHeight())
# Add items
for i in range(0, numItems):
if dnaList[i]:
# Get the node
node = DNASTORE.findNode(dnaList[i])
else:
node = None
if node:
# Add it to the window menu
# This instance was causing problems for dna nodes that were
# loaded as singletons, so I changed it to copyTo.
# path = node.instanceTo(newMenu)
path = node.copyTo(newMenu)
# Place menu nodes in a circle, offset each in X and Z
# by half node width/height
bounds = path.getBounds()
center = bounds.getCenter()
center = center * sf
path.setPos((radius * math.cos(i * angle)) - center[0],
0.0,
((radius * aspectRatio * math.sin(i * angle)) -
center[2]))
path.setScale(sf)
# Scale the whole shebang down by 0.5
newMenu.setScale(0.5)
# Create and return a pie menu
return PieMenu(newMenu, dnaList)
def createTextPieMenu(self, dnaType, textList, radius = 0.7, sf = 1.0):
numItems = len(textList)
# Create top level node for new menu
newMenu = hidden.attachNewNode(dnaType + 'Menu')
# Compute angle per item
if numItems == 0:
angle = 0.0
else:
angle = deg2Rad(360.0/numItems)
aspectRatio = base.direct.dr.getWidth()/float(base.direct.dr.getHeight())
# Add items
for i in range (numItems):
# Create text node for each item
if (textList[i] != None):
tn = TextNode('TextItem')
tn.setFont(DGG.getDefaultFont())
tn.setTransform(Mat4.scaleMat(0.07, 0.07, 0.07 * aspectRatio))
tn.setTextColor(0, 0, 0, 1)
tn.setCardColor(1, 1, 1, 1)
tn.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
tn.setText(str(textList[i]))
# Reposition it
card = tn.getCardTransformed()
center = (card[1] - card[0], card[3] - card[2])
node = newMenu.attachNewNode(tn)
node.setScale(sf)
node.setPos(radius * math.cos(i * angle) - center[0], 0.0,
((radius * aspectRatio * math.sin(i * angle)) -
center[1]))
# Scale the whole shebang down by 0.5
newMenu.setScale(0.5)
# Create and return a pie menu
return PieMenu(newMenu, textList)
def createScrollMenu(self, dnaType, textList):
newMenu = hidden.attachNewNode(dnaType+'ScrollMenu')
return ScrollMenu(newMenu, textList)
# MISCELLANEOUS MENUS
def createMiscAttributes(self):
# Num windows menu
self.createMiscAttribute('window_count', [0, 1, 2, 3, 4])
# Building width menu
self.createMiscAttribute('building_width', [5, 10, 15, 15.6, 20, 20.7, 25])
# Building types
self.createMiscAttribute('building_type', BUILDING_TYPES)
# Building heights
self.createMiscAttribute('building_height', [10, 14, 20, 24, 25, 30])
# MRM: Need offset on these menus
# Wall orientation menu
self.createMiscAttribute('wall_orientation', ['ur','ul','dl','dr'])
# Wall height menu
self.createMiscAttribute('wall_height', [10, 20])
# Window orientation menu
self.createMiscAttribute('window_orientation', ['ur','ul', None, None])
# Sign orientation menu
self.createMiscAttribute('sign_orientation', ['ur','ul', None, None])
# Door orientation menu
self.createMiscAttribute('door_orientation', ['ur','ul', None, None])
# Cornice orientation menu
self.createMiscAttribute('cornice_orientation', ['ur','ul', None, None])
def createMiscAttribute(self, miscType, miscList, sf = 3.0):
# Create a dictionary from miscList
dict = {}
# Add items to attribute dictionary
for i in range(len(miscList)):
dict[i] = miscList[i]
# Create the miscellaneous Attribute entries
attribute = LevelAttribute(miscType)
attribute.setDict(dict)
# Now create a pie menu
attribute.setMenu(self.createTextPieMenu(miscType, miscList,
sf = sf))
# Add it to the attributeDictionary
self.attributeDictionary[miscType] = attribute
# GENERAL FUNCTIONS
def getStyleFileData(self, filename):
"""
Open the specified file and strip out unwanted whitespace and
empty lines. Return file as list, one file line per element.
"""
fname = Filename(dnaDirectory.getFullpath() +
'/stylefiles/' + filename)
# We use binary mode to avoid Windows' end-of-line convention
f = open(fname.toOsSpecific(), 'rb')
rawData = f.readlines()
f.close()
styleData = []
for line in rawData:
l = string.strip(line)
if l:
styleData.append(l)
return styleData
# UTILITY FUNCTIONS
def getAttribute(self, attribute):
""" Return specified attribute for current neighborhood """
levelAttribute = self.attributeDictionary[attribute]
# Get attribute for current neighborhood
if (type(levelAttribute) == types.DictionaryType):
levelAttribute = levelAttribute[self.getEditMode()]
return levelAttribute
# UTILITY FUNCTIONS
def hasAttribute(self, attribute):
""" Return specified attribute for current neighborhood """
if not self.attributeDictionary.has_key(attribute):
return 0
else:
levelAttribute = self.attributeDictionary[attribute]
# Get attribute for current neighborhood
if (type(levelAttribute) == types.DictionaryType):
editMode = self.getEditMode()
return levelAttribute.has_key(editMode)
else:
return 1
def getCatalogCode(self, category, i):
return DNASTORE.getCatalogCode(category, i)
def getCatalogCodes(self, category):
numCodes = DNASTORE.getNumCatalogCodes(category)
codes = []
for i in range(numCodes):
codes.append(DNASTORE.getCatalogCode(category, i))
return codes
def getCatalogCodesSuffix(self, category, suffix):
codes = self.getCatalogCodes(category)
orientedCodes = []
for code in codes:
if code[-3:] == suffix:
orientedCodes.append(code)
return orientedCodes
def setEditMode(self, mode):
"""Set current neighborhood editing mode"""
self._editMode = mode
def getEditMode(self):
"""Get current neighborhood editing mode"""
return self._editMode
class LevelAttribute:
"""Class which encapsulates a pie menu and a set of items"""
def __init__(self, name):
# Record name
self.name = name
# Pie menu used to pick an option
self._menu = None
# Dictionary of available options
self._dict = {}
self._list = []
self.count = 0
# Currently selected option
self._current = None
def setCurrent(self, newValue, fEvent = 1):
self._current = newValue
# Send event if specified
if fEvent:
messenger.send('select_' + self.name, [self._current])
def setMenu(self, menu):
self._menu = menu
self._menu.action = self.setCurrent
def setDict(self, dict):
self._dict = dict
# Create a list from the dictionary
self._list = dict.values()
# Update count
self.count = len(self._list)
# Initialize current to first item
if (len(self._list) > 0):
self._current = self._list[0]
def setList(self, list):
self._list = list
# Create a dictionary from the list
self._dict = {}
self.count = 0
for item in list:
self._dict[self.count] = item
self.count += 1
# Initialize current to first item
if (self.count > 0):
self._current = self._list[0]
def add(self, item):
self._dict[self.count] = item
self._list.append(item)
self.count += 1
def getCurrent(self):
return self._current
def getMenu(self):
return self._menu
def getDict(self):
return self._dict
def getList(self):
return self._list
def getCount(self):
return self.count
class DNAFlatBuildingStyle:
"""Class to hold attributes of a building style"""
def __init__(self, building = None, styleList = None, name = 'bldg_style'):
self.name = name
if building:
# Passed in a building
self.copy(building)
elif styleList != None:
# Passed in a list of style-height pairs
self.styleList = []
self.heightList = []
self.numWalls = 0
for pair in styleList:
self.add(pair[0], pair[1])
else:
# Use default style/height
self.styleList = [DNAWallStyle()]
self.heightList = [10]
self.numWalls = 1
def add(self, style, height):
self.styleList.append(style)
self.heightList.append(height)
self.numWalls += 1
def copy(self, building):
self.styleList = []
self.heightList = DNAGetWallHeights(building)[0]
self.numWalls = 0
for i in range(building.getNumChildren()):
child = building.at(i)
if DNAClassEqual(child, DNA_WALL):
wallStyle = DNAWallStyle(wall = child)
self.styleList.append(wallStyle)
self.numWalls += 1
def output(self, file = sys.stdout):
file.write('buildingStyle: %s\n' % createHeightCode(self.heightList))
for style in self.styleList:
style.output(file)
file.write('endBuildingStyle\n')
def createHeightCode(heightList):
def joinHeights(h1, h2):
return '%s_%s' % (h1, h2)
hl = map(ROUND_INT, heightList)
if len(hl) == 1:
return `hl[0]`
return reduce(joinHeights, hl)
def calcHeight(heightList):
height = 0
for h in heightList:
height = height + h
return int(height)
class DNABaselineStyle:
"""Class to hold attributes of a baseline style (wiggle, colors, etc)"""
def __init__(self, baseline = None, name = 'baseline_style'):
# First initialize everything
self.name = name
self.code = None # i.e. font
self.kern = None
self.wiggle = None
self.stumble = None
self.stomp = None
self.curve = None
self.x = None
self.z = None
self.scaleX = 1.0
self.scaleZ = 1.0
self.roll = None
self.flags = None
self.color = Vec4(1.0)
# Then copy the specifics for the baseline if input
if baseline:
self.copy(baseline)
def copy(self, baseline):
self.code = baseline.getCode()
self.kern = baseline.getKern()
self.wiggle = baseline.getWiggle()
self.stumble = baseline.getStumble()
self.stomp = baseline.getStomp()
width=baseline.getWidth()
if width:
self.curve = 1.0/width
else:
self.curve = 0.0
pos = baseline.getPos()
self.x = pos[0]
self.z = pos[2]
scale = baseline.getScale()
self.scaleX = scale[0]
self.scaleZ = scale[2]
hpr = baseline.getHpr()
self.roll = hpr[2]
self.flags = baseline.getFlags()
self.color = baseline.getColor()
def copyTo(self, baseline):
if self.code != None:
baseline.setCode(self.code)
if self.kern != None:
baseline.setKern(self.kern)
if self.wiggle != None:
baseline.setWiggle(self.wiggle)
if self.stumble != None:
baseline.setStumble(self.stumble)
if self.stomp != None:
baseline.setStomp(self.stomp)
if self.curve != None:
diameter=0.0
if self.curve:
diameter=1.0/self.curve
baseline.setWidth(diameter)
baseline.setHeight(diameter)
if (self.x != None) or (self.z != None):
pos=baseline.getPos()
if self.x != None:
pos=Vec3(self.x, pos[1], pos[2])
if self.z != None:
pos=Vec3(pos[0], pos[1], self.z)
baseline.setPos(pos)
if self.roll != None:
baseline.setHpr(Vec3(0.0, 0.0, self.roll))
if (self.scaleX != None) or (self.scaleZ != None):
scale=baseline.getScale()
if self.scaleX != None:
scale=Vec3(self.scaleX, scale[1], scale[2])
if self.scaleZ != None:
scale=Vec3(scale[0], scale[1], self.scaleZ)
baseline.setScale(scale)
if self.flags != None:
baseline.setFlags(self.flags)
if self.color != None:
baseline.setColor(self.color)
def output(self, file = sys.stdout):
""" Output style description to a file """
file.write('baselineStyle\n')
if self.name != None:
file.write('name: %s\n' % self.name)
if self.code != None:
file.write('code: %s\n' % self.code)
if self.kern != None:
file.write('kern: %s\n' % self.kern)
if self.wiggle != None:
file.write('wiggle: %s\n' % self.wiggle)
if self.stumble != None:
file.write('stumble: %s\n' % self.stumble)
if self.stomp != None:
file.write('stomp: %s\n' % self.stomp)
if self.curve != None:
file.write('curve: %s\n' % self.curve)
if self.x != None:
file.write('x: %s\n' % self.x)
if self.z != None:
file.write('z: %s\n' % self.z)
if self.scaleX != None:
file.write('scaleX: %s\n' % self.scaleX)
if self.scaleZ != None:
file.write('scaleZ: %s\n' % self.scaleZ)
if self.roll != None:
file.write('roll: %s\n' % self.roll)
if self.flags != None:
file.write('flags: %s\n' % self.flags)
if self.color != None:
file.write('color: Vec4(%.2f, %.2f, %.2f, 1.0)\n'
% (self.color[0], self.color[1], self.color[2]))
file.write('endBaselineStyle\n')
# Convience functions to facilitate class use
def __setitem__(self, index, item):
self.__dict__[index] = item
def __getitem__(self, index):
return self.__dict__[index]
def __repr__(self):
return(
'name: %s\n' % self.name +
'code: %s\n' % self.code +
'kern: %s\n' % self.kern +
'wiggle: %s\n' % self.wiggle +
'stumble: %s\n' % self.stumble +
'stomp: %s\n' % self.stomp +
'curve: %s\n' % self.curve +
'x: %s\n' % self.x +
'z: %s\n' % self.z +
'scaleX: %s\n' % self.scaleX +
'scaleZ: %s\n' % self.scaleZ +
'roll: %s\n' % self.roll +
'flags: %s\n' % self.flags +
'color: %s\n' % self.color
)
class DNAWallStyle:
"""Class to hold attributes of a wall style (textures, colors, etc)"""
def __init__(self, wall = None, name = 'wall_style'):
# First initialize everything
self.name = name
self.wall_texture = 'wall_md_blank_ur'
self.wall_color = Vec4(1.0)
self.window_count = 2
self.window_texture = None
self.window_color = Vec4(1.0)
self.window_awning_texture = None
self.window_awning_color = Vec4(1.0)
self.door_texture = None
self.door_color = Vec4(1.0)
self.door_awning_texture = None
self.door_awning_color = Vec4(1.0)
self.cornice_texture = None
self.cornice_color = Vec4(1.0)
# Then copy the specifics for the wall if input
if wall:
self.copy(wall)
def copy(self, wall):
self.wall_texture = wall.getCode()
self.wall_color = wall.getColor()
for i in range(wall.getNumChildren()):
child = wall.at(i)
if DNAClassEqual(child, DNA_WINDOWS):
self.window_count = child.getWindowCount()
self.window_texture = child.getCode()
self.window_color = child.getColor()
# MRM: Check for awnings here
elif DNAClassEqual(child, DNA_DOOR):
self.door_texture = child.getCode()
self.door_color = child.getColor()
elif DNAClassEqual(child, DNA_FLAT_DOOR):
self.door_texture = child.getCode()
self.door_color = child.getColor()
# MRM: Check for awnings here
elif DNAClassEqual(child, DNA_CORNICE):
self.cornice_texture = child.getCode()
self.cornice_color = child.getColor()
def output(self, file = sys.stdout):
""" Output style description to a file """
def writeAttributes(f, type, s = self):
color = s[type + '_color']
f.write('%s_texture: %s\n' % (type, s[type + '_texture']))
f.write('%s_color: Vec4(%.2f, %.2f, %.2f, 1.0)\n' %
(type, color[0], color[1], color[2]))
file.write('wallStyle\n')
writeAttributes(file, 'wall')
if self['window_texture']:
writeAttributes(file, 'window')
file.write('window_count: %s\n' % self['window_count'])
if self['window_awning_texture']:
writeAttributes(file, 'window_awning')
if self['door_texture']:
writeAttributes(file, 'door')
if self['door_awning_texture']:
writeAttributes(file, 'door_awning')
if self['cornice_texture']:
writeAttributes(file, 'cornice')
file.write('endWallStyle\n')
# Convience functions to facilitate class use
def __setitem__(self, index, item):
self.__dict__[index] = item
def __getitem__(self, index):
return self.__dict__[index]
def __repr__(self):
return(
'Name: %s\n' % self.name +
'Wall Texture: %s\n' % self.wall_texture +
'Wall Color: %s\n' % self.wall_color +
'Window Texture: %s\n' % self.window_texture +
'Window Color: %s\n' % self.window_color +
'Window Awning Texture: %s\n' % self.window_awning_texture +
'Window Awning Color: %s\n' % self.window_awning_color +
'Door Texture: %s\n' % self.door_texture +
'Door Color: %s\n' % self.door_color +
'Door Awning Texture: %s\n' % self.door_awning_texture +
'Door Awning Color: %s\n' % self.door_awning_color +
'Cornice Texture: %s\n' % self.cornice_texture +
'Cornice Color: %s\n' % self.cornice_color
)