DEMO.DESIGN
Frequently Asked Questions
 
оглавление | demo party в ex-СССР | infused bytes e-mag | новости от ib/news | другие проекты | письмо | win koi lat

следующий фpагмент (2)
Эффект пламени (flame) Первое, что надо сделать - это установить два массива, размер массива зависит от многих вещей: режима экрана, скорости компьютера итд.Это не очень важно лишь бы они были одного размера. Используем 320x200 (64000 байта) массивы, потому, что это размер необходимый для использования целого экрана в режиме 13h. Следующее, что надо сделать - это установить градиентную палитру. Она может плавно проходить через любые цвета, но в этом тексте максимум будет у белого/желтого, минимум (низ) у черного, и пройдет через крас- ный в середине. Имеется два массива. Назовем их start buffer и screen buffer,чтобы по- нимать что происходит.Сначала надо установит внутренние значения start buffer. Для этого нужна функция случайных чисел, которая возвращает значение между 0 и 199 (т.к. принятый экран высотой 200). Это даст ус- тановочные значения для случайных точек("hotspots"), таким образом,де- лаем это столько раз сколько нужно,и устанавливаем все значения нижних линий start buffer на максимальное значение цвета. Как получить требуемый эффект. Для этого надо скопировать start buffer, модифицировать его и сохранить его в screenbuffer, сделаем это "усред- няя" (вычисляя среднее/averading) точки окружающие исходную. Понять это легче представляя эту операцию в X,Y координатах. Ниже дана диаграмма для одиночной точки... Это startbuffer Это screenbuffer ----T---T---T---T---¬ ----T---T---T---T---¬ ¦0,0¦0,1¦0,2¦0,3¦0,4¦ итд... ¦ ¦ ¦ ¦ ¦ ¦ +---+---+---+---+---+ +---+---+---+---+---+ ¦1,0¦1,1¦1,2¦1,3¦1,4¦ итд.. ¦ ¦X,Y¦ ¦ ¦ ¦ +---+---+---+---+---+ +---+---+---+---+---+ ¦2,0¦2,1¦2,2¦2,3¦2,4¦ итд.. ¦ ¦ ¦ ¦ ¦ ¦ L---+---+---+---+---- L---+---+---+---+---- Сейчас расчитаем значения для X,Y ( обратите внимание, новые значения точки рассчитываются не с 0,0, так как необходимо усреднить 8 окружаю- щих точек для получения нового значения, а у точек вокруг краев нет 8 окружающих точек), итак все что требуется - вычислить среднее значения всех окружающих точек, т.е. сложить (0,0 0,1 0,2 + 1,0 1,2 + 2,0 2,1 2,2) и затем разделить результат на 8, но появляются три проблемы... 1) Пламя остается на нижней линии... 2) Оно медленно 3) Цвета пламени не блекнут/угасают Первое что надо сделать - заставить пламя двигаться. Это очень просто сделать. Все что надо для этого - брать средние значения со значений точки НИЖЕ той для который делается расчет, этот метод сдвинет линии нового массива на строчку вверх.Например рассчитывая значения для X,Y= 1,1 мы рассчитываем их для 2, 1 и помещаем на место 1,1 Вторая проблема решается несколькими путями.Первый и самый простой за- ключается в том, чтобы рассчитать меньше точек в окружении...то вместо 8 окружающих точек мы расчитываем например 2 (одну выше и одну ниже) и делим на 2 вместо 8.Второй - использование экранного режима, где можно устанавливать сразу 4 точки одновременно, или установить экран так, чтобы можно было использовать более маленькие массивы. Третяя проблема решается путем декремента вычиленного значения на еди- ницу и сохранения этого значения. === Cut here ====== ; tasm ; tlink ; as usual 8-) .286 JUMPS ASSUME CS:_Code,DS:_DATA,SS:_Stack EXTRN _X_set_mode: FAR _Stack Segment Para Stack 'Stack' db 2048 dup (?) _Stack EndS _Data Segment Para Public 'Data' flames db 32*64 dup (0) new_flames db 32*64 dup (0) x dw 0 y dw 0 _Data EndS _Code Segment Para Public 'Code' SetBorder Macro color mov dx,03dah ; Used for speed test in al,dx nop nop nop mov dx,03c0h mov al,11h+32 out dx,al mov al,color out dx,al EndM Intro Proc Far push ds xor ax,ax push ax ASSUME ds:_DATA mov ax,_DATA mov ds,ax mov ax,0013h int 10h mov dx,03c8h ; Set up palette, black -> red xor al,al out dx,al inc dx mov cx,8 @set_red: mov al,16 ; Some stupid comments sub al,cl shl al,3 ; Multiply al with 4 out dx,al xor al,al ; Xor al with al out dx,al out dx,al loop @set_red ; Loop this 16 times (nah...no more stupid comments) mov cx,16 ; Set red -> yellow @set_yellow: mov al,60 out dx,al mov al,16 sub al,cl shl al,2 out dx,al xor al,al out dx,al loop @set_yellow mov cx,16 ; set yellow -> white @set_white: mov al,60 out dx,al out dx,al mov al,16 sub al,cl shl al,2 out dx,al loop @set_white mov cx,208 ; Set remaing colors to white mov al,63 @whithey: out dx,al out dx,al out dx,al loop @whithey @WaitESC: SetBorder 200 ; Delete the speed test when used in a proggie push ds pop es cld lea di,flames mov si,di add di,64 add si,96 mov cx,61*16 rep movsw ; Scroll the array 1 step up inc di add di,5 mov cx,4 @put_hot_spots: push di push cx push di mov ax,20 ; Get a random x value for hotspot call random pop di add di,ax push di mov ax,190 call random pop di pop cx mov ah,al mov [di],ax ; Set the hotspot pop di loop @put_hot_spots ; Set 4 new hotspots mov word ptr x,1 mov word ptr y,1 @scanning_flames: ; Loop for calculate the new flame array mov di,y ; Interpolate the 8 pixels around the location we wanna calculte a new value for shl di,5 add di,x xor ax,ax xor bx,bx mov bl,flames[di-33] mov al,flames[di-32] add bx,ax mov al,flames[di-31] add bx,ax mov al,flames[di-1] add bx,ax mov al,flames[di+1] add bx,ax mov al,flames[di+31] add bx,ax mov al,flames[di+33] add bx,ax mov al,flames[di+33] add bx,ax shr bx,3 mov new_flames[di],bl ; Save this in the new array inc x cmp word ptr x,32 jb @scanning_flames mov word ptr x,1 inc y cmp word ptr y,64 jb @scanning_flames ; Do it for the whole "map" lea di,flames lea si,new_flames mov cx,64*16 rep movsw ; Move new "map" to old "map" array mov ax,0a000h mov es,ax lea si,flames mov di,320*100+100 mov bx,60 @plot_it: mov cx,16 rep movsw add di,320-32 dec bx jnz @plot_it ; Plot the flames SetBorder 0 ; Delete this speed test mov dx,03dah @bettan: in al,dx test al,8 je @bettan @bettan2: in al,dx test al,8 jne @bettan2 ; Wait for vertical retrace in al,60h cmp al,1 jne @WaitESC ; Wait until the user have pressed ESC mov ax,0003h ; Text mode and Leave the program. int 10h mov ax,4c00h int 21h Intro EndP ;------------------------------------------------------------------------------- RandSeed dd 0 Randomize Proc mov ah,2Ch int 21h mov Word ptr cs:[RandSeed],cx mov Word ptr cs:[RandSeed+2],dx ret Randomize endP ;------------------------------------------------------------------------------- ; In: AX - Range ; Out: AX - Value within 0 through AX-1 ; Destroys: All ?X and ?I registers Random proc mov cx,ax ; save limit mov ax,Word ptr cs:[RandSeed+2] mov bx,Word ptr cs:[RandSeed] mov si,ax mov di,bx mov dl,ah mov ah,al mov al,bh mov bh,bl xor bl,bl rcr dl,1 rcr ax,1 rcr bx,1 add bx,di adc ax,si add bx,62e9h adc ax,3619h mov word ptr cs:[RandSeed],bx mov word ptr cs:[RandSeed+2],ax xor dx,dx div cx mov ax,dx ; return modulus ret Random EndP _Code EndS END Intro
следующий фpагмент (3)|пpедыдущий фpагмент (1)
[Ushakov Sergey, 2:50/521.2] SK> Подскажите алгоритм 3D огня. Алгоритм аналогичен двух мерному огню. a[1..100,1..100,1..100] of byte; z y x Инитишь буфер, экран, палитру и т. д. 1. Создать нижний слой (y=1) 2. Для каждой точки ищешь среднее арифметическое всех ее соседей (всего соседей 26) и присваиваешь его точке (можно отнять от среднего арифметического 1) 3. Изображаешь на экран 4. Сдвигаешь все это дело на единицу вверх a[z,y,x] := a[z,y-1,x] 5. Повторяешь с 1 - го. Hасчет изображения на экран. Тут уже вопрос 3-х мерной графики, можешь использовать Z-буфер. Hо с некоторыми оговорками (у тебя каждый цвет точки должен иметь свой коэффицент прозрачности)
следующий фpагмент (4)|пpедыдущий фpагмент (2)
;г=[¦]============ Редактор - C:\WORK\PAS\GRAPH\FIRE\FIRE.ASM ==========[]=¬ ;¦ Файл Редактор Поиск Параграф Блок Pазное Опции  ;¦--------------------------------------------------------------------------- ;¦ Имитация огня - бегущая (и при этом горящая) строка - ;¦ Автор - Pasha.K (Maniac Research Ltd.) ¦ ;¦ Можете распространять и использовать ее как хотите - если не будете - ;¦ выкидывать эти строки. - ;¦ Pasha.K - ;¦ Date: 3-02-98 Time: 03:12:43  ;L=¤==12:2 [032] ()=====------¦------------------------------------------- .286 ; Будет и короче и быстрее MODEL TINY ; COM файл, однако CODESEG ; кодовый сегмент здесь STARTUPCODE ; Это мне больше нравится, чем ORG 100h mov ax,13h ; int 10h ; Переходим в режим 320x200 256 lea si,dac ; mov ax,1010h ; mov bl,32 ; Устанавливаем цвета xor cx,cx ; палитры ldac: ; mov dh,[si] ; Используются цвета 32-224 int 10h ; inc si ; add bl,32 ; jnz ldac ; mov ch,25 ; Для цвета N 224 (им будут буквы рисоваться) mov bl,224 ; установим красно-желтый цвет int 10h ; (чтобы они с пламенем не сливались) mov di,offset scr ; mov cx,20000 ; Забиваем нулями внутренний xor ax,ax ; rep stosw ; буфер ; lp: cmp exitcnt,255 ; Это проверка - после нажатия jz dap ; клавиши (см. ниже) строка dec exitcnt ; перестает перерисовываться jnz $+5 ; и эффектно "сгорает" в одно jmp exitfire ; мгновение jmp noinc ; exitcnt - счетчик, который = 255, когда ; клавиша еще не нажата и который после нажатия ; постепенно уменьшается до нуля dap: push ds ; push es ; Получаем в BIOS-е адрес mov ax,1130h ; таблицы символов (8x14) mov bh,6 ; int 10h ; Я решил сэкономить 4 байта push es ; памяти и чуть замедлить pop ds ; программу :) mov si,bp ; Ни то ни другое почти не сказывается pop es ; на работе mov di,offset scr+45*320+20000 ; Указатель в буфере, куда будет печататься строка add di,es:count ; Смещаем вправо на x пикс. (для скролинга) mov bp,es:strpos ; В BP загружаем указатель на строку mov al,es:[bp] ; Проверяем, если строка уже кончилась ... cmp al,0 ; .... jnz dal ; .... mov ax,offset strbuf ; Обнуляем указатель mov es:strpos,ax ; .... mov bp,ax ; .... dal: mov cx,40 ; На экране 40 символов mov ax,es:count ; Однако мы рисуем строку не test ax,7 ; с левого края. Поэтому jz rovno ; приходится высчитывать число add ax,8 ; символов, которые будут видны rovno: ; на экране. shr ax,3 ; ... Округляем в большую сторону sub cx,ax ; lchr: push cx ; push si ; xor ah,ah ; Берем текущий символ из строки mov al,es:[bp] ; .... cmp al,0 ; Это конец строки ..? jnz dal1 ; .... mov bp,offset strbuf ; Циклически повторяем строку mov al,[bp] ; в AL теперь первый символ строки dal1: shl ax,4 ; Вычисляем адрес символа add si,ax ; .... mov cl,16 ; Размер символа по Y - 16 пикс. lchry: lodsb ; Считываем байт из образа символа mov dl,al ; Сохраняем его mov bh,128 ; Маска : 10000000B push cx mov cl,8 ; Размер символа по X - 8 пикс. lchrx: mov bl,dl ; Соответствующий бит and bl,bh ; образа = 1 ?.. jz nopix ; mov al,224 ; Да ... stosb ; Рисуем точку jmp short epix ; DI уже увеличен на 1 nopix: inc di ; Нет ... Просто увеличиваем DI epix: shr bh,1 ; Сдвигаем маску вправо - проверяем следующий бит loop lchrx ; ... Так рисуем всю строку pop cx ; add di,312 ; Переходим на одну строку ниже +(320-8) loop lchry ; pop si ; sub di,5112 ; Позиция следующего символа -((320*16)-8) inc bp ; pop cx ; loop lchr ; ... Так печатаем все символы pop ds ; Восстанавливаем DS dec count ; В следующий раз строка будет печататься на пиксел левее jnz noinc ; Мы дошли до левого края экрана ? mov bp,strpos ; mov cl,1 ; llw: ; mov al,[bp] ; cmp al,0 ; Здесь мы находим границу jz send ; левого слова и исключаем ее cmp al,' ' ; из вывода, корректируя jz wend ; соответственно строковый inc cl ; указатель и смещение строки inc bp ; cmp cl,20 ; jnz llw ; send: dec cx ; Это чтобы все не прыгало при достижении конца строки wend: inc bp ; mov strpos,bp ; ..................... shl cx,3 ; ..................... mov count,cx ; noinc: push es ; push 0a000h ; Сегмент экранной области pop es ; mov di,320*30+16000 ; Буфер разделен на две части : mov si,offset scr+20000 ; во второй изображение после обработки, ; в первой - до mov cx,10000 ; На экран копируется вторая область, rep movsw ; чтобы небыло размытия символов push 40h ; Сегмент Bios Data Area pop es ; lltim: mov al,es:[6ch] ; Младший байт таймера cmp al,cs:tim ; цикл задержки может быть jz lltim ; полезен на быстрых машинах ; ПОЧЕМУ ЭТА ХРЕНЬ НЕ РАБОТАЕТ ? pop es ; mov tim,al ; Запоминаем показания таймера см. выше mov si,1+offset scr+20000 ; Перед началом обработки экрана mov di,offset scr+1 ; следует настроить указатели на первый и второй буфера mov cx,19678 ; Столько байт будем обрабатывать lea bx,xltab ; См. ниже lscr: push si ; Подготовляем xor ax,ax ; регистры dec si ; .... xor dx,dx ; .... mov dl,[si] ; add ax,dx ; inc si ; Для каждой точки считаем inc si ; сумму значений пиуселов mov dl,[si] ; окружаюших ее след. образом: add ax,dx ; add si,318 ; mov dl,[si] ; add ax,dx ; X O X inc si ; X X X mov dl,[si] ; add ax,dx ; inc si ; mov dl,[si] ; add ax,dx ; pop si ; push si ; shr ax,5 ; Так как исп. только 3 старших бита в значении цвета, полезно поделить все на 32 cmp ax,24 ; Если значение слишком большое - jnc dcol ; - пригасим его. xlat ; Если нет - заменим его в соответствии с таблицей xltab (ее адрес в DS:BX) cmp al,0 ; Если в таблице 0 - пригасим пиксел jnz ppix ; Если нет - изменяем его значение в соотв. с таблицей dcol: lodsb ; Пригашение пиксела cmp al,0 ; Если там 0 jz ppix ; - то нечего его гасить sub al,32 ; Если нет - просто отнимем 32 ppix: and al,224 ; На всякий случай оставим только три старших бита (AND 11100000B) stosb ; Внесем, то что получилось в первый буфер pop si ; inc si ; Так надо loop lscr ; И так все пикселы mov di,offset scr ; mov al,0 ; Чтобы огонь ушедший за правую mov cx,80 ; границу экрана не выходил lnul: ; из под левой - просто stosb ; зануляем все крайние левые add di,319 ; пикселы loop lnul ; mov si,offset scr ; mov di,offset scr+20000 ; А теперь скопируем первый буфер во второй mov cx,10000 ; rep movsw ; nscr: mov ah,1 ; Там случайно клавишу не нажали ? int 16h ; jnz $+5 ; Relative jump out of range by 00BBh bytes (c) Intel Inc. jmp lp ; Не нажали ... xor ah,ah ; Нажали ... int 16h ; Вытащим ее из клавиатурного буфера cmp exitcnt,255 ; Если это уже второе нажатие ... jnz exitfire ; ... то немедленно выходим mov exitcnt,65 ; ... иначе - запускаем отсчет времени jmp lp ; возврат в цикл exitfire: mov ax,03h ; Снова в текстовый режим ! int 10h ; .... int 20h ; EXIT ;xltab db 0,0,0,0,32,0,64,32 ; Раскоментарь эту таблицу ; db 32,96,0,96,32,0,96,0 ; и закомментарь вторую, ; db 0,64,0,0,0,96,0,0 ; если не хочешь разводить ; большого огня xltab db 0,0,0,32,32,0,64,32 ; Можете поэксперементировать db 32,96,0,96,64,32,96,32 ; с таблицей db 32,64,96,32,32,96,96,0 ; ;dac db 5,17,30,42,52,61 ; Палитра dac db 5,17,29,41,52,61 ; Палитра count dw 312 ; См. вывод строки Exitcnt db 255 ; Счетчик / флаг выхода tim db 0 ; Тут храним младший байт таймера strpos dw offset strbuf ; Строковый указатель strbuf db ' Hi, All !!! Я тут на досуге решил себе новый' ; Надеюсь db ' скринсейвер сделать, а то старые уже надоели Ж:)' ; понятно что это db ' И вот - после долгих (полдня, однако, угрохал) раздумий и' ; такое ?.. db ' экспериментов я наконец сумел сделать приличную (по крайней' ; db ' мере мне так кажется :) имитацию огня. Как она работает ?' ; db ' Лучше не спрашивайте, скажу только, что я изобрел новую' ; db ' разновидность клеточного автомата Ж:))))))) Кстати -' ; db ' НЕ ВЕРЬТЕ tech help-у - я полчаса страдал над дебагером,' ; db ' прежде чем до меня дошло, что комманда XLAT использует DS, а не ES (!@#$% !!!)' db ' Ну, пока ! Pasha.K ' db 0 scr db 40000 dup(?) ; А это тот самый буфер END ; Все - приехали ...

Всего 3 фpагмент(а/ов) |пpедыдущий фpагмент (3)

Если вы хотите дополнить FAQ - пожалуйста пишите.

design/collection/some content by Frog,
DEMO DESIGN FAQ (C) Realm Of Illusion 1994-2000,
При перепечатке материалов этой страницы пожалуйста ссылайтесь на источник: "DEMO.DESIGN FAQ, http://www.enlight.ru/demo/faq".