Blog. Just Blog

Эффект пламени на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Эффект пламени на Ассемблере
Эффект пламени на Ассемблере

Классический эффект горящего пламени используется в различных интро и демонстрашках еще со времен MS-DOS, а может быть и раньше. Алгоритм достаточно простой, но при этом выглядит очень красиво. Суть его заключается в следующем. Сперва создается палитра, в ней должны быть только оттенки белого, желтого, красного и черный цвет. Далее создается массив, который соответствует размеру изображения и содержит значения цветов его пикселов. По нижней строчке записываются в случайном порядке пикселы или пропуски, после этого по таймеру запускается основной цикл обработки.

Вот пример заполнения палитры. Меняя значения цветов, можно сделать, например, пламя в оттенках синего или извернуться еще как-нибудь.
  1.         ; Заполнить палитру
  2.         mov     edi,palette
  3.  
  4.         mov     ecx,64
  5. @@:
  6.         mov     eax,64
  7.         sub     eax,ecx
  8.         shl     eax,2
  9.         stosd
  10.         loop    @b
  11.  
  12.         mov     ecx,64
  13. @@:
  14.         mov     eax,64
  15.         sub     eax,ecx
  16.         shl     eax,10
  17.         mov     al,0xFF
  18.         stosd
  19.         loop    @b
  20.  
  21.         mov     ecx,64
  22. @@:
  23.         mov     eax,64
  24.         sub     eax,ecx
  25.         shl     eax,10
  26.         bswap   eax
  27.         mov     ax,0xFFFF
  28.         stosd
  29.         loop    @b
  30.  
  31.         mov     ecx,65
  32.         mov     eax,0x00FFFFFF
  33.         rep     stosd
Начиная с нижней строчки для каждой точки из массива выполняется следующее действие: берется сумма цвета самой точки и трех окружающих ее точек - слева, справа и сверху. Итоговая сумма делится на количество точек, то есть на 4, полученное значение цвета присваивается обрабатываемой точке. Затем обрабатывается следующая точка линии, затем следующая линия и так далее. Чтобы "огонь" не "погас", перед каждым проходом цикла на нижнюю строчку записывается новая партия случайных точек и пропусков. В результате получаются поднимающиеся языки пламени.
  1.         ; Заполнить нижнюю линию изображения
  2.         stdcall WIRandom,1,(WINDOW_WIDTH-1)
  3.         inc     eax
  4.         xor     edx,edx
  5.         mov     ecx,WINDOW_WIDTH
  6.         xchg    eax,ecx
  7.         div     ecx
  8.         mov     ecx,eax
  9.         mov     esi,WINDOW_WIDTH*(WINDOW_HEIGHT-1)
  10.         add     esi,eax
  11. .loc_fill:
  12.         stdcall WIRandom,1,100
  13.         mov     bl,255
  14.         cmp     eax,11
  15.         jbe     @f
  16.         mov     bl,0
  17.         cmp     eax,19
  18.         jbe     @f
  19.         mov     bl,[px_data-1+esi]
  20.         cmp     eax,59
  21.         jbe     @f
  22.         mov     bl,[px_data+1+esi]
  23. @@:
  24.         mov     [px_data+esi],bl
  25.  
  26.         inc     esi
  27.         inc     ecx
  28.         cmp     ecx,(WINDOW_WIDTH-1)
  29.         jb      .loc_fill
  30.  
  31.         ; Смиксовать ближайшие точки
  32.         mov     esi,WINDOW_WIDTH*(WINDOW_HEIGHT-1)-1
  33. .loc_mix:
  34.         movzx   eax,byte [px_data+esi]
  35.  
  36.         add     al,[px_data+esi+WINDOW_WIDTH]
  37.         adc     ah,0
  38.         add     al,[px_data+esi+WINDOW_WIDTH+1]
  39.         adc     ah,0
  40.         add     al,[px_data+esi+WINDOW_WIDTH-1]
  41.         adc     ah,0
  42.  
  43.         dec     eax
  44.         jns     @f
  45.         xor     eax,eax
  46. @@:
  47.         shr     eax,2
  48.         mov     [px_data+esi],al
  49.         dec     esi
  50.         jnz     .loc_mix
