Вертикальный скроллер на Ассемблере

Такой эффект очень часто используется в различных кейгенах, окнах "О программе", демо-роликах, просмотрщиках текстовых файлов и подобных программах. Код основан на аналогичной процедуре от Av0id, я добавил в него несколько усовершенствований. Для настройки размеров и внешнего вида скроллера в сегменте данных определяются вспомогательные константы и структуры, не описанные в FASM:
; Настройки внешнего вида скроллера
SCROLL_FONT_WIDTH  = 8          ; Ширина символов текста
SCROLL_FONT_HEIGHT = 8          ; Высота символов текста
SCROLL_WIDTH       = 430        ; Ширина окна скроллера
SCROLL_HEIGHT      = 350        ; Высота окна скроллера
SCROLL_BACKCOLOR   = 0808080h   ; Цвет фона
SCROLL_TEXTCOLOR   = 000FFFFh   ; Цвет текста
SCROLL_SHADOWCOLOR = 0          ; Цвет тени
SCROLL_SLEEP       = 40         ; Скорость скроллирования
SCROLL_SHADOW      = FALSE      ; Рисовать тень TRUE/FALSE  
 
; Структуры для создания виртуального BMP-файла
struct  RGBQUAD
    rgbBlue      db ?
    rgbGreen     db ?
    rgbRed       db ?
    rgbReserved  db ?
ends
 
struct  BITMAPINFO
    bmiHeader     BITMAPINFOHEADER
    bmiColors     RGBQUAD
ends

А также переменные и другие данные, необходимые для его работы:
section '.data' data readable writeable
 
hThread         dd ?    ; Хэндл потока скроллера
exit_flag       dd ?    ; Флаг завершения потока
active_flag     dd ?    ; Флаг активности скроллера
 
szTerminalFont  db 'Terminal',0 ; Шрифт скроллера
                ; Файл с текстом скроллера
szScrollerText  file 'scroller.txt'
                db 0

Если в скроллере используется псевдографика, то желательно оставить шрифт "Terminal", а если будет только текст, то можете выбрать любой другой системный шрифт, лишь бы он был установлен у пользователя на компьютере. Текст скроллера можно создавать в любом редакторе, поддерживающем псевдографику. При использовании рамок или рисунков из символов, они обязательно должны быть дополнены пробелами до правой границы текста. Ширина и высота символов задается в настройках, но имейте в виду, что размеры должны поддерживаться свойствами самого шрифта. Поэкспериментируйте.

Запуск скроллера выполняется в отдельном окне, отдельным потоком. При этом свойства окна прописываются в ресурсах, а его размер подгоняется под размер, описанный в настройках скроллера.
        ...
        ; Инициализация окна скроллера
        cmp     [wMsg],WM_INITDIALOG
        je      .wminit
        ...
 
.wminit:
        ; Флаг завершения потока скроллера
        mov     [exit_flag],FALSE
 
        ; Подогнать размеры окна под размер скроллера
        invoke  SetWindowPos,[hWnd],NULL,NULL,NULL,SCROLL_WIDTH,\
                SCROLL_HEIGHT,SWP_NOACTIVATE+SWP_NOZORDER+SWP_NOMOVE
 
        ; Запустить скроллер
        invoke  CreateThread,NULL,NULL,VerticalScrollShadow,\
                [hWnd],NULL,NULL
        ; Сохранить хэндл потока
        mov     [hThread],eax
 
        ; Установить приоритет потока скроллера
        invoke  SetThreadPriority,eax,THREAD_BASE_PRIORITY_MAX

А вот и сама процедура скроллера. Принцип ее работы ненамного отличается от горизонтального скроллера. Точно так же текст преобразуется в картинку, а затем на фон из этой картинки в цикле накладывается "кадр" со сдвигом. Если задана тень, то сперва на фон накладывается тот же текст, но темного цвета и со смещением в несколько пикселов для создания нужного визуального эффекта. При достижении конца текста он "перематывается" на начало.
;---------------------------------------------------
; Процедура вертикального скроллера текста в окне
; На основе кода от Av0id
;---------------------------------------------------
proc  VerticalScrollShadow hWnd:DWORD
 
  ; Локальные переменные
  locals
        hDC           dd ?
        hCompatDC     dd ?
        hCompatDC2    dd ?
        hFont         dd ?
        hLen          dd ?
        hTextHeight   dd ?
        hDIBits       dd ?
        hDIBits2      dd ?
        hDIBSection   dd ?
        hDIBSection2  dd ?
        hBrush        dd ?
 
        dStep         dd ?
        dPos          dd ?
 
        rct            RECT
        bmi            BITMAPINFO
  endl
 
        pusha
 
        xor     ebx,ebx
 
        invoke  GetDC,[hWnd]
        mov     [hDC],eax
        invoke  CreateCompatibleDC,eax
        mov     [hCompatDC],eax
        invoke  CreateCompatibleDC,[hDC]
        mov     [hCompatDC2],eax
 
        ; Моноширинный шрифт Terminal
        invoke  CreateFont,SCROLL_FONT_WIDTH,SCROLL_FONT_HEIGHT,\
                ebx,ebx,FW_NORMAL,ebx,ebx,ebx,OEM_CHARSET,ebx,ebx,\
                ebx,ebx,szTerminalFont
        mov     [hFont],eax
        invoke  SelectObject,[hCompatDC],eax
 
        ; Вычислить размеры блока текста
        xor     esi,esi
        dec     esi
        mov     edi,szScrollerText
        invoke  lstrlen,edi
        inc     eax
        mov     [hLen],eax
        mov     ecx,eax
        ; Количество строк равно количеству символов переноса строки
        mov     al,13
