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. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to