След от водомерки на поверхности водыЭтап первый Код (ASM): ; masm dos com # .model tiny .code .386 org 100h PALSIZE equ 300h WIDTH_SCREEN equ 320 HEIGHT_SCREEN equ 200 SCREENSIZE equ WIDTH_SCREEN*HEIGHT_SCREEN IMPUT_STATUS_0 equ 3DAh ;регистр статуса ввода 0 VGA_SEGMENT equ 0A000h start: mov ax, 13h;установили необходимый режим 320х200х256 int 10h mov ax, 4309h;создать палитру mov dx, 3D4h out dx, ax xor bx, bx mov dl, 0C8h mov al, 0 out dx, al inc dx @0: mov al, 0 cmp bl, 128 jnb @f mov al, 127 sub al, bl shr al, 1 @@: out dx, al out dx, al mov cl, bl shr cl, 1 mov al, 127 sub al, cl shr al, 1 out dx, al inc bl jnz @0 ;----------------------------------------- mov ax,cs add ax,1000h mov fs,ax ; watertable1=AX mov es,ax add ax,2000 mov gs,ax ; watertable2=AX+WATERTABLE PARAGRAPH SIZE ;очистить буфер xor di,di mov cx, SCREENSIZE/4 ; CX=WATERTABLESIZE xor eax, eax rep stosd ; initialize wt1 and wt2 push VGA_SEGMENT pop es main_loop:mov dx,IMPUT_STATUS_0 WaitVerticalSync:in al,dx; притормозить вывод на экран до следующего кадра test al,8 jz WaitVerticalSync WaitNotVerticalSync:in al,dx test al,8 jnz WaitNotVerticalSync ;Вывод на экран из буфера xor di, di mov cx, SCREENSIZE/4 @@: mov ax, fs:[di] sub ax, fs:[di-2] sar ax, 3; AX=(FS:[DI]-FS:[DI-2])/8 add al, HEIGHT_SCREEN/2 stosb stosb loop @b ;Эффект воды mov di,WIDTH_SCREEN+2 mov cx,SCREENSIZE/4 - WIDTH_SCREEN @@: mov ax,fs:[di-WIDTH_SCREEN] add ax,fs:[di-2] add ax,fs:[di+2] add ax,fs:[di+WIDTH_SCREEN] sar ax,1; AX=(FS:[DI-320]+FS:[DI-2]+FS:[DI+2]+FS:[DI+320])/2 sub ax,gs:[di] ; AX-=GS:[DI] mov bx,ax sar bx,3 sub ax,bx mov gs:[di],ax add di,2 loop @b push gs push fs pop gs pop fs ; watertable2 <-> watertable1 ;перемещение объекта mov bx,offset locobj cmp word ptr [bx+4],WIDTH_SCREEN*2 sbb dx,dx or dl,1; IF( DS:[BX+4] > 640 ) DS:[BX]-- sub [bx],dx; ELSE DSWORD[BX]++ cmp word ptr [bx+6],HEIGHT_SCREEN*2 sbb dx,dx ; IF( DS:[BX+6] > 400 ) DS:[BX+2]-- or dl,1 sub [bx+2],dx; ELSE DS:[BX+2]++ mov ax,[bx] add [bx+4],ax ; DS:[BX+4]+=DS:[BX] mov ax,[bx+2] add [bx+6],ax ; DS:[BX+6]+=DS:[BX+2] mov di,[bx+4] shr di,3 ; di=x-координата mov ax,[bx+6] shr ax,3 imul ax,WIDTH_SCREEN/2;ax=y-координата add di,ax ; di=x+y add di,di ; DI*= 2 mov dword ptr gs:[di],3840384h; GS=watertable1 mov dword ptr fs:[di],1C401C4h; FS=watertable2 add di,4 mov ah,1 int 16h ;нажали на любую клавишу? jz main_loop mov ax, 3 ;восстанавливаем текстовый режим int 10h retn ;завершаем программу locobj dw 5,0,80,40 end start Размер COM-файла 265 байт.Этап второйУсложняем программу. Теперь у нас водомерка на поверхности воды и след от рыбы, которая пытается поймать водомерку Код (ASM): ; masm dos com # .model tiny .code .386 org 100h PALSIZE equ 300h WIDTH_SCREEN equ 320 HEIGHT_SCREEN equ 200 SCREENSIZE equ WIDTH_SCREEN*HEIGHT_SCREEN IMPUT_STATUS_0 equ 3DAh ;регистр статуса ввода 0 VGA_SEGMENT equ 0A000h palette equ byte ptr ende start: mov ax, 13h;установили необходимый режим 320х200х256 int 10h mov ax, 4309h;создать палитру mov dx, 3D4h out dx, ax xor bx, bx mov di,offset palette push ds pop es @0: xor ax, ax cmp bl, 128 jnb @f mov al, 127 sub al, bl shr al, 1 mov ah, al @@: stosw mov cl, bl shr cl, 1 mov al, 127 sub al, cl shr al, 1 stosb inc bl jnz @0 xor ax, ax mov cx, PALSIZE mov si, offset palette+3 mov dx, 3C8h out dx, al inc dx rep outsb push ds pop ax add ah, 10h mov fs,ax ; watertable1=AX mov es,ax add ax,2000 mov gs,ax ; watertable2=AX+WATERTABLEPARAGRAPHSIZE xor di,di mov cx, SCREENSIZE/4 ; CX=WATERTABLESIZE xor eax, eax rep stosd ; initialize wt1 and wt2 xor si, si main_loop:mov dx,IMPUT_STATUS_0 WaitVerticalSync:in al,dx ; притормозить test al,8 jz WaitVerticalSync WaitNotVerticalSync:in al,dx test al,8 jnz WaitNotVerticalSync ;ShowWater push VGA_SEGMENT pop es xor di, di mov cx, SCREENSIZE/4 @@: mov ax, fs:[di] sub ax, fs:[di-2] sar ax, 3; AX=(FS:[DI]-FS:[DI-2])/8 add al, HEIGHT_SCREEN/2 stosb stosb loop @b ;CalcWaterEffect mov di,WIDTH_SCREEN+2 mov cx,(HEIGHT_SCREEN-4)*WIDTH_SCREEN/4 @@: mov ax,fs:[di-WIDTH_SCREEN] add ax,fs:[di-2] add ax,fs:[di+2] add ax,fs:[di+WIDTH_SCREEN] sar ax,1; AX=(FS:[DI-320]+FS:[DI-2]+FS:[DI+2]+FS:[DI+320])/2 sub ax,gs:[di] ; AX-=GS:[DI] mov bx,ax sar bx,3 sub ax,bx mov gs:[di],ax add di,2 loop @b push gs push fs pop gs pop fs ; watertable2 <-> watertable1 mov bx,offset small call CALCADR mov dword ptr gs:[di],3840384h; GS=watertable1 mov dword ptr fs:[di],1C401C4h; FS=watertable2 add di,4 test si,100h ; IF(SI&256) jz @5 mov bx, offset big call CALCADR mov cx, 5 @4: mov bx, 5 @@: mov word ptr gs:[di],384h; GS=watertable1 mov word ptr fs:[di],1C4h; FS=watertable2 add di,2 dec bx jnz @b add di,WIDTH_SCREEN-10 loop @4 @5: add si,2 mov ah,1 int 16h ; KEYBOARD - CHECK BUFFER, DO NOT CLEAR jz main_loop mov ax, 3 int 10h ; - VIDEO - SET VIDEO MODE retn CALCADR proc cmp word ptr [bx+4],WIDTH_SCREEN*2 sbb dx,dx or dl,1; IF(DSWORD[BX+4] > XSIZE*4) DSWORD[BX]-- sub [bx],dx; ELSE DSWORD[BX]++ cmp word ptr [bx+6],HEIGHT_SCREEN*2 sbb dx,dx ; IF(DSWORD[BX+6] > YSIZE*4) DSWORD[BX+2]-- or dl,1 sub [bx+2],dx; ELSE DSWORD[BX+2]++ mov ax,[bx] add [bx+4],ax ; DSWORD[BX+4]+=DSWORD[BX] mov ax,[bx+2] add [bx+6],ax ; DSWORD[BX+6]+=DSWORD[BX+2] mov di,[bx+4] shr di,3 ; DI=DSWORD[BX+4]>>3 mov ax,[bx+6] shr ax,3 imul ax,WIDTH_SCREEN/2 add di,ax ; DI+=AX add di,di ; DI+=DI retn CALCADR endp small dw 5,0,80,40 big dw -3,0,304,120 ende: end start Размер COM-файла 342 байт. Заключительный этап Довольно загадочный, для непосвященных, но простой, эффект. В основе лежит, все тот же Blur. Я выбрал 8-пиксельный блюр, так как он дает более красивую картинку. Установим палитру так: Номер цвета0 255ЦветСинийБелыйЗаведем два буфера: buf1 и buf2, и указатели на них: buf1_ptr и buf2_ptr. Важно понять, что, хоть указатель называется buf1_ptr, но он может указывать совсем не на buf1, а на buf2. Аналогично для buf2_ptr. Далее по тексту, если массив будет называться buf1_ptr, то имеется в виду тот массив, на который, в данный момент, ссылается buf1_ptr. Тоже самое подразумевается под массивом buf2_ptr. Далее описывается последовательность, которую надо проделать, для расчета очередного кадра: Если buf1_ptr, действительно указывает на buf1, то заносим в buf1_ptr точки возмущения. Проходим по всем точкам массива buf1_ptr и buf2_ptr вот таким алгоритмом: 2.1. Складываем значения точек окружающих текущую, в массиве buf1_ptr. 2.2. Делим эту сумму на 4. 2.3 Вычитаем из этой суммы значение текущей точки массива buf2_ptr. 2.4 Если результат меньше 0, то результат равен 0. 2.5 Записываем результат в текущую точку массива buf2_ptr. Теперь меняем местами buf1 и buf2 (собственно для этого нам и были нужны указатели): Код (C): long temp_ptr=buf1_ptr; buf1_ptr=buf2_ptr; buf2_ptr=temp_ptr; Выводим на экран buf2_ptr. В результате получим эффект поверхности воды с всплывающими и лопающимися пузырьками и бегающими водомерками.
Код (ASM): ; masm dos com # .model tiny .code .686 org 100h VGA_SEGMENT equ 0A000h IMPUT_STATUS_0 equ 3DAh SCREEN_WIDTH equ 320 SCREEN_HEIGHT equ 200 SCREENSIZE equ SCREEN_HEIGHT*SCREEN_WIDTH MEMBLOCKSIZE equ SCREENSIZE/16 yd equ dword ptr [bp-4] xd equ dword ptr [bp-8] buf1 equ word ptr [bp-10] buf2 equ word ptr [bp-12] buf1_ptr equ word ptr [bp-14] buf2_ptr equ word ptr [bp-16] temp1 equ word ptr [bp-18] temp2 equ word ptr [bp-20] start: mov sp, 1260h mov ah, 4Ah; ADJUST MEMORY BLOCK SIZE (SETBLOCK) mov bx, 126h; ES = segment address of block to change int 21h; BX = new size in paragraphs enter 20,0 mov bx, MEMBLOCKSIZE mov ah, 48h; ALLOCATE MEMORY int 21h; BX = number of 16-byte paragraphs desired mov buf1, ax mov buf1_ptr, ax mov es,ax xor eax,eax xor di, di mov cx,SCREENSIZE/4 rep stosd rdtsc mov dword ptr temp1, eax mov bx, MEMBLOCKSIZE mov ah, 48h; ALLOCATE MEMORY int 21h; BX = number of 16-byte paragraphs desired mov buf2, ax mov buf2_ptr, ax mov es,ax xor eax,eax xor di,di mov cx,SCREENSIZE/4 rep stosd mov ax,13h int 10h ; - VIDEO - SET VIDEO MODE ;setcolortable-------------------------------- mov cx,255 @@: mov dx, 3C8h mov al,cl;color mov ah,cl sar ah,2;red out dx, ax inc dx mov al,ah;gren=red out dx, al mov al,63;blue out dx, al dec cx jns @b fldz ;------------------------------------------- main: mov ax, buf1 cmp buf1_ptr, ax jnz @f mov es, ax;buf1 mov ax, temp2 mov cx, temp1 shld ax,cx,8 shl cx,8 rcr ax, 1 rcr cx, 1 add temp1, cx adc ax, temp2 add word ptr temp1,25321 adc ax,13849 mov temp2, ax movsx eax, ax add eax, eax xor edx, edx mov ecx,62000 div ecx mov si, dx ;RAND()<<1%62000 add si, SCREEN_WIDTH mov dword ptr es:[si], 7FFFFF7Fh mov dword ptr es:[si+SCREEN_WIDTH],0FFFFFFFFh mov dword ptr es:[si+SCREEN_WIDTH*2],0FFFFFFFFh mov dword ptr es:[si+SCREEN_WIDTH*3],7FFFFF7Fh fld st;time fld st fld st fld st fmul const2_5 fadd const1_5 fsin fmul const120 fistp xd add xd,160;xd=sin(time*2.5+1.5)*120+160 ;fld time fmul const1_5 fadd const2_5 fcos fmul const60 fistp yd add yd,100;yd=cos(time*1.5+2.5)*60+100 imul si,word ptr yd,SCREEN_WIDTH add si, word ptr xd mov word ptr es:[si+SCREEN_WIDTH], 0FFFFh mov word ptr es:[si+SCREEN_WIDTH*2], 0FFFFh ;fld time fmul const1_5 fadd const2_5 fsin fmul const120 fistp xd add xd,160;xd=160+120*sin(time*1.5+2.5) fmul const2_5 fadd const1_5 fcos fmul const60 fistp yd add yd,100;yd=100+60*cos(time*2.5+1.5) imul si,word ptr yd,SCREEN_WIDTH add si, word ptr xd mov word ptr es:[si+SCREEN_WIDTH], 0FFFFh mov word ptr es:[si+SCREEN_WIDTH*2], 0FFFFh fadd const003;time=+0.03 ;waterscreen-------------------------------- @@: mov fs, buf1_ptr mov es, buf2_ptr mov di, SCREEN_WIDTH+1 mov cx,0F8BFh-SCREEN_WIDTH-1 loc_103BE: movzx ax, byte ptr fs:[di-SCREEN_WIDTH-1] add al, byte ptr fs:[di-SCREEN_WIDTH] adc ah, 0 add al, byte ptr fs:[di-SCREEN_WIDTH+1] adc ah, 0 add al, byte ptr fs:[di-1] adc ah, 0 add al, byte ptr fs:[di+1] adc ah, 0 add al, byte ptr fs:[di+SCREEN_WIDTH-1] adc ah, 0 add al, byte ptr fs:[di+SCREEN_WIDTH] adc ah, 0 add al, byte ptr fs:[di+SCREEN_WIDTH+1] adc ah, 0 shr ax, 2 sub al, byte ptr es:[di] sbb ah, 0 test ax, ax jns @f xor ax, ax @@: stosb loop loc_103BE mov ax, buf1_ptr xchg ax, buf2_ptr mov buf1_ptr, ax push ds mov ds,ax;buf1_ptr ;copyvirtualscreen-------------------------- mov dx,IMPUT_STATUS_0 ;=3DAh WaitVerticalSync:in al, dx test al, 8 jz WaitVerticalSync WaitNotVerticalSync:in al, dx test al, 8 jnz WaitNotVerticalSync mov cx,SCREENSIZE/4 xor si,si xor di,di push VGA_SEGMENT pop es rep movsd mov ds,cx;ds=0 mov ax, ds:[41Ah]; было ли нажатие на клавиатуру? sub ax, ds:[41Ch] pop ds jz main exit: mov ax, 3 int 10h ; - VIDEO - SET VIDEO MODE int 20h ;--------------------------------- const1_5 dd 1.5 const2_5 dd 2.5 const60 dd 60.0 const120 dd 120.0 const003 dd 0.03 end start Неплохо бы было добавить background какую-нибудь картинку, например такую да еще чтоб волны искажали его. Что ж нет ничего невозможного... Добавим два буфера: pics и screen_end. В pics будем хранить картинку, которую используем в качестве background`а. А screen_end мы будем выводить на экран. Палитру надо взять из считываемой картинки. Как же нам добиться эффекта искажения, из-за преломления лучей света на границе двух разнородных сред? Сейчас подумаем. Берем в руки учебник физики, ищем раздел "Оптика" и находим формулу расчета угла преломленного луча. Применив знания, полученные на уроках геометрии, выведем формулу, с помощью которой будем находить смещение, относительно текущего пикселя, по которому находиться пиксель, который и надо вывести на экран вместо текущего: [math]D=h\cdot tg(arcsin(0.75\cdot sin(\alpha)))[/math][math]D[/math]-искомое смещение, [math]h[/math] - высота слоя воды (высота волны), [math]\alpha[/math] - угол между нормалью к поверхности воды в данной точке и вектором наблюдения. Нужно искать тангенс арксинуса синуса, да еще расчет нормали к поверхности, плюс это надо разложить на нахождение смещения по [math]X[/math] и [math]Y[/math], сложновато... Конечно, можно воспользоваться табличным разложением, но таблица получиться слишком уж большой. Как же быть? Взглянем еще раз на нашу формулу и подумаем, нельзя ее как нибудь сократить. Допустим, что наш тангенс арксинуса синуса, есть величина величина постоянная и равная, например 0.25. (Воспользуемся калькулятором). Опыт показал, что такое допущение вполне возможно, если ширина волны небольшая. Тогда формула значительно упроститься и будет выглядеть так:[math]D=\frac{h}{4}[/math] Теперь, чтобы найти координаты нужного пикселя, надо прибавить к текущим, [math]D[/math]: [math]x'=x+D[/math] [math]y'=y+D[/math]В наш алгоритм добавиться пункт 2.5. 2.5. Делим результат на 4, полученное значение прибавляем к текущим X и Y. Если X, больше максимально допустимого значения, то X приравняем максимальному допустимому значению. Аналогичную проверку надо сделать и для Y. Считываем по этим координатам из массива pics, число и записываем по текущим координатам в screen_end. Теперь модифицируем этот алгоритм чтобы получить более реалистичное изображение. Недостаток описанного выше метода - смещение не зависит от наклона нормали к поверхности воды. Как исправить этот недостаток, не усложняя алгоритм? Довольно просто. Достаточно знать куда наклонена нормаль, тогда сможем смещать координаты в соответствии с этим направлением. Для того чтобы найти смещения по x и y, используем следующие формулы: Код (C): Dx=(buf1_ptr[x+1][y]-buf1_ptr[x-1][y])>>2; Dy=(buf1_ptr[x][y+1]-buf1_ptr[x][y-1])>>2; Как надо изменить пункт 2.6., вы наверняка догадаетесь сами.
Код (ASM): ; masm dos com # .model tiny .code .686 org 100h IMPUT_STATUS_0 equ 3DAh VGA_SEGMENT equ 0A000h SCREEN_HEIGHT equ 200 SCREEN_WIDTH equ 320 SCREENSIZE equ SCREEN_WIDTH*SCREEN_HEIGHT MEMBLOCKSIZE equ SCREENSIZE/16 yd equ dword ptr [bp-4] xd equ dword ptr [bp-8] buf1 equ word ptr [bp-10] buf2 equ word ptr [bp-12] screen_end equ word ptr [bp-14] pics equ word ptr [bp-16] buf1_ptr equ word ptr [bp-18] buf2_ptr equ word ptr [bp-20] temp1 equ word ptr [bp-22] temp2 equ word ptr [bp-24] pal equ byte ptr [bp-1048] start: mov sp, 1260h mov ah, 4Ah; ADJUST MEMORY BLOCK SIZE (SETBLOCK) mov bx, 126h; ES = segment address of block to change int 21h; BX = new size in paragraphs enter 1048, 0 rdtsc mov dword ptr temp1,eax mov bx,MEMBLOCKSIZE mov ah,48h; ALLOCATE MEMORY int 21h; BX = number of 16-byte paragraphs desired mov buf1, ax mov buf1_ptr, ax mov es,ax xor eax,eax xor di,di mov cx,SCREENSIZE/4 rep stosd mov bx,MEMBLOCKSIZE mov ah,48h; ALLOCATE MEMORY int 21h; BX = number of 16-byte paragraphs desired mov buf2, ax mov buf2_ptr, ax mov es,ax xor eax,eax xor di, di mov cx,SCREENSIZE/4 rep stosd mov bx,MEMBLOCKSIZE mov ah,48h; ALLOCATE MEMORY int 21h; BX = number of 16-byte paragraphs desired mov screen_end,ax mov es,ax xor eax,eax xor di,di mov cx,SCREENSIZE/4 rep stosd mov bx,MEMBLOCKSIZE mov ah,48h; ALLOCATE MEMORY int 21h; BX = number of 16-byte paragraphs desired mov pics,ax mov ax,13h int 10h ; - VIDEO - SET VIDEO MODE ;readbmp--------------------------------------------------------- mov dx,offset filename; OPEN DISK FILE WITH HANDLE mov ax,3D00h ; DS:DX -> ASCIZ filename int 21h ; AL = access mode 0 - read mov bx,ax;bx=handle xor cx,cx mov dx,54;размер заголовка BMP-файла mov ax,4200h; MOVE FILE READ/WRITE POINTER (LSEEK) int 21h; AL = method: offset from beginning of file lea dx,pal mov cx,1024 mov ah,3Fh; READ FROM FILE WITH HANDLE int 21h; BX = file handle, CX = number of bytes to read ; DS:DX -> buffer mov di,1023 @@: shr byte ptr pal[di],2 dec di jns @b push ds mov ds,pics mov di,SCREEN_HEIGHT-1 @@: imul dx,di,SCREEN_WIDTH mov cx,SCREEN_WIDTH mov ah,3Fh; READ FROM FILE WITH HANDLE int 21h; BX = file handle, CX = number of bytes to read ; DS:DX -> buffer dec di jns @b pop ds mov ah,3Eh; CLOSE A FILE WITH HANDLE int 21h ; BX = file handle ;-------------------------------------------------- mov cx,255 @@: mov di,cx shl di,2 mov dx,3C8h mov al,cl;color mov ah,pal[di+2];red out dx,ax inc dx mov al,pal[di+1];green out dx,al mov al,pal[di];blue out dx,al dec cx jns @b ;----------------------------------------------------- fldz ;time=0 main: mov ax,buf1 cmp buf1_ptr,ax jnz @f mov es,ax;buf1 mov ax,temp2 mov cx,temp1 shld ax,cx,8 shl cx,8 rcr ax,1 rcr cx,1 add temp1,cx adc ax,temp2 add word ptr temp1,25321 adc ax,13849 mov temp2,ax movsx eax,ax add eax,eax xor edx,edx mov ecx,62000 div ecx mov si,dx add si,SCREEN_WIDTH mov dword ptr es:[si],7FFFFF7Fh mov dword ptr es:[si+SCREEN_WIDTH],0FFFFFFFFh mov dword ptr es:[si+SCREEN_WIDTH*2],0FFFFFFFFh mov dword ptr es:[si+SCREEN_WIDTH*3],7FFFFF7Fh fld st;time fld st fld st fld st fmul const2_5 fadd const1_5 fsin fmul const120 fistp xd add xd,160;xd=sin(time*2.5+1.5)*120+160 fmul const1_5 fadd const2_5 fcos fmul const60 fistp yd add yd,100;yd=cos(time*1.5+2.5)*60+100 imul si,word ptr yd,SCREEN_WIDTH add si,word ptr xd mov word ptr es:[si+SCREEN_WIDTH], 0FFFFh mov word ptr es:[si+SCREEN_WIDTH*2], 0FFFFh fmul const1_5 fadd const2_5 fsin fmul const120 fistp xd add xd, 160;xd=sin(time*1.5+2.5)*120+160 fmul const2_5 fadd const1_5 fcos fmul const60 fistp yd add yd,100;yd=cos(time*2.5+1.5)*60+100 imul si,word ptr yd,SCREEN_WIDTH add si,word ptr xd mov word ptr es:[si+SCREEN_WIDTH], 0FFFFh mov word ptr es:[si+SCREEN_WIDTH*2], 0FFFFh fadd const003;time=+0.03 ;waterscreen--------------------------------------------------- @@: mov gs,buf1_ptr mov fs,buf2_ptr mov di, SCREEN_WIDTH+1 mov cx,64000-321 loc_10440: movzx ax, byte ptr gs:[di-SCREEN_WIDTH-1] add al, byte ptr gs:[di-SCREEN_WIDTH] adc ah, 0 add al, byte ptr gs:[di-SCREEN_WIDTH+1] adc ah, 0 add al, byte ptr gs:[di-1] adc ah, 0 add al, byte ptr gs:[di+1] add ah, 0 add al, byte ptr gs:[di+SCREEN_WIDTH-1] adc ah, 0 add al, byte ptr gs:[di+SCREEN_WIDTH] adc ah, 0 add al, byte ptr gs:[di+SCREEN_WIDTH+1] adc ah, 0 shr ax, 2 sub al, byte ptr fs:[di] sbb ah, 0 test ax, ax jns @f xor ax, ax @@: mov fs:[di], al shr ax,2 imul si,ax,SCREEN_WIDTH+1 add si, di;si=ax*321+di cmp si,SCREENSIZE-1 jbe @f mov si,SCREENSIZE-1 @@: mov es,pics lods byte ptr es:[si] mov es,screen_end stosb loop loc_10440 mov ax, buf1_ptr xchg ax, buf2_ptr mov buf1_ptr, ax ;copyvirtualscreen------------------------------------ mov dx,IMPUT_STATUS_0 WaitVerticalSync:in al, dx test al, 8 jz WaitVerticalSync WaitNotVerticalSync:in al, dx test al, 8 jnz WaitNotVerticalSync mov cx,SCREENSIZE/4 xor si,si push ds push es pop ds;ds=screen_end xor di,di push VGA_SEGMENT pop es rep movsd mov ds,cx;ds=0 mov ax,ds:[41Ah] sub ax,ds:[41Ch] pop ds jz main exit: mov ax,3 int 10h ; - VIDEO - SET VIDEO MODE int 20h filename db 'aqua11.bmp',0 const1_5 dd 1.5 const2_5 dd 2.5 const60 dd 60.0 const120 dd 120.0 const003 dd 0.03 end start Результат