@@:
        inc     esi
        repne   scasb
        jz      @b
 
        ; Высота картинки равна количеству строк * высоту шрифта
        xor     edx,edx
        mov     eax,SCROLL_FONT_HEIGHT
        imul    esi
        add     eax,SCROLL_HEIGHT
 
        mov     [hTextHeight],eax
 
        ; Создать виртуальный BMP-файл с нарисованным текстом
        lea     edi,[bmi]
        mov     [edi+BITMAPINFO.bmiHeader.biSize],sizeof.BITMAPINFOHEADER
        mov     [edi+BITMAPINFO.bmiHeader.biWidth],SCROLL_WIDTH
        mov     eax,[hTextHeight]
        not     eax
        mov     [edi+BITMAPINFO.bmiHeader.biHeight],eax
        mov     [edi+BITMAPINFO.bmiHeader.biPlanes],1
        mov     [edi+BITMAPINFO.bmiHeader.biBitCount],24
 
        lea     eax,[hDIBits]
        invoke  CreateDIBSection,[hCompatDC],edi,ebx,eax,ebx,ebx
        mov     [hDIBSection],eax
 
        mov     [edi+BITMAPINFO.bmiHeader.biHeight],SCROLL_HEIGHT
 
        lea     eax,[hDIBits2]
        invoke  CreateDIBSection,[hCompatDC2],edi,ebx,eax,ebx,ebx
        mov     [hDIBSection2],eax
 
        invoke  SelectObject,[hCompatDC],[hDIBSection]
        invoke  SelectObject,[hCompatDC2],[hDIBSection2]
 
        ; Размеры области заливки
        lea     edi,[rct]
        mov     [edi+RECT.top],0
        mov     [edi+RECT.left],0
        mov     ecx,[hTextHeight]
        add     ecx,SCROLL_HEIGHT
        mov     [edi+RECT.bottom],ecx
        mov     [edi+RECT.right],SCROLL_WIDTH
 
        ; Заливка фона
        invoke  CreateSolidBrush,SCROLL_BACKCOLOR
        mov     [hBrush],eax
        invoke  FillRect,[hCompatDC],edi,[hBrush]
        invoke  FillRect,[hCompatDC2],edi,[hBrush]
 
        ; Режим отображения - прозрачный
        invoke  SetBkMode,[hCompatDC],TRANSPARENT
 
        ; Рисовать текст с тенью?
        mov     eax,SCROLL_SHADOW
        cmp     eax,FALSE
        je      @f
 
        ; Установить координаты сдвига для тени
        mov     [edi+RECT.top],1
        mov     [edi+RECT.left],2
 
        ; Нарисовать подложку тени со сдвигом
        invoke  SetTextColor,[hCompatDC],SCROLL_SHADOWCOLOR
        invoke  DrawText,[hCompatDC],szScrollerText,[hLen],edi,1
@@:
        ; Координаты вывода нормального текста
        mov     [edi+RECT.top],0
        mov     [edi+RECT.left],0
 
        ; Нарисовать основной текст
        invoke  SetTextColor,[hCompatDC],SCROLL_TEXTCOLOR
        invoke  DrawText,[hCompatDC],szScrollerText,[hLen],edi,1
 
        mov     esi,SCROLL_HEIGHT
        not     esi
 
.reset:
        mov     edi,esi
 
.paint:
        ; Отрисовка картинки со сдвигом
        invoke  BitBlt,[hCompatDC2],ebx,ebx,SCROLL_WIDTH,SCROLL_HEIGHT,\
                [hCompatDC],ebx,edi,SRCCOPY
        invoke  BitBlt,[hDC],ebx,ebx,SCROLL_WIDTH,SCROLL_HEIGHT,\
                [hCompatDC2],ebx,ebx,SRCCOPY
 
        ; Таймаут
        invoke  Sleep,SCROLL_SLEEP
 
        ; Картинка прокручена до конца?
        inc     edi
        mov     eax,[hTextHeight]
        sub     eax,SCROLL_HEIGHT
        cmp     eax,edi
        jz      .reset
 
        ; Флаг выхода установлен?
        cmp     [exit_flag],1
        jnz     .paint
 
.exit:
        ; Прибраться за собой и завершить поток
        invoke  DeleteObject,[hBrush]
        invoke  DeleteObject,[hDIBSection]
        invoke  DeleteObject,[hDIBSection2]
        invoke  DeleteObject,[hFont]
        invoke  DeleteDC,[hCompatDC]
        invoke  DeleteDC,[hCompatDC2]
        invoke  ReleaseDC,[hWnd],[hDC]
        invoke  ExitThread,ebx
 
        popa
        ret
endp
Добавлено: 13 Сентября 2013 04:36:18 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...