Ejemplo n.º 1
0
 def load(collada, localscope, node):
     pnode = node.find('%s/%s' % (tag('technique_common'), tag('point')))
     colornode = pnode.find(tag('color'))
     if colornode is None:
         raise DaeIncompleteError('Missing color for point light')
     try:
         color = tuple([float(v) for v in colornode.text.split()])
     except ValueError as ex:
         raise DaeMalformedError(
             'Corrupted color values in light definition')
     constant_att = linear_att = quad_att = zfar = None
     qattnode = pnode.find(tag('quadratic_attenuation'))
     cattnode = pnode.find(tag('constant_attenuation'))
     lattnode = pnode.find(tag('linear_attenuation'))
     zfarnode = pnode.find(tag('zfar'))
     try:
         if cattnode is not None:
             constant_att = float(cattnode.text)
         if lattnode is not None:
             linear_att = float(lattnode.text)
         if qattnode is not None:
             quad_att = float(qattnode.text)
         if zfarnode is not None:
             zfar = float(zfarnode.text)
     except ValueError as ex:
         raise DaeMalformedError('Corrupted values in light definition')
     return PointLight(node.get('id'),
                       color,
                       constant_att,
                       linear_att,
                       quad_att,
                       zfar,
                       xmlnode=node)
Ejemplo n.º 2
0
def checkSource( source, components, maxindex):
    """Check if a source objects complies with the needed `components` and has the needed length

    :param collada.source.Source source:
      A source instance to check
    :param tuple components:
      A tuple describing the needed channels, e.g. ``('X','Y','Z')``
    :param int maxindex:
      The maximum index that refers to this source

    """
    if len(source.data) <= maxindex:
        raise DaeMalformedError(
            "Indexes (maxindex=%d) for source '%s' (len=%d) go beyond the limits of the source"
            % (maxindex, source.id, len(source.data)) )

    #some files will write sources with no named parameters
    #by spec, these params should just be skipped, but we need to
    #adapt to the failed output of others...
    if len(source.components) == len(components):
        source.components = components

    if source.components != components:
        raise DaeMalformedError('Wrong format in source %s'%source.id)
    return source
Ejemplo n.º 3
0
 def _loadShadingParam( collada, localscope, node ):
     """Load from the node a definition for a material property."""
     children = node.getchildren()
     if not children: raise DaeIncompleteError('Incorrect effect shading parameter '+node.tag)
     vnode = children[0]
     if vnode.tag == tag('color'):
         try:
             value = tuple([ float(v) for v in vnode.text.split() ])
         except ValueError as ex:
             raise DaeMalformedError('Corrupted color definition in effect '+id)
         except IndexError as ex:
             raise DaeMalformedError('Corrupted color definition in effect '+id)
     elif vnode.tag == tag('float'):
         try: value = float(vnode.text)
         except ValueError as ex:
             raise DaeMalformedError('Corrupted float definition in effect '+id)
     elif vnode.tag == tag('texture'):
         value = Map.load(collada, localscope, vnode)
     elif vnode.tag == tag('param'):
         refid = vnode.get('ref')
         if refid is not None and refid in localscope:
             value = localscope[refid]
         else:
             return None
     else:
         raise DaeUnsupportedError('Unknown shading param definition ' + \
                 vnode.tag)
     return value
Ejemplo n.º 4
0
    def load( collada, localscope, node ):
        indexnode = node.find(tag('p'))
        if indexnode is None: raise DaeIncompleteError('Missing index in polylist')
        vcountnode = node.find(tag('vcount'))
        if vcountnode is None: raise DaeIncompleteError('Missing vcount in polylist')

        try:
            if vcountnode.text is None:
                vcounts = numpy.array([], dtype=numpy.int32)
            else:
                vcounts = numpy.fromstring(vcountnode.text, dtype=numpy.int32, sep=' ')
            vcounts[numpy.isnan(vcounts)] = 0
        except ValueError as ex:
            raise DaeMalformedError('Corrupted vcounts in polylist')

        all_inputs = primitive.Primitive._getInputs(collada, localscope, node.findall(tag('input')))

        try:
            if indexnode.text is None:
                index = numpy.array([], dtype=numpy.int32)
            else:
                index = numpy.fromstring(indexnode.text, dtype=numpy.int32, sep=' ')
            index[numpy.isnan(index)] = 0
        except: raise DaeMalformedError('Corrupted index in polylist')

        polylist = Polylist(all_inputs, node.get('material'), index, vcounts, node)
        return polylist
