예제 #1
0
def _walk_point_cache(ctx: ModifierContext, block_name: bytes,
                      bfile: blendfile.BlendFile,
                      pointcache: blendfile.BlendFileBlock, extension: bytes):
    flag = pointcache[b'flag']
    if flag & cdefs.PTCACHE_EXTERNAL:
        path, field = pointcache.get(b'path', return_field=True)
        log.info('    external cache at %s', path)
        bpath = bpathlib.BlendPath(path)
        yield result.BlockUsage(pointcache,
                                bpath,
                                path_full_field=field,
                                is_sequence=True,
                                block_name=block_name)
    elif flag & cdefs.PTCACHE_DISK_CACHE:
        # See ptcache_path() in pointcache.c
        name, field = pointcache.get(b'name', return_field=True)
        if not name:
            # See ptcache_filename() in pointcache.c
            idname = ctx.owner[b'id', b'name']
            name = idname[2:].hex().upper().encode()
        path = b'//%b%b/%b_*%b' % (
            cdefs.PTCACHE_PATH, bfile.filepath.stem.encode(), name, extension)
        log.info('   disk cache at %s', path)
        bpath = bpathlib.BlendPath(path)
        yield result.BlockUsage(pointcache,
                                bpath,
                                path_full_field=field,
                                is_sequence=True,
                                block_name=block_name)
예제 #2
0
def scene(
        block: blendfile.BlendFileBlock) -> typing.Iterator[result.BlockUsage]:
    """Scene data blocks."""
    # Sequence editor is the only interesting bit.
    block_ed = block.get_pointer(b'ed')
    if block_ed is None:
        return

    single_asset_types = {
        cdefs.SEQ_TYPE_MOVIE, cdefs.SEQ_TYPE_SOUND_RAM, cdefs.SEQ_TYPE_SOUND_HD
    }
    asset_types = single_asset_types.union({cdefs.SEQ_TYPE_IMAGE})

    for seq, seq_type in iterators.sequencer_strips(block_ed):
        if seq_type not in asset_types:
            continue

        seq_strip = seq.get_pointer(b'strip')
        if seq_strip is None:
            continue
        seq_stripdata = seq_strip.get_pointer(b'stripdata')
        if seq_stripdata is None:
            continue

        dirname, dn_field = seq_strip.get(b'dir', return_field=True)
        basename, bn_field = seq_stripdata.get(b'name', return_field=True)
        asset_path = bpathlib.BlendPath(dirname) / basename

        is_sequence = seq_type not in single_asset_types
        yield result.BlockUsage(seq_strip,
                                asset_path,
                                is_sequence=is_sequence,
                                path_dir_field=dn_field,
                                path_base_field=bn_field)
예제 #3
0
    def _visit_blocks(self, bfile, limit_to):
        bpath = bfile.filepath.absolute().resolve()
        root_dir = bpathlib.BlendPath(bpath.parent)

        # Mapping from library path to data blocks to expand.
        blocks_per_lib = collections.defaultdict(set)

        while not self.to_visit.empty():
            block = self.to_visit.get()
            assert isinstance(block, blendfile.BlendFileBlock)
            if (bpath, block.addr_old) in self.blocks_yielded:
                continue

            if block.code == b'ID':
                # ID blocks represent linked-in assets. Those are the ones that
                # should be loaded from their own blend file and "expanded" to
                # the entire set of data blocks required to render them. We
                # defer the handling of those so that we can work with one
                # blend file at a time.
                lib = block.get_pointer(b'lib')
                lib_bpath = bpathlib.BlendPath(lib[b'name']).absolute(root_dir)
                blocks_per_lib[lib_bpath].add(block)

                # The library block itself should also be reported, because it
                # represents a blend file that is a dependency as well.
                self.to_visit.put(lib)
                continue

            if limit_to:
                # We're limiting the blocks, so we have to expand them to make
                # sure we don't miss anything. Otherwise we're yielding the
                # entire file anyway, and no expansion is necessary.
                self._queue_dependencies(block)
            self.blocks_yielded.add((bpath, block.addr_old))
            yield block

        return blocks_per_lib
예제 #4
0
    def abspath(self, relpath: bpathlib.BlendPath) -> bpathlib.BlendPath:
        """Construct an absolute path from a blendfile-relative path."""

        if relpath.is_absolute():
            return relpath

        bfile_dir = self.filepath.absolute().parent
        root = bpathlib.BlendPath(bfile_dir)
        abspath = relpath.absolute(root)

        my_log = self.log.getChild('abspath')
        my_log.debug('Resolved %s relative to %s to %s', relpath,
                     self.filepath, abspath)

        return abspath
