コード例 #1
0
ファイル: signage.py プロジェクト: slawekwaga/BEE2.4
def place_sign(
    vmf: VMF,
    faces: Iterable[Side],
    sign: Sign,
    pos: Vec,
    normal: Vec,
    forward: Vec,
    rotate: bool = True,
) -> None:
    """Place the sign into the map."""

    if rotate and normal.z == 0:
        # On the wall, point upward.
        forward = Vec(0, 0, 1)

    texture = sign.overlay
    if texture.startswith('<') and texture.endswith('>'):
        texture = vbsp.get_tex(texture[1:-1])

    width, height = SIZES[sign.type]
    over = make_overlay(
        vmf,
        -normal,
        pos,
        uax=-width * Vec.cross(normal, forward).norm(),
        vax=-height * forward,
        material=texture,
        surfaces=faces,
    )

    over['startu'] = '1'
    over['endu'] = '0'

    vbsp.IGNORED_OVERLAYS.add(over)
コード例 #2
0
ファイル: brushes.py プロジェクト: mariovct/BEE2.4
def res_add_brush(inst: Entity, res: Property):
    """Spawn in a brush at the indicated points.

    - point1 and point2 are locations local to the instance, with `0 0 0`
      as the floor-position.
    - type is either `black` or `white`.
    - detail should be set to True/False. If true the brush will be a
      func_detail instead of a world brush.

    The sides will be textured with 1x1, 2x2 or 4x4 wall, ceiling and floor
    textures as needed.
    """
    import vbsp

    point1 = Vec.from_str(res['point1'])
    point2 = Vec.from_str(res['point2'])

    point1.z -= 64  # Offset to the location of the floor
    point2.z -= 64

    # Rotate to match the instance
    point1.rotate_by_str(inst['angles'])
    point2.rotate_by_str(inst['angles'])

    origin = Vec.from_str(inst['origin'])
    point1 += origin  # Then offset to the location of the instance
    point2 += origin

    tex_type = res['type', None]
    if tex_type not in ('white', 'black'):
        LOGGER.warning(
            'AddBrush: "{}" is not a valid brush '
            'color! (white or black)',
            tex_type,
        )
        tex_type = 'black'

    dim = point2 - point1
    dim.max(-dim)

    # Figure out what grid size and scale is needed
    # Check the dimensions in two axes to figure out the largest
    # tile size that can fit in it.
    x_maxsize = min(dim.y, dim.z)
    y_maxsize = min(dim.x, dim.z)
    if x_maxsize <= 32:
        x_grid = '4x4'
    elif x_maxsize <= 64:
        x_grid = '2x2'
    else:
        x_grid = 'wall'

    if y_maxsize <= 32:
        y_grid = '4x4'
    elif y_maxsize <= 64:
        y_grid = '2x2'
    else:
        y_grid = 'wall'

    grid_offset = origin // 128  # type: Vec

    # All brushes in each grid have the same textures for each side.
    random.seed(grid_offset.join(' ') + '-partial_block')

    solids = vbsp.VMF.make_prism(point1, point2)
    ':type solids: VLib.PrismFace'

    # Ensure the faces aren't re-textured later
    vbsp.IGNORED_FACES.update(solids.solid.sides)

    solids.north.mat = vbsp.get_tex(tex_type + '.' + y_grid)
    solids.south.mat = vbsp.get_tex(tex_type + '.' + y_grid)
    solids.east.mat = vbsp.get_tex(tex_type + '.' + x_grid)
    solids.west.mat = vbsp.get_tex(tex_type + '.' + x_grid)
    solids.top.mat = vbsp.get_tex(tex_type + '.floor')
    solids.bottom.mat = vbsp.get_tex(tex_type + '.ceiling')

    if srctools.conv_bool(res['detail', False], False):
        # Add the brush to a func_detail entity
        vbsp.VMF.create_ent(classname='func_detail').solids = [solids.solid]
    else:
        # Add to the world
        vbsp.VMF.add_brush(solids.solid)