Ejemplo n.º 5
0
    def load(collada, localscope, morphnode, controllernode):
        baseid = morphnode.get('source')
        if len(baseid) < 2 or baseid[0] != '#' or \
                not baseid[1:] in collada.geometries:
            raise DaeBrokenRefError('Base source of morph %s not found' %
                                    baseid)
        basegeom = collada.geometries[baseid[1:]]

        method = morphnode.get('method')
        if method is None:
            method = 'NORMALIZED'
        if not (method == 'NORMALIZED' or method == 'RELATIVE'):
            raise DaeMalformedError(
                "Morph method must be either NORMALIZED or RELATIVE. Found '%s'"
                % method)

        inputnodes = morphnode.findall(
            '%s/%s' % (collada.tag('targets'), collada.tag('input')))
        if inputnodes is None or len(inputnodes) < 2:
            raise DaeIncompleteError("Not enough inputs in a morph")

        try:
            inputs = [(i.get('semantic'), i.get('source')) for i in inputnodes]
        except ValueError as ex:
            raise DaeMalformedError('Corrupted inputs in morph')

        target_source = None
        weight_source = None
        for i in inputs:
            if len(i[1]) < 2 or i[1][0] != '#' or not i[1][1:] in localscope:
                raise DaeBrokenRefError('Input in morph node %s not found' %
                                        i[1])
            if i[0] == 'MORPH_TARGET':
                target_source = localscope[i[1][1:]]
            elif i[0] == 'MORPH_WEIGHT':
                weight_source = localscope[i[1][1:]]

        if not type(target_source) is source.IDRefSource or \
                not type(weight_source) is source.FloatSource:
            raise DaeIncompleteError("Not enough inputs in targets of morph")

        if len(target_source) != len(weight_source):
            raise DaeMalformedError("Morph inputs must be of same length")

        target_list = []
        for target, weight in zip(target_source, weight_source):
            if len(target) < 1 or not (target in collada.geometries):
                raise DaeBrokenRefError(
                    "Targeted geometry %s in morph not found" % target)
            target_list.append((collada.geometries[target], weight[0]))

        return Morph(basegeom, target_list, controllernode)
Ejemplo n.º 6
0
    def load(collada, localscope, node):
        sourceid = node.get('id')
        arraynode = node.find(tag('float_array'))
        if arraynode is None:
            raise DaeIncompleteError('No float_array in source node')
        if arraynode.text is None:
            data = numpy.array([], dtype=numpy.float32)
        else:
            try:
                data = numpy.fromstring(arraynode.text,
                                        dtype=numpy.float32,
                                        sep=' ')
            except ValueError:
                raise DaeMalformedError('Corrupted float array')
        data[numpy.isnan(data)] = 0

        paramnodes = node.findall(
            '%s/%s/%s' %
            (tag('technique_common'), tag('accessor'), tag('param')))
        if not paramnodes:
            raise DaeIncompleteError('No accessor info in source node')
        components = [param.get('name') for param in paramnodes]
        if len(components
               ) == 2 and components[0] == 'U' and components[1] == 'V':
            #U,V is used for "generic" arguments - convert to S,T
            components = ['S', 'T']
        if len(components) == 3 and components[0] == 'S' and components[
                1] == 'T' and components[2] == 'P':
            components = ['S', 'T']
            data.shape = (-1, 3)
            #remove 3d texcoord dimension because we don't support it
            #TODO
            data = numpy.array(zip(data[:, 0], data[:, 1]))
            data.shape = (-1)
        return FloatSource(sourceid, data, tuple(components), xmlnode=node)
Ejemplo n.º 7
0
 def load(collada, node):
     url = node.get('url')
     if not url.startswith('#'):
         raise DaeMalformedError('Invalid url in camera instance %s' % url)
     camera = collada.cameras.get(url[1:])
     if not camera:
         raise DaeBrokenRefError('Camera %s not found in library' % url)
     return CameraNode(camera, xmlnode=node)
Ejemplo n.º 8
0
 def load(collada, node):
     url = node.get('url')
     if not url.startswith('#'):
         raise DaeMalformedError('Invalid url in light instance %s' % url)
     light = collada.lights.get(url[1:])
     if not light:
         raise DaeBrokenRefError('Light %s not found in library' % url)
     return LightNode(light, xmlnode=node)
Ejemplo n.º 9
0
    def _getInputs(collada, localscope, inputnodes):
        try:
            inputs = [(int(i.get('offset')), i.get('semantic'),
                       i.get('source'), i.get('set')) for i in inputnodes]
        except ValueError as ex:
            raise DaeMalformedError('Corrupted offsets in primitive')

        return Primitive._getInputsFromList(collada, localscope, inputs)
Ejemplo n.º 10
0
 def load(collada, node):
     inputs = []
     for inputnode in node.findall( tag('bind_vertex_input') ):
         inputs.append( ( inputnode.get('semantic'), inputnode.get('input_semantic'), inputnode.get('input_set') ) )
     targetid = node.get('target')
     if not targetid.startswith('#'): raise DaeMalformedError('Incorrect target id in material '+targetid)
     target = collada.materials.get(targetid[1:])
     if not target: raise DaeBrokenRefError('Material %s not found'%targetid)
     return MaterialNode(node.get('symbol'), target, inputs, xmlnode = node)
