[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17797] trunk/blender/release/scripts: VRML/X3D

Campbell Barton ideasman42 at gmail.com
Fri Dec 12 06:46:08 CET 2008


Revision: 17797
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17797
Author:   campbellbarton
Date:     2008-12-12 06:46:07 +0100 (Fri, 12 Dec 2008)

Log Message:
-----------
VRML/X3D
* Improved compatibility with VRML files
* Extract strings so they dont get modified for parsing, filename URL's with {} [] dont break importing anymore.
* Cameras were rotated incorrectly
* inline files were not opened with GZip
* Animation Support - currently only loc/scale/rot (scale untested)
* Lists of image URLs now use the first image from the list since there is no support for dynamic switching.
* use imagemagick to convert GIF's so they load in linux. (WIP - could be extended, At least it should not break anything)

BPyMathutils angle2ToLength function could be simplified (pointed out by brecht)

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

Modified: trunk/blender/release/scripts/bpymodules/BPyMathutils.py
===================================================================
--- trunk/blender/release/scripts/bpymodules/BPyMathutils.py	2008-12-12 05:32:15 UTC (rev 17796)
+++ trunk/blender/release/scripts/bpymodules/BPyMathutils.py	2008-12-12 05:46:07 UTC (rev 17797)
@@ -225,15 +225,5 @@
 
 def angleToLength(angle):
 	# Alredy accounted for
-	if angle < 0.000001:
-		return 1.0
-	
-	angle = 2*pi*angle/360
-	x,y = cos(angle), sin(angle)
-	# print "YX", x,y
-	# 0 d is hoz to the right.
-	# 90d is vert upward.
-	fac=1/x
-	x=x*fac
-	y=y*fac
-	return sqrt((x*x)+(y*y))
+	if angle < 0.000001:	return 1.0
+	else:					return abs(1.0 / cos(pi*angle/180));

Modified: trunk/blender/release/scripts/import_web3d.py
===================================================================
--- trunk/blender/release/scripts/import_web3d.py	2008-12-12 05:32:15 UTC (rev 17796)
+++ trunk/blender/release/scripts/import_web3d.py	2008-12-12 05:46:07 UTC (rev 17797)
@@ -48,6 +48,27 @@
 def dirName(path):
 	return path[:-len(baseName(path))]
 
+def imageConvertCompat(path):
+	
+	try:	import os
+	except:
+		return path
+	
+	if path.endswith('.gif'):
+		path_to = path[:-3] + 'png'
+		
+		'''
+		if exists(path_to):
+			return path_to
+		'''
+		# print '\n'+path+'\n'+path_to+'\n'
+		os.system('convert "%s" "%s"' % (path, path_to)) # for now just hope we have image magick
+		
+		if exists(path_to):
+			return path_to
+	
+	return path
+
 # notes
 # transform are relative 
 # order dosnt matter for loc/size/rot
@@ -78,6 +99,7 @@
 			return l
 		
 		# Most cases accounted for! if we have a comment at the end of the line do this...
+		#j = l.find('url "')
 		j = l.find('"')
 		
 		if j == -1: # simple no strings
@@ -96,7 +118,40 @@
 	
 	data = '\n'.join([strip_comment(l) for l in data.split('\n') ]) # remove all whitespace
 	
+	EXTRACT_STRINGS = True # only needed when strings or filesnames containe ,[]{} chars :/
+	
+	if EXTRACT_STRINGS:
 		
+		# We need this so we can detect URL's
+		data = '\n'.join([' '.join(l.split()) for l in data.split('\n')]) # remove all whitespace
+		
+		string_ls = []
+		
+		#search = 'url "'
+		search = '"'
+		
+		ok = True
+		last_i = 0
+		while ok:
+			ok = False
+			i = data.find(search, last_i)
+			if i != -1:
+				
+				start = i + len(search) # first char after end of search
+				end = data.find('"', start)
+				if end != -1:
+					item = data[start:end]
+					string_ls.append( item )
+					data = data[:start] + data[end:]
+					ok = True # keep looking
+					
+					last_i = end - len(item) + 1
+					# print last_i, item, '|' + data[last_i] + '|'
+		
+	# done with messy extracting strings part
+	
+	
+	
 	# Bad, dont take strings into account
 	'''
 	data = data.replace('#', '\n#')
@@ -108,6 +163,27 @@
 	data = data.replace(']', '\n]\n')
 	data = data.replace(',', ' , ') # make sure comma's seperate
 	
+	if EXTRACT_STRINGS:
+		# add strings back in 
+		
+		search = '"' # fill in these empty strings
+		
+		ok = True
+		last_i = 0
+		while ok:
+			ok = False
+			i = data.find(search + '"', last_i)
+			
+			if i != -1:
+				start = i + len(search) # first char after end of search
+				item = string_ls.pop(0)
+				data = data[:start] + item + data[start:]
+				
+				last_i = start + len(item)
+				
+				ok = True
+	
+	
 	# More annoying obscure cases where USE or DEF are placed on a newline
 	# data = data.replace('\nDEF ', ' DEF ')
 	# data = data.replace('\nUSE ', ' USE ')
@@ -199,21 +275,46 @@
 	'''
 	Does this line start with a number?
 	'''
+	
+	# Works but too slow.
+	'''
 	l = lines[i]
