def process(self, definitions_asset, nodes, nvtristrip, materials, effects):
        # Look at the material to check for geometry requirements
        need_normals = False
        need_tangents = False
        generate_normals = False
        generate_tangents = False

        # Assumed to be a graphics geometry
        is_graphics_geometry = True

        if is_graphics_geometry:
            LOG.info('"%s" is assumed to be a graphics geometry. ' \
                     'Check referencing node for physics properties otherwise', self.name)
            self.meta['graphics'] = True

        def _find_material_from_instance_on_node(mat, node):
            for instance in node.instance_geometry:
                if instance.geometry == self.id:
                    for surface, material in instance.materials.iteritems():
                        if surface == mat:
                            return material
            for child in node.children:
                material = _find_material_from_instance_on_node(mat, child)
                if material is not None:
                    return material
            return None

        for mat_name in self.surfaces.iterkeys():
            # Ok, we have a mat_name but this may need to be mapped if the node has an instanced material.
            # So we find the node referencing this geometry, and see if the material has a mapping on it.
            for _, node in nodes.iteritems():
                instance_mat_name = _find_material_from_instance_on_node(mat_name, node)
                if instance_mat_name is not None:
                    LOG.debug('Using instance material:%s to %s', mat_name, instance_mat_name)
                    mat_name = instance_mat_name
                    break

            if mat_name is None:
                mat_name = 'default'

            effect_name = None
            meta = { }

            material = definitions_asset.retrieve_material(mat_name, False)
            if material is not None:
                effect_name = material.get('effect', None)
                if 'meta' in material:
                    meta.update(material['meta'])
            else:
                material = materials.get(mat_name, None)
                if material is not None:
                    effect_name = material.effect_name
                    # Dae2Material has no meta data, everything is on Dae2Effect
                else:
                    continue

            if effect_name is not None:
                effect = definitions_asset.retrieve_effect(effect_name)
                if effect is not None:
                    if 'meta' in effect:
                        meta.update(effect['meta'])
                else:
                    effect = effects.get(effect_name, None)
                    if effect is not None and effect.meta is not None:
                        meta.update(effect.meta)

            if meta.get('normals', False) is True:
                need_normals = True

            if meta.get('tangents', False) is True:
                need_tangents = True

            if meta.get('generate_normals', False) is True:
                generate_normals = True

            if meta.get('generate_tangents', False) is True:
                generate_tangents = True
                break

        if need_normals and 'NORMAL' not in self.inputs:
            generate_normals = True

        if need_tangents and 'TANGENT' not in self.inputs and 'BINORMAL' not in self.inputs:
            generate_tangents = True

        if generate_normals is False and generate_tangents is False and nvtristrip is None:
            return

        # Generate a single vertex pool.
        new_sources = { }
        old_semantics = { }
        old_offsets = { }

        has_uvs = False
        for semantic, input_stream in self.inputs.iteritems():
            new_sources[input_stream.source] = [ ]
            old_offsets[input_stream.source] = input_stream.offset
            old_semantics[semantic] = True
            if semantic == 'TEXCOORD' or semantic == 'TEXCOORD0':
                has_uvs = True

        if generate_tangents:
            if has_uvs is False:
                LOG.warning('Material "%s" requires tangents but geometry "%s" has no UVs', mat_name, self.name)
                return

        for mat_name, surface in self.surfaces.iteritems():
            if surface.type == JsonAsset.SurfaceTriangles:
                if generate_tangents:
                    LOG.info('Process:generate_tangents:geometry:%s:surface:%s', self.name, mat_name)
                elif generate_normals:
                    LOG.info('Process:generate_normals:geometry:%s:surface:%s', self.name, mat_name)
            elif surface.type == JsonAsset.SurfaceQuads:
                triangles = [ ]
                for (q0, q1, q2, q3) in surface.primitives:
                    triangles.append( ( q0, q1, q2) )
                    triangles.append( ( q0, q2, q3) )
                surface.primitives = triangles
                surface.type = JsonAsset.SurfaceTriangles
                LOG.info('Triangulated geometry:%s:surface:%s', self.name, mat_name)
                if generate_tangents:
                    LOG.info('Process:generate_tangents:geometry:%s:surface:%s', self.name, mat_name)
                elif generate_normals:
                    LOG.info('Process:generate_normals:geometry:%s:surface:%s', self.name, mat_name)
            else:
                return

        # For each surface in the geometry...
        new_surfaces = { }

        index = 0
        for mat_name, surface in self.surfaces.iteritems():
            start_index = index
            surface_sources = surface.sources

            # For each primitive within the surface...
            for primitive in surface.primitives:
                index += 1

                if isinstance(primitive[0], (tuple, list)):
                    # For each input source and input offset...
                    for source, offset in old_offsets.iteritems():
                        new_source = new_sources[source]
                        if source in surface_sources:
                            source_values = self.sources[source].values
                            # For each vertex in the primitive (triangle or quad)...
                            for vertex in primitive:
                                new_source.append( source_values[vertex[offset]] )
                        else:
                            zero = self.sources[source].zero_value
                            for vertex in primitive:
                                new_source.append(zero)
                else:
                    # For each input source and input offset...
                    for source in old_offsets.iterkeys():
                        new_source = new_sources[source]
                        if source in surface_sources:
                            source_values = self.sources[source].values
                            # For each vertex in the primitive (triangle or quad)...
                            for vertex in primitive:
                                new_source.append( source_values[vertex] )
                        else:
                            zero = self.sources[source].zero_value
                            for vertex in primitive:
                                new_source.append(zero)

            end_index = index
            new_surfaces[mat_name] = (start_index, end_index)

        mesh = Mesh()
        for semantic, input_stream in self.inputs.iteritems():
            mesh.set_values(new_sources[input_stream.source], semantic)

        mesh.primitives = [ (i, i + 1, i + 2) for i in range(0, index * 3, 3) ]
        #mesh.mirror_in('z')

        if generate_normals:
            mesh.generate_normals()
            mesh.smooth_normals()
            old_semantics['NORMAL'] = True

        if generate_tangents:
            mesh.generate_tangents()
            mesh.normalize_tangents()
            mesh.smooth_tangents()
            mesh.generate_normals_from_tangents()
            mesh.smooth_normals()
            old_semantics['TANGENT'] = True
            old_semantics['BINORMAL'] = True

        def compact_stream(values, semantic):
            """Generate a new value and index stream remapping and removing duplicate elements."""
            new_values = [ ]
            new_values_hash = { }
            new_index = [ ]
            for v in values:
                if v in new_values_hash:
                    new_index.append(new_values_hash[v])
                else:
                    i = len(new_values)
                    new_index.append(i)
                    new_values.append(v)
                    new_values_hash[v] = i

            LOG.info('%s stream compacted from %i to %i elements', semantic, len(values), len(new_values))
            return (new_values, new_index)

        # !!! This should be updated to find index buffers that are similar rather than identical.
        new_indexes = [ ]
        new_offsets = { }
        for semantic in old_semantics.iterkeys():
            values = mesh.get_values(semantic)
            (new_values, new_values_index) = compact_stream(values, semantic)
            mesh.set_values(new_values, semantic)
            for i, indexes in enumerate(new_indexes):
                if indexes == new_values_index:
                    new_offsets[semantic] = i
                    break
            else:
                new_offsets[semantic] = len(new_indexes)
                new_indexes.append(new_values_index)

        indexes = zip(*new_indexes)

        # Use NVTriStrip to generate a vertex cache aware triangle list
        if nvtristrip is not None:
            for (start_index, end_index) in new_surfaces.itervalues():
                reverse_map = {}
                indexes_map = {}
                num_vertices = 0
                for n in xrange(start_index * 3, end_index * 3):
                    index = indexes[n]
                    if index not in indexes_map:
                        indexes_map[index] = num_vertices
                        reverse_map[num_vertices] = index
                        num_vertices += 1
                #LOG.info(num_vertices)

                if num_vertices < 65536:
                    #LOG.info(indexes)
                    try:
                        nvtristrip_proc = subprocess.Popen([nvtristrip],
                                                           stdin = subprocess.PIPE,
                                                           stdout = subprocess.PIPE)

                        stdin_write = nvtristrip_proc.stdin.write
                        for n in xrange(start_index * 3, end_index * 3):
                            index = indexes[n]
                            value = indexes_map[index]
                            stdin_write(str(value) + "\n")
                        stdin_write("-1\n")
                        stdin_write = None
                        indexes_map = None

                        stdout_readline = nvtristrip_proc.stdout.readline
                        try:
                            num_groups = int(stdout_readline())
                            group_type = int(stdout_readline())
                            num_indexes = int(stdout_readline())
                            if num_groups != 1 or group_type != 0 or num_indexes != (end_index - start_index) * 3:
                                LOG.warning("NvTriStripper failed: %d groups, type %d, %d indexes.",
                                            num_groups, group_type, num_indexes)
                            else:
                                n = start_index * 3
                                for value in stdout_readline().split():
                                    value = int(value)
                                    indexes[n] = reverse_map[value]
                                    n += 1
                        except ValueError as e:
                            error_string = str(e).split("'")
                            if 1 < len(error_string):
                                error_string = error_string[1]
                            else:
                                error_string = str(e)
                            LOG.warning("NvTriStripper failed: %s", error_string)
                        stdout_readline = None
                        nvtristrip_proc = None
                        #LOG.info(indexes)

                    except __HOLE__ as e:
                        LOG.warning("NvTriStripper failed: " + str(e))
                else:
                    LOG.warning("Too many vertices to use NvTriStrip: %d", num_vertices)
                indexes_map = None
                reverse_map = None

        primitives = [ (indexes[i], indexes[i + 1], indexes[i + 2]) for i in xrange(0, len(indexes), 3) ]

        # Fix up the surfaces...
        for mat_name, (start_index, end_index) in new_surfaces.iteritems():
            self.surfaces[mat_name].primitives = primitives[start_index:end_index]

        # Fix up the inputs...
        for semantic, input_stream in self.inputs.iteritems():
            input_stream.offset = new_offsets[semantic]

        # Fix up the sources...
        for _, source in self.sources.iteritems():
            source.values = mesh.get_values(source.semantic)

        if generate_normals:
            self.inputs['NORMAL'] = Dae2Geometry.Input('NORMAL', 'normals', new_offsets['NORMAL'])
            self.sources['normals'] = Dae2Geometry.Source(mesh.normals, 'NORMAL', 'normals', 3, len(mesh.normals))

        if generate_tangents:
            self.inputs['BINORMAL'] = Dae2Geometry.Input('BINORMAL', 'binormals', new_offsets['BINORMAL'])
            self.inputs['TANGENT'] = Dae2Geometry.Input('TANGENT', 'tangents', new_offsets['TANGENT'])
            self.sources['binormals'] = Dae2Geometry.Source(mesh.binormals,
                                                            'BINORMAL',
                                                            'binormals',
                                                            3,
                                                            len(mesh.binormals))
            self.sources['tangents'] = Dae2Geometry.Source(mesh.tangents,
                                                           'TANGENT',
                                                           'tangents',
                                                           3,
                                                           len(mesh.tangents))
   # pylint: enable=R0914
dataset/ETHPy150Open turbulenz/turbulenz_tools/turbulenz_tools/tools/dae2json.py/Dae2Geometry.process