Ejemplo n.º 11
0
 def load( collada, node ):
     url = node.get('url')
     if not url.startswith('#'): raise DaeMalformedError('Invalid url in geometry instance %s' % url)
     geometry = collada.geometries.get(url[1:])
     if not geometry: raise DaeBrokenRefError('Geometry %s not found in library'%url)
     matnodes = node.findall('%s/%s/%s'%( tag('bind_material'), tag('technique_common'), tag('instance_material') ) )
     materials = []
     for matnode in matnodes:
         materials.append( MaterialNode.load(collada, matnode) )
     return GeometryNode( geometry, materials, xmlnode=node)
Ejemplo n.º 12
0
 def load( collada, node ):
     url = node.get('url')
     if not url.startswith('#'): raise DaeMalformedError('Invalid url in controller instance %s' % url)
     controller = collada.controllers.get(url[1:])
     if not controller: raise DaeBrokenRefError('Controller %s not found in library'%url)
     matnodes = node.findall('%s/%s/%s'%( tag('bind_material'), tag('technique_common'), tag('instance_material') ) )
     materials = []
     for matnode in matnodes:
         materials.append( MaterialNode.load(collada, matnode) )
     return ControllerNode( controller, materials, xmlnode=node)
Ejemplo n.º 13
0
 def load( collada, node, localscope ):
     url = node.get('url')
     if not url.startswith('#'):
         raise DaeMalformedError('Invalid url in node instance %s' % url)
     referred_node = localscope.get(url[1:])
     if not referred_node:
         referred_node = collada.nodes.get(url[1:])
     if not referred_node:
         raise DaeInstanceNotLoadedError('Node %s not found in library'%url)
     return NodeNode(referred_node, xmlnode=node)
Ejemplo n.º 14
0
 def load(collada, localscope, node):
     colornode = node.find(
         '%s/%s/%s' %
         (tag('technique_common'), tag('directional'), tag('color')))
     if colornode is None:
         raise DaeIncompleteError('Missing color for directional light')
     try:
         color = tuple([float(v) for v in colornode.text.split()])
     except ValueError as ex:
         raise DaeMalformedError(
             'Corrupted color values in light definition')
     return DirectionalLight(node.get('id'), color, xmlnode=node)
Ejemplo n.º 15
0
 def load(collada, localscope, node):
     pnode = node.find(
         '%s/%s' % (collada.tag('technique_common'), collada.tag('spot')))
     colornode = pnode.find(collada.tag('color'))
     if colornode is None:
         raise DaeIncompleteError('Missing color for spot light')
     try:
         color = tuple([float(v) for v in colornode.text.split()])
     except ValueError as ex:
         raise DaeMalformedError(
             'Corrupted color values in spot light definition')
     constant_att = linear_att = quad_att = falloff_ang = falloff_exp = None
     cattnode = pnode.find(collada.tag('constant_attenuation'))
     lattnode = pnode.find(collada.tag('linear_attenuation'))
     qattnode = pnode.find(collada.tag('quadratic_attenuation'))
     fangnode = pnode.find(collada.tag('falloff_angle'))
     fexpnode = pnode.find(collada.tag('falloff_exponent'))
     try:
         if cattnode is not None:
             constant_att = float(cattnode.text)
         if lattnode is not None:
             linear_att = float(lattnode.text)
         if qattnode is not None:
             quad_att = float(qattnode.text)
         if fangnode is not None:
             falloff_ang = float(fangnode.text)
         if fexpnode is not None:
             falloff_exp = float(fexpnode.text)
     except ValueError as ex:
         raise DaeMalformedError(
             'Corrupted values in spot light definition')
     return SpotLight(node.get('id'),
                      color,
                      constant_att,
                      linear_att,
                      quad_att,
                      falloff_ang,
                      falloff_exp,
                      xmlnode=node)
Ejemplo n.º 16
0
 def _loadDefaultScene(self):
     """Loads the default scene from <scene> tag in the root node."""
     node = self.xmlnode.find('%s/%s' % (tag('scene'), tag('instance_visual_scene')))
     try:
         if node != None:
             sceneid = node.get('url')
             if not sceneid.startswith('#'):
                 raise DaeMalformedError('Malformed default scene reference to %s: '%sceneid)
             self.scene = self.scenes.get(sceneid[1:])
             if not self.scene:
                 raise DaeBrokenRefError('Default scene %s not found' % sceneid)
     except DaeError as ex:
         self.handleError(ex)
Ejemplo n.º 17
0
 def load( collada, localscope, node ):
     sourceid = node.get('id')
     arraynode = node.find(tag('Name_array'))
     if arraynode is None: raise DaeIncompleteError('No Name_array in source node')
     if arraynode.text is None:
         values = []
     else:
         try: values = [v for v in arraynode.text.split()]
         except ValueError: raise DaeMalformedError('Corrupted Name array')
     data = numpy.array( values, dtype=numpy.string_ )
     paramnodes = node.findall('%s/%s/%s'%(tag('technique_common'), tag('accessor'), tag('param')))
     if not paramnodes: raise DaeIncompleteError('No accessor info in source node')
     components = [ param.get('name') for param in paramnodes ]
     return NameSource( sourceid, data, tuple(components), xmlnode=node )
