def __init__(self, id, name, effect, xmlnode=None): """Creates a material. :param str id: A unique string identifier for the material :param str name: A name for the material :param collada.material.Effect effect: The effect instantiated in this material :param xmlnode: If loaded from xml, the xml node """ self.id = id """The unique string identifier for the material""" self.name = name """The name for the material""" self.effect = effect """The :class:`collada.material.Effect` instantiated in this material""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the surface.""" else: self.xmlnode = E.material( E.instance_effect(url="#%s" % self.effect.id) , id=str(self.id), name=str(self.name))
def __init__(self, sources, material, polygons, xmlnode=None): """A Polygons should not be created manually. Instead, call the :meth:`collada.geometry.Geometry.createPolygons` method after creating a geometry instance. """ max_offset = max([ max([input[0] for input in input_type_array]) for input_type_array in sources.itervalues() if len(input_type_array) > 0]) vcounts = numpy.zeros(len(polygons), dtype=numpy.int32) for i, poly in enumerate(polygons): vcounts[i] = len(poly) / (max_offset + 1) indices = numpy.concatenate(polygons) super(Polygons, self).__init__(sources, material, indices, vcounts, xmlnode) if xmlnode is not None: self.xmlnode = xmlnode else: acclen = len(polygons) self.xmlnode = E.polygons(count=str(acclen), material=self.material) all_inputs = [] for semantic_list in self.sources.itervalues(): all_inputs.extend(semantic_list) for offset, semantic, sourceid, set, src in all_inputs: inpnode = E.input(offset=str(offset), semantic=semantic, source=sourceid) if set is not None: inpnode.set('set', str(set)) self.xmlnode.append(inpnode) for poly in polygons: self.xmlnode.append(E.p(' '.join(map(str, poly.flatten().tolist()))))
def __init__(self, id, color, xmlnode = None): """Create a new ambient light. :param str id: A unique string identifier for the light :param tuple color: Either a tuple of size 3 containing the RGB color value of the light or a tuple of size 4 containing the RGBA color value of the light :param xmlnode: If loaded from xml, the xml node """ self.id = id """The unique string identifier for the light""" self.color = color """Either a tuple of size 3 containing the RGB color value of the light or a tuple of size 4 containing the RGBA color value of the light""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the light.""" else: self.xmlnode = E.light( E.technique_common( E.ambient( E.color(' '.join(map(str, self.color ) )) ) ) , id=self.id, name=self.id)
def __init__(self, id, color, xmlnode = None): """Create a new directional light. :param str id: A unique string identifier for the light :param tuple color: Either a tuple of size 3 containing the RGB color value of the light or a tuple of size 4 containing the RGBA color value of the light :param xmlnode: If loaded from xml, the xml node """ self.id = id """The unique string identifier for the light""" self.direction = numpy.array( [0, 0, -1], dtype=numpy.float32 ) #Not documenting this because it doesn't make sense to set the direction # of an unbound light. The direction isn't set until binding in a scene. self.color = color """Either a tuple of size 3 containing the RGB color value of the light or a tuple of size 4 containing the RGBA color value of the light""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the light.""" else: self.xmlnode = E.light( E.technique_common( E.directional( E.color(' '.join(map(str, self.color))) ) ) , id=self.id, name=self.id)
def __init__(self, symbol, target, inputs, xmlnode = None): """Creates a material node :param str symbol: The symbol within a geometry this material should be bound to :param collada.material.Material target: The material object being bound to :param list inputs: A list of tuples of the form ``(semantic, input_semantic, set)`` mapping texcoords or other inputs to material input channels, e.g. ``('TEX0', 'TEXCOORD', '0')`` would map the effect parameter ``'TEX0'`` to the ``'TEXCOORD'`` semantic of the geometry, using texture coordinate set ``0``. :param xmlnode: When loaded, the xmlnode it comes from """ self.symbol = symbol """The symbol within a geometry this material should be bound to""" self.target = target """An object of type :class:`collada.material.Material` representing the material object being bound to""" self.inputs = inputs """A list of tuples of the form ``(semantic, input_semantic, set)`` mapping texcoords or other inputs to material input channels, e.g. ``('TEX0', 'TEXCOORD', '0')`` would map the effect parameter ``'TEX0'`` to the ``'TEXCOORD'`` semantic of the geometry, using texture coordinate set ``0``.""" if xmlnode is not None: self.xmlnode = xmlnode """ElementTree representation of the material node.""" else: self.xmlnode = E.instance_material( *[E.bind_vertex_input(semantic=sem, input_semantic=input_sem, input_set=set) for sem, input_sem, set in self.inputs] , **{'symbol': self.symbol, 'target':"#%s"%self.target.id} )
def __init__(self, id, color, xmlnode=None): """Create a new sun light. :Parameters: id Id for the object color Light color xmlnode If load form xml, the xml node """ self.id = id """Id in the light library.""" # TODO: check if this is actually the initial direction self.direction = numpy.array([0, 0, 1], dtype=numpy.float32) """Incoming direction of the light.""" self.color = color """Light color.""" if xmlnode != None: self.xmlnode = xmlnode else: self.xmlnode = E.light( E.technique_common(E.directional(E.color(" ".join([str(v) for v in self.color])))), id=self.id, name=self.id, )
def __init__(self, geometry, materials=None, xmlnode=None): """Creates a geometry node :param collada.geometry.Geometry geometry: A geometry to instantiate in the scene :param list materials: A list containing items of type :class:`collada.scene.MaterialNode`. Each of these represents a material that the geometry should be bound to. :param xmlnode: When loaded, the xmlnode it comes from """ self.geometry = geometry """An object of type :class:`collada.geometry.Geometry` representing the geometry to bind in the scene""" self.materials = [] """A list containing items of type :class:`collada.scene.MaterialNode`. Each of these represents a material that the geometry is bound to.""" if materials is not None: self.materials = materials if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the geometry node.""" else: self.xmlnode = E.instance_geometry(url="#%s" % self.geometry.id) if len(self.materials) > 0: self.xmlnode.append(E.bind_material( E.technique_common( *[mat.xmlnode for mat in self.materials] ) ))
def save(self): """Saves the geometry node back to :attr:`xmlnode`""" self.xmlnode.set('url', "#%s" % self.geometry.id) for m in self.materials: m.save() matparent = self.xmlnode.find('%s/%s'%( tag('bind_material'), tag('technique_common') ) ) if matparent is None and len(self.materials)==0: return elif matparent is None: matparent = E.technique_common() self.xmlnode.append(E.bind_material(matparent)) elif len(self.materials) == 0 and matparent is not None: bindnode = self.xmlnode.find('%s' % tag('bind_material')) self.xmlnode.remove(bindnode) return for m in self.materials: if m.xmlnode not in matparent: matparent.append(m.xmlnode) xmlnodes = [m.xmlnode for m in self.materials] for n in matparent: if n not in xmlnodes: matparent.remove(n)
def __init__(self, id, surface, minfilter=None, magfilter=None, xmlnode=None): """Create a Sampler2D object. :param str id: A string identifier for the sampler within the local scope of the material :param collada.material.Surface surface: Surface instance that this object samples from :param str minfilter: Minification filter string id, see collada spec for details :param str magfilter: Maximization filter string id, see collada spec for details :param xmlnode: If loaded from xml, the xml node """ self.id = id """The string identifier for the sampler within the local scope of the material""" self.surface = surface """Surface instance that this object samples from""" self.minfilter = minfilter """Minification filter string id, see collada spec for details""" self.magfilter = magfilter """Maximization filter string id, see collada spec for details""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the sampler.""" else: sampler_node = E.sampler2D(E.source(self.surface.id)) if minfilter: sampler_node.append(E.minfilter(self.minfilter)) if magfilter: sampler_node.append(E.magfilter(self.magfilter)) self.xmlnode = E.newparam(sampler_node, sid=self.id)
def __init__(self, id, img, format=None, xmlnode=None): """Creates a surface. :param str id: A string identifier for the surface within the local scope of the material :param collada.material.CImage img: The image object :param str format: The format of the image :param xmlnode: If loaded from xml, the xml node """ self.id = id """The string identifier for the surface within the local scope of the material""" self.image = img """:class:`collada.material.CImage` object from the image library.""" self.format = format if format is not None else "A8R8G8B8" """Format string.""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the surface.""" else: self.xmlnode = E.newparam( E.surface( E.init_from(self.image.id), E.format(self.format) , type="2D") , sid=self.id)
def __init__(self, id, path, collada = None, xmlnode = None): """Create an image object. :param str id: A unique string identifier for the image :param str path: Path relative to the collada document where the image is located :param collada.Collada collada: The collada object this image belongs to :param xmlnode: If loaded from xml, the node this data comes from """ self.id = id """The unique string identifier for the image""" self.path = path """Path relative to the collada document where the image is located""" self.collada = collada self._data = None self._pilimage = None self._uintarray = None self._floatarray = None if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the image.""" else: self.xmlnode = E.image( E.init_from(path) , id=self.id, name=self.id)
def getPropNode(prop, value): propnode = E(prop) if type(value) is Map: propnode.append(copy.deepcopy(value.xmlnode)) elif type(value) is float: propnode.append(E.float(str(value))) else: propnode.append(E.color(' '.join(map(str, value) ))) return propnode
def __init__(self, id, color, constant_att=None, linear_att=None, quad_att=None, zfar=None, xmlnode = None): """Create a new sun light. :param str id: A unique string identifier for the light :param tuple color: Either a tuple of size 3 containing the RGB color value of the light or a tuple of size 4 containing the RGBA color value of the light :param float constant_att: Constant attenuation factor :param float linear_att: Linear attenuation factor :param float quad_att: Quadratic attenuation factor :param float zfar: Distance to the far clipping plane :param xmlnode: If loaded from xml, the xml node """ self.id = id """The unique string identifier for the light""" self.position = numpy.array( [0, 0, 0], dtype=numpy.float32 ) #Not documenting this because it doesn't make sense to set the position # of an unbound light. The position isn't set until binding in a scene. self.color = color """Either a tuple of size 3 containing the RGB color value of the light or a tuple of size 4 containing the RGBA color value of the light""" self.constant_att = constant_att """Constant attenuation factor.""" self.linear_att = linear_att """Linear attenuation factor.""" self.quad_att = quad_att """Quadratic attenuation factor.""" self.zfar = zfar """Distance to the far clipping plane""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the light.""" else: pnode = E.point( E.color(' '.join(map(str, self.color ) )) ) if self.constant_att is not None: pnode.append(E.constant_attenuation(str(self.constant_att))) if self.linear_att is not None: pnode.append(E.linear_attenuation(str(self.linear_att))) if self.quad_att is not None: pnode.append(E.quadratic_attenuation(str(self.quad_att))) if self.zfar is not None: pnode.append(E.zfar(str(self.zvar))) self.xmlnode = E.light( E.technique_common(pnode) , id=self.id, name=self.id)
def __init__(self, x, y, z, angle, xmlnode=None): """Creates a rotation transformation :param float x: x coordinate :param float y: y coordinate :param float z: z coordinate :param float angle: angle of rotation, in radians :param xmlnode: When loaded, the xmlnode it comes from """ self.x = x """x coordinate""" self.y = y """y coordinate""" self.z = z """z coordinate""" self.angle = angle """angle of rotation, in radians""" self.matrix = makeRotationMatrix(x, y, z, angle*numpy.pi/180.0) """The resulting transformation matrix. This will be a numpy.array of size 4x4.""" self.xmlnode = xmlnode """ElementTree representation of the transform.""" if xmlnode is None: self.xmlnode = E.rotate(' '.join([str(x),str(y),str(z),str(angle)]))
def __init__(self, id, nodes, xmlnode=None, collada=None): """Create a scene :param str id: A unique string identifier for the scene :param list nodes: A list of type :class:`collada.scene.Node` representing the nodes in the scene :param xmlnode: When loaded, the xmlnode it comes from :param collada: The collada instance this is part of """ self.id = id """The unique string identifier for the scene""" self.nodes = nodes """A list of type :class:`collada.scene.Node` representing the nodes in the scene""" self.collada = collada """The collada instance this is part of""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the scene node.""" else: self.xmlnode = E.visual_scene(id=self.id) for node in nodes: self.xmlnode.append( node.xmlnode )
def __init__(self, x, y, z, xmlnode=None): """Creates a translation transformation :param float x: x coordinate :param float y: y coordinate :param float z: z coordinate :param xmlnode: When loaded, the xmlnode it comes from """ self.x = x """x coordinate""" self.y = y """y coordinate""" self.z = z """z coordinate""" self.matrix = numpy.identity(4, dtype=numpy.float32) """The resulting transformation matrix. This will be a numpy.array of size 4x4.""" self.matrix[:3,3] = [ x, y, z ] self.xmlnode = xmlnode """ElementTree representation of the transform.""" if xmlnode is None: self.xmlnode = E.translate(' '.join([str(x),str(y),str(z)]))
def _recreateXmlNode(self): perspective_node = E.perspective() if self.xfov is not None: perspective_node.append(E.xfov(str(self.xfov))) if self.yfov is not None: perspective_node.append(E.yfov(str(self.yfov))) if self.aspect_ratio is not None: perspective_node.append(E.aspect_ratio(str(self.aspect_ratio))) perspective_node.append(E.znear(str(self.znear))) perspective_node.append(E.zfar(str(self.zfar))) self.xmlnode = E.camera( E.optics( E.technique_common(perspective_node) ) , id=self.id, name=self.id)
def _recreateXmlNode(self): orthographic_node = E.orthographic() if self.xmag is not None: orthographic_node.append(E.xmag(str(self.xmag))) if self.ymag is not None: orthographic_node.append(E.ymag(str(self.ymag))) if self.aspect_ratio is not None: orthographic_node.append(E.aspect_ratio(str(self.aspect_ratio))) orthographic_node.append(E.znear(str(self.znear))) orthographic_node.append(E.zfar(str(self.zfar))) self.xmlnode = E.camera( E.optics( E.technique_common(orthographic_node) ) , id=self.id, name=self.id)
def __init__(self, id, data, components, xmlnode=None): """Create a name source instance. :param str id: A unique string identifier for the source :param numpy.array data: Numpy array (unshaped) with the source values :param tuple components: Tuple of strings describing the semantic of the data, e.g. ``('JOINT')`` would cause :attr:`data` to be reshaped as ``(-1, 1)`` :param xmlnode: When loaded, the xmlnode it comes from. """ self.id = id """The unique string identifier for the source""" self.data = data """Numpy array with the source values. This will be shaped as ``(-1,N)`` where ``N = len(self.components)``""" self.data.shape = (-1, len(components) ) self.components = components """Tuple of strings describing the semantic of the data, e.g. ``('JOINT')``""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the source.""" else: self.data.shape = (-1,) txtdata = ' '.join(map(str, self.data.tolist() )) rawlen = len( self.data ) self.data.shape = (-1, len(self.components) ) acclen = len( self.data ) stridelen = len(self.components) sourcename = "%s-array"%self.id self.xmlnode = E.source( E.Name_array(txtdata, count=str(rawlen), id=sourcename), E.technique_common( E.accessor( *[E.param(type='Name', name=c) for c in self.components] , **{'count':str(acclen), 'stride':str(stridelen), 'source':sourcename}) ) , id=self.id )
def _recreateXmlNode(self): self.index.shape = (-1) acclen = len(self.index) txtindices = ' '.join(map(str, self.index.tolist())) self.index.shape = (-1, 3, self.nindices) self.xmlnode = E.triangles(count=str(self.ntriangles)) if self.material is not None: self.xmlnode.set('material', self.material) all_inputs = [] for semantic_list in self.sources.itervalues(): all_inputs.extend(semantic_list) for offset, semantic, sourceid, set, src in all_inputs: inpnode = E.input(offset=str(offset), semantic=semantic, source=sourceid) if set is not None: inpnode.set('set', str(set)) self.xmlnode.append(inpnode) self.xmlnode.append(E.p(txtindices))
def _recreateXmlNode(self): self.xmlnode = E.asset() for contributor in self.contributors: self.xmlnode.append(contributor.xmlnode) self.xmlnode.append(E.created(self.created.isoformat())) if self.keywords is not None: self.xmlnode.append(E.keywords(self.keywords)) self.xmlnode.append(E.modified(self.modified.isoformat())) if self.revision is not None: self.xmlnode.append(E.revision(self.revision)) if self.subject is not None: self.xmlnode.append(E.subject(self.subject)) if self.title is not None: self.xmlnode.append(E.title(self.title)) if self.unitmeter is not None and self.unitname is not None: self.xmlnode.append(E.unit(name=self.unitname, meter=str(self.unitmeter))) self.xmlnode.append(E.up_axis(self.upaxis))
def __init__(self, xmlnode): """Create an extra node which stores arbitrary xml :param xmlnode: Should be an ElementTree instance of tag type <extra> """ if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the extra node.""" else: self.xmlnode = E.extra()
def save(self): """Saves the surface data back to :attr:`xmlnode`""" surfacenode = self.xmlnode.find( tag('surface') ) initnode = surfacenode.find( tag('init_from') ) if self.format: formatnode = surfacenode.find( tag('format') ) if formatnode is None: surfacenode.append(E.format(self.format)) else: formatnode.text = self.format initnode.text = self.image.id self.xmlnode.set('sid', self.id)
def __init__(self, id, color, xmlnode=None): """Create a new ambient light. :Parameters: id Id for the object color Light color xmlnode If load form xml, the xml node """ self.id = id """Id in the light library.""" self.color = color """Light color.""" if xmlnode != None: self.xmlnode = xmlnode else: self.xmlnode = E.light( E.technique_common(E.ambient(E.color(" ".join([str(v) for v in self.color])))), id=self.id, name=self.id )
def save(self): """Saves the material node back to :attr:`xmlnode`""" self.xmlnode.set('symbol', self.symbol) self.xmlnode.set('target', "#%s"%self.target.id) inputs_in = [] for i in self.xmlnode.findall( tag('bind_vertex_input') ): input_tuple = ( i.get('semantic'), i.get('input_semantic'), i.get('input_set') ) if input_tuple not in self.inputs: self.xmlnode.remove(i) else: inputs_in.append(input_tuple) for i in self.inputs: if i not in inputs_in: self.xmlnode.append(E.bind_vertex_input(semantic=i[0], input_semantic=i[1], input_set=i[2]))
def __init__(self, camera, xmlnode=None): """Create a camera instance :param collada.camera.Camera camera: The camera being instantiated :param xmlnode: When loaded, the xmlnode it comes from """ self.camera = camera """An object of type :class:`collada.camera.Camera` representing the instantiated camera""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the camera node.""" else: self.xmlnode = E.instance_camera(url="#%s"%camera.id)
def __init__(self, light, xmlnode=None): """Create a light instance :param collada.light.Light light: The light being instantiated :param xmlnode: When loaded, the xmlnode it comes from """ self.light = light """An object of type :class:`collada.light.Light` representing the instantiated light""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the light node.""" else: self.xmlnode = E.instance_light(url="#%s"%light.id)
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)))
def __init__(self, node, xmlnode=None): """Creates a node node :param collada.scene.Node node: A node to instantiate in the scene :param xmlnode: When loaded, the xmlnode it comes from """ self.node = node """An object of type :class:`collada.scene.Node` representing the node to bind in the scene""" if xmlnode != None: self.xmlnode = xmlnode """ElementTree representation of the node node.""" else: self.xmlnode = E.instance_node(url="#%s" % self.node.id)
def __init__(self, id, children=None, transforms=None, xmlnode=None): """Create a node in the scene graph. :param str id: A unique string identifier for the node :param list children: A list of child nodes of this node. This can contain any object that inherits from :class:`collada.scene.SceneNode` :param list transforms: A list of transformations effecting the node. This can contain any object that inherits from :class:`collada.scene.Transform` :param xmlnode: When loaded, the xmlnode it comes from """ self.id = id """The unique string identifier for the node""" self.children = [] """A list of child nodes of this node. This can contain any object that inherits from :class:`collada.scene.SceneNode`""" if children is not None: self.children = children self.transforms = [] if transforms is not None: self.transforms = transforms """A list of transformations effecting the node. This can contain any object that inherits from :class:`collada.scene.Transform`""" self.matrix = numpy.identity(4, dtype=numpy.float32) """A numpy.array of size 4x4 containing a transformation matrix that combines all the transformations in :attr:`transforms`. This will only be updated after calling :meth:`save`.""" for t in self.transforms: self.matrix = numpy.dot(self.matrix, t.matrix) if xmlnode is not None: self.xmlnode = xmlnode """ElementTree representation of the transform.""" else: self.xmlnode = E.node(id=self.id, name=self.id) for t in self.transforms: self.xmlnode.append(t.xmlnode) for c in self.children: self.xmlnode.append(c.xmlnode)