Эффект бегущей строки на Ассемблере

Очередной интересный визуальный эффект для ваших программ - бегущая строка. Обычно подобный эффект используется в различных кейгенах, но вполне может пригодиться и для более мирных приложений. В качестве основы взята ассемблерная библиотека Scroller lib 1.01 от ReWolf / HTBTeam. Изначально она предназначалась для MASM, так что пришлось ее портировать под FASM. В процессе переноса библиотека была немного переработана и дополнена, а также упрощена ее структура и подключение к проектам. Сперва в сегменте данных определяются вспомогательные константы и структура для создания скроллера.
; Константы, определяющие режим скроллера
SCROLL_START = 0  ; Скроллер запущен
SCROLL_PAUSE = 1  ; Скроллер на паузе
SCROLL_STOP  = 2  ; Скроллер полностью остановлен
 
; Структура для скроллера
struct SCROLLSTRUCT
        ; Значения заполняются пользователем
        hwDlg      dd ?  ; Хэндл окна для скроллера
        hFont      dd ?  ; Шрифт скроллера
        ddWidth    dd ?  ; Ширина скроллера
        X          dd ?  ; Координата X
        Y          dd ?  ; Координата Y
        lpstrText  dd ?  ; Строка скроллера ASCIIZ
        ddTxtColor dd ?  ; Цвет текста скроллера
        ddBkgColor dd ?  ; Цвет фона скроллера
        ddSpeed    dd ?  ; Скорость движения
        dbMode     db ?  ; Режим скроллера
 
        ; Внутренние переменные
        ddROP      dd ?
        hBkgDC     dd ?
        hTxtBmp    dd ?
        hTmpBmp    dd ?
        hBakTmpBmp dd ?
        hInDC      dd ?
        ddHeight   dd ?
        ddPos      dd ?
        ddTxtWidth dd ?
ends

В структуре два типа переменных - пользовательские и служебные. Пользовательские предназначены для задания координат, цвета и других параметров скроллера, они все обязательны для заполнения. Служебные используются процедурой скроллера и не должны изменяться пользователем.

После инициализации переменных вызывается основная функция скроллера. Обратите внимание, что скроллер должен быть привязан только к существующему и видимому окну, поэтому в функции выполняется проверка существования родительского окна, а само окно принудительно делается видимым. Принцип работы скроллера в том, что из окна считывается фрагмент заданного размера, текст скроллера преобразуется в картинку, а затем в цикле по ней передвигается "кадр" и накладывается на фрагмент из окна.
;-----------------------------------------------------------------------
; Процедура инициализации и запуска скроллера
; by ManHunter / PCL
; http://www.manhunter.ru
;
; Based on Scroller lib v1.01 by ReWolf / HTBTeam
; http://rewolf.prv.pl
;
; Параметры вызова:
;     lpScrollData - указатель на заполненную структуру SCROLLSTRUCT
;-----------------------------------------------------------------------
proc    Scroller lpScrollData:DWORD
 
        ; Локальные переменные
        local   sz_x      :DWORD
        local   sz_y      :DWORD
        local   ddLen     :DWORD
        local   hBkgBrush :DWORD
        local   hBkgPen   :DWORD
 
        ; Локальная проекция структуры
        virtual at 0
        scroll SCROLLSTRUCT
        end virtual
 
        ; Сохранить все регистры
        pusha
 
        ; Указатель на структуру SCROLLSTRUCT
        mov     edi,[lpScrollData]
 
        ; Родительское окно существует?
        invoke  IsWindow,[edi+scroll.hwDlg]
        or      eax,eax
        jnz     @f
 
        ; Восстановить все регистры
        popa
        ; EAX = 0, функция завершилась с ошибкой
        xor     eax,eax
        ret