Ejemplo n.º 18
0
    def load( collada, localscope, node ):
        matid = node.get('id')
        matname = node.get('name')

        effnode = node.find( tag('instance_effect'))
        if effnode is None: raise DaeIncompleteError('No effect inside material')
        effectid = effnode.get('url')

        if not effectid.startswith('#'):
            raise DaeMalformedError('Corrupted effect reference in material %s' % effectid)

        effect = collada.effects.get(effectid[1:])
        if not effect:
            raise DaeBrokenRefError('Effect not found: '+effectid)

        return Material(matid, matname, effect, xmlnode=node)
Ejemplo n.º 19
0
    def load( collada, localscope, node ):
        indexnode = node.find(tag('p'))
        if indexnode is None: raise DaeIncompleteError('Missing index in line set')

        source_array = primitive.Primitive._getInputs(collada, localscope, node.findall(tag('input')))

        try:
            if indexnode.text is None or indexnode.text.isspace():
                index = numpy.array([],  dtype=numpy.int32)
            else:
                index = numpy.fromstring(indexnode.text, dtype=numpy.int32, sep=' ')
            index[numpy.isnan(index)] = 0
        except: raise DaeMalformedError('Corrupted index in line set')

        lineset = LineSet(source_array, node.get('material'), index, node)
        lineset.xmlnode = node
        return lineset
Ejemplo n.º 20
0
    def __init__(self, matrix, xmlnode=None):
        """Creates a matrix transformation

        :param numpy.array matrix:
          This should be an unshaped numpy array of floats of length 16
        :param xmlnode:
           When loaded, the xmlnode it comes from

        """
        self.matrix = matrix
        """The resulting transformation matrix. This will be a numpy.array of size 4x4."""
        if len(self.matrix) != 16: raise DaeMalformedError('Corrupted matrix transformation node')
        self.matrix.shape = (4, 4)
        self.xmlnode = xmlnode
        """ElementTree representation of the transform."""
        if xmlnode is None:
            self.xmlnode = E.matrix(' '.join(map(str, self.matrix.flat)))
Ejemplo n.º 21
0
 def load( collada, localscope, node ):
     surfacenode = node.find( tag('surface') )
     if surfacenode is None: raise DaeIncompleteError('No surface found in newparam')
     if surfacenode.get('type') != '2D': raise DaeMalformedError('Hard to imagine a non-2D surface, isn\'t it?')
     initnode = surfacenode.find( tag('init_from') )
     if initnode is None: raise DaeIncompleteError('No init image found in surface')
     formatnode = surfacenode.find( tag('format') )
     if formatnode is None: format = None
     else: format = formatnode.text
     imgid = initnode.text
     id = node.get('sid')
     if imgid in localscope:
         img = localscope[imgid]
     else:
         img = collada.images.get(imgid)
     if img is None: raise DaeBrokenRefError("Missing image '%s' in surface '%s'" % (imgid, id))
     return Surface(id, img, format, xmlnode=node)
Ejemplo n.º 22
0
    def load(collada, localscope, node):
        orthonode = node.find(
            '%s/%s/%s' %
            (collada.tag('optics'), collada.tag('technique_common'),
             collada.tag('orthographic')))

        if orthonode is None:
            raise DaeIncompleteError(
                'Missing orthographic for camera definition')

        xmag = orthonode.find(collada.tag('xmag'))
        ymag = orthonode.find(collada.tag('ymag'))
        aspect_ratio = orthonode.find(collada.tag('aspect_ratio'))
        znearnode = orthonode.find(collada.tag('znear'))
        zfarnode = orthonode.find(collada.tag('zfar'))
        id = node.get('id', '')

        try:
            if xmag is not None:
                xmag = float(xmag.text)
            if ymag is not None:
                ymag = float(ymag.text)
            if aspect_ratio is not None:
                aspect_ratio = float(aspect_ratio.text)
            znear = float(znearnode.text)
            zfar = float(zfarnode.text)
        except (TypeError, ValueError) as ex:
            raise DaeMalformedError(
                'Corrupted float values in camera definition')

        #There are some exporters that incorrectly output all three of these.
        # Worse, they actually got the calculation of aspect_ratio wrong!
        # So instead of failing to load, let's just add one more hack because of terrible exporters
        if xmag is not None and ymag is not None and aspect_ratio is not None:
            aspect_ratio = None

        return OrthographicCamera(id,
                                  znear,
                                  zfar,
                                  xmag=xmag,
                                  ymag=ymag,
                                  aspect_ratio=aspect_ratio,
                                  xmlnode=node)
