[Bf-extensions-cvs] [5e72555] temp-x3d_import-T44758: Initial patch from sevaa (Seva Alekseyev (NIH)) T44758

Campbell Barton noreply at git.blender.org
Sat May 23 06:00:04 CEST 2015


Commit: 5e72555f61bbc75d239872dfe26d2d57c7290702
Author: Campbell Barton
Date:   Thu May 21 09:37:54 2015 +1000
Branches: temp-x3d_import-T44758
https://developer.blender.org/rBA5e72555f61bbc75d239872dfe26d2d57c7290702

Initial patch from sevaa (Seva Alekseyev (NIH)) T44758

===================================================================

M	io_scene_x3d/import_x3d.py

===================================================================

diff --git a/io_scene_x3d/import_x3d.py b/io_scene_x3d/import_x3d.py
index 15ac760..2c59855 100644
--- a/io_scene_x3d/import_x3d.py
+++ b/io_scene_x3d/import_x3d.py
@@ -23,7 +23,10 @@ DEBUG = False
 # This should work without a blender at all
 import os
 import shlex
+import math
+from math import sin, cos, pi
 
+EPSILON = 0.0000001 # Very crude.
 
 def imageConvertCompat(path):
 
@@ -330,7 +333,8 @@ class vrmlNode(object):
                  'DEF_NAMESPACE',
                  'ROUTE_IPO_NAMESPACE',
                  'PROTO_NAMESPACE',
-                 'x3dNode')
+                 'x3dNode',
+                 'parsed')
 
     def __init__(self, parent, node_type, lineno):
         self.id = None
@@ -338,6 +342,7 @@ class vrmlNode(object):
         self.parent = parent
         self.blendObject = None
         self.x3dNode = None  # for x3d import only
+        self.parsed = None  # We try to reuse objects in a smart way 
         if parent:
             parent.children.append(self)
 
@@ -471,6 +476,11 @@ class vrmlNode(object):
         else:
             # Check inside a list of optional types
             return [child for child in self_real.children if child.getSpec() in node_spec]
+        
+    def getChildrenBySpecCondition(self, cond):  # 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
+        return [child for child in self_real.children if cond(child.getSpec())]
 
     def getChildBySpec(self, node_spec):  # spec could be Transform, Shape, Appearance
         # Use in cases where there is only ever 1 child of this type
@@ -479,6 +489,14 @@ class vrmlNode(object):
             return ls[0]
         else:
             return None
+        
+    def getChildBySpecCondition(self, cond):  # spec could be Transform, Shape, Appearance
+        # Use in cases where there is only ever 1 child of this type
+        ls = self.getChildrenBySpecCondition(cond)
+        if ls:
+            return ls[0]
+        else:
+            return None
 
     def getChildrenByName(self, node_name):  # type could be geometry, children, appearance
         self_real = self.getRealNode()
@@ -728,7 +746,7 @@ class vrmlNode(object):
         def array_as_number(array_string):
             array_data = []
             try:
-                array_data = [int(val) for val in array_string]
+                array_data = [int(val, 0) for val in array_string]
             except:
                 try:
                     array_data = [float(val) for val in array_string]
@@ -1214,6 +1232,14 @@ class vrmlNode(object):
                         else:
                             self.fields.append(value)
                 i += 1
+                
+    # This is a prerequisite for DEF/USE-based material caching
+    def canHaveReferences(self):
+        return self.node_type == NODE_NORMAL and self.getDefName()
+    
+    # This is a prerequisite for raw XML-based material caching. For now, only for X3D 
+    def desc(self):
+        return None
 
 
 def gzipOpen(path):
@@ -1353,6 +1379,12 @@ class x3dNode(vrmlNode):
             return value.split()
         else:
             return None
+        
+    def canHaveReferences(self):
+        return self.x3dNode.getAttributeNode('DEF')
+    
+    def desc(self):
+        return self.getRealNode().x3dNode.toxml()
 
 
 def x3d_parse(path):