@@:
        ; Сделать окно видимым и обновить его
        invoke  ShowWindow,[edi+scroll.hwDlg],SW_SHOW
        invoke  UpdateWindow,[edi+scroll.hwDlg]
 
        ; Получить контекст устройства окна
        invoke  GetDC,[edi+scroll.hwDlg]
        mov     [edi+scroll.hBkgDC],eax
 
        ; Режим наложения AND
        mov     [edi+scroll.ddROP],SRCAND
 
        ; Стартовая позиция скроллера = 0
        mov     [edi+scroll.ddPos],0
 
        invoke  CreateCompatibleDC,[edi+scroll.hBkgDC]
        mov     [edi+scroll.hInDC],eax
 
        ; Установить шрифт скроллера
        invoke  SelectObject,[edi+scroll.hInDC],[edi+scroll.hFont]
 
        ; Получить длину строки скроллера
        invoke  lstrlen,[edi+scroll.lpstrText]
        mov     [ddLen],eax
 
        lea     eax,[sz_x]
        invoke  GetTextExtentPoint32,[edi+scroll.hInDC],[edi+scroll.lpstrText],\
                [ddLen],eax
        push    [sz_y]
        pop     [edi+scroll.ddHeight]
        push    [sz_x]
        pop     [edi+scroll.ddTxtWidth]
 
        mov     eax,[edi+scroll.ddWidth]
        shl     eax,1
        add     eax,[edi+scroll.ddTxtWidth]
        invoke  CreateCompatibleBitmap,[edi+scroll.hBkgDC],eax,\
                [edi+scroll.ddHeight]
        mov     [edi+scroll.hTxtBmp],eax
 
        invoke  SelectObject,[edi+scroll.hInDC],[edi+scroll.hTxtBmp]
        invoke  SetBkMode,[edi+scroll.hInDC],OPAQUE; TRANSPARENT;
        invoke  SetTextColor,[edi+scroll.hInDC],[edi+scroll.ddTxtColor]
        invoke  CreateSolidBrush,[edi+scroll.ddBkgColor]
        mov     [hBkgBrush],eax
 
        invoke  SelectObject,[edi+scroll.hInDC],eax
 
        invoke  CreatePen,PS_SOLID,1,[edi+scroll.ddBkgColor]
        mov     [hBkgPen],eax
 
        invoke  SelectObject,[edi+scroll.hInDC],eax
 
        mov     eax,[edi+scroll.ddWidth]
        shl     eax,1
        add     eax,[edi+scroll.ddTxtWidth]
        invoke  Rectangle,[edi+scroll.hInDC],0,0,eax,[edi+scroll.ddHeight]
 
        invoke  TextOut,[edi+scroll.hInDC],[edi+scroll.ddWidth],0,\
                [edi+scroll.lpstrText],[ddLen]
 
        invoke  SelectObject,[edi+scroll.hInDC],[hBkgPen]
        invoke  SelectObject,[edi+scroll.hInDC],[hBkgBrush]
 
        invoke  DeleteObject,[hBkgPen]
        invoke  DeleteObject,[hBkgBrush]
 
        invoke  CreateCompatibleBitmap,[edi+scroll.hBkgDC],\
                [edi+scroll.ddWidth],[edi+scroll.ddHeight]
        mov     [edi+scroll.hBakTmpBmp],eax
 
        invoke  SelectObject,[edi+scroll.hInDC],eax
        invoke  BitBlt,[edi+scroll.hInDC],0,0,[edi+scroll.ddWidth],\
                [edi+scroll.ddHeight],[edi+scroll.hBkgDC],[edi+scroll.X],\
                [edi+scroll.Y],SRCCOPY
 
        invoke  SelectObject,[edi+scroll.hInDC],[edi+scroll.hBakTmpBmp]
 
        invoke  CreateCompatibleBitmap,[edi+scroll.hBkgDC],\
                [edi+scroll.ddWidth],[edi+scroll.ddHeight]
        mov     [edi+scroll.hTmpBmp],eax
 
        ; Запустить основную процедуру скроллера
        xor     eax,eax
        push    eax
        invoke  CreateThread,NULL,NULL,scroll_proc,[lpScrollData],NULL,esp
        pop     eax
 
        ; Обновить родительское окно
        invoke  UpdateWindow,[edi+scroll.hwDlg]
 
        ; Восстановить все регистры
        popa
        ; EAX = 1, функция выполнена успешно
        xor     eax,eax
        inc     eax
 
        ret
endp

Вспомогательная функция скроллера запускается в отдельном потоке, управляется только через поле dbMode структуры SCROLLSTRUCT соответствующего скроллера. Пример смотрите в прилагаемом исходнике. При полной остановке скроллера поток завершается и скроллер становится недоступным для управления.
;-----------------------------------------------------------------------
; Вспомогательная функция скроллера, напрямую не вызывается
;-----------------------------------------------------------------------
proc scroll_proc lpScrollData:DWORD
 
        ; Локальная проекция структуры
        virtual at 0
        pscroll SCROLLSTRUCT
        end virtual
 
        ; Указатель на структуру SCROLLSTRUCT
        mov     edi,[lpScrollData]
.scroll_loop:
        ; Проверить режим скроллера
        cmp     [edi+pscroll.dbMode],SCROLL_STOP
        ; Выход
        je      .scroll_exit
 
        ; Если скроллер только создан, то отрисовать его
        cmp     [edi+pscroll.ddPos],1
        jbe     @f
 
        ; Выдержать паузу согласно заданной скорости
        invoke  Sleep,[edi+pscroll.ddSpeed]
        ; Скроллер приостановлен?
        cmp     [edi+pscroll.dbMode],SCROLL_PAUSE
        je      .scroll_loop
@@:
        mov     ebx,[edi+pscroll.ddTxtWidth]
        add     ebx,[edi+pscroll.ddWidth]
        cmp     ebx,[edi+pscroll.ddPos]
        jne     @f
        mov     [edi+pscroll.ddPos],0
@@:
        invoke  CreateCompatibleDC,[edi+pscroll.hInDC]
        mov     esi,eax
        invoke  SelectObject,eax,[edi+pscroll.hBakTmpBmp]
        invoke  SelectObject,[edi+pscroll.hInDC],[edi+pscroll.hTmpBmp]
        invoke  BitBlt,[edi+pscroll.hInDC],0,0,[edi+pscroll.ddWidth],\
                [edi+pscroll.ddHeight],esi,0,0,SRCCOPY
        invoke  SelectObject,esi,[edi+pscroll.hTxtBmp]
        invoke  BitBlt,[edi+pscroll.hInDC],0,0,[edi+pscroll.ddWidth],\
                [edi+pscroll.ddHeight],esi,[edi+pscroll.ddPos],\
                0,[edi+pscroll.ddROP]
        invoke  BitBlt,[edi+pscroll.hBkgDC],[edi+pscroll.X],\
                [edi+pscroll.Y],[edi+pscroll.ddWidth],[edi+pscroll.ddHeight],\
                [edi+pscroll.hInDC],0,0,SRCCOPY
        invoke  DeleteDC,esi
 
        inc     [edi+pscroll.ddPos]
        jmp     .scroll_loop
.scroll_exit:
        ret
endp

В приложении пример программы с двумя независимыми скроллерами, по нажатию кнопки Pause они останавливаются, при повторном нажатии запускаются снова.
Теги:
бегущая строка
Добавлено: 10 Апреля 2018 17:48:16 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...