Ejemplo n.º 23
0
    def load(collada, localscope, node):
        persnode = node.find(
            '%s/%s/%s' %
            (tag('optics'), tag('technique_common'), tag('perspective')))

        if persnode is None:
            raise DaeIncompleteError(
                'Missing perspective for camera definition')

        xfov = persnode.find(tag('xfov'))
        yfov = persnode.find(tag('yfov'))
        aspect_ratio = persnode.find(tag('aspect_ratio'))
        znearnode = persnode.find(tag('znear'))
        zfarnode = persnode.find(tag('zfar'))
        id = node.get('id', '')

        try:
            if xfov is not None:
                xfov = float(xfov.text)
            if yfov is not None:
                yfov = float(yfov.text)
            if aspect_ratio is not None:
                aspect_ratio = float(aspect_ratio.text)
            znear = float(znearnode.text)
            zfar = float(zfarnode.text)
        except (TypeError, ValueError) as ex:
            raise DaeMalformedError(
                'Corrupted float values in camera definition')

        #There are some exporters that incorrectly output all three of these.
        # Worse, they actually got the caculation of aspect_ratio wrong!
        # So instead of failing to load, let's just add one more hack because of terrible exporters
        if xfov is not None and yfov is not None and aspect_ratio is not None:
            aspect_ratio = None

        return PerspectiveCamera(id,
                                 znear,
                                 zfar,
                                 xfov=xfov,
                                 yfov=yfov,
                                 aspect_ratio=aspect_ratio,
                                 xmlnode=node)
Ejemplo n.º 24
0
    def load(collada, localscope, node):
        indexnodes = node.findall(collada.tag('p'))
        if not indexnodes:
            raise DaeIncompleteError('Missing index in triangle set')

        source_array = primitive.Primitive._getInputs(
            collada, localscope, node.findall(collada.tag('input')))

        def parse_p(indexnode):
            if indexnode.text is None or indexnode.text.isspace():
                index = numpy.array([], dtype=numpy.int32)
            else:
                index = numpy.fromstring(indexnode.text,
                                         dtype=numpy.int32,
                                         sep=' ')
            index[numpy.isnan(index)] = 0
            return index

        indexlist = []
        tag_bare = node.tag.split('}')[-1]

        extendfunc = _indexExtendFunctions[tag_bare]

        max_offset = max(input[0]
                         for input_type_array in source_array.values()
                         for input in input_type_array)

        try:
            for indexnode in indexnodes:
                index = parse_p(indexnode)
                if extendfunc is None:
                    break

                extendfunc(indexlist, index.reshape((-1, max_offset + 1)))
            else:
                index = numpy.concatenate(indexlist)
        except:
            raise DaeMalformedError('Corrupted index in triangleset')

        triset = TriangleSet(source_array, node.get('material'), index, node)
        triset.xmlnode = node
        return triset
Ejemplo n.º 25
0
 def _checkValidParams(self):
     if self.xmag is not None and self.ymag is None \
             and self.aspect_ratio is None:
         pass
     elif self.xmag is None and self.ymag is not None \
             and self.aspect_ratio is None:
         pass
     elif self.xmag is not None and self.ymag is None \
             and self.aspect_ratio is not None:
         pass
     elif self.xmag is None and self.ymag is not None \
             and self.aspect_ratio is not None:
         pass
     elif self.xmag is not None and self.ymag is not None \
             and self.aspect_ratio is None:
         pass
     else:
         raise DaeMalformedError(
             "Received invalid combination of xmag (%s), ymag (%s), and aspect_ratio (%s)"
             % (str(self.xmag), str(self.ymag), str(self.aspect_ratio)))
Ejemplo n.º 26
0
    def __init__(self, eye, interest, upvector, xmlnode=None):
        """Creates a lookat transformation

        :param numpy.array eye:
          An unshaped numpy array of floats of length 3 containing the position of the eye
        :param numpy.array interest:
          An unshaped numpy array of floats of length 3 containing the point of interest
        :param numpy.array upvector:
          An unshaped numpy array of floats of length 3 containing the up-axis direction
        :param xmlnode:
          When loaded, the xmlnode it comes from

        """
        self.eye = eye
        """A numpy array of length 3 containing the position of the eye"""
        self.interest = interest
        """A numpy array of length 3 containing the point of interest"""
        self.upvector = upvector
        """A numpy array of length 3 containing the up-axis direction"""

        if len(eye) != 3 or len(interest) != 3 or len(upvector) != 3:
            raise DaeMalformedError('Corrupted lookat transformation node')

        self.matrix = numpy.identity(4, dtype=numpy.float32)
        """The resulting transformation matrix. This will be a numpy.array of size 4x4."""

        front = toUnitVec(numpy.subtract(eye, interest))
        side = numpy.multiply(-1, toUnitVec(numpy.cross(front, upvector)))
        self.matrix[0, 0:3] = side
        self.matrix[1, 0:3] = upvector
        self.matrix[2, 0:3] = front
        self.matrix[3, 0:3] = eye

        self.xmlnode = xmlnode
        """ElementTree representation of the transform."""
        if xmlnode is None:
            self.xmlnode = E.lookat(' '.join(
                map(
                    str,
                    numpy.concatenate(
                        (self.eye, self.interest, self.upvector)))))
