def _create_anim_src_elem(anim_name, src_data, src_suffix, src_type, param_name, param_type): """""" idName = anim_name + "-" + src_suffix src_elem = E.source(id=idName) idName += "-array" count = len(src_data) / 16 if param_type == "float4x4" else len( src_data) if src_type == "float": str_src_data = " ".join( [str(round(val, precision)) for val in src_data]) + " " str_src_data = str_src_data.replace(".0 ", " ") else: str_src_data = " ".join(map(str, src_data)) src_elem.append( E(src_type + "_array", str_src_data, id=idName, count=str(count))) src_elem.append( E.technique_common( E.accessor( E.param(name=param_name, type=param_type), #accessor child source="#" + idName, count=str(count) #accessor attribs ))) if param_type == "float4x4": src_elem.find(tag("technique_common")).find(tag("accessor")).set( "stride", str(16)) return src_elem
def _correctValInNode(outernode, tagname, value): innernode = outernode.find( tag(tagname) ) if value is None and innernode is not None: outernode.remove(innernode) elif innernode is not None: innernode.text = str(value) elif value is not None: outernode.append(E(tagname, str(value)))
def save(self): """Saves the collada document back to :attr:`xmlnode`""" libraries = [(self.geometries, 'library_geometries'), (self.controllers, 'library_controllers'), (self.lights, 'library_lights'), (self.cameras, 'library_cameras'), (self.images, 'library_images'), (self.effects, 'library_effects'), (self.materials, 'library_materials'), (self.nodes, 'library_nodes'), (self.scenes, 'library_visual_scenes')] self.assetInfo.save() assetnode = self.xmlnode.getroot().find(self.tag('asset')) if assetnode is not None: self.xmlnode.getroot().remove(assetnode) self.xmlnode.getroot().insert(0, self.assetInfo.xmlnode) library_loc = 0 for i, node in enumerate(self.xmlnode.getroot()): if node.tag == self.tag('asset'): library_loc = i + 1 for arr, name in libraries: node = self.xmlnode.find(self.tag(name)) if node is None: if len(arr) == 0: continue self.xmlnode.getroot().insert(library_loc, E(name)) node = self.xmlnode.find(self.tag(name)) elif node is not None and len(arr) == 0: self.xmlnode.getroot().remove(node) continue for o in arr: o.save() if o.xmlnode not in node: node.append(o.xmlnode) xmlnodes = [o.xmlnode for o in arr] for n in node: if n not in xmlnodes: node.remove(n) scenenode = self.xmlnode.find(self.tag('scene')) scenenode.clear() if self.scene is not None: sceneid = self.scene.id if sceneid not in self.scenes: raise DaeBrokenRefError('Default scene %s not found' % sceneid) scenenode.append(E.instance_visual_scene(url="#%s" % sceneid)) if self.validator is not None: if not self.validator.validate(self.xmlnode): raise DaeSaveValidationError( "Validation error when saving: " + self.validator. COLLADA_SCHEMA_1_4_1_INSTANCE.error_log.last_error.message)
def getPropNode(prop, value): propnode = E(prop) if prop == 'transparent' and self.opaque_mode == OPAQUE_MODE.RGB_ZERO: propnode.set('opaque', OPAQUE_MODE.RGB_ZERO) 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 save(self): """Saves the effect back to :attr:`xmlnode`""" self.xmlnode.set('id', self.id) self.xmlnode.set('name', self.id) profilenode = self.xmlnode.find( tag('profile_COMMON') ) tecnode = profilenode.find( tag('technique') ) tecnode.set('sid', 'common') self._fixColorValues() for param in self.params: param.save() if param.xmlnode not in profilenode.getchildren(): profilenode.insert(list(profilenode).index(tecnode), param.xmlnode) deletenodes = [] for oldparam in profilenode.findall( tag('newparam') ): if oldparam not in [param.xmlnode for param in self.params]: deletenodes.append(oldparam) for d in deletenodes: profilenode.remove(d) for shader in self.shaders: shadnode = tecnode.find(tag(shader)) if shadnode is not None and shader != self.shadingtype: tecnode.remove(shadnode) def getPropNode(prop, value): propnode = E(prop) if prop == 'transparent' and self.opaque_mode == OPAQUE_MODE.RGB_ZERO: propnode.set('opaque', OPAQUE_MODE.RGB_ZERO) 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 shadnode = tecnode.find(tag(self.shadingtype)) if shadnode is None: shadnode = E(self.shadingtype) for prop in self.supported: value = getattr(self, prop) if value is None: continue shadnode.append(getPropNode(prop, value)) tecnode.append(shadnode) else: for prop in self.supported: value = getattr(self, prop) propnode = shadnode.find(tag(prop)) if propnode is not None: shadnode.remove(propnode) if value is not None: shadnode.append(getPropNode(prop, value)) double_sided_node = profilenode.find('.//%s//%s' % (tag('extra'), tag('double_sided'))) if double_sided_node is None or double_sided_node.text is None: extranode = profilenode.find(tag('extra')) if extranode is None: extranode = E.extra() profilenode.append(extranode) teqnodes = extranode.findall(tag('technique')) goognode = None for teqnode in teqnodes: if teqnode.get('profile') == 'GOOGLEEARTH': goognode = teqnode break if goognode is None: goognode = E.technique(profile='GOOGLEEARTH') extranode.append(goognode) double_sided_node = goognode.find(tag('double_sided')) if double_sided_node is None: double_sided_node = E.double_sided() goognode.append(double_sided_node) double_sided_node.text = "1" if self.double_sided else "0"
def __init__(self, id, params, shadingtype, bumpmap = None, double_sided = False, emission = (0.0, 0.0, 0.0, 1.0), ambient = (0.0, 0.0, 0.0, 1.0), diffuse = (0.0, 0.0, 0.0, 1.0), specular = (0.0, 0.0, 0.0, 1.0), shininess = 0.0, reflective = (0.0, 0.0, 0.0, 1.0), reflectivity = 0.0, transparent = (0.0, 0.0, 0.0, 1.0), transparency = None, index_of_refraction = None, opaque_mode = None, xmlnode = None): """Create an effect instance out of properties. :param str id: A string identifier for the effect :param list params: A list containing elements of type :class:`collada.material.Sampler2D` and :class:`collada.material.Surface` :param str shadingtype: The type of shader to be used for this effect. Right now, we only supper the shaders listed in :attr:`shaders` :param `collada.material.Map` bumpmap: The bump map for this effect, or None if there isn't one :param bool double_sided: Whether or not the material should be rendered double sided :param emission: Either an RGBA-format tuple of four floats or an instance of :class:`collada.material.Map` :param ambient: Either an RGBA-format tuple of four floats or an instance of :class:`collada.material.Map` :param diffuse: Either an RGBA-format tuple of four floats or an instance of :class:`collada.material.Map` :param specular: Either an RGBA-format tuple of four floats or an instance of :class:`collada.material.Map` :param shininess: Either a single float or an instance of :class:`collada.material.Map` :param reflective: Either an RGBA-format tuple of four floats or an instance of :class:`collada.material.Map` :param reflectivity: Either a single float or an instance of :class:`collada.material.Map` :param tuple transparent: Either an RGBA-format tuple of four floats or an instance of :class:`collada.material.Map` :param transparency: Either a single float or an instance of :class:`collada.material.Map` :param float index_of_refraction: A single float indicating the index of refraction for perfectly refracted light :param `collada.material.OPAQUE_MODE` opaque_mode: The opaque mode for the effect. If not specified, defaults to A_ONE. :param xmlnode: If loaded from xml, the xml node """ self.id = id """The string identifier for the effect""" self.params = params """A list containing elements of type :class:`collada.material.Sampler2D` and :class:`collada.material.Surface`""" self.shadingtype = shadingtype """String with the type of the shading.""" self.bumpmap = bumpmap """Either the bump map of the effect of type :class:`collada.material.Map` or None if there is none.""" self.double_sided = double_sided """A boolean indicating whether or not the material should be rendered double sided""" self.emission = emission """Either an RGB-format tuple of three floats or an instance of :class:`collada.material.Map`""" self.ambient = ambient """Either an RGB-format tuple of three floats or an instance of :class:`collada.material.Map`""" self.diffuse = diffuse """Either an RGB-format tuple of three floats or an instance of :class:`collada.material.Map`""" self.specular = specular """Either an RGB-format tuple of three floats or an instance of :class:`collada.material.Map`""" self.shininess = shininess """Either a single float or an instance of :class:`collada.material.Map`""" self.reflective = reflective """Either an RGB-format tuple of three floats or an instance of :class:`collada.material.Map`""" self.reflectivity = reflectivity """Either a single float or an instance of :class:`collada.material.Map`""" self.transparent = transparent """Either an RGB-format tuple of three floats or an instance of :class:`collada.material.Map`""" self.transparency = transparency """Either a single float or an instance of :class:`collada.material.Map`""" self.index_of_refraction = index_of_refraction """A single float indicating the index of refraction for perfectly refracted light""" self.opaque_mode = OPAQUE_MODE.A_ONE if opaque_mode is None else opaque_mode """The opaque mode for the effect. An instance of :class:`collada.material.OPAQUE_MODE`.""" if self.transparency is None: if self.opaque_mode == OPAQUE_MODE.A_ONE: self.transparency = 1.0 else: self.transparency = 0.0 self._fixColorValues() if xmlnode is not None: self.xmlnode = xmlnode """ElementTree representation of the effect""" else: shadnode = E(self.shadingtype) for prop in self.supported: value = getattr(self, prop) if value is None: continue propnode = E(prop) if prop == 'transparent' and self.opaque_mode == OPAQUE_MODE.RGB_ZERO: propnode.set('opaque', OPAQUE_MODE.RGB_ZERO) shadnode.append( propnode ) if type(value) is Map: propnode.append(value.xmlnode) elif type(value) is float: propnode.append(E.float(str(value))) else: propnode.append(E.color(' '.join(map(str, value) ))) effect_nodes = [param.xmlnode for param in self.params] effect_nodes.append(E.technique(shadnode, sid='common')) self.xmlnode = E.effect( E.profile_COMMON(*effect_nodes) , id=self.id, name=self.id)
def write_collada_animation_from_transforms(collada_animation, collada_scene, timeline, transforms, precision): """ """ def _create_anim_src_elem(anim_name, src_data, src_suffix, src_type, param_name, param_type): """""" idName = anim_name + "-" + src_suffix src_elem = E.source(id=idName) idName += "-array" count = len(src_data) / 16 if param_type == "float4x4" else len( src_data) if src_type == "float": str_src_data = " ".join( [str(round(val, precision)) for val in src_data]) + " " str_src_data = str_src_data.replace(".0 ", " ") else: str_src_data = " ".join(map(str, src_data)) src_elem.append( E(src_type + "_array", str_src_data, id=idName, count=str(count))) src_elem.append( E.technique_common( E.accessor( E.param(name=param_name, type=param_type), #accessor child source="#" + idName, count=str(count) #accessor attribs ))) if param_type == "float4x4": src_elem.find(tag("technique_common")).find(tag("accessor")).set( "stride", str(16)) return src_elem def _create_anim_elem(name, timeline, value): """""" idName = name + "-animation" animElem = E.animation(id=idName) animElem.append( _create_anim_src_elem(idName, timeline, "input", "float", "TIME", "float")) animElem.append( _create_anim_src_elem(idName, ["STEP"] * len(timeline), "interpolation", "Name", "INTERPOLATION", "name")) animElem.append( _create_anim_src_elem(idName, value.flatten(), "output", "float", "TRANSFORM", "float4x4")) animElem.append( E.sampler(*[ E.input(semantic=sem.upper(), source="#" + idName + "-" + sem) for sem in ["input", "output", "interpolation"] ], id=idName + "-sampler")) animElem.append( E.channel(source="#" + idName + "-sampler", target=name + "/matrix")) return animElem dae = collada.Collada(collada_scene) # save animation node: this is not supported by pycollada, so the xml node is written using pycollada.common.E anim_lib = dae.xmlnode.find(tag('library_animations')) if anim_lib is None: children = list(dae.xmlnode.getroot()) dae.xmlnode.getroot().insert( children.index(dae.xmlnode.find(tag("scene"))), E('library_animations')) anim_lib = dae.xmlnode.find(tag('library_animations')) for name, val in transforms.items(): anim_lib.append(_create_anim_elem(name, timeline, val)) _write_pycollada_in_file(dae, collada_animation)