@@ -1414,7 +1446,7 @@ for i, f in enumerate(files):
 # -----------------------------------------------------------------------------------
 import bpy
 from bpy_extras import image_utils
-from mathutils import Vector, Matrix
+from mathutils import Vector, Matrix, Quaternion
 
 GLOBALS = {'CIRCLE_DETAIL': 16}
 
@@ -1515,12 +1547,6 @@ def translateTexTransform(node, ancestry):
 
     return new_mat
 
-
-# 90d X rotation
-import math
-MATRIX_Z_TO_Y = Matrix.Rotation(math.pi / 2.0, 4, 'X')
-
-
 def getFinalMatrix(node, mtx, ancestry, global_matrix):
 
     transform_nodes = [node_tx for node_tx in ancestry if node_tx.getSpec() == 'Transform']
@@ -1540,306 +1566,624 @@ def getFinalMatrix(node, mtx, ancestry, global_matrix):
 
     return mtx
 
+# -----------------------------------------------------------------------------------
+# Mesh import utilities
+
+# Assumes that the mesh has tessfaces - doesn't support polygons.
+# Also assumes that tessfaces are all triangles.
+# Assumes that the sequence of the mesh vertices array matches the source file.
+# For indexed meshes, that's almost a given; for nonindexed ones, this is a consideration.
+def importMesh_ApplyColors(bpymesh, geom, ancestry):
+    colors = geom.getChildBySpec(['ColorRGBA', 'Color'])
+    if colors:
+        if colors.getSpec() == 'ColorRGBA': # Array of arrays; no need to flatten
+            rgb = [c[:3] for c in colors.getFieldAsArray('color', 4, ancestry)] 
+        else:
+            rgb = colors.getFieldAsArray('color', 3, ancestry)
+        tc = bpymesh.tessface_vertex_colors.new()
+        tc.data.foreach_set("color1", [i for face in bpymesh.tessfaces for i in rgb[face.vertices[0]]])
+        tc.data.foreach_set("color2", [i for face in bpymesh.tessfaces for i in rgb[face.vertices[1]]])
+        tc.data.foreach_set("color3", [i for face in bpymesh.tessfaces for i in rgb[face.vertices[2]]])
+
+# Assumes that the vertices have not been rearranged compared to the source file order
+# or in the order assumed by the spec (e. g. in Elevation, in rows by x).
+# Assumes tessfaces have been set, doesn't support polygons.
+def importMesh_ApplyNormals(bpymesh, geom, ancestry):
+    normals = geom.getChildBySpec('Normal')
+    if normals:
+        normalPerVertex = geom.getFieldAsBool('normalPerVertex', True, ancestry)
+        vectors = normals.getFieldAsArray('vector', 0, ancestry)
+        if normalPerVertex:
+            bpymesh.vertices.foreach_set("normal", vectors)
+        else:
+            bpymesh.tessfaces.foreach_set("normal", vectors)
+
+# Reads the standard Coordinate object - common for all mesh elements
+# Feeds the vertices in the mesh.
+# Rearranging the vertex order is a bad idea - other elements in X3D might rely on it,
+# if you need to rearrange, please play with vertex indices in the tessfaces/polygons instead.
+def importMesh_ReadVertices(bpymesh, geom, ancestry):
+    # We want points here as a flat array, but the caching logic in IndexedFaceSet presumes a 2D one.
+    # The case for caching is stronger over there.
+    
+    points = geom.getChildBySpec('Coordinate').getFieldAsArray('point', 0, ancestry)
+    bpymesh.vertices.add(len(points)//3)
+    bpymesh.vertices.foreach_set("co", points)    
+    
+# Assumes the mesh only contains triangular tessfaces, and the order
+# of vertices matches the source.
+# Relies upon texture coordinates in the node; if a coordinate generation
+# algorithm for a geometry is in the spec (e. g. for ElevationGrid), it needs to be elsewhere.
+# Texture transform is applied elsewhere.
+def importMesh_ApplyTextureToTessfaces(bpymesh, geom, ancestry, bpyima):
+    if bpyima:
+        tex_coord = geom.getChildBySpec('TextureCoordinate')
+        if tex_coord:
+            coord_points = tex_coord.getFieldAsArray('point', 2, ancestry)
+            if coord_points:
+                d = bpymesh.tessface_uv_textures.new().data
+                for face in d: # No foreach_set for nonscalars
+                    face.image = bpyima 
+                d.foreach_set('uv', [i for face in bpymesh.tessfaces for vno in range(3) for i in coord_points[face.vertices[vno]]])
+                
+# Common steps for all triangle meshes once the geometry has been set: normals, vertex colors, and texture.
+def importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima):        
+    bpymesh.validate()
+    importMesh_ApplyNormals(bpymesh, geom, ancestry)
+    importMesh_ApplyColors(bpymesh, geom, ancestry)
+    importMesh_ApplyTextureToTessfaces(bpymesh, geom, ancestry, bpyima)
+    bpymesh.update()
+    return bpymesh
 