Ejemplo n.º 27
0
    def __init__(self, source_geometry, target_list, xmlnode=None):
        """Create a morph instance

        :Parameters:
          source_geometry
            The source geometry (Geometry)
          targets
            A list of tuples where each tuple (g,w) contains
            a Geometry (g) and a float weight value (w)
          xmlnode
            When loaded, the xmlnode it comes from

        """
        self.id = xmlnode.get('id')
        if self.id is None:
            raise DaeMalformedError('Controller node requires an ID')
        self.source_geometry = source_geometry
        """The source geometry (Geometry)"""
        self.target_list = target_list
        """A list of tuples where each tuple (g,w) contains
            a Geometry (g) and a float weight value (w)"""

        self.xmlnode = xmlnode
Ejemplo n.º 28
0
    def __init__(self,
                 sourcebyid,
                 bind_shape_matrix,
                 joint_source,
                 joint_matrix_source,
                 weight_source,
                 weight_joint_source,
                 vcounts,
                 vertex_weight_index,
                 offsets,
                 geometry,
                 controller_node=None,
                 skin_node=None):
        """Create a skin.

        :Parameters:
          sourceById
            A dict mapping id's to a collada source
          bind_shape_matrix
            A numpy array of floats (pre-shape)
          joint_source
            The string id for the joint source
          joint_matrix_source
            The string id for the joint matrix source
          weight_source
            The string id for the weight source
          weight_joint_source
            The string id for the joint source of weights
          vcounts
            A list with the number of influences on each vertex
          vertex_weight_index
            An array with the indexes as they come from <v> array
          offsets
            A list with the offsets in the weight index array for each source
            in (joint, weight)
          geometry
            The source geometry this should be applied to (geometry.Geometry)
          controller_node
            XML node of the <controller> tag which is the parent of this
          skin_node
            XML node of the <skin> tag if this is from there

        """
        self.sourcebyid = sourcebyid
        self.bind_shape_matrix = bind_shape_matrix
        self.joint_source = joint_source
        self.joint_matrix_source = joint_matrix_source
        self.weight_source = weight_source
        self.weight_joint_source = weight_joint_source
        self.vcounts = vcounts
        self.vertex_weight_index = vertex_weight_index
        self.offsets = offsets
        self.geometry = geometry
        self.controller_node = controller_node
        self.skin_node = skin_node
        self.xmlnode = controller_node

        if not type(self.geometry) is Geometry:
            raise DaeMalformedError('Invalid reference geometry in skin')

        self.id = controller_node.get('id')
        if self.id is None:
            raise DaeMalformedError('Controller node requires an ID')

        self.nindices = max(self.offsets) + 1

        if len(bind_shape_matrix) != 16:
            raise DaeMalformedError('Corrupted bind shape matrix in skin')
        self.bind_shape_matrix.shape = (4, 4)

        if not (joint_source in sourcebyid
                and joint_matrix_source in sourcebyid):
            raise DaeBrokenRefError("Input in joints not found")
        if not (type(sourcebyid[joint_source]) is source.NameSource
                or type(sourcebyid[joint_source]) is source.IDRefSource):
            raise DaeIncompleteError(
                "Could not find joint name input for skin")
        if not type(sourcebyid[joint_matrix_source]) is source.FloatSource:
            raise DaeIncompleteError(
                "Could not find joint matrix source for skin")
        joint_names = [j for j in sourcebyid[joint_source]]
        joint_matrices = sourcebyid[joint_matrix_source].data
        joint_matrices.shape = (-1, 4, 4)
        if len(joint_names) != len(joint_matrices):
            raise DaeMalformedError(
                "Skin joint and matrix inputs must be same length")
        self.joint_matrices = {}
        for n, m in zip(joint_names, joint_matrices):
            self.joint_matrices[n] = m

        if not (weight_source in sourcebyid
                and weight_joint_source in sourcebyid):
            raise DaeBrokenRefError("Weights input in joints not found")
        if not type(sourcebyid[weight_source]) is source.FloatSource:
            raise DaeIncompleteError("Could not find weight inputs for skin")
        if not (type(sourcebyid[weight_joint_source]) is source.NameSource or
                type(sourcebyid[weight_joint_source]) is source.IDRefSource):
            raise DaeIncompleteError(
                "Could not find weight joint source input for skin")
        self.weights = sourcebyid[weight_source]
        self.weight_joints = sourcebyid[weight_joint_source]

        try:
            newshape = []
            at = 0
            for ct in self.vcounts:
                this_set = self.vertex_weight_index[self.nindices *
                                                    at:self.nindices *
                                                    (at + ct)]
                this_set.shape = (ct, self.nindices)
                newshape.append(numpy.array(this_set))
                at += ct
            self.index = newshape
        except:
            raise DaeMalformedError(
                'Corrupted vcounts or index in skin weights')

        try:
            self.joint_index = [
                influence[:, self.offsets[0]] for influence in self.index
            ]
            self.weight_index = [
                influence[:, self.offsets[1]] for influence in self.index
            ]
        except:
            raise DaeMalformedError('Corrupted joint or weight index in skin')

        self.max_joint_index = numpy.max([
            numpy.max(joint) if len(joint) > 0 else 0
            for joint in self.joint_index
        ])
        self.max_weight_index = numpy.max([
            numpy.max(weight) if len(weight) > 0 else 0
            for weight in self.weight_index
        ])
        checkSource(self.weight_joints, ('JOINT', ), self.max_joint_index)
        checkSource(self.weights, ('WEIGHT', ), self.max_weight_index)