После обработки массива он переносится на холст, который выводится на форму. Для того, чтобы огонь выглядел более красиво, две нижние строчки, в которых записаны случайные значения и результат самой первой миксовки, лучше не выводить.
  1.         invoke  BeginPaint,[hwnddlg],ps
  2.         mov     [hDC],eax
  3.  
  4.         invoke  CreateCompatibleDC,[hDC]
  5.         mov     [hCompDC],eax
  6.         invoke  CreateCompatibleBitmap,[hDC],WINDOW_WIDTH,WINDOW_HEIGHT
  7.         mov     [hBitmap],eax
  8.         invoke  SelectObject,[hCompDC],[hBitmap]
  9.         mov     [hOldBitmap],eax
  10.  
  11.         ; Перенести точки на холст
  12.         mov     esi,WINDOW_WIDTH*WINDOW_HEIGHT
  13. @@:
  14.         movzx   ebx,byte[px_data+esi]
  15.         shl     ebx,2
  16.         xor     edx,edx
  17.         mov     eax,esi
  18.         mov     ecx,WINDOW_WIDTH
  19.         div     ecx
  20.         invoke  SetPixel,[hCompDC],edx,eax,[palette+ebx]
  21.         dec     esi
  22.         jnz     @b
  23.  
  24.         invoke  BitBlt,[hDC],0,0,WINDOW_WIDTH,WINDOW_HEIGHT-2,\
  25.                 [hCompDC],0,0,SRCCOPY
  26.  
  27.         ; Прибраться за собой
  28.         invoke  SelectObject,[hCompDC],[hOldBitmap]
  29.         invoke  DeleteObject,[hBitmap]
  30.         invoke  DeleteDC,[hCompDC]
  31.  
  32.         invoke  EndPaint,[hwnddlg],ps
Огненный эффект можно значительно улучшить, если выводить поверх языков пламени какой-нибудь текст, а потом "сжигать" его. Наверняка вы видели нечто подобное в различных кейгенах. Это реализуется следующим образом. Некоторое время текст просто выводится поверх пламени, затем все его точки переносятся на холст с огнем. Там в течение следующих итераций цикла обработки они сливаются с уже имеющимися языками пламени, а также "разгораются" самостоятельно. Для переноса точек надписи я использую вспомогательную функцию, где текст отрисовывается на изображение такого же размера, как и основной холст, затем в цикле проверяется цвет каждой точки. Если точка вспомогательного изображения заполнена, то она переносится в соответствующую координату основного холста.
  1. proc FireText
  2.         locals
  3.                 hzCompDC dd ?
  4.                 hzBitmap dd ?
  5.                 hzDC dd ?
  6.                 zps PAINTSTRUCT
  7.         endl
  8.  
  9.         ; Нанести надпись
  10.         invoke  CreateCompatibleDC,NULL
  11.         mov     [hzCompDC],eax
  12.         invoke  CreateCompatibleBitmap,[hzCompDC],WINDOW_WIDTH,WINDOW_HEIGHT
  13.         mov     [hzBitmap],eax
  14.         invoke  SelectObject,[hzCompDC],[hzBitmap]
  15.  
  16.         invoke  FillRect,[hzCompDC],rc,0
  17.  
  18.         ; Шрифт
  19.         invoke  SelectObject,[hzCompDC],[hFont]
  20.         invoke  SetTextColor,[hzCompDC],0x0000FF00
  21.         invoke  DrawText,[hzCompDC],[pointer],-1,rc,\
  22.                 DT_VCENTER+DT_CENTER+DT_NOPREFIX+DT_SINGLELINE
  23.  
  24.         ; Перенести точки на холст
  25.         mov     esi,WINDOW_WIDTH*WINDOW_HEIGHT
  26. @@:
  27.         xor     edx,edx
  28.         mov     eax,esi
  29.         mov     ecx,WINDOW_WIDTH
  30.         div     ecx
  31.         invoke  GetPixel,[hzCompDC],edx,eax
  32.         dec     esi
  33.         jz      @f
  34.         cmp     eax,0x00
  35.         jne     @b
  36.         mov     byte[px_data+1+esi],255
  37.         jmp     @b
  38. @@:
  39.         invoke  DeleteObject,[hzBitmap]
  40.         invoke  DeleteDC,[hzCompDC]
  41.         ret
  42. endp
В приложении пример программы с исходным текстом, которая реализует описанный в статье эффект пламени и огненного текста.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Fire.Effect.Demo.zip (5,083 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 521 | Комментариев: 7

Метки: Assembler

Комментарии

Отзывы посетителей сайта о статье
CpuBench (27.07.2024 в 23:10):
Эффект воды был, как горит огонь теперь есть, осталось сделать эффект как работают люди и можно смотреть вечно вместо ютуба.
ManHunter (16.07.2024 в 22:05):
Никаких эффектов, только совокупность палитры из оттенков четырех базовых цветов и микс сопредельных точек. В результате и получается такое размытие.
Евгений (16.07.2024 в 22:03):
С горящими буквами получилось интересно,такого не встречал, круто. Скажите на всю область пламени (кроме узкой полоски снизу) применён какой-то эффект размытия, пламя заблюрено, или мне кажется?
denis(ufa) (16.07.2024 в 18:45):
Огонь! Плохо что очень ресурсо-затратно.
ManHunter (16.07.2024 в 12:16):
Григорий, насколько я помню, это рипы из кейгенов, которые когда-то собирал Cyberdoom. А тут хорошо, что они собраны в одном месте. Спасибо.
Григорий (16.07.2024 в 11:47):
Процессор норм так просаживает... :D Хотя может это только у меня так, на win 11

Кстати ManHunter вот куча забавных эффектов. Может вас заинтересует.
Ссылка https://github.com/Xyl2k/MASM3...ical-effects
Grey (16.07.2024 в 10:44):
Офигенно

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0045 сек.) / Память: 4.5 Mb
Наверх