コード例 #3
0
ファイル: brushes.py プロジェクト: mariovct/BEE2.4
def res_set_texture(inst: Entity, res: Property):
    """Set the brush face at a location to a particular texture.

    pos is the position, relative to the instance
      (0 0 0 is the floor-surface).
    dir is the normal of the texture.
    If gridPos is true, the position will be snapped so it aligns with
     the 128 brushes (Useful with fizzler/light strip items).

    tex is the texture used.
    If tex begins and ends with '<>', certain
    textures will be used based on style:
    - '<delete>' will remove the brush entirely (it should be hollow).
      Caution should be used to ensure no leaks occur.
    - '<special>' the brush will be given a special texture
      like angled and flip panels.
    - '<white>' and '<black>' will use the regular textures for the
      given color.
    - '<white-2x2>', '<white-4x4>', '<black-2x2>', '<black-4x4'> will use
      the given wall-sizes. If on floors or ceilings these always use 4x4.
    - '<2x2>' or '<4x4>' will force to the given wall-size, keeping color.
    - '<special-white>' and '<special-black>' will use a special texture
       of the given color.
    If tex begins and ends with '[]', it is an option in the 'Textures' list.
    These are composed of a group and texture, separated by '.'. 'white.wall'
    are the white wall textures; 'special.goo' is the goo texture.

    If 'template' is set, the template should be an axis aligned cube. This
    will be rotated by the instance angles, and then the face with the same
    orientation will be applied to the face (with the rotation and texture).
    """
    import vbsp
    pos = Vec.from_str(res['pos', '0 0 0'])
    pos.z -= 64  # Subtract so origin is the floor-position
    pos = pos.rotate_by_str(inst['angles', '0 0 0'])

    # Relative to the instance origin
    pos += Vec.from_str(inst['origin', '0 0 0'])

    norm = Vec.from_str(res['dir', '0 0 -1']).rotate_by_str(inst['angles',
                                                                 '0 0 0'])

    if srctools.conv_bool(res['gridpos', '0']):
        for axis in 'xyz':
            # Don't realign things in the normal's axis -
            # those are already fine.
            if not norm[axis]:
                pos[axis] //= 128
                pos[axis] *= 128
                pos[axis] += 64

    brush = SOLIDS.get(pos.as_tuple(), None)
    ':type brush: solidGroup'

    if not brush or brush.normal != norm:
        return

    face_to_mod = brush.face  # type: Side

    # Don't allow this to get overwritten later.
    vbsp.IGNORED_FACES.add(face_to_mod)

    temp = res['template', None]
    if temp:
        # Grab the scaling template and apply it to the brush.
        template_brush.get_scaling_template(temp).rotate(
            Vec.from_str(inst['angles']),
            Vec.from_str(inst['origin']),
        ).apply(face_to_mod)
        return

    tex = res['tex']

    if tex.startswith('[') and tex.endswith(']'):
        face_to_mod.mat = vbsp.get_tex(tex[1:-1])
    elif tex.startswith('<') and tex.endswith('>'):
        # Special texture names!
        tex = tex[1:-1].casefold()
        if tex == 'delete':
            vbsp.VMF.remove_brush(brush)
            return

        if tex == 'white':
            face_to_mod.mat = 'tile/white_wall_tile003a'
        elif tex == 'black':
            face_to_mod.mat = 'metal/black_wall_metal_002c'

        if tex == 'black' or tex == 'white':
            # For these two, run the regular logic to apply textures
            # correctly.
            vbsp.alter_mat(
                face_to_mod,
                vbsp.face_seed(face_to_mod),
                vbsp_options.get(bool, 'tile_texture_lock'),
            )

        if tex == 'special':
            vbsp.set_special_mat(face_to_mod, str(brush.color))
        elif tex == 'special-white':
            vbsp.set_special_mat(face_to_mod, 'white')
            return
        elif tex == 'special-black':
            vbsp.set_special_mat(brush.face, 'black')

        # Do <4x4>, <white-2x4>, etc
        color = str(brush.color)
        if tex.startswith('black') or tex.endswith('white'):
            # Override the color used for 2x2/4x4 brushes
            color = tex[:5]
        if tex.endswith('2x2') or tex.endswith('4x4'):
            # 4x4 and 2x2 instructions are ignored on floors and ceilings.
            orient = vbsp.get_face_orient(face_to_mod)
            if orient == vbsp.ORIENT.wall:
                face_to_mod.mat = vbsp.get_tex(color + '.' + tex[-3:])
            else:
                face_to_mod.mat = vbsp.get_tex(color + '.' + str(orient))
    else:
        face_to_mod.mat = tex