+	for w in l.split():
+		if w==',':
+			pass
+		else:
+			try:
+				float(w)
+				return True
+			
+			except:
+				return False
+	
+	return False
+	'''
+	
+	l = lines[i]
+	
+	line_start = 0
+	
+	if l.startswith(', '):
+		line_start += 2
+	
 	line_end = len(l)-1
-	line_end_new = l.find(' ') # comma's always have a space before them
+	line_end_new = l.find(' ', line_start) # comma's always have a space before them
 	
 	if line_end_new != -1:
 		line_end = line_end_new
 	
 	try:
-		float(l[:line_end]) # works for a float or int
+		float(l[line_start:line_end]) # works for a float or int
 		return True
 	except:
 		return False
+	
 
 class vrmlNode(object):
-	__slots__ = 'id', 'fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'FIELD_NAMESPACE', 'x3dNode'
+	__slots__ = 'id', 'fields', 'node_type', 'parent', 'children', 'parent', 'array_data', 'reference', 'lineno', 'filename', 'blendObject', 'DEF_NAMESPACE', 'ROUTE_IPO_NAMESPACE', 'FIELD_NAMESPACE', 'x3dNode'
 	def __init__(self, parent, node_type, lineno):
 		self.id = None
 		self.node_type = node_type
@@ -231,6 +332,7 @@
 		
 		# 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.reference = None
@@ -257,12 +359,25 @@
 			return self.DEF_NAMESPACE
 		else:
 			return self.parent.getDefDict()
+			
+	def getRouteIpoDict(self):
+		if self.ROUTE_IPO_NAMESPACE != None:
+			return self.ROUTE_IPO_NAMESPACE
+		else:
+			return self.parent.getRouteIpoDict()
 	
 	def setRoot(self, filename):
 		self.filename = filename
-		self.FIELD_NAMESPACE =	{}
-		self.DEF_NAMESPACE=		{}
-		
+		self.FIELD_NAMESPACE =		{}
+		self.DEF_NAMESPACE =		{}
+		self.ROUTE_IPO_NAMESPACE =	{}
+	
+	def isRoot(self):
+		if self.filename == None:
+			return False
+		else:
+			return True
+	
 	def getFilename(self):
 		if self.filename:
 			return self.filename
@@ -284,6 +399,11 @@
 		except:
 			return None
 	
+	def getPrefix(self):
+		if self.id:
+			return self.id[0]
+		return None
+	
 	def getDefName(self):
 		self_real = self.getRealNode()
 		
@@ -464,11 +584,13 @@
 		
 		child_array = None
 		for child in self_real.children:
+			# print "ID IS", child.id
 			if child.id and len(child.id) == 1 and child.id[0] == field:
 				child_array = child
 				break
 		
 		if child_array==None:
+			
 			# 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)
@@ -489,10 +611,13 @@
 					print '\tWarning, could not parse array data from field'
 					array_data = []
 		else:
-			
+			# print child_array
 			# Normal vrml
 			array_data = child_array.array_data
+			
 		
+		# print 'array_data', array_data
+		
 		if group==-1 or len(array_data)==0:
 			return array_data
 		
@@ -520,8 +645,6 @@
 		# We requested a flat array
 		if group == 0:
 			return flat_array
-			
-			
 		
 		new_array = []
 		sub_array = []
@@ -537,6 +660,30 @@
 		
 		return new_array
 	
+	def getFieldAsStringArray(self, field):
+		'''
+		Get a list of strings
+		'''
+		self_real = self.getRealNode() # incase we're an instance
+		
+		child_array = None
+		for child in self_real.children:
+			if child.id and len(child.id) == 1 and child.id[0] == field:
+				child_array = child
+				break
+		if not child_array:
+			return []
+		
+		# each string gets its own list, remove ""'s
+		try:
+			new_array = [f[0][1:-1] for f in child_array.fields]
+		except:
+			print '\twarning, string array could not be made'
+			new_array = []
+		
+		return new_array
+	
+	
 	def getLevel(self):
 		# Ignore self_real
 		level = 0
@@ -564,19 +711,24 @@
 		else:
 			text = ''
 		
-		text += ind + 'ID: ' + str(self.id) + ' ' + str(level) + ('lineno %d\n' % self.lineno)
+		text += ind + 'ID: ' + str(self.id) + ' ' + str(level) + (' lineno %d\n' % self.lineno)
 		
 		if self.node_type==NODE_REFERENCE:
+			text += ind + "(reference node)\n"
 			return text
 		
-		for item in self.fields:
+		text += ind + 'FIELDS:\n'
+		
+		for i,item in enumerate(self.fields):
+			text += ind + 'FIELD:\n'
 			text += ind + str(item) +'\n'
 		
 		#text += ind + 'ARRAY: ' + str(len(self.array_data)) + ' ' + str(self.array_data) + '\n'
 		text += ind + 'ARRAY: ' + str(len(self.array_data)) + '[...] \n'
 		
 		text += ind + 'CHILDREN: ' + str(len(self.children)) + '\n'
-		for child in self.children:
+		for i, child in enumerate(self.children):
+			text += ind + ('CHILD%d:\n' % i)
 			text += str(child)
 		
 		text += '\n' + ind + brackets[1]
@@ -590,12 +742,24 @@
 		
 		# If we were an inline then try load the file
 		if self.node_type == NODE_NORMAL and self.getSpec() == 'Inline':
+			
 			url = self.getFieldAsString('url', None)
 			
 			if url != None:
-				if not exists(url):
-					url = dirName(self.getFilename()) + baseName(url)
-				if not exists(url):
+				urls = []
+				urls.append( url )
+				urls.append( BPySys.caseInsensitivePath(urls[-1]) )
+				
+				urls.append( dirName(self.getFilename()) + baseName(url) )
+				urls.append( BPySys.caseInsensitivePath(urls[-1]) )
+				
+				try:
+					url = [url for url in urls if exists(url)][0]
+					url_found = True
+				except:
+					url_found = False
+				
+				if not url_found:
 					print '\tWarning: Inline URL could not be found:', url
 				else:
 					if url==self.getFilename(): 
@@ -603,12 +767,12 @@
 					else:
 						
 						try:
-							f = open(url, 'rU')
+							data = gzipOpen(url)
 						except:
 							print '\tWarning: cant open the file:', url
-							f = None
+							data = None
 						
-						if f:
+						if data:
 							# Tricky - inline another VRML
 							print '\tLoading Inline:"%s"...' % url
 							
@@ -616,12 +780,15 @@
 							lines_old = lines[:]
 							
 							
-							lines[:] = vrmlFormat( f.read() )
-							f.close()
+							lines[:] = vrmlFormat( data )
 							
 							lines.insert(0, '{')
 							lines.insert(0, 'root_node____')
 							lines.append('}')
+							'''
+							ff = open('/test.txt', 'w')
+							ff.writelines([l+'\n' for l in lines])
+							'''
 							
 							child = vrmlNode(self, NODE_NORMAL, -1)
 							child.setRoot(url) # initialized dicts
@@ -723,7 +890,9 @@
 					values = l_split
 				
 				# This should not extend over multiple lines however it is possible
-				self.array_data.extend( values )
+				# print self.array_data
+				if values:
+					self.array_data.extend( values )
 				i+=1
 			else:
 				words = l.split()
@@ -843,13 +1012,13 @@
 	lines.insert(0, '{')
 	lines.insert(0, 'dymmy_node')
 	lines.append('}')
-	
 	# Use for testing our parsed output, so we can check on line numbers.
 	
-	## ff = open('m:\\test.txt', 'w')
-	## ff.writelines([l+'\n' for l in lines])
+	'''
+	ff = open('/test.txt', 'w')
+	ff.writelines([l+'\n' for l in lines])
+	'''
 	
-	
 	# Now evaluate it
 	node_type, new_i = is_nodeline(0, [])
 	if not node_type:

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list