|
@@ -0,0 +1,1558 @@
|
|
|
|
|
+import sys, string, math, types
|
|
|
|
|
+from pandac.PandaModules import *
|
|
|
|
|
+import direct.gui.DirectGuiGlobals as DGG
|
|
|
|
|
+
|
|
|
|
|
+from PieMenu 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))
|
|
|
|
|
+ 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)
|
|
|
|
|
+
|
|
|
|
|
+ # 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
|
|
|
|
|
+ )
|