Ejemplo n.º 29
0
    def load(collada, localscope, skinnode, controllernode):
        if len(localscope) < 3:
            raise DaeMalformedError('Not enough sources in skin')

        geometry_source = skinnode.get('source')
        if geometry_source is None or len(geometry_source) < 2 \
                or geometry_source[0] != '#':
            raise DaeBrokenRefError('Invalid source attribute of skin node')
        if not geometry_source[1:] in collada.geometries:
            raise DaeBrokenRefError('Source geometry for skin node not found')
        geometry = collada.geometries[geometry_source[1:]]

        bind_shape_mat = skinnode.find(collada.tag('bind_shape_matrix'))
        if bind_shape_mat is None:
            bind_shape_mat = numpy.identity(4, dtype=numpy.float32)
            bind_shape_mat.shape = (-1, )
        else:
            try:
                values = [float(v) for v in bind_shape_mat.text.split()]
            except ValueError:
                raise DaeMalformedError('Corrupted bind shape matrix in skin')
            bind_shape_mat = numpy.array(values, dtype=numpy.float32)

        inputnodes = skinnode.findall(
            '%s/%s' % (collada.tag('joints'), collada.tag('input')))
        if inputnodes is None or len(inputnodes) < 2:
            raise DaeIncompleteError("Not enough inputs in skin joints")

        try:
            inputs = [(i.get('semantic'), i.get('source')) for i in inputnodes]
        except ValueError as ex:
            raise DaeMalformedError('Corrupted inputs in skin')

        joint_source = None
        matrix_source = None
        for i in inputs:
            if len(i[1]) < 2 or i[1][0] != '#':
                raise DaeBrokenRefError('Input in skin node %s not found' %
                                        i[1])
            if i[0] == 'JOINT':
                joint_source = i[1][1:]
            elif i[0] == 'INV_BIND_MATRIX':
                matrix_source = i[1][1:]

        weightsnode = skinnode.find(collada.tag('vertex_weights'))
        if weightsnode is None:
            raise DaeIncompleteError("No vertex_weights found in skin")
        indexnode = weightsnode.find(collada.tag('v'))
        if indexnode is None:
            raise DaeIncompleteError('Missing indices in skin vertex weights')
        vcountnode = weightsnode.find(collada.tag('vcount'))
        if vcountnode is None:
            raise DaeIncompleteError('Missing vcount in skin vertex weights')
        inputnodes = weightsnode.findall(collada.tag('input'))

        try:
            index = numpy.array([float(v) for v in indexnode.text.split()],
                                dtype=numpy.int32)
            vcounts = numpy.array([int(v) for v in vcountnode.text.split()],
                                  dtype=numpy.int32)
            inputs = [(i.get('semantic'), i.get('source'),
                       int(i.get('offset'))) for i in inputnodes]
        except ValueError as ex:
            raise DaeMalformedError(
                'Corrupted index or offsets in skin vertex weights')

        weight_joint_source = None
        weight_source = None
        offsets = [0, 0]
        for i in inputs:
            if len(i[1]) < 2 or i[1][0] != '#':
                raise DaeBrokenRefError('Input in skin node %s not found' %
                                        i[1])
            if i[0] == 'JOINT':
                weight_joint_source = i[1][1:]
                offsets[0] = i[2]
            elif i[0] == 'WEIGHT':
                weight_source = i[1][1:]
                offsets[1] = i[2]

        if joint_source is None or weight_source is None:
            raise DaeMalformedError(
                'Not enough inputs for vertex weights in skin')

        return Skin(localscope, bind_shape_mat, joint_source, matrix_source,
                    weight_source, weight_joint_source, vcounts, index,
                    offsets, geometry, controllernode, skinnode)
