[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [34228] trunk/blender/release/scripts/op/ io_scene_x3d/import_x3d.py: copy x3d/vrml importer from blender 2.4x.

Campbell Barton ideasman42 at gmail.com
Mon Jan 10 14:11:56 CET 2011


Revision: 34228
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=34228
Author:   campbellbarton
Date:     2011-01-10 13:11:56 +0000 (Mon, 10 Jan 2011)
Log Message:
-----------
copy x3d/vrml importer from blender 2.4x.
svn cp https://svn.blender.org/svnroot/bf-blender/branches/blender2.4/release/scripts/import_web3d.py release/scripts/op/io_scene_x3d/import_x3d.py

Added Paths:
-----------
    trunk/blender/release/scripts/op/io_scene_x3d/import_x3d.py

Copied: trunk/blender/release/scripts/op/io_scene_x3d/import_x3d.py (from rev 34227, branches/blender2.4/release/scripts/import_web3d.py)
===================================================================
--- trunk/blender/release/scripts/op/io_scene_x3d/import_x3d.py	                        (rev 0)
+++ trunk/blender/release/scripts/op/io_scene_x3d/import_x3d.py	2011-01-10 13:11:56 UTC (rev 34228)
@@ -0,0 +1,2594 @@
+#!BPY
+"""
+Name: 'X3D & VRML97 (.x3d / wrl)...'
+Blender: 248
+Group: 'Import'
+Tooltip: 'Load an X3D or VRML97 file'
+"""
+
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# (C) Copyright 2008 Paravizion
+# Written by Campbell Barton aka Ideasman42
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# ***** END GPL LICENCE BLOCK *****
+# --------------------------------------------------------------------------
+
+__author__ = "Campbell Barton"
+__url__ = ['www.blender.org', 'blenderartists.org', 'http://wiki.blender.org/index.php/Scripts/Manual/Import/X3D_VRML97']
+__version__ = "0.1"
+
+__bpydoc__ = """\
+This script is an importer for the X3D and VRML97 file formats.
+"""
+
+DEBUG = False
+
+# This should work without a blender at all
+try:
+	from Blender.sys import exists
+except:
+	from os.path import exists
+
+def baseName(path):
+	return path.split('/')[-1].split('\\')[-1]
+
+def dirName(path):
+	return path[:-len(baseName(path))]
+
+def imageConvertCompat(path):
+	
+	try:             import os
+	except:          return path
+	if os.sep=='\\': return path # assime win32 has quicktime, dont convert
+	
+	if path.lower().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
+# right handed rotation
+# angles are in radians
+# rotation first defines axis then ammount in radians
+
+
+
+# =============================== VRML Spesific
+
+
+def vrmlFormat(data):
+	'''
+	Keep this as a valid vrml file, but format in a way we can predict.
+	'''
+	# Strip all commends - # not in strings - warning multiline strings are ignored.
+	def strip_comment(l):
+		#l = ' '.join(l.split())
+		l = l.strip()
+		
+		if l.startswith('#'):
+			return ''
+		
+		i = l.find('#')
+		
+		if i==-1:
+			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
+			return l[:i].strip()
+		
+		q = False
+		for i,c in enumerate(l):
+			if c == '"':
+				q = not q # invert
+			
+			elif c == '#':
+				if q==False:
+					return l[:i-1]
+		
+		return l
+	
+	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#')
+	data = '\n'.join([ll for l in data.split('\n') for ll in (l.strip(),) if not ll.startswith('#')]) # remove all whitespace
+	'''
+	data = data.replace('{', '\n{\n')
+	data = data.replace('}', '\n}\n')
+	data = data.replace('[', '\n[\n')
+	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)
+			# print i
+			if i != -1:
+				start = i + len(search) # first char after end of search
+				item = string_ls.pop(0)
+				# print item
+				data = data[:start] + item + data[start:]
+				
+				last_i = start + len(item) + 1
+				
+				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 ')
+	
+	data = '\n'.join([' '.join(l.split()) for l in data.split('\n')]) # remove all whitespace
+	
+	# Better to parse the file accounting for multiline arrays
+	'''
+	data = data.replace(',\n', ' , ') # remove line endings with commas
+	data = data.replace(']', '\n]\n') # very very annoying - but some comma's are at the end of the list, must run this again.
+	'''
+	
+	return [l for l in data.split('\n') if l]
+
+NODE_NORMAL = 1 # {}
+NODE_ARRAY = 2 # []
+NODE_REFERENCE = 3 # USE foobar
+# NODE_PROTO = 4 #
+
+lines = []
+
+def getNodePreText(i, words):
+	# print lines[i]
+	use_node = False
+	while len(words) < 5:
+		
+		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"
+			return NODE_NORMAL, i+1
+		elif lines[i].count('"') % 2 != 0: # odd number of quotes? - part of a string.
+			# print 'ISSTRING'
+			break
+		else:
+			new_words = lines[i].split()
+			if 'USE' in new_words:
+				use_node = True
+			
+			words.extend(new_words)
+			i += 1
+		
+		# Check for USE node - no {
+		# USE #id - should always be on the same line.
+		if use_node:
+			# print 'LINE', i, words[:words.index('USE')+2]
+			words[:] = words[:words.index('USE')+2]
+			if lines[i] == '{' and lines[i+1] == '}':
+				# USE sometimes has {} after it anyway
+				i+=2 
+			return NODE_REFERENCE, i
+		
+	# print "error value!!!", words
+	return 0, -1
+
+def is_nodeline(i, words):
+	
+	if not lines[i][0].isalpha():
+		return 0, 0
+	
+	#if lines[i].startswith('field'):
+	#	return 0, 0
+	
+	# Is this a prototype??
+	if lines[i].startswith('PROTO'):
+		words[:] = lines[i].split()
+		return NODE_NORMAL, i+1 # TODO - assumes the next line is a '[\n', skip that
+	if lines[i].startswith('EXTERNPROTO'):
+		words[:] = lines[i].split()
+		return NODE_ARRAY, i+1 # TODO - assumes the next line is a '[\n', skip that
+	
+	'''
+	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:
+			words[:] = lines[i].split()
+			return NODE_ARRAY, i+2
+	
+	node_type, new_i = getNodePreText(i, words)
+	
+	if not node_type:
+		if DEBUG: print "not node_type", lines[i]
+		return 0, 0
+	
+	# Ok, we have a { after some values
+	# Check the values are not fields
+	for i, val in enumerate(words):
+		if i != 0 and words[i-1] in ('DEF', 'USE'):
+			# ignore anything after DEF, it is a ID and can contain any chars.
+			pass
+		elif val[0].isalpha() and val not in ('TRUE', 'FALSE'):
+			pass
+		else:
+			# There is a number in one of the values, therefor we are not a node.
+			return 0, 0
+	
+	#if node_type==NODE_REFERENCE:
+	#	print words, "REF_!!!!!!!"
+	return node_type, new_i
+
+def is_numline(i):
+	'''
+	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(' ', line_start) # comma's always have a space before them
+	
+	if line_end_new != -1:
+		line_end = line_end_new
+	
+	try:
+		float(l[line_start:line_end]) # works for a float or int
+		return True
+	except:
+		return False
+
+
+class vrmlNode(object):
+	__slots__ = 'id', 'fields', 'proto_node', '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
+		self.parent = parent
+		self.blendObject = None
+		self.x3dNode = None # for x3d import only
+		if parent:
+			parent.children.append(self)
+		
+		self.lineno = lineno
+		
+		# This is only set from the root nodes.
+		# Having a filename also denotes a root node
+		self.filename = None
+		self.proto_node = None # proto field definition eg: "field SFColor seatColor .6 .6 .1"
+		
+		# 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:
+			# For references, only the parent and ID are needed
+			# the reference its self is assigned on parsing
+			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:

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list