[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [18014] trunk/blender/release/scripts/ import_web3d.py: WIP - support for VRML PROTO's

Campbell Barton ideasman42 at gmail.com
Mon Dec 22 16:05:21 CET 2008


Revision: 18014
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=18014
Author:   campbellbarton
Date:     2008-12-22 16:05:07 +0100 (Mon, 22 Dec 2008)

Log Message:
-----------
WIP - support for VRML PROTO's

Modified Paths:
--------------
    trunk/blender/release/scripts/import_web3d.py

Modified: trunk/blender/release/scripts/import_web3d.py
===================================================================
--- trunk/blender/release/scripts/import_web3d.py	2008-12-22 12:57:53 UTC (rev 18013)
+++ trunk/blender/release/scripts/import_web3d.py	2008-12-22 15:05:07 UTC (rev 18014)
@@ -201,6 +201,7 @@
 NODE_NORMAL = 1 # {}
 NODE_ARRAY = 2 # []
 NODE_REFERENCE = 3 # USE foobar
+# NODE_PROTO = 4 #
 
 lines = []
 
@@ -211,6 +212,10 @@
 		
 		if i>=len(lines):
 			break
+			'''
+		elif lines[i].startswith('PROTO'):
+			return NODE_PROTO, i+1
+			'''
 		elif lines[i]=='{':
 			# words.append(lines[i]) # no need
 			# print "OK"
@@ -239,11 +244,45 @@
 	# print "error value!!!", words
 	return 0, -1
 
-def is_nodeline(i, words):
+def is_protoline(i, words, proto_field_defs):
 	
+	node_type = NODE_NORMAL
+	# print "PRPTOTOOOO ---- test", i, lines[i]
+	if not lines[i].startswith('PROTO' ):
+		# print 'not a proto'
+		return node_type, -1
+	
+	words[:] = lines[i].split() # TODO - maybe multiline proto's exist?
+	
+	i+=1
+	if lines[i].startswith('['): # ']\n'
+		while not lines[i].startswith(']'):
+			proto_field_defs.append(lines[i].split())
+			i+=1
+		i+=1 # advance past the ']\n'
+	
+	if lines[i].startswith('{'):
+		node_type = NODE_NORMAL
+		i+=1 # advance past the '{\n'
+	
+	elif lines[i].startswith('['): # does this even exist??, add incase
+		node_type = NODE_ARRAY
+		i+=1 # advance past the '{\n'
+	
+	print "IS PROTO", i, node_type
+	return node_type, i
+
+def is_nodeline(i, words, proto_field_defs):
+	
 	if not lines[i][0].isalpha():
 		return 0, 0
 	
+	# Is this a prototype??
+	proto_type, new_i = is_protoline(i, words, proto_field_defs)
+	if new_i != -1:
+		return proto_type, new_i
+		
+	
 	# Simple "var [" type
 	if lines[i+1] == '[':
 		if lines[i].count('"') % 2 == 0:
@@ -253,6 +292,7 @@
 	node_type, new_i = getNodePreText(i, words)
 	
 	if not node_type:
+		print "not node_type", lines[i]
 		return 0, 0
 	
 	# Ok, we have a { after some values
@@ -311,10 +351,10 @@
 		return True
 	except:
 		return False
-	
 
+
 class vrmlNode(object):
-	__slots__ = 'id', 'fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'ROUTE_IPO_NAMESPACE', 'FIELD_NAMESPACE', 'x3dNode'
+	__slots__ = 'id', 'fields', 'proto_field_defs', 'proto_fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'ROUTE_IPO_NAMESPACE', 'PROTO_NAMESPACE', 'x3dNode'
 	def __init__(self, parent, node_type, lineno):
 		self.id = None
 		self.node_type = node_type
@@ -333,8 +373,13 @@
 		# Store in the root node because each inline file needs its own root node and its own namespace
 		self.DEF_NAMESPACE = None 
 		self.ROUTE_IPO_NAMESPACE = None 
+		'''
 		self.FIELD_NAMESPACE = None
+		'''
 		
+		
+		self.PROTO_NAMESPACE = None
+		
 		self.reference = None
 		
 		if node_type==NODE_REFERENCE:
@@ -343,16 +388,25 @@
 			return 
 		
 		self.fields = [] # fields have no order, in some cases rool level values are not unique so dont use a dict
+		self.proto_field_defs = [] # proto field definition eg: "field SFColor seatColor .6 .6 .1"
+		self.proto_fields = [] # proto field usage "diffuseColor IS seatColor"
 		self.children = []
 		self.array_data = [] # use for arrays of data - should only be for NODE_ARRAY types
 		
 	
 	# Only available from the root node
+	'''
 	def getFieldDict(self):
 		if self.FIELD_NAMESPACE != None:
 			return self.FIELD_NAMESPACE
 		else:
 			return self.parent.getFieldDict()
+	'''
+	def getProtoDict(self):
+		if self.PROTO_NAMESPACE != None:
+			return self.PROTO_NAMESPACE
+		else:
+			return self.parent.getProtoDict()
 	
 	def getDefDict(self):
 		if self.DEF_NAMESPACE != None:
@@ -368,9 +422,10 @@
 	
 	def setRoot(self, filename):
 		self.filename = filename
-		self.FIELD_NAMESPACE =		{}
+		# self.FIELD_NAMESPACE =		{}
 		self.DEF_NAMESPACE =		{}
 		self.ROUTE_IPO_NAMESPACE =	{}
+		self.PROTO_NAMESPACE =		{}
 	
 	def isRoot(self):
 		if self.filename == None:
@@ -404,16 +459,18 @@
 			return self.id[0]
 		return None
 	
-	def getDefName(self):
+	def getSpecialTypeName(self, typename):
 		self_real = self.getRealNode()
-		
-		if 'DEF' in self_real.id:
-			# print self_real.id
-			return self_real.id[ list(self_real.id).index('DEF')+1 ]
-		else:
-			return None
-		
+		try:		return self_real.id[ list(self_real.id).index(typename)+1 ]
+		except:	return None
 	
+	
+	def getDefName(self):
+		return self.getSpecialTypeName('DEF')
+	
+	def getProtoName(self):
+		return self.getSpecialTypeName('PROTO')
+	
 	def getChildrenBySpec(self, node_spec): # spec could be Transform, Shape, Appearance
 		self_real = self.getRealNode()
 		# using getSpec functions allows us to use the spec of USE children that dont have their spec in their ID
@@ -449,7 +506,21 @@
 		ancestry.append(self)
 		for child in self.getRealNode().children:
 			if child not in ancestry:
-				child.getSerialized(results, ancestry)
+				# We dont want to load proto's, they are only references
+				# We could enforce this elsewhere
+				
+				# Only add this in a very special case
+				# where the parent of this object is not the real parent
+				# - In this case we have added the proto as a child to a node instancing it.
+				# This is a bit arbitary, but its how Proto's are done with this importer.
+				if child.getProtoName() == None:
+					child.getSerialized(results, ancestry)
+				else:
+					print "\n\n\n\nTEST!!!!!!!!!!!!!"
+					print child.getProtoName(), self.getSpec()
+					if child.getProtoName()==self.getSpec():
+						print "PROTO!!!!!!!!!!!!!!!!\n"
+						child.getSerialized(results, ancestry)
 		
 		return results
 		
@@ -462,7 +533,7 @@
 			child.searchNodeTypeID(node_spec, results)
 		return results
 	
-	def getFieldName(self, field):
+	def getFieldName(self, field, ancestry):
 		self_real = self.getRealNode() # incase we're an instance
 		
 		for f in self_real.fields:
@@ -470,14 +541,51 @@
 			if f and f[0] == field:
 				# print '\tfound field', f
 				
-				return f[1:]
+				if len(f)>=3 and f[1] == 'IS': # eg: 'diffuseColor IS legColor'
+					field_id = f[2]
+					
+					# print "\n\n\n\n\n\nFOND IS!!!"
+					f_proto_lookup = None
+					i = len(ancestry)
+					while i:
+						i -= 1
+						node = ancestry[i]
+						
+						# Get the default value from the proto, this can be overwridden by the proto instace
+						# 'field SFColor legColor .8 .4 .7'
+						for f_def in node.proto_field_defs:
+							if len(f_def) >= 4:
+								if f_def[0]=='field' and f_def[2]==field_id:
+									f_proto_lookup = f_def[3:]
+						
+						# Node instance, Will be 1 up from the proto-node in the ancestry list. but NOT its parent.
+						# This is the setting as defined by the instance, including this setting is optional,
+						# and will override the default PROTO value 
+						# eg: 'legColor 1 0 0'
+						for f_def in node.fields:
+							# print "\n\n\n\n\nASSSSSSSS", f_def
+							if len(f_def) >= 2:
+								if f_def[0]==field_id:
+									f_proto_lookup = f_def[1:]
+					# print "\n\n\n\nWOOOOHOOO", field, f_proto_lookup
+					
+					return f_proto_lookup
+				else:
+					# Not using a proto
+					return f[1:]
 		# print '\tfield not found', field
+		
+		
+		# See if this is a proto name
+		
+		
+		
 		return None
 	
-	def getFieldAsInt(self, field, default):
+	def getFieldAsInt(self, field, default, ancestry):
 		self_real = self.getRealNode() # incase we're an instance
 		
-		f = self_real.getFieldName(field)
+		f = self_real.getFieldName(field, ancestry)
 		if f==None:	return default
 		if ',' in f: f = f[:f.index(',')] # strip after the comma
 		
@@ -491,10 +599,10 @@
 			print '\tvalue "%s" could not be used as an int for field "%s"' % (f[0], field)
 			return default
 	
-	def getFieldAsFloat(self, field, default):
+	def getFieldAsFloat(self, field, default, ancestry):
 		self_real = self.getRealNode() # incase we're an instance
 		
-		f = self_real.getFieldName(field)
+		f = self_real.getFieldName(field, ancestry)
 		if f==None:	return default
 		if ',' in f: f = f[:f.index(',')] # strip after the comma
 		
@@ -508,10 +616,10 @@
 			print '\tvalue "%s" could not be used as a float for field "%s"' % (f[0], field)
 			return default
 	
-	def getFieldAsFloatTuple(self, field, default):
+	def getFieldAsFloatTuple(self, field, default, ancestry):
 		self_real = self.getRealNode() # incase we're an instance
 		
-		f = self_real.getFieldName(field)
+		f = self_real.getFieldName(field, ancestry)
 		if f==None:	return default
 		# if ',' in f: f = f[:f.index(',')] # strip after the comma
 		
@@ -532,10 +640,10 @@
 			print '\tvalue "%s" could not be used as a float tuple for field "%s"' % (f, field)
 			return default
 	
-	def getFieldAsBool(self, field, default):
+	def getFieldAsBool(self, field, default, ancestry):
 		self_real = self.getRealNode() # incase we're an instance
 		
-		f = self_real.getFieldName(field)
+		f = self_real.getFieldName(field, ancestry)
 		if f==None:	return default
 		if ',' in f: f = f[:f.index(',')] # strip after the comma
 		
@@ -551,10 +659,10 @@
 			print '\t"%s" could not be used as a bool for field "%s"' % (f[1], field)
 			return default
 	
-	def getFieldAsString(self, field, default=None):
+	def getFieldAsString(self, field, default, ancestry):
 		self_real = self.getRealNode() # incase we're an instance
 		
-		f = self_real.getFieldName(field)
+		f = self_real.getFieldName(field, ancestry)
 		if f==None:	return default
 		if len(f) < 1:
 			print '\t"%s" wrong length for string conversion for field "%s"' % (f, field)
@@ -576,7 +684,7 @@
 			print '\tvalue "%s" could not be used as a string for field "%s"' % (f[0], field)
 			return default
 	
-	def getFieldAsArray(self, field, group):
+	def getFieldAsArray(self, field, group, ancestry):
 		'''
 		For this parser arrays are children
 		'''
@@ -593,7 +701,7 @@
 			
 			# For x3d, should work ok with vrml too
 			# for x3d arrays are fields, vrml they are nodes, annoying but not tooo bad.
-			data_split = self.getFieldName(field)
+			data_split = self.getFieldName(field, ancestry)
 			if not data_split:
 				return []
 			array_data = ' '.join(data_split)
@@ -660,7 +768,7 @@
 		
 		return new_array
 	
-	def getFieldAsStringArray(self, field):
+	def getFieldAsStringArray(self, field, ancestry):
 		'''
 		Get a list of strings
 		'''
@@ -698,7 +806,7 @@
 	def __repr__(self):
 		level = self.getLevel()
 		ind = '  ' * level
-		
+		print self.id
 		if self.node_type==NODE_REFERENCE:

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list