эффект "линза" + сталкивающиеся шары Если линза на экране - окружность [math](x_{0},y_{0},r_{0})[/math], то в точках [math](x,y)[/math], для которых [math](x-x_{0})^{2}+(y-y_{0})^{2}\leqslant r_{0}^{2}[/math], рисуется точка, которая, если бы линзы не было, изображалась бы в точке [math](x_{0}+(x-x_{0})\cdot k[/math], [math]y_{0}+(y-y_{0})\cdot k)[/math], где [math]k=\frac{const_{1}}{\sqrt{(x-x_{2})^{2}+(y-y_{0})^{2}}+const_{2}}[/math]. Можно заранее рассчитать таблицу смещений [math][-r_{0}..r_{0},-r_{0}..r_{0}][/math]. Размер COM-файла 1030 байт. Исходный текст, СОМ-файл, картинка в формате pcx во вложении Код (ASM): [code=asm]; masm dos com # .model tiny .code .686 org 100h NUMBALL equ 3 PCXBUFSIZE equ 400h PALSIZE equ 256*3 WIDTH_SCREEN equ 320 HEIGHT_SCREEN equ 200 SIZESCREEN equ WIDTH_SCREEN*HEIGHT_SCREEN VGA_SEGMENT equ 0A000h IMPUT_STATUS_0 equ 3DAh ;регистр статуса ввода 0 BALLINFO struct X dw ?;+0 Y dw ?;+2 R dw ?;+4 xD dw ?;+6 yD dw ?;+8 Clinch dw ?;+10 BALLINFO ends PCX_HEADER struct PCX_manufacturer db ?; manufacturer byte (always 0A0h) PCX_version db ?; pcx Version PCX_encoding db ?;(always 1) PCX_bits_per_pixel db ?; color bits per pixel PCX_xmin dw ?; image origin x PCX_ymin dw ?; image origin y PCX_xmax dw ?; image end x PCX_ymax dw ?; image end y PCX_hres dw ?; horizontal resolution PCX_vres dw ?; vertical resolution PCX_palette1 db 48 dup(?); (color palette, for older not 256 col vers.) PCX_reserved db ?; reserved byte PCX_color_planes db ?; number of color planes PCX_bytes_per_line dw ?; line buffer size PCX_palette_type dw ?; grey or color palette indicator PCX_reserved2 db 58 dup(?); reserved PCX_HEADER ends start proc local z:dword local i:word local hpcx:PCX_HEADER local xcount:word local ycount:word local local_bytesperline:word local readbuf[400h]:byte mov ax, 13h int 10h ; - VIDEO - SET VIDEO MODE mov ax, cs add ax, 1000h mov segm_buf,ax ; segm_buf=CS+0x1000 mov es,ax;es=segm_buf add ax, 1000h mov seg2, ax ; seg2=AX+0x1000 rdtsc mov temp,eax; RANDOMIZE() ;загрузить PCX-файл--------------------------------------------------------- mov dx,offset filename; DS:DX -> ASCIZ filename mov ax,3D00h; OPEN DISK FILE for read WITH HANDLE int 21h mov bx,ax;BX = file handle mov cx, 80h;CX = number of bytes to read lea dx,hpcx; DS:DX -> buffer mov ah, 3Fh; READ FROM FILE WITH HANDLE int 21h mov ax, hpcx.PCX_ymax sub ax, hpcx.PCX_ymin inc ax mov ycount,ax mov ax,hpcx.PCX_xmax sub ax,hpcx.PCX_xmin inc ax mov local_bytesperline, ax xor di, di mov si, PCXBUFSIZE @1: mov ax,local_bytesperline mov xcount,ax @2: cmp si,PCXBUFSIZE jnz @f mov cx, PCXBUFSIZE ;CX = number of bytes to read lea dx, readbuf ;DS:DX -> buffer mov ah, 3Fh; READ FROM FILE WITH HANDLE BX = file handle, int 21h xor si, si @@: mov al, readbuf[si] inc si cmp al, 192 jb short @3 and al, 3Fh xor cx, cx mov cl, al sub xcount, cx cmp si, PCXBUFSIZE jnz @f push cx mov cx, PCXBUFSIZE lea dx, readbuf mov ah, 3Fh; READ FROM FILE WITH HANDLE BX = file handle, int 21h; CX = number of bytes to read DS:DX -> buffer pop cx xor si, si @@: mov al,readbuf[si] inc si rep stosb jmp @f @3: dec xcount stosb @@: cmp xcount,0 ja short @2 dec ycount jnz short @1 or cx,-1 mov dx,-(PALSIZE+1) mov ax, 4202h; MOVE FILE READ/WRITE POINTER (LSEEK) int 21h ; AL = method: offset from end of file mov cx,PALSIZE+1 ; CX = number of bytes to read lea dx,readbuf ; DS:DX -> buffer mov ah, 3Fh ; READ FROM FILE WITH HANDLE int 21h ; BX = file handle lea di, readbuf+1 mov cx, PALSIZE @@: shr byte ptr [di], 2 inc di loop @b xor ax, ax mov cx, PALSIZE lea si, readbuf+1 mov dx, 3C8h out dx, al inc dx rep outsb mov ah, 3Eh; CLOSE A FILE WITH HANDLE int 21h ; BX = file handle ;инициализируем шары-------------------------------------- mov i,0 @0: imul di,i,sizeof(BALLINFO) add di,offset ballinfox call RAND and ax,1Fh add ax,10 assume di: ptr BALLINFO mov [di].R, ax @6: mov bx,[di].R add bx,bx mov ax,WIDTH_SCREEN sub ax,bx mov [di].X,ax sub ax,(WIDTH_SCREEN-HEIGHT_SCREEN) mov [di].Y,ax call RAND xor dx,dx div word ptr [di].X add dx,[di].R mov [di].X, dx call RAND xor dx,dx div word ptr [di].Y add dx,[di].R mov [di].Y,dx ;вычисляем расстояние-------------------------------- xor cx, cx B1: cmp i,cx jbe short B9 imul si,cx,sizeof(BALLINFO) add si, offset ballinfox assume si: ptr BALLINFO mov ax,[di].X sub ax,[si].X jnb short @f neg ax @@: movzx eax, ax mul eax mov z,eax mov ax,[di].Y sub ax,[si].Y jnb short @f neg ax @@: movzx eax,ax mul eax add z,eax fild z fsqrt fistp z mov ax,[si].R add ax,[di].R cmp word ptr z,ax ja short @f mov ax, cx jmp short BC @@: inc cx jmp short B1 B9: or ax,-1 BC: inc ax ;cmp ax,0FFFFh jnz @6
Код (ASM): ;выбираем направление call RAND and ax,1 jnz @f dec ax @@: mov [di].xD,ax ;выбираем направление call RAND and ax, 1 jnz @f dec ax @@: mov [di].yD,ax mov [di].Clinch,0 inc i cmp i,NUMBALL jl @0 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 push ds mov es,seg2 mov ds,segm_buf xor si,si xor di,di mov cx,SIZESCREEN/4 rep movsd pop ds mov i,cx ;cx=0 @@: imul si,i,sizeof(BALLINFO) add si,offset ballinfox push [si].X push [si].Y push [si].R call Ball inc i cmp i,NUMBALL jl @b push ds push VGA_SEGMENT pop es mov ds,seg2 xor si,si xor di,di mov cx,SIZESCREEN/4 rep movsd pop ds xor bx,bx loc_10512: imul di,bx,sizeof(BALLINFO) add di,offset ballinfox mov ax,[di].X add ax,[di].R add ax,[di].xD cmp ax,WIDTH_SCREEN jbe @f mov word ptr [di].xD,-1 jmp short @8 @@: mov ax,[di].X sub ax,[di].R add ax,[di].xD jge @8 mov word ptr [di].xD,1 @8: mov ax,[di].Y add ax,[di].R add ax,[di].yD cmp ax,HEIGHT_SCREEN jbe @f mov word ptr [di].yD,-1 jmp @9 @@: mov ax,[di].Y sub ax,[di].R add ax,[di].yD jge @9 mov word ptr [di].yD,1 @9: xor cx, cx @4: cmp bx,cx jbe loc_10509 imul si,cx,sizeof(BALLINFO) add si,offset ballinfox mov ax,[di].X add ax,[di].xD sub ax,[si].X jnb @f neg ax @@: movzx eax, ax mul eax mov z,eax mov ax,[di].Y add ax,[di].yD sub ax,[si].Y jnb @f neg ax @@: movzx eax,ax mul eax add z,eax fild z fsqrt fistp z mov ax,[si].R add ax,[di].R cmp word ptr z,ax ja @f mov ax,cx jmp locret_1050C @@: inc cx jmp @4 loc_10509: or ax,-1 locret_1050C: inc ax;cmp ax, 0FFFFh jz loc_105CB imul si,ax,sizeof(BALLINFO) add si, offset ballinfox - sizeof(BALLINFO) mov bx,[di].Clinch cmp bx,NUMBALL ja loc_105BB add bx, bx jmp switchtable[bx] case0:: neg [si].xD case1:: neg [di].xD case2:: neg [si].yD case3:: neg [di].yD loc_105BB: mov ax, [si].xD add [si].X,ax mov ax,[si].yD add [si].Y,ax inc [di].Clinch jmp loc_105D0 loc_105CB: mov [di].Clinch, 0 loc_105D0: mov ax,[di].xD add [di].X,ax mov ax,[di].yD add [di].Y,ax inc bx cmp bx,NUMBALL jb loc_10512 assume si: nothing assume di: nothing mov ah, 1 int 16h jz main_loop mov ax, 3 int 10h ; - VIDEO - SET VIDEO MODE int 20h start endp Ball proc Rad_V_Kv = word ptr -6 Y = word ptr -4 Z = word ptr -2 sr = word ptr 4 Yc = word ptr 6 Xc = word ptr 8 enter 6, 0 push ds mov ax,[bp+sr] imul ax mov [bp+Rad_V_Kv],ax mov es,seg2 mov ds,segm_buf mov ax,[bp+sr] neg ax mov [bp+Y],ax ;Y = -sr @5: mov cx,[bp+sr] neg cx @7: mov bx,cx imul bx,cx ;bx = (sr)^2 mov ax,[bp+Y] mul ax add bx,ax ;bx = (sr)^2 + Y^2 cmp [bp+Rad_V_Kv],bx jb @f mov ax, [bp+Rad_V_Kv] sub ax, bx mov [bp+Z], ax mov bx, [bp+Xc] add bx, cx js @f cmp bx, WIDTH_SCREEN jnb @f mov ax, [bp+Yc] add ax, [bp+Y] js @f cmp ax, HEIGHT_SCREEN jnb @f imul di,ax,WIDTH_SCREEN add di, bx fild [bp+Z] fsqrt fistp [bp+Z] mov bx, [bp+Z] add bx, [bp+sr] mov ax, [bp+Y] imul [bp+sr] idiv bx add ax, [bp+Yc] imul si,ax,WIDTH_SCREEN mov ax, cx imul [bp+sr] idiv bx add ax, [bp+Xc] add si,ax movsb @@: inc cx cmp [bp+sr], cx jg @7 inc [bp+Y] mov ax, [bp+sr] cmp [bp+Y], ax jl @5 pop ds leave retn 6 Ball endp RAND proc mov ax,word ptr temp+2 mov cx,word ptr temp shld ax,cx,8 shl cx,8 rcr ax, 1 rcr cx, 1 add word ptr temp, cx adc ax,word ptr temp+2 add word ptr temp,25321 adc ax,13849 mov word ptr temp+2,ax retn RAND endp switchtable dw case0,case1,case2,case3 filename db 'forest.pcx',0 segm_buf dw ? seg2 dw ? ballinfox BALLINFO <?>,<?>,<?> temp dd ? end start