view utils/frminfo/make_xml.py @ 105:2241b0d5379e

use strings as grouping in generic renderer, easier for the clients...
author spq@33b003aa-7bff-0310-803a-e67f0ece8222
date Thu, 24 Jul 2008 13:20:39 +0000
parents 4a0efb7baf70
children
line wrap: on
line source

#! /usr/bin/env python
import os,sys,string
SUFFIX_LIST = [ "aa","ab","at","ae","ak","al","an","ao","ap","ar","as","aq" ]
IDLE,WALK,RUN,CLIMB,PICKUP,USE,DODGE,HITFRONT,HITBACK,KICK,THROW,PUNCH =  range(len(SUFFIX_LIST))
ACTION_IDS = range(len(SUFFIX_LIST))
ACTION_NAMES = [
"IDLE","WALK","RUN","CLIMB","PICKUP","USE","DODGE","HITFRONT","HITBACK","KICK","THROW","PUNCH"
]
SUFFIX_DICT = dict(zip(SUFFIX_LIST,ACTION_IDS))

USAGE="""
*** make_xml.py ***
Generates XML Critter information from frm info in critter.dat
--list			List all critters
--to-xml CRITTER	Output XML generated for a critter CRITTER
			into a file in the current directory
--all-xml DIRECTORY	Output XML files for all critters in the list
			into the directory DIRECTORY
"""

CRITTER_XML = string.Template("""\
<!--
	This is an auto-generated XML file
	defining the animation actions a
	critter can perform.
	
	Generator: make_xml.py
-->
<complex-animation name="$name" geometry="1">
$actions
</complex-animation>""")

ACTION_XML = string.Template("""\
	<!-- ACTION: $name FRAMES: $numFrames FPS: $fps -->
	<action id="$id" direction="255">
		<animation src="$filename"/>
$partialActions
	</action>
""")

PARTIAL_ACTION_XML=string.Template("""\
		<partial-action number="$number">
			<frames start="$startFrame" number="$endFrame"/>
			<step number="$stepNumber"/>
			<partial-action action="$nextActionId" number="$nextNumber" direction="255"/>
		</partial-action>
""")

MOTION_XML = string.Template("""\
		<motion distance="$distance"/>
""")

class Action(object):
	def __init__(self,critter,suffix):
		self.critter = critter
		self.suffix = suffix
		self.id = SUFFIX_DICT[ suffix ]
		self.filename = "art/critters/" + self.critter.basename + self.suffix +".frm"
		self.frminfo_parsed = False
		
	def __str__(self):
		if self.frminfo_parsed:
			return self.suffix + "[nframes="+str(self.numframes)+",fps="+str(self.fps)+"]"
		return self.suffix + "[id="+str(self.id)+"]"
	
	def parseFrmInfo(self):
		if self.frminfo_parsed: 
			return
		frminfo = os.popen("./frminfo -t " + self.filename).read()
		print >> sys.stderr, "Parsing FRMINFO: ",self.filename
		frminfo = [tuple(line.replace(" ","").split("=")) for line in frminfo.split("\n")[:-1]]
		values = dict(frminfo)
		self.numframes = int(values['num_frames'])
		self.fps = int(values['frames_per_second'])
		self.shiftx = int(values["shift_xy"].split(',')[0])
		self.frminfo_parsed = True
	def measureDistance(self):
		cmd ="./frminfo -t " +self.filename + " -i " + str(self.numframes-1)+ " -d 1"
		frminfo = os.popen(cmd).read()
		frminfo = [tuple(line.replace(" ","").split("=")) for line in frminfo.split("\n")[:-1]]
		values = dict(frminfo)
		x,y = map(int,values["shift_xy"].split(","))
		distance = (x - self.shiftx+ 16) / 32
		print >> sys.stderr, ACTION_NAMES[self.id],"distance:",distance
		return distance
		
	def generatePartialActions(self,actionId):
		partialActions = ""
		npas=1
		if actionId in  [WALK,RUN]:
			npas = self.measureDistance()
			partialActions += MOTION_XML.substitute(distance=npas)
			
		if npas==0:
			npas=1
			
		delta = (self.numframes/npas)
		startFrame=0
		endFrame = delta 
		nextActionId = actionId	
		for number in range(npas):
			nextNumber = (number+1) % npas
			stepNumber=number
			partialActions += PARTIAL_ACTION_XML.safe_substitute(locals())
			startFrame += delta
		return partialActions
		
	def buildXML(self):
		#if self.id not in [RUN,WALK]: return ""
		self.parseFrmInfo()
		id = self.id
		name = ACTION_NAMES[id]
		fps = self.fps
		numFrames = self.numframes
		filename = self.filename
		partialActions = self.generatePartialActions(id)
		return ACTION_XML.safe_substitute(locals())
		
class Critter(object):
	def __init__(self,basename):
		self.basename = basename
		self.actions = {}
		self.xml=""
	def __str__(self):
		return self.basename +"("+",".join(map(str,self.actions.values()))+")"
	
	def addAction(self,suffix):
		action = Action(self,suffix)
		self.actions[ action.id ] = action
		
	def buildXML(self):
		if self.xml: return self.xml
		name = self.basename
		actions = ""
		for action in self.actions.values():
			actions += action.buildXML()
		
		return CRITTER_XML.safe_substitute(locals())
		
def readCritters():
	critters = os.popen("./frminfo -l 14").read().split("\n")[1:]
	critter_types = {}
	for critter in critters:
		basename = os.path.basename(critter).split('.')[0][:6]
		if not basename:
			continue
		
		action = os.path.basename(critter).split('.')[0][6:]
		if not critter_types.has_key(basename):
			critter_types[ basename ] = Critter(basename)
		critter = critter_types[ basename ]
		critter.addAction( action )
		
	return critter_types
		

def exportToXML(critter_name,critters,directory="./"):
	if not critters.has_key(critter_name):
		print >> sys.stderr, "Critter ",critter_name," not found."
		sys.exit(1)
		
	critter = critters[critter_name]
	
	xml= critter.buildXML()
	fname = os.path.join(directory,critter.basename + ".xml")
	file =open(fname,"w")
	file.write(xml)
	print >> sys.stderr, "Wrote to ",fname
	
def main():
	if len(sys.argv) == 1:
		print USAGE
		sys.exit(1)
	print >> sys.stderr, "Reading Critter List"
	critters = readCritters()
	if sys.argv[1] == '--list':
		for name,critter in critters.items():
			name_getter = lambda x: ACTION_NAMES[x]
			print name," actions  = ",map(name_getter,critter.actions.keys())
		sys.exit(0)
			
	if len(sys.argv) == 2:
		print USAGE
		sys.exit(1)
		
	if sys.argv[1] == '--to-xml':
		exportToXML( sys.argv[2], critters)
	if sys.argv[1]=='--all-xml':
		for critter_name in critters.keys():
			exportToXML(critter_name,critters,sys.argv[2])
	
if __name__=="__main__": main();