コード例 #4
0
def convert_floor(
    vmf: VMF,
    loc: Vec,
    overlay_ids,
    mats,
    settings,
    signage_loc,
    detail,
    noise_weight,
    noise_func: SimplexNoise,
):
    """Cut out tiles at the specified location."""
    # We pop it, so the face isn't detected by other logic - otherwise it'll
    # be retextured and whatnot, which we don't want.
    try:
        brush = conditions.SOLIDS.pop(loc.as_tuple())
    except KeyError:
        return False  # No tile here!

    if brush.normal == (0, 0, 1):
        # This is a pillar block - there isn't actually tiles here!
        # We need to generate a squarebeams brush to fill this gap.

        brush.face.mat = 'tools/toolsnodraw'  # It won't be visible
        temp_data = template_brush.import_template(
            vmf,
            temp_name=FLOOR_TEMP_PILLAR,
            origin=loc,
        )
        template_brush.retexture_template(
            temp_data,
            loc,
            # Switch to use the configured squarebeams texture
            replace_tex={
                consts.Special.SQUAREBEAMS: random.choice(MATS['squarebeams']),
            })
        return False

    # The new brush IDs overlays need to use
    # NOTE: strings, not ints!
    ant_locs = overlay_ids[str(brush.face.id)] = []

    # Move the floor brush down and switch to the floorbase texture.
    for plane in brush.face.planes:
        plane.z -= FLOOR_DEPTH
    brush.face.mat = random.choice(mats['floorbase'])

    loc.x -= 64
    loc.y -= 64

    for x, y in utils.iter_grid(max_x=4, max_y=4):
        tile_loc = loc + (x * 32 + 16, y * 32 + 16, 0)
        if tile_loc.as_tuple() in signage_loc:
            # Force the tile to be present under signage..
            should_make_tile = True
            rand = 100
            # We don't need to check this again in future!
            signage_loc.remove(tile_loc.as_tuple())
        else:
            # Create a number between 0-100
            rand = 100 * get_noise(tile_loc // 32, noise_func) + 10

            # Adjust based on the noise_weight value, so boundries have more tiles
            rand *= 0.1 + 0.9 * (1 - noise_weight)

            should_make_tile = rand < settings['floor_chance']
            if random.randint(0, 7) == 0:
                # Sometimes there'll be random holes/extra tiles
                should_make_tile = not should_make_tile

        if should_make_tile:
            # Full tile
            tile = make_tile(
                vmf,
                p1=tile_loc - (16, 16, 0),
                p2=tile_loc + (16, 16, -2),
                top_mat=vbsp.get_tex(str(brush.color) + '.floor'),
                bottom_mat='tools/toolsnodraw',
                beam_mat=random.choice(mats['squarebeams']),
            )
            detail.solids.append(tile.solid)
            ant_locs.append(str(tile.top.id))
        elif rand < settings['floor_glue_chance']:
            # 'Glue' tile - this chance should be higher, making these appear
            # bordering the full tiles.
            tile = make_tile(
                vmf,
                p1=tile_loc - (16, 16, 1),
                p2=tile_loc + (16, 16, -2),
                top_mat=random.choice(mats['tile_glue']),
                bottom_mat='tools/toolsnodraw',
                beam_mat=random.choice(mats['squarebeams']),
            )
            detail.solids.append(tile.solid)
        else:
            # No tile at this loc!
            pass

    return True
コード例 #5
0
ファイル: brushes.py プロジェクト: goodDOS/BEE2.4
def res_add_brush(inst, res):
    """Spawn in a brush at the indicated points.

    - point1 and point2 are locations local to the instance, with '0 0 0'
      as the floor-position.
    - type is either 'black' or 'white'.
    - detail should be set to True/False. If true the brush will be a
      func_detail instead of a world brush.

    The sides will be textured with 1x1, 2x2 or 4x4 wall, ceiling and floor
    textures as needed.
    """
    import vbsp

    point1 = Vec.from_str(res['point1'])
    point2 = Vec.from_str(res['point2'])

    point1.z -= 64  # Offset to the location of the floor
    point2.z -= 64

    # Rotate to match the instance
    point1.rotate_by_str(inst['angles'])
    point2.rotate_by_str(inst['angles'])

    origin = Vec.from_str(inst['origin'])
    point1 += origin  # Then offset to the location of the instance
    point2 += origin

    tex_type = res['type', None]
    if tex_type not in ('white', 'black'):
        LOGGER.warning(
            'AddBrush: "{}" is not a valid brush '
            'color! (white or black)',
            tex_type,
        )
        tex_type = 'black'

    dim = point2 - point1
    dim.max(-dim)

    # Figure out what grid size and scale is needed
    # Check the dimensions in two axes to figure out the largest
    # tile size that can fit in it.
    x_maxsize = min(dim.y, dim.z)
    y_maxsize = min(dim.x, dim.z)
    if x_maxsize <= 32:
        x_grid = '4x4'
    elif x_maxsize <= 64:
        x_grid = '2x2'
    else:
        x_grid = 'wall'

    if y_maxsize <= 32:
        y_grid = '4x4'
    elif y_maxsize <= 64:
        y_grid = '2x2'
    else:
        y_grid = 'wall'

    grid_offset = origin // 128  # type: Vec

    # All brushes in each grid have the same textures for each side.
    random.seed(grid_offset.join(' ') + '-partial_block')

    solids = vbsp.VMF.make_prism(point1, point2)
    ':type solids: VLib.PrismFace'

    # Ensure the faces aren't re-textured later
    vbsp.IGNORED_FACES.update(solids.solid.sides)

    solids.north.mat = vbsp.get_tex(tex_type + '.' + y_grid)
    solids.south.mat = vbsp.get_tex(tex_type + '.' + y_grid)
    solids.east.mat = vbsp.get_tex(tex_type + '.' + x_grid)
    solids.west.mat = vbsp.get_tex(tex_type + '.' + x_grid)
    solids.top.mat = vbsp.get_tex(tex_type + '.floor')
    solids.bottom.mat = vbsp.get_tex(tex_type + '.ceiling')

    if utils.conv_bool(res['detail', False], False):
        # Add the brush to a func_detail entity
        vbsp.VMF.create_ent(
            classname='func_detail'
        ).solids = [
            solids.solid
        ]
    else:
        # Add to the world
        vbsp.VMF.add_brush(solids.solid)
コード例 #6
0
ファイル: brushes.py プロジェクト: goodDOS/BEE2.4
def res_set_texture(inst, res):
    """Set the brush face at a location to a particular texture.

    pos is the position, relative to the instance
      (0 0 0 is the floor-surface).
    dir is the normal of the texture.
    If gridPos is true, the position will be snapped so it aligns with
     the 128 brushes (Useful with fizzler/light strip items).

    tex is the texture used.
    If tex begins and ends with '<>', certain
    textures will be used based on style:
    - If tex is '<special>', the brush will be given a special texture
      like angled and clear panels.
    - '<white>' and '<black>' will use the regular textures for the
      given color.
    - '<white-2x2>', '<white-4x4>', '<black-2x2>', '<black-4x4'> will use
      the given wall-sizes. If on floors or ceilings these always use 4x4.
    - '<2x2>' or '<4x4>' will force to the given wall-size, keeping color.
    - '<special-white>' and '<special-black>' will use a special texture
       of the given color.
    If tex begins and ends with '[]', it is an option in the 'Textures' list.
    These are composed of a group and texture, separated by '.'. 'white.wall'
    are the white wall textures; 'special.goo' is the goo texture.
    """
    import vbsp
    pos = Vec.from_str(res['pos', '0 0 0'])
    pos.z -= 64  # Subtract so origin is the floor-position
    pos = pos.rotate_by_str(inst['angles', '0 0 0'])

    # Relative to the instance origin
    pos += Vec.from_str(inst['origin', '0 0 0'])

    norm = Vec.from_str(res['dir', '0 0 -1']).rotate_by_str(
        inst['angles', '0 0 0']
    )

    if utils.conv_bool(res['gridpos', '0']):
        for axis in 'xyz':
            # Don't realign things in the normal's axis -
            # those are already fine.
            if not norm[axis]:
                pos[axis] //= 128
                pos[axis] *= 128
                pos[axis] += 64

    brush = SOLIDS.get(pos.as_tuple(), None)
    ':type brush: solidGroup'

    if not brush or brush.normal != norm:
        return

    tex = res['tex']

    if tex.startswith('[') and tex.endswith(']'):
        brush.face.mat = vbsp.get_tex(tex[1:-1])
        brush.face.mat = tex
    elif tex.startswith('<') and tex.endswith('>'):
        # Special texture names!
        tex = tex[1:-1].casefold()
        if tex == 'white':
            brush.face.mat = 'tile/white_wall_tile003a'
        elif tex == 'black':
            brush.face.mat = 'metal/black_wall_metal_002c'

        if tex == 'black' or tex == 'white':
            # For these two, run the regular logic to apply textures
            # correctly.
            vbsp.alter_mat(
                brush.face,
                vbsp.face_seed(brush.face),
                vbsp.get_bool_opt('tile_texture_lock', True),
            )

        if tex == 'special':
            vbsp.set_special_mat(brush.face, str(brush.color))
        elif tex == 'special-white':
            vbsp.set_special_mat(brush.face, 'white')
            return
        elif tex == 'special-black':
            vbsp.set_special_mat(brush.face, 'black')

        # Do <4x4>, <white-2x4>, etc
        color = str(brush.color)
        if tex.startswith('black') or tex.endswith('white'):
            # Override the color used for 2x2/4x4 brushes
            color = tex[:5]
        if tex.endswith('2x2') or tex.endswith('4x4'):
            # 4x4 and 2x2 instructions are ignored on floors and ceilings.
            orient = vbsp.get_face_orient(brush.face)
            if orient == vbsp.ORIENT.wall:
                brush.face.mat = vbsp.get_tex(
                    color + '.' + tex[-3:]
                )
            else:
                brush.face.mat = vbsp.get_tex(
                    color + '.' + str(orient)
                )
    else:
        brush.face.mat = tex

    # Don't allow this to get overwritten later.
    vbsp.IGNORED_FACES.add(brush.face)
コード例 #7
0
def res_insert_overlay(inst: Entity, res: Property):
    """Use a template to insert one or more overlays on a surface.

    Options:

    - ID: The template ID. Brushes will be ignored.
    - Replace: old -> new material replacements.
    - Face_pos: The offset of the brush face.
    - Normal: The direction of the brush face.
    - Offset: An offset to move the overlays by.
    """
    (
        temp_id,
        replace,
        face,
        norm,
        offset,
    ) = res.value

    if temp_id[:1] == '$':
        temp_id = inst.fixup[temp_id]

    origin = Vec.from_str(inst['origin'])  # type: Vec
    angles = Vec.from_str(inst['angles', '0 0 0'])

    face_pos = Vec(face).rotate(*angles)
    face_pos += origin
    normal = Vec(norm).rotate(*angles)

    # Don't make offset change the face_pos value..
    origin += offset.copy().rotate_by_str(inst['angles', '0 0 0'])

    for axis, norm in enumerate(normal):
        # Align to the center of the block grid. The normal direction is
        # already correct.
        if norm == 0:
            face_pos[axis] = face_pos[axis] // 128 * 128 + 64

    try:
        face_id = SOLIDS[face_pos.as_tuple()].face.id
    except KeyError:
        LOGGER.warning(
            'Overlay brush position is not valid: {}',
            face_pos,
        )
        return

    temp = template_brush.import_template(
        temp_id,
        origin,
        angles,
        targetname=inst['targetname', ''],
        force_type=TEMP_TYPES.detail,
    )

    for over in temp.overlay:  # type: Entity
        random.seed('TEMP_OVERLAY_' + over['basisorigin'])
        mat = random.choice(
            replace.get(
                over['material'],
                (over['material'], ),
            ))
        if mat[:1] == '$':
            mat = inst.fixup[mat]
        if mat.startswith('<') or mat.endswith('>'):
            # Lookup in the style data.
            import vbsp
            LOGGER.info('Tex: {}', vbsp.settings['textures'].keys())
            mat = vbsp.get_tex(mat[1:-1])
        over['material'] = mat
        over['sides'] = str(face_id)

    # Wipe the brushes from the map.
    if temp.detail is not None:
        temp.detail.remove()
        LOGGER.info(
            'Overlay template "{}" could set keep_brushes=0.',
            temp_id,
        )
コード例 #8
0
def retexture_template(
    template_data: ExportedTemplate,
    origin: Vec,
    fixup: srctools.vmf.EntityFixup=None,
    replace_tex: dict= srctools.EmptyMapping,
    force_colour: MAT_TYPES=None,
    force_grid: str=None,
    use_bullseye=False,
    no_clumping=False,
):
    """Retexture a template at the given location.

    - Only textures in the TEMPLATE_RETEXTURE dict will be replaced.
    - Others will be ignored (nodraw, plasticwall, etc)
    - Wall textures pointing up and down will switch to floor/ceiling textures.
    - Textures of the same type, normal and inst origin will randomise to the
      same type.
    - replace_tex is a replacement table. This overrides everything else.
      The values should either be a list (random), or a single value.
    - If force_colour is set, all tile textures will be switched accordingly.
      If set to 'INVERT', white and black textures will be swapped.
    - If force_grid is set, all tile textures will be that size:
      ('wall', '2x2', '4x4', 'special')
    - If use_bullseye is true, the bullseye textures will be used for all panel
      sides instead of the normal textures. (This overrides force_grid.)
    - Fixup is the inst.fixup value, used to allow $replace in replace_tex.
    - Set no_clump if the brush is used on a special entity, and therefore
      won't get retextured by the main code. That means we need to directly
      retexture here.
    """
    import vbsp

    template = template_data.template  # type: Template

    rev_id_mapping = {
        new_id: str(old_id)
        for old_id, new_id in
        template_data.orig_ids.items()
    }

    all_brushes = list(template_data.world)  # type: List[Solid]
    if template_data.detail is not None:
        all_brushes.extend(template_data.detail.solids)

    # Template faces are randomised per block and side. This means
    # multiple templates in the same block get the same texture, so they
    # can clip into each other without looking bad.
    rand_prefix = 'TEMPLATE_{}_{}_{}:'.format(*(origin // 128))

    # Even if not axis-aligned, make mostly-flat surfaces
    # floor/ceiling (+-40 degrees)
    # sin(40) = ~0.707
    floor_tolerance = 0.8

    can_clump = vbsp.can_clump()

    # Ensure all values are lists.
    replace_tex = {
        key.casefold(): ([value] if isinstance(value, str) else value)
        for key, value in
        replace_tex.items()
    }

    # For each face, if it needs to be forced to a colour, or None if not.
    force_colour_face = defaultdict(lambda: None)

    # Already sorted by priority.
    for color_picker in template.color_pickers:
        picker_pos = color_picker.offset.copy().rotate(*template_data.angles)
        picker_pos += template_data.origin
        picker_norm = color_picker.normal.copy().rotate(*template_data.angles)

        if color_picker.grid_snap:
            for axis in 'xyz':
                # Don't realign things in the normal's axis -
                # those are already fine.
                if not picker_norm[axis]:
                    picker_pos[axis] = picker_pos[axis] // 128 * 128 + 64

        brush = conditions.SOLIDS.get(picker_pos.as_tuple(), None)

        if brush is None or abs(brush.normal) != abs(picker_norm):
            # Doesn't exist.
            continue

        if color_picker.remove_brush and brush.solid in vbsp.VMF.brushes:
            brush.solid.remove()

        for side in color_picker.sides:
            # Only do the highest priority successful one.
            if force_colour_face[side] is None:
                force_colour_face[side] = brush.color

    for brush in all_brushes:
        for face in brush:
            orig_id = rev_id_mapping[face.id]

            if orig_id in template.skip_faces:
                continue

            folded_mat = face.mat.casefold()

            norm = face.normal()
            random.seed(rand_prefix + norm.join('_'))

            if orig_id in template.realign_faces:
                try:
                    uaxis, vaxis = REALIGN_UVS[norm.as_tuple()]
                except KeyError:
                    LOGGER.warning(
                        'Realign face in template "{}" ({} in final) is '
                        'not on grid!',
                        template.id,
                        face.id,
                    )
                else:
                    face.uaxis = uaxis.copy()
                    face.vaxis = vaxis.copy()

            try:
                override_mat = replace_tex['#' + orig_id]
            except KeyError:
                try:
                    override_mat = replace_tex[folded_mat]
                except KeyError:
                    override_mat = None

            if override_mat is not None:
                # Replace_tex overrides everything.
                mat = random.choice(override_mat)
                if mat[:1] == '$' and fixup is not None:
                    mat = fixup[mat]
                if mat.startswith('<') or mat.endswith('>'):
                    # Lookup in the style data.
                    mat = vbsp.get_tex(mat[1:-1])
                face.mat = mat
                continue

            try:
                tex_type = TEMPLATE_RETEXTURE[folded_mat]
            except KeyError:
                continue  # It's nodraw, or something we shouldn't change

            if isinstance(tex_type, str):
                # It's something like squarebeams or backpanels, just look
                # it up
                face.mat = vbsp.get_tex(tex_type)

                if tex_type == 'special.goo_cheap':
                    if norm != (0, 0, 1):
                        # Goo must be facing upright!
                        # Retexture to nodraw, so a template can be made with
                        # all faces goo to work in multiple orientations.
                        face.mat = 'tools/toolsnodraw'
                    else:
                        # Goo always has the same orientation!
                        face.uaxis = UVAxis(
                            1, 0, 0,
                            offset=0,
                            scale=vbsp_options.get(float, 'goo_scale'),
                        )
                        face.vaxis = UVAxis(
                            0, -1, 0,
                            offset=0,
                            scale=vbsp_options.get(float, 'goo_scale'),
                        )
                continue
            # It's a regular wall type!
            tex_colour, grid_size = tex_type

            if force_colour_face[orig_id] is not None:
                tex_colour = force_colour_face[orig_id]
            elif force_colour == 'INVERT':
                # Invert the texture
                tex_colour = (
                    MAT_TYPES.white
                    if tex_colour is MAT_TYPES.black else
                    MAT_TYPES.black
                )
            elif force_colour is not None:
                tex_colour = force_colour

            if force_grid is not None:
                grid_size = force_grid

            if 1 in norm or -1 in norm:  # Facing NSEW or up/down
                # If axis-aligned, make the orientation aligned to world
                # That way multiple items merge well, and walls are upright.
                # We allow offsets < 1 grid tile, so items can be offset.
                face.uaxis.offset %= TEMP_TILE_PIX_SIZE[grid_size]
                face.vaxis.offset %= TEMP_TILE_PIX_SIZE[grid_size]

            if use_bullseye:
                # We want to use the bullseye textures, instead of normal
                # ones
                if norm.z < -floor_tolerance:
                    face.mat = vbsp.get_tex(
                        'special.bullseye_{}_floor'.format(tex_colour)
                    )
                elif norm.z > floor_tolerance:
                    face.mat = vbsp.get_tex(
                        'special.bullseye_{}_ceiling'.format(tex_colour)
                    )
                else:
                    face.mat = ''  # Ensure next if statement triggers

                # If those aren't defined, try the wall texture..
                if face.mat == '':
                    face.mat = vbsp.get_tex(
                        'special.bullseye_{}_wall'.format(tex_colour)
                    )
                if face.mat != '':
                    continue  # Set to a bullseye texture,
                    # don't use the wall one

            if grid_size == 'special':
                # Don't use wall on faces similar to floor/ceiling:
                if -floor_tolerance < norm.z < floor_tolerance:
                    face.mat = vbsp.get_tex(
                        'special.{!s}_wall'.format(tex_colour)
                    )
                else:
                    face.mat = ''  # Ensure next if statement triggers

                # Various fallbacks if not defined
                if face.mat == '':
                    face.mat = vbsp.get_tex(
                        'special.{!s}'.format(tex_colour)
                    )
                if face.mat == '':
                    # No special texture - use a wall one.
                    grid_size = 'wall'
                else:
                    # Set to a special texture,
                    continue # don't use the wall one

            if norm.z > floor_tolerance:
                grid_size = 'ceiling'
            if norm.z < -floor_tolerance:
                grid_size = 'floor'

            if can_clump and not no_clumping:
                # For the clumping algorithm, set to Valve PeTI and let
                # clumping handle retexturing.
                vbsp.IGNORED_FACES.remove(face)
                if tex_colour is MAT_TYPES.white:
                    if grid_size == '4x4':
                        face.mat = 'tile/white_wall_tile003f'
                    elif grid_size == '2x2':
                        face.mat = 'tile/white_wall_tile003c'
                    else:
                        face.mat = 'tile/white_wall_tile003h'
                elif tex_colour is MAT_TYPES.black:
                    if grid_size == '4x4':
                        face.mat = 'metal/black_wall_metal_002b'
                    elif grid_size == '2x2':
                        face.mat = 'metal/black_wall_metal_002a'
                    else:
                        face.mat = 'metal/black_wall_metal_002e'
            else:
                face.mat = vbsp.get_tex(
                    '{!s}.{!s}'.format(tex_colour, grid_size)
                )

    for over in template_data.overlay[:]:
        random.seed('TEMP_OVERLAY_' + over['basisorigin'])
        mat = over['material'].casefold()
        if mat in replace_tex:
            mat = random.choice(replace_tex[mat])
            if mat[:1] == '$':
                mat = fixup[mat]
            if mat.startswith('<') or mat.endswith('>'):
                # Lookup in the style data.
                mat = vbsp.get_tex(mat[1:-1])
        elif mat in vbsp.TEX_VALVE:
            mat = vbsp.get_tex(vbsp.TEX_VALVE[mat])
        else:
            continue
        if mat == '':
            # If blank, remove the overlay from the map and the list.
            # (Since it's inplace, this can affect the tuple.)
            template_data.overlay.remove(over)
            over.remove()
        else:
            over['material'] = mat
コード例 #9
0
ファイル: cutoutTile.py プロジェクト: BenVlodgi/BEE2.4
def convert_floor(
    vmf: VMF,
    loc: Vec,
    overlay_ids,
    mats,
    settings,
    signage_loc,
    detail,
    noise_weight,
    noise_func: SimplexNoise,
):
    """Cut out tiles at the specified location."""
    # We pop it, so the face isn't detected by other logic - otherwise it'll
    # be retextured and whatnot, which we don't want.
    try:
        brush = conditions.SOLIDS.pop(loc.as_tuple())
    except KeyError:
        return False  # No tile here!

    if brush.normal == (0, 0, 1):
        # This is a pillar block - there isn't actually tiles here!
        # We need to generate a squarebeams brush to fill this gap.

        brush.face.mat = 'tools/toolsnodraw'  # It won't be visible
        temp_data = template_brush.import_template(
            temp_name=FLOOR_TEMP_PILLAR,
            origin=loc,
        )
        template_brush.retexture_template(
            temp_data,
            loc,
            # Switch to use the configured squarebeams texture
            replace_tex={
                consts.Special.SQUAREBEAMS: random.choice(
                    MATS['squarebeams']
                ),
            }
        )
        return False

    # The new brush IDs overlays need to use
    # NOTE: strings, not ints!
    ant_locs = overlay_ids[str(brush.face.id)] = []

    # Move the floor brush down and switch to the floorbase texture.
    for plane in brush.face.planes:
        plane.z -= FLOOR_DEPTH
    brush.face.mat = random.choice(mats['floorbase'])

    loc.x -= 64
    loc.y -= 64

    for x, y in utils.iter_grid(max_x=4, max_y=4):
        tile_loc = loc + (x * 32 + 16, y * 32 + 16, 0)
        if tile_loc.as_tuple() in signage_loc:
            # Force the tile to be present under signage..
            should_make_tile = True
            rand = 100
            # We don't need to check this again in future!
            signage_loc.remove(tile_loc.as_tuple())
        else:
            # Create a number between 0-100
            rand = 100 * get_noise(tile_loc // 32, noise_func) + 10

            # Adjust based on the noise_weight value, so boundries have more tiles
            rand *= 0.1 + 0.9 * (1 - noise_weight)

            should_make_tile = rand < settings['floor_chance']
            if random.randint(0, 7) == 0:
                # Sometimes there'll be random holes/extra tiles
                should_make_tile = not should_make_tile

        if should_make_tile:
            # Full tile
            tile = make_tile(
                vmf,
                p1=tile_loc - (16, 16, 0),
                p2=tile_loc + (16, 16, -2),
                top_mat=vbsp.get_tex(str(brush.color) + '.floor'),
                bottom_mat='tools/toolsnodraw',
                beam_mat=random.choice(mats['squarebeams']),
            )
            detail.solids.append(tile.solid)
            ant_locs.append(str(tile.top.id))
        elif rand < settings['floor_glue_chance']:
            # 'Glue' tile - this chance should be higher, making these appear
            # bordering the full tiles.
            tile = make_tile(
                vmf,
                p1=tile_loc - (16, 16, 1),
                p2=tile_loc + (16, 16, -2),
                top_mat=random.choice(mats['tile_glue']),
                bottom_mat='tools/toolsnodraw',
                beam_mat=random.choice(mats['squarebeams']),
            )
            detail.solids.append(tile.solid)
        else:
            # No tile at this loc!
            pass

    return True
コード例 #10
0
ファイル: brushes.py プロジェクト: BenVlodgi/BEE2.4
def res_set_texture(inst: Entity, res: Property):
    """Set the brush face at a location to a particular texture.

    pos is the position, relative to the instance
      (0 0 0 is the floor-surface).
    dir is the normal of the texture.
    If gridPos is true, the position will be snapped so it aligns with
     the 128 brushes (Useful with fizzler/light strip items).

    tex is the texture used.
    If tex begins and ends with `<>`, certain
    textures will be used based on style:
    - `<delete>` will remove the brush entirely (it should be hollow).
      Caution should be used to ensure no leaks occur.
    - `<special>` the brush will be given a special texture
      like angled and flip panels.
    - `<white>` and `<black>` will use the regular textures for the
      given color.
    - `<white-2x2>`, `<white-4x4>`, `<black-2x2>`, `<black-4x4>` will use
      the given wall-sizes. If on floors or ceilings these always use 4x4.
    - `<2x2>` or `<4x4>` will force to the given wall-size, keeping color.
    - `<special-white>` and `<special-black>` will use a special texture
       of the given color.
    If tex begins and ends with `[]`, it is an option in the `Textures` list.
    These are composed of a group and texture, separated by `.`. `white.wall`
    are the white wall textures; `special.goo` is the goo texture.

    If `template` is set, the template should be an axis aligned cube. This
    will be rotated by the instance angles, and then the face with the same
    orientation will be applied to the face (with the rotation and texture).
    """
    import vbsp
    pos = Vec.from_str(res['pos', '0 0 0'])
    pos.z -= 64  # Subtract so origin is the floor-position
    pos = pos.rotate_by_str(inst['angles', '0 0 0'])

    # Relative to the instance origin
    pos += Vec.from_str(inst['origin', '0 0 0'])

    norm = Vec.from_str(res['dir', '0 0 -1']).rotate_by_str(
        inst['angles', '0 0 0']
    )

    if srctools.conv_bool(res['gridpos', '0']):
        for axis in 'xyz':
            # Don't realign things in the normal's axis -
            # those are already fine.
            if not norm[axis]:
                pos[axis] //= 128
                pos[axis] *= 128
                pos[axis] += 64

    brush = SOLIDS.get(pos.as_tuple(), None)

    if not brush or brush.normal != norm:
        return

    face_to_mod = brush.face  # type: Side

    # Don't allow this to get overwritten later.
    vbsp.IGNORED_FACES.add(face_to_mod)

    temp = res['template', None]
    if temp:
        # Grab the scaling template and apply it to the brush.
        template_brush.get_scaling_template(temp).rotate(
            Vec.from_str(inst['angles']),
            Vec.from_str(inst['origin']),
        ).apply(face_to_mod)
        return

    tex = res['tex']

    if tex.startswith('[') and tex.endswith(']'):
        face_to_mod.mat = vbsp.get_tex(tex[1:-1])
    elif tex.startswith('<') and tex.endswith('>'):
        # Special texture names!
        tex = tex[1:-1].casefold()
        if tex == 'delete':
            vbsp.VMF.remove_brush(brush)
            return

        if tex == 'white':
            face_to_mod.mat = 'tile/white_wall_tile003a'
        elif tex == 'black':
            face_to_mod.mat = 'metal/black_wall_metal_002c'

        if tex == 'black' or tex == 'white':
            # For these two, run the regular logic to apply textures
            # correctly.
            vbsp.alter_mat(
                face_to_mod,
                vbsp.face_seed(face_to_mod),
                vbsp_options.get(bool, 'tile_texture_lock'),
            )

        if tex == 'special':
            vbsp.set_special_mat(face_to_mod, str(brush.color))
        elif tex == 'special-white':
            vbsp.set_special_mat(face_to_mod, 'white')
            return
        elif tex == 'special-black':
            vbsp.set_special_mat(brush.face, 'black')

        # Do <4x4>, <white-2x4>, etc
        color = str(brush.color)
        if tex.startswith('black') or tex.endswith('white'):
            # Override the color used for 2x2/4x4 brushes
            color = tex[:5]
        if tex.endswith('2x2') or tex.endswith('4x4'):
            # 4x4 and 2x2 instructions are ignored on floors and ceilings.
            orient = vbsp.get_face_orient(face_to_mod)
            if orient == vbsp.ORIENT.wall:
                face_to_mod.mat = vbsp.get_tex(
                    color + '.' + tex[-3:]
                )
            else:
                face_to_mod.mat = vbsp.get_tex(
                    color + '.' + str(orient)
                )
    else:
        face_to_mod.mat = tex
コード例 #11
0
ファイル: entities.py プロジェクト: BenVlodgi/BEE2.4
def res_insert_overlay(inst: Entity, res: Property):
    """Use a template to insert one or more overlays on a surface.

    Options:

    - ID: The template ID. Brushes will be ignored.
    - Replace: old -> new material replacements.
    - Face_pos: The offset of the brush face.
    - Normal: The direction of the brush face.
    - Offset: An offset to move the overlays by.
    """
    (
        temp_id,
        replace,
        face,
        norm,
        offset,
    ) = res.value

    if temp_id[:1] == '$':
        temp_id = inst.fixup[temp_id]

    origin = Vec.from_str(inst['origin'])  # type: Vec
    angles = Vec.from_str(inst['angles', '0 0 0'])

    face_pos = Vec(face).rotate(*angles)
    face_pos += origin
    normal = Vec(norm).rotate(*angles)

    # Don't make offset change the face_pos value..
    origin += offset.copy().rotate_by_str(
        inst['angles', '0 0 0']
    )

    for axis, norm in enumerate(normal):
        # Align to the center of the block grid. The normal direction is
        # already correct.
        if norm == 0:
            face_pos[axis] = face_pos[axis] // 128 * 128 + 64

    try:
        face_id = SOLIDS[face_pos.as_tuple()].face.id
    except KeyError:
        LOGGER.warning(
            'Overlay brush position is not valid: {}',
            face_pos,
        )
        return

    temp = template_brush.import_template(
        temp_id,
        origin,
        angles,
        targetname=inst['targetname', ''],
        force_type=TEMP_TYPES.detail,
    )

    for over in temp.overlay:  # type: Entity
        random.seed('TEMP_OVERLAY_' + over['basisorigin'])
        mat = random.choice(replace.get(
            over['material'],
            (over['material'], ),
        ))
        if mat[:1] == '$':
            mat = inst.fixup[mat]
        if mat.startswith('<') or mat.endswith('>'):
            # Lookup in the style data.
            import vbsp
            LOGGER.info('Tex: {}', vbsp.settings['textures'].keys())
            mat = vbsp.get_tex(mat[1:-1])
        over['material'] = mat
        over['sides'] = str(face_id)

    # Wipe the brushes from the map.
    if temp.detail is not None:
        temp.detail.remove()
        LOGGER.info(
            'Overlay template "{}" could set keep_brushes=0.',
            temp_id,
        )
コード例 #12
0
ファイル: cutoutTile.py プロジェクト: goodDOS/BEE2.4
def convert_floor(
        loc,
        overlay_ids,
        mats,
        settings,
        signage_loc,
        detail,
):
    """Cut out tiles at the specified location."""
    try:
        brush = conditions.SOLIDS[loc.as_tuple()]
    except KeyError:
        return False  # No tile here!

    if brush.normal == (0, 0, 1):
        # This is a pillar block - there isn't actually tiles here!
        # We need to generate a squarebeams brush to fill this gap.

        brush.face.mat = 'tools/toolsnodraw'  # It won't be visible
        temp_data = conditions.import_template(
            temp_name=FLOOR_TEMP_PILLAR,
            origin=loc,
        )
        conditions.retexture_template(
            temp_data,
            loc,
            # Switch to use the configured squarebeams texture
            replace_tex={
                'anim_wp/framework/squarebeams': random.choice(
                    MATS['squarebeams']
                ),
            }
        )
        return False

    # The new brush IDs overlays need to use
    # NOTE: strings, not ints!
    ant_locs = overlay_ids[str(brush.face.id)] = []

    # Move the floor brush down and switch to the floorbase texture.
    for plane in brush.face.planes:
        plane.z -= FLOOR_DEPTH
    brush.face.mat = random.choice(mats['floorbase'])

    loc.x -= 64
    loc.y -= 64

    random.seed('cutout_tile' + loc.join(' '))
    tile_map = [
        (random.randint(0, 100) < settings['floor_chance'])
        for _ in range(16)
    ]

    for x, y in utils.iter_grid(max_x=4, max_y=4):
        tile_loc = loc + (x*32 + 16, y*32 + 16, 0)
        if tile_loc.as_tuple() in signage_loc:
            should_make_tile = True
            # We don't need to check this again in future!
            signage_loc.remove(tile_loc.as_tuple())
        else:
            should_make_tile = tile_map[x*4 + y]
        if should_make_tile:
            # Full tile
            tile = make_tile(
                p1=tile_loc - (16, 16, 0),
                p2=tile_loc + (16, 16, -2),
                top_mat=vbsp.get_tex(str(brush.color) + '.floor'),
                bottom_mat='tools/toolsnodraw',
                beam_mat=random.choice(mats['squarebeams']),
            )
            detail.solids.append(tile.solid)
            ant_locs.append(str(tile.top.id))
        elif random.randint(0, 100) < settings['floor_glue_chance']:
            # 'Glue' tile
            tile = make_tile(
                p1=tile_loc - (16, 16, 1),
                p2=tile_loc + (16, 16, -2),
                top_mat=random.choice(mats['tile_glue']),
                bottom_mat='tools/toolsnodraw',
                beam_mat=random.choice(mats['squarebeams']),
            )
            detail.solids.append(tile.solid)
        else:
            # No tile at this loc!
            pass

    return True