-def importMesh_IndexedFaceSet(geom, bpyima, ancestry):
-    # print(geom.lineno, geom.id, vrmlNode.DEF_NAMESPACE.keys())
-
-    ccw = geom.getFieldAsBool('ccw', True, ancestry)
-    ifs_colorPerVertex = geom.getFieldAsBool('colorPerVertex', True, ancestry)  # per vertex or per face
-    ifs_normalPerVertex = geom.getFieldAsBool('normalPerVertex', True, ancestry)
-
-    # This is odd how point is inside Coordinate
-
-    # VRML not x3d
-    #coord = geom.getChildByName('coord') # 'Coordinate'
+# Assumes that the mesh is stored as polygons and loops, and the premade array of
+# texture coordinates follows the loop array.
+# The loops array must be flat.
+def importMesh_ApplyTextureToLoops(bpymesh, bpyima, loops):
+    for f in bpymesh.uv_textures.new().data:
+        f.image = bpyima   
+    bpymesh.uv_layers[0].data.foreach_set('uv', loops)
+
+        
+def flip(r, ccw):
+    return r if ccw else r[::-1]        
+        
+# -----------------------------------------------------------------------------------
+# Now specific geometry importers
 
-    coord = geom.getChildBySpec('Coordinate')  # works for x3d and vrml
 
-    if coord:
-        ifs_points = coord.getFieldAsArray('point', 3, ancestry)
+def importMesh_IndexedTriangleSet(geom, ancestry, bpyima):
+    # Ignoring solid
+    # colorPerVertex is always true
+    ccw = geom.getFieldAsBool('ccw', True, ancestry)
+    
+    bpymesh = bpy.data.meshes.new(name="XXX")
+    importMesh_ReadVertices(bpymesh, geom, ancestry)
+
+    # Read the faces
+    index = geom.getFieldAsArray('index', 0, ancestry)
+    if not ccw:
+        index = [index[3*i+j] for i in range(n//3) for j in (1, 0, 2)]
+    bpymesh.tessfaces.add(len(index)//3)
+    bpymesh.tessfaces.foreach_set("vertices", index)
+    
+    return importMesh_FinalizeTriangleMesh(bpymesh, geom, ancestry, bpyima)
+
+def importMesh_IndexedTriangleStripSet(geom, ancestry, bpyima):
+    # Ignoring solid
+    # colorPerVertex is always true
+    cw = 0 if geom.getFieldAsBool('ccw', True, ancestry) else 1
+    bpymesh = bpy.data.meshes.new(name="IndexedTriangleStripSet")
+    importMesh_ReadVertices(bpymesh, geom, ancestry)
+ 
+    # Read the 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list