def __init__(self): VmfClass.__init__(self) self.mins = types.Vertex(99999, 99999, 99999) self.maxs = types.Vertex(-99999, -99999, -99999) self.active = types.Bool(0) self.auto_properties = ['mins', 'maxs', 'active']
def __init__(self, source, source_alphas=None, origin=types.Vertex(), size=types.Vertex(), x_subdisplacements=4, y_subdisplacements=4, power=3, add_nodraw_brush=False): # This is the data we will use to build our displacements. self.source = source # This is the data we use to build the alpha map self.source_alphas = source_alphas # This is the physical location of the DM's center. self.origin = origin # This is the length, width, and height of the DM self.size = size # This is the number of displacements we will have along the x and y axis, respectively. self.sub_displacements = (x_subdisplacements, y_subdisplacements) # This is whether we want to add nodraw brushes underneath the displacement to block visibility. self.add_nodraw_brush = add_nodraw_brush if power not in (2, 3, 4): raise ValueError( "Power of a DisplacementMap must be 2, 3, or 4, not {0}.". format(power)) # The power of each subdisplacement. (2 ^ power) is the number of grid points the displacement will have. self.power = power self.source_width = (2**self.power * self.sub_displacements[0]) + 1 self.source_height = (2**self.power * self.sub_displacements[1]) + 1 # The actual grid-size of displacement brushes self.d_x_size = self.size[0] / self.sub_displacements[0] self.d_y_size = self.size[1] / self.sub_displacements[1] # The actual grid-distance between points self.d_x_p_size = self.d_x_size / (2**self.power) self.d_y_p_size = self.d_y_size / (2**self.power) self.material = "" self.displacement_brushes = [] self.misc_brushes = []
def __init__(self, origin=types.Vertex(), size=types.Vertex(), thickness=32): self.origin = origin for dim in size: if dim <= 0: raise ValueError("Solid cannot have negative size!") self.size = size self.thickness = thickness # Left wall self.left_wall = Block( types.Vertex( -self.thickness / 2 + self.origin[0] - self.size[0] / 2, self.origin[1], self.origin[2]), (self.thickness, self.size[1], self.size[2])) # Right wall self.right_wall = Block( types.Vertex( +self.thickness / 2 + self.origin[0] + self.size[0] / 2, self.origin[1], self.origin[2]), (self.thickness, self.size[1], self.size[2])) # Forward wall self.front_wall = Block( types.Vertex( self.origin[0], self.thickness / 2 + self.origin[1] + self.size[1] / 2, self.origin[2]), (self.size[0] + 2 * self.thickness, self.thickness, self.size[2])) # Rear wall self.back_wall = Block( types.Vertex( self.origin[0], -self.thickness / 2 + self.origin[1] - self.size[1] / 2, self.origin[2]), (self.size[0] + 2 * self.thickness, self.thickness, self.size[2])) # Ceiling self.ceiling = self.get_level_brush( self.size[2] / 2 + self.thickness / 2 + self.origin[2], self.thickness) # Floor self.floor = self.get_level_brush( -self.size[2] / 2 - self.thickness / 2 + self.origin[2], self.thickness) self.brushes = [ self.left_wall, self.right_wall, self.front_wall, self.back_wall, self.ceiling, self.floor ]
def __init__(self, origin=types.Vertex(), dimensions=(64, 64, 64), material='BRICK/BRICKFLOOR001A'): """Create a new Block at origin with dimensions and material.""" self.origin = origin self.dimensions = dimensions # Create brush self.brush = brush.Solid() # Create (un-positioned) sides sides = [] for i in range(6): sides.append(brush.Side(types.Plane(), material)) self.brush.children.extend(sides) # Compute initial side planes self.update_sides() # Apply material self.set_material(material)
def update_sides(self): """Call this when the origin or dimensions have changed.""" x = self.origin.x y = self.origin.y z = self.origin.z w, l, h = self.dimensions a = w / 2 b = l / 2 c = h / 2 self.brush.children[0].plane = types.Plane( types.Vertex(x - a, y + b, z + c), types.Vertex(x + a, y + b, z + c), types.Vertex(x + a, y - b, z + c)) self.brush.children[1].plane = types.Plane( types.Vertex(x - a, y - b, z - c), types.Vertex(x + a, y - b, z - c), types.Vertex(x + a, y + b, z - c)) self.brush.children[2].plane = types.Plane( types.Vertex(x - a, y + b, z + c), types.Vertex(x - a, y - b, z + c), types.Vertex(x - a, y - b, z - c)) self.brush.children[3].plane = types.Plane( types.Vertex(x + a, y + b, z - c), types.Vertex(x + a, y - b, z - c), types.Vertex(x + a, y - b, z + c)) self.brush.children[4].plane = types.Plane( types.Vertex(x + a, y + b, z + c), types.Vertex(x - a, y + b, z + c), types.Vertex(x - a, y + b, z - c)) self.brush.children[5].plane = types.Plane( types.Vertex(x + a, y - b, z - c), types.Vertex(x - a, y - b, z - c), types.Vertex(x - a, y - b, z + c)) for side in self.brush.children: side.uaxis, side.vaxis = side.plane.sensible_axes()
def realize(self): """Actually create the displacements that this entity is made out of.""" if len(self.displacement_brushes) > 0: raise ValueError( "Displacement map cannot be realized more than once!") rotation_counts = { (True, True): 3, (True, False): 0, (False, False): 1, (False, True): 2 } for dx in range(self.sub_displacements[0]): for dy in range(self.sub_displacements[1]): power = 2**self.power x_offset = power * dx y_offset = power * dy # The actual position the displacement brush will be in x_pos = (dx - (self.sub_displacements[0] / 2) + 0.5) * self.d_x_size + self.origin.x y_pos = (dy - (self.sub_displacements[1] / 2) + 0.5) * self.d_y_size + self.origin.y # The modifications of which order we load the values into the array need to happen for some reason. # Source just wants things in a different order depending on which quadrant you're in I guess. forward_range = list(range(power + 1)) backwards_range = list(range(power, -1, -1)) x_range = forward_range y_range = backwards_range norms = [] for i in x_range: row = [] for j in y_range: row.append(types.Vertex(0, 0, 1)) norms.append(row) dists = [] for x in x_range: row = [] for y in y_range: rel_x = x + x_offset rel_y = y + y_offset row.append(self[rel_x, rel_y]) dists.append(row) if self.source_alphas: alphas = [] for x in x_range: alphas_row = [] for y in y_range: rel_x = x + x_offset rel_y = y + y_offset alphas_row.append(self.source_alphas[rel_x, rel_y]) alphas.append(alphas_row) else: alphas = None # There's a weird quirk where the displacement gets rotated depending on what quadrant it's origin is # in. I'm not sure whether this is something to do with the source engine, or the Block tool. # either way, the following StackOverflow-code accounts for it by rotating the displacement back. # (it's still wrong sometimes when the displacements' origin x or y are 0, so don't do that) rotation_count = rotation_counts[x_pos > 0, y_pos >= 0] for i in range(rotation_count): dists = list(zip(*dists[::-1])) norms = list(zip(*norms[::-1])) if alphas: alphas = list(zip(*alphas[::-1])) d = brush.DispInfo(self.power, norms, dists, alphas) floor = Block(types.Vertex(x_pos, y_pos, self.origin.z), (self.d_x_size, self.d_y_size, self.size[2])) if self.material != "": floor.set_material(self.material) floor.top().children.append(d) # Add disp map to the ground # Store these in case they're needed. floor.x_offset = x_offset floor.y_offset = y_offset floor.displacement_distances = dists self.displacement_brushes.append(floor) if self.add_nodraw_brush: lowest_height = int(min(map(min, dists))) - 1 if lowest_height > 1: # Don't make any brushes that are too small. nodraw_brush = Block( types.Vertex( x_pos, y_pos, self.origin.z + 0.5 * (lowest_height + self.size[2])), (self.d_x_size, self.d_y_size, int(lowest_height)), "tools/toolsnodraw") self.misc_brushes.append(nodraw_brush)
def get_level_brush(self, z_origin, z_size): """Returns a brush the horizontal size of this box, with z_position and z_height given. Think of filling the box part way with water, and letting it settle. That's what this function generates.""" return Block(types.Vertex(self.origin[0], self.origin[1], z_origin), (self.size[0], self.size[1], z_size))