Ejemplo n.º 1
0
def place_sign(
    vmf: VMF,
    faces: Iterable[Side],
    sign: Sign,
    pos: Vec,
    normal: Vec,
    forward: Vec,
    rotate: bool = True,
) -> Entity:
    """Place the sign into the map."""
    if rotate and abs(normal.z) < 0.1:
        # On the wall, point upward.
        forward = Vec(0, 0, 1)

    texture = sign.overlay
    if texture.startswith('<') and texture.endswith('>'):
        gen, tex_name = texturing.parse_name(texture[1:-1])
        texture = gen.get(pos, tex_name)

    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,
    )
    vbsp.IGNORED_OVERLAYS.add(over)

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

    return over
Ejemplo n.º 2
0
    def insert_over(inst: Entity) -> None:
        """Apply the result."""
        temp_id = inst.fixup.substitute(orig_temp_id)

        origin = Vec.from_str(inst['origin'])
        angles = Angle.from_str(inst['angles', '0 0 0'])

        face_pos = conditions.resolve_offset(inst, face_str)
        normal = orig_norm @ angles

        # Don't make offset change the face_pos value..
        origin += offset @ angles

        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

        # Shift so that the user perceives the position as the pos of the face
        # itself.
        face_pos -= 64 * normal

        try:
            tiledef = tiling.TILES[face_pos.as_tuple(), normal.as_tuple()]
        except KeyError:
            LOGGER.warning(
                'Overlay brush position is not valid: {}',
                face_pos,
            )
            return

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

        for over in temp.overlay:
            pos = Vec.from_str(over['basisorigin'])
            mat = over['material']
            try:
                replace = replace_tex[mat.casefold().replace('\\', '/')]
            except KeyError:
                pass
            else:
                mat = rand.seed(b'temp_over', temp_id, pos).choice(replace)

            if mat[:1] == '$':
                mat = inst.fixup[mat]
            if mat.startswith('<') or mat.endswith('>'):
                # Lookup in the texture data.
                gen, mat = texturing.parse_name(mat[1:-1])
                mat = gen.get(pos, mat)
            over['material'] = mat
            tiledef.bind_overlay(over)

        # 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,
            )
Ejemplo n.º 3
0
def res_set_texture(inst: Entity, res: Property):
    """Set the tile at a particular place to use a specific texture.

    This can only be set for an entire voxel side at once.

    `pos` is the position, relative to the instance (0 0 0 is the floor-surface).
    `dir` is the normal of the texture (pointing out)
    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 to use.

    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).
    """
    angles = Angle.from_str(inst['angles'])
    origin = Vec.from_str(inst['origin'])

    pos = Vec.from_str(res['pos', '0 0 0'])
    pos.z -= 64  # Subtract so origin is the floor-position
    pos.localise(origin, angles)

    norm = round(Vec.from_str(res['dir', '0 0 1']) @ angles, 6)

    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

    try:
        # The user expects the tile to be at it's surface pos, not the
        # position of the voxel.
        tile = tiling.TILES[(pos - 64 * norm).as_tuple(), norm.as_tuple()]
    except KeyError:
        LOGGER.warning(
            '"{}": Could not find tile at {} with orient {}!',
            inst['targetname'],
            pos,
            norm,
        )
        return

    temp_id = inst.fixup.substitute(res['template', ''])
    if temp_id:
        temp = template_brush.get_scaling_template(temp_id).rotate(
            angles, origin)
    else:
        temp = template_brush.ScalingTemplate.world()

    tex = inst.fixup.substitute(res['tex', ''])

    if tex.startswith('<') and tex.endswith('>'):
        LOGGER.warning(
            'Special <lookups> for AlterTexture are '
            'no longer usable! ("{}")', tex)
    elif tex.startswith('[') and tex.endswith(']'):
        gen, name = texturing.parse_name(tex[1:-1])
        tex = gen.get(pos - 64 * norm, name)

    tile.override = (tex, temp)
Ejemplo n.º 4
0
def res_insert_overlay(vmf: VMF, inst: Entity, res: Property) -> None:
    """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

    # Shift so that the user perceives the position as the pos of the face
    # itself.
    face_pos -= 64 * normal

    try:
        tiledef = tiling.TILES[face_pos.as_tuple(), normal.as_tuple()]
    except KeyError:
        LOGGER.warning(
            'Overlay brush position is not valid: {}',
            face_pos,
        )
        return

    temp = template_brush.import_template(
        vmf,
        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 = over['material']
        try:
            mat = random.choice(replace[over['material'].casefold().replace(
                '\\', '/')])
        except KeyError:
            pass

        if mat[:1] == '$':
            mat = inst.fixup[mat]
        if mat.startswith('<') or mat.endswith('>'):
            # Lookup in the texture data.
            gen, mat = texturing.parse_name(mat[1:-1])
            mat = gen.get(Vec.from_str(over['basisorigin']), mat)
        over['material'] = mat
        tiledef.bind_overlay(over)

    # 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,
        )