def __init__(self, model2, img):
        mesh = model2.mesh.copy()

        # Compute bounding box of the (projection of the) mesh
        v2_min, v2_max = mesh.get_bounds_2d(util.project)
        v2_size = (v2_max[0] - v2_min[0], v2_max[1] - v2_min[1])

        # The user provided the bounding box of the region covered by the
        # image.  (Usually this is just (0,0,0) .. (struct_size).)  Using that,
        # extract the image for the part actually covered by the mesh.
        b_min, b_max = model2.bounds
        b2_min = (b_min[0], b_min[1] - b_max[2])
        b2_max = (b_max[0], b_max[1] - b_min[2])
        b2_size = (b2_max[0] - b2_min[0], b2_max[1] - b2_min[1])

        # Crop image to the mesh's bounding box

        # Special hack
        if img.px_size == (TILE_SIZE, TILE_SIZE) and \
                b2_size == (TILE_SIZE, 2 * TILE_SIZE):
            pass
        else:
            assert img.px_size == b2_size, \
                    'image has wrong size for bounds: %s != %s' % (img.px_size, b2_size)

            # Extract the region (v2_min - b2_min, v2_max - b2_min)
            r2_min = (v2_min[0] - b2_min[0], v2_min[1] - b2_min[1])
            img = img.extract(r2_min, size=v2_size, unit=1)

        # Crop mesh & image to image's bounding box.  We do this after the
        # previous step because cropping the image may remove some non-blank
        # content, letting us crop the image more aggressively here.
        img, i2_min = img.autocrop()
        v2_min = geom.add(v2_min, i2_min)
        v2_max = geom.add(v2_min, img.px_size)
        geom.clip_xv(mesh, *(v2_min + v2_max))

        self.mesh = mesh
        self.img = img
        self.base = v2_min

        # Set by `build_sheets`
        self.sheet_idx = None
        self.offset = None

        # Set by `collect_verts'
        self.vert_idx = None
        self.vert_count = None
    def __init__(self, name, image, model, shape, layer):
        super(StructureDef, self).__init__(name, shape, layer)
        px_size = tuple(x * TILE_SIZE for x in shape.size)
        mesh = model.to_mesh()

        if isinstance(image, StaticAnimDef):
            base = image2.Image(img=image_cache.ConstImage(image.static_base))
            base_model2 = Model2(mesh, ((0, 0, 0), px_size))
            self.add_part(base_model2, base)

            frame_sheet = image2.Image(img=image_cache.ConstImage(image.anim_sheet),
                    unit=image.anim_size)
            frames = [frame_sheet.extract((x, 0)) for x in range(image.length)]
            anim = image2.Anim(frames, image.framerate, image.oneshot)
            box_min = geom.sub(image.anim_offset, (0, shape.size[2] * TILE_SIZE))
            box_max = geom.add(box_min, image.anim_size)
            anim_mesh = mesh.copy()
            geom.clip_xv(anim_mesh, *(box_min + box_max))
            anim_model2 = Model2(anim_mesh, anim_mesh.get_bounds())
            self.add_part(anim_model2, anim)
        else:
            image = image2.Image(img=image_cache.ConstImage(image))
            model2 = Model2(mesh, ((0, 0, 0), px_size))
            self.add_part(model2, image)