Экранная лупа с регулируемой на лету степенью zoom-а

Ссылка на архив с проектом

# показать лупу:
# call show_zoom
# поменять масштаб:
# $ zoom = 4

init python:
    # увеличение по-умолчанию
    zoom = 2

    # размер лупы (поменяются автоматически в соответствии с размером маски)
    zoom_w, zoom_h = 0, 0

    # имя спрайта с маской для участка под стеклом лупы
    zoom_mask = "zoom mask"

    # имя спрайта с изображением лупы (с прозрачным кругом в центре)
    zoom_idle = "zoom idle"

    # для хранения скриншота
    zoom_shot = Null(1, 1)

    # получить размер объявленного спрайта
    def get_size(image):
        w, h = renpy.render(renpy.easy.displayable(image), 0, 0, 0, 0).get_size()
        return int(w), int(h)

    # получить скриншот заданного размера, по умолчанию - весь экран
    def shot(w=config.screen_width, h=config.screen_height):
        renpy.take_screenshot((w, h))
        return FileCurrentScreenshot()

    # делаем скрин
    def get_shot():
        global zoom_shot, zoom_w, zoom_h
        # делаем скриншот
        zoom_shot = shot(config.screen_width, config.screen_height)
        # размер лупы
        zoom_w, zoom_h = get_size(zoom_idle)
    GetShot = renpy.curry(get_shot)

    # получить картинку скрин+лупа
    def zoom_f(st, at):
        # координаты мышки
        x, y = renpy.get_mouse_pos()
        # левый верхний угол (курсор в центре)
        x = int(x - zoom_w / 2)
        y = int(y - zoom_h / 2)
        # вырезаем из скриншота квадрат
        d = Crop((x, y, zoom_w, zoom_h), zoom_shot)
        # увеличиваем
        d = Transform(d, zoom=zoom)
        # снова вырезаем квадрат
        x2 = int(zoom_w * zoom - zoom_w) / 2
        y2 = int(zoom_h * zoom - zoom_h) / 2
        d = Crop((x2, y2, zoom_w, zoom_h), d)
        # затем вырезаем круг
        d = AlphaMask(d, zoom_mask)
        # накладываем картинку лупы
        d = LiveComposite((zoom_w, zoom_h), (0, 0), d, (0, 0), zoom_idle)
        return d, .01

    # координаты мышки
    def at_zoom_f(trans, st, at):
        trans.pos = renpy.get_mouse_pos()
        return 0

    # поменять степень увеличения [2, 4, 8]
    def re_zoom():
        global zoom
        zoom *= 2
        if zoom > 8:
            zoom = 2
    ReZoom = renpy.curry(re_zoom)

init:
    # скрин
    image zoom_zoom = DynamicDisplayable(zoom_f)

    # трансформ для перемещения лупы
    transform at_zoom():
        anchor(.5, .5)
        function at_zoom_f

# экран с лупой
screen ZOOM:
    modal True
    on "show" action GetShot()
    add "zoom_zoom" at at_zoom()
    key "dismiss" action Hide("ZOOM"), With(dissolve)
    key "K_TAB" action ReZoom()

# метка, которую нужно вызывать, чтобы включилась лупа
# call show_zoom
label show_zoom:
    # убираем окно
    window hide
    pause .0001

    # показываем экран с лупой
    show screen ZOOM
    with dissolve
    centered "{nw}"
    return

В этой версии сначала делаем скриншот, а потом показываем его часть, но увеличенную. Если спрайты будут меняться или двигаться, увеличенная часть останется прежней и на том же месте. Но существует версия лупы, работающей в реальном времени:

Комментарии