Пример #1
0
def save_embeddedvoxel(item: Item, vmf: VMF) -> None:
    """Save embedded voxel volumes."""
    for bbox_min, bbox_max in bounding_boxes(item.embed_voxels):
        vmf.create_ent('bee2_editor_embeddedvoxel').solids.append(
            vmf.make_prism(
                Vec(bbox_min) * 128 + (-64.0, -64.0, -192.0),
                Vec(bbox_max) * 128 + (+64.0, +64.0, -64.0),
                # Entirely ignored, but makes it easier to distinguish.
                'tools/toolshint',
            ).solid)
Пример #2
0
def save_occupiedvoxel(item: Item, vmf: VMF) -> None:
    """Save occupied voxel volumes."""
    for voxel in item.occupy_voxels:
        pos = Vec(voxel.pos) * 128

        if voxel.subpos is not None:
            pos += Vec(voxel.subpos) * 32 - (48, 48, 48)
            p1 = pos - (16.0, 16.0, 16.0)
            p2 = pos + (16.0, 16.0, 16.0)
            norm_dist = 32.0 - 4.0
        else:
            p1 = pos - (64.0, 64.0, 64.0)
            p2 = pos + (64.0, 64.0, 64.0)
            norm_dist = 128.0 - 4.0

        if voxel.normal is not None:
            for axis in ['x', 'y', 'z']:
                val = getattr(voxel.normal, axis)
                if val == +1:
                    p2[axis] -= norm_dist
                elif val == -1:
                    p1[axis] += norm_dist

        if voxel.against is not None:
            against = str(voxel.against).replace('COLLIDE_', '')
        else:
            against = ''

        vmf.create_ent(
            'bee2_editor_occupiedvoxel',
            coll_type=str(voxel.type).replace('COLLIDE_', ''),
            coll_against=against,
        ).solids.append(
            vmf.make_prism(
                p1,
                p2,
                # Use clip for voxels, invisible for normals.
                # Entirely ignored, but makes it easier to use.
                'tools/toolsclip'
                if voxel.normal is None else 'tools/toolsinvisible',
            ).solid)
Пример #3
0
    def setup(self, vmf: VMF, global_seed: str,
              tiles: List['TileDef']) -> None:
        """Build the list of clump locations."""
        assert self.portal is not None
        assert self.orient is not None

        # Convert the generator key to a generator-specific seed.
        # That ensures different surfaces don't end up reusing the same
        # texture indexes.
        self.gen_seed = int.from_bytes(
            self.category.name.encode() + self.portal.name.encode() +
            self.orient.name.encode(),
            'big',
        )

        LOGGER.info('Generating texture clumps...')

        clump_length: int = self.options['clump_length']
        clump_width: int = self.options['clump_width']

        # The tiles currently present in the map.
        orient_z = self.orient.z
        remaining_tiles: Set[Tuple[float, float, float]] = {
            (tile.pos + 64 * tile.normal // 128 * 128).as_tuple()
            for tile in tiles if tile.normal.z == orient_z
        }

        # A global RNG for picking clump positions.
        clump_rand = random.Random(global_seed + '_clumping')

        pos_min = Vec()
        pos_max = Vec()

        # For debugging, generate skip brushes with the shape of the clumps.
        debug_visgroup: Optional[VisGroup]
        if self.options['clump_debug']:
            debug_visgroup = vmf.create_visgroup(
                f'{self.category.name}_{self.orient.name}_{self.portal.name}')
        else:
            debug_visgroup = None

        while remaining_tiles:
            # Pick from a random tile.
            tile_pos = next(
                itertools.islice(
                    remaining_tiles,
                    clump_rand.randrange(0, len(remaining_tiles)),
                    len(remaining_tiles),
                ))
            remaining_tiles.remove(tile_pos)

            pos = Vec(tile_pos)

            # Clumps are long strips mainly extended in one direction
            # In the other directions extend by 'width'. It can point any axis.
            direction = clump_rand.choice('xyz')
            for axis in 'xyz':
                if axis == direction:
                    dist = clump_length
                else:
                    dist = clump_width
                pos_min[axis] = pos[axis] - clump_rand.randint(0, dist) * 128
                pos_max[axis] = pos[axis] + clump_rand.randint(0, dist) * 128

            remaining_tiles.difference_update(
                map(Vec.as_tuple, Vec.iter_grid(pos_min, pos_max, 128)))

            self._clump_locs.append(
                Clump(
                    pos_min.x,
                    pos_min.y,
                    pos_min.z,
                    pos_max.x,
                    pos_max.y,
                    pos_max.z,
                    # We use this to reseed an RNG, giving us the same textures
                    # each time for the same clump.
                    clump_rand.getrandbits(32),
                ))
            if debug_visgroup is not None:
                # noinspection PyUnboundLocalVariable
                debug_brush: Solid = vmf.make_prism(
                    pos_min - 64,
                    pos_max + 64,
                    'tools/toolsskip',
                ).solid
                debug_brush.visgroup_ids.add(debug_visgroup.id)
                debug_brush.vis_shown = False
                vmf.add_brush(debug_brush)

        LOGGER.info(
            '{}.{}.{}: {} Clumps for {} tiles',
            self.category.name,
            self.orient.name,
            self.portal.name,
            len(self._clump_locs),
            len(tiles),
        )