Ejemplo n.º 30
0
    def __init__(self,
                 filename=None,
                 ignore=None,
                 aux_file_loader=None,
                 zip_filename=None,
                 validate_output=False):
        """Load collada data from filename or file like object.

        :param filename:
          String containing path to filename to open or file-like object.
          Uncompressed .dae files are supported, as well as zip file archives.
          If this is set to ``None``, a new collada instance is created.
        :param list ignore:
          A list of :class:`common.DaeError` types that should be ignored
          when loading the collada document. Instances of these types will
          be added to :attr:`errors` after loading but won't be raised.
          Only used if `filename` is not ``None``.
        :param function aux_file_loader:
          Referenced files (e.g. texture images) are loaded from disk when
          reading from the local filesystem and from the zip archive when
          loading from a zip file. If these files are coming from another source
          (e.g. database) and/or you're loading with StringIO, set this to
          a function that given a filename, returns the binary data in the file.
          If `filename` is ``None``, you must set this parameter if you want to
          load auxiliary files.
        :param str zip_filename:
          If the file being loaded is a zip archive, you can set this parameter
          to indicate the file within the archive that should be loaded. If not
          set, a file that ends with .dae will be searched.
        :param bool validate_output:
          If set to True, the XML written when calling :meth:`save` will be
          validated against the COLLADA 1.4.1 schema. If validation fails, the
          :class:`common.DaeSaveValidationError` exception will be thrown.
        """

        self.errors = []
        """List of :class:`common.common.DaeError` objects representing errors encountered while loading collada file"""
        self.assetInfo = None
        """Instance of :class:`collada.asset.Asset` containing asset information"""

        self._geometries = IndexedList([], ('id', ))
        self._controllers = IndexedList([], ('id', ))
        self._animations = IndexedList([], ('id', ))
        self._lights = IndexedList([], ('id', ))
        self._cameras = IndexedList([], ('id', ))
        self._images = IndexedList([], ('id', ))
        self._effects = IndexedList([], ('id', ))
        self._materials = IndexedList([], ('id', ))
        self._nodes = IndexedList([], ('id', ))
        self._scenes = IndexedList([], ('id', ))

        self.scene = None
        """The default scene. This is either an instance of :class:`collada.scene.Scene` or `None`."""

        # a function which will apply the namespace
        self.tag = tag

        if validate_output and schema:
            self.validator = schema.ColladaValidator()
        else:
            self.validator = None

        self.maskedErrors = []
        if ignore is not None:
            self.ignoreErrors(*ignore)

        if filename is None:
            self.filename = None
            self.zfile = None
            self.getFileData = self._nullGetFile
            if aux_file_loader is not None:
                self.getFileData = self._wrappedFileLoader(aux_file_loader)

            self.xmlnode = ElementTree.ElementTree(
                E.COLLADA(E.library_cameras(),
                          E.library_controllers(),
                          E.library_effects(),
                          E.library_geometries(),
                          E.library_images(),
                          E.library_lights(),
                          E.library_materials(),
                          E.library_nodes(),
                          E.library_visual_scenes(),
                          E.scene(),
                          version='1.4.1'))
            """ElementTree representation of the collada document"""

            self.assetInfo = asset.Asset()
            return

        if isinstance(filename, basestring):
            fdata = open(filename, 'rb')
            self.filename = filename
            self.getFileData = self._getFileFromDisk
        else:
            fdata = filename  # assume it is a file like object
            self.filename = None
            self.getFileData = self._nullGetFile
        strdata = fdata.read()

        try:
            self.zfile = zipfile.ZipFile(BytesIO(strdata), 'r')
        except:
            self.zfile = None

        if self.zfile:
            self.filename = ''
            daefiles = []
            if zip_filename is not None:
                self.filename = zip_filename
            else:
                for name in self.zfile.namelist():
                    if name.upper().endswith('.DAE'):
                        daefiles.append(name)
                for name in daefiles:
                    if not self.filename:
                        self.filename = name
                    elif "MACOSX" in self.filename:
                        self.filename = name
            if not self.filename or self.filename not in self.zfile.namelist():
                raise DaeIncompleteError(
                    'COLLADA file not found inside zip compressed file')
            data = self.zfile.read(self.filename)
            self.getFileData = self._getFileFromZip
        else:
            data = strdata

        if aux_file_loader is not None:
            self.getFileData = self._wrappedFileLoader(aux_file_loader)

        etree_parser = ElementTree.XMLParser()
        try:
            self.xmlnode = ElementTree.ElementTree(element=None,
                                                   file=BytesIO(data))
        except ElementTree.ParseError as e:
            raise DaeMalformedError("XML Parsing Error: %s" % e)

        # if we can't get the current namespace
        # the tagger from above will use a hardcoded default
        try:
            # get the root node, same for both etree and lxml
            xml_root = self.xmlnode.getroot()
            if hasattr(xml_root, 'nsmap'):
                # lxml has an nsmap
                # use the first value in the namespace map
                namespace = next(iter(xml_root.nsmap.values()))
            elif hasattr(xml_root, 'tag'):
                # for xml.etree we need to extract ns from root tag
                namespace = xml_root.tag.split('}')[0].lstrip('{')
            # create a tagging function using the extracted namespace
            self.tag = tagger(namespace)
        except BaseException:
            # failed to extract a namespace, using default
            traceback.print_exc()

        # functions which will load various things into collada object
        self._loadAssetInfo()
        self._loadImages()
        self._loadEffects()
        self._loadMaterials()
        self._loadAnimations()
        self._loadGeometry()
        self._loadControllers()
        self._loadLights()
        self._loadCameras()
        self._loadNodes()
        self._loadScenes()
        self._loadDefaultScene()