예제 #5
0
파일: test_pack.py 프로젝트: GigiSpligi/bat
    def test_execute_rewrite(self):
        infile, _ = self._pack_with_rewrite()

        extpath = pathlib.PurePosixPath('//_outside_project',
                                        *self.blendfiles.parts[1:])
        extbpath = bpathlib.BlendPath(extpath)

        # Those libraries should be properly rewritten.
        bfile = blendfile.open_cached(self.tpath / infile.name,
                                      assert_cached=False)
        libs = sorted(bfile.code_index[b'LI'])
        self.assertEqual(b'LILib', libs[0].id_name)
        self.assertEqual(extbpath / b'linked_cube.blend', libs[0][b'name'])
        self.assertEqual(b'LILib.002', libs[1].id_name)
        self.assertEqual(extbpath / b'material_textures.blend',
                         libs[1][b'name'])
예제 #6
0
def modifier_fluid_sim(ctx: ModifierContext, modifier: blendfile.BlendFileBlock, block_name: bytes) \
        -> typing.Iterator[result.BlockUsage]:
    my_log = log.getChild('modifier_fluid_sim')

    fss = modifier.get_pointer(b'fss')
    if fss is None:
        my_log.debug('Modifier %r (%r) has no fss',
                     modifier[b'modifier', b'name'], block_name)
        return

    path, field = fss.get(b'surfdataPath', return_field=True)

    # This may match more than is used by Blender, but at least it shouldn't
    # miss any files.
    # The 'fluidsurface' prefix is defined in source/blender/makesdna/DNA_object_fluidsim_types.h
    bpath = bpathlib.BlendPath(path)
    yield result.BlockUsage(fss,
                            bpath,
                            path_full_field=field,
                            is_sequence=True,
                            block_name=block_name)
예제 #7
0
    def __init__(
        self,
        block: blendfile.BlendFileBlock,
        asset_path: bpathlib.BlendPath,
        is_sequence: bool = False,
        path_full_field: dna.Field = None,
        path_dir_field: dna.Field = None,
        path_base_field: dna.Field = None,
        block_name: bytes = b'',
    ) -> None:
        if block_name:
            self.block_name = block_name
        else:
            self.block_name = self.guess_block_name(block)

        assert isinstance(block, blendfile.BlendFileBlock)
        assert isinstance(asset_path, (bytes, bpathlib.BlendPath)), \
            'asset_path should be BlendPath, not %r' % type(asset_path)

        if path_full_field is None:
            assert isinstance(path_dir_field, dna.Field), \
                'path_dir_field should be dna.Field, not %r' % type(path_dir_field)
            assert isinstance(path_base_field, dna.Field), \
                'path_base_field should be dna.Field, not %r' % type(path_base_field)
        else:
            assert isinstance(path_full_field, dna.Field), \
                'path_full_field should be dna.Field, not %r' % type(path_full_field)

        if isinstance(asset_path, bytes):
            asset_path = bpathlib.BlendPath(asset_path)

        self.block = block
        self.asset_path = asset_path
        self.is_sequence = bool(is_sequence)
        self.path_full_field = path_full_field
        self.path_dir_field = path_dir_field
        self.path_base_field = path_base_field

        # cached by __fspath__()
        self._abspath = None  # type: typing.Optional[pathlib.Path]
예제 #8
0
파일: test_pack.py 프로젝트: GigiSpligi/bat
    def test_rewrite_sequence(self):
        ppath = self.blendfiles / 'subdir'
        infile = ppath / 'image_sequence_dir_up.blend'

        with pack.Packer(infile, ppath, self.tpath) as packer:
            packer.strategise()
            packer.execute()

        bf = blendfile.open_cached(self.tpath / infile.name,
                                   assert_cached=False)
        scene = bf.code_index[b'SC'][0]
        ed = scene.get_pointer(b'ed')
        seq = ed.get_pointer((b'seqbase', b'first'))
        seq_strip = seq.get_pointer(b'strip')

        imgseq_path = (self.blendfiles / 'imgseq').absolute()
        as_bytes = str(imgseq_path.relative_to(imgseq_path.anchor)).encode()
        relpath = bpathlib.BlendPath(b'//_outside_project') / as_bytes

        # The image sequence base path should be rewritten.
        self.assertEqual(b'SQ000210.png', seq[b'name'])
        self.assertEqual(relpath, seq_strip[b'dir'])