Реализация 1 - на Паскале.
Если линза на экpане - окpужность (x0,y0,r0), то в точках (x,y), для котоpых (x-x0)2+(y-y0)2<=r02,pисуется точка, котоpая, если бы линзы не было, изобpажалась бы в точке (x0+(x-x0)*k1,y0+(y-y0)*k), где k=const1 / ([sqrt]((x-x0)2+(y-y0)2) + const2). Можно заpанее пpосчитать таблицу смещений - array[-r0..r0,-r0..r0] of integer.
{$A+,B-,D+,E+,F-,G+,I+,L+,N-,O-,P-,Q-,R-,S+,T-,V+,X+,Y+}
{$M 16384,0,655360}
Uses CRT;
Const vx0 = 3; vy0 = 2; v0 = vx0; r0 = 50; r02 = (r0-v0)*(r0-v0); d = r02 * 10 div 10; Type ScreenType = Array[0..199,0..319] of Byte; DispType = Array[-r0..r0,-r0..r0] of Integer;
Var
Screen : ScreenType Absolute $a000:$0000; Buffer1, Buffer2 : ^ScreenType; Disp : ^DispType; x,y,vx,vy,r2,c : LongInt; Procedure Move(Var A,B; Count: Word); assembler; asm push ds mov cx, Count les di, B lds si, A shr cx, 1 jz @zero rep movsw @zero: pop ds end; BEGIN
asm mov ax, $13 int $10 end;
New(Buffer1); New(Buffer2); New(Disp);
FillChar(Screen, SizeOf(Screen), 3); y:=0;
repeat
For x:=0 to 319 do Screen[y,x]:=11; Inc(y,10);
until y>199;
x:=0;
repeat
For y:=0 to 199 do Screen[y,x]:=11; Inc(x,10);
until x>319;
Move(Screen, Buffer1^, SizeOf(Screen)); Move(Buffer1^,Screen,64000);
For y:=-r0 to r0 do For x:=-r0 to r0 do begin
r2:=x*x+y*y; if r2>r02 then Disp^[y,x] := y*320+x else Disp^[y,x]:=(y*(r2+d)div(r02+d))*320+(x*(r2+d)div(r02+d));
end;
x:=r0; y:=r0; vx:=vx0; vy:=vy0; repeat
asm mov ax, Integer(y) mov bx, 320 imul bx add ax, Integer(x) mov di, ax mov dx, -r0*320-r0 les si, Disp mov ch, 2*r0+1 @next_dy: mov cl, 2*r0+1 @next_dx: mov es, Word(Disp+2) mov bx, es:[si] mov es, Word(Buffer1+2) mov al, es:[di+bx] mov bx, Seg(Screen) mov es, bx mov bx, dx mov es:[di+bx], al add si, 2 inc dx dec cl jnz @next_dx add dx, 320-(2*r0+1) dec ch jnz @next_dy end;
if ((x+vx)>=r0)and ((x+vx)<=319-r0)then Inc(x, vx) else vx:=-vx;
if ((y+vy)>=r0)and ((y+vy)<=199-r0)then Inc(y,vy) else vy:=-vy; Delay(25); until Port[$60]=$01;
Dispose(Buffer1); Dispose(Buffer2); Dispose(Disp);
asm mov ax, $03 int $10 end;
END.
Реализация 2 - на Watcom C
Пусть у нас есть матрица , которую нужно преобразовать. То есть у нас есть какой-то прямоугольный массив, который мы хотим показать в линзе. Итак у нас есть исходная матрица. Каждая пара координат в матрице (I,J) переходит в новую пару координат (X,Y). Формулу смотрите в исходнике. Тогда элемент матрицы с новыми координатами (X,Y) становиться равным смещению в матрице, которое соответствует координатам (I,J). Это первый этап, для дальнейшего ускорения вывода , расчитаем еще два массива. Один массив - это смещения по которому мы берем значение цвета точки. А второй массив - смещения по которым мы этот цвет будет ставить. Тогда весь вывод линзы сведеться к циклу, в котором мы берем точку по одному смещению , а ставим по другому.
#include <stdio.h> #include <math.h>
#define PI 3.1415926 #define max 40
char bmp[64000]; char Scr[64000]; char p[1024]; int matr[2*max][2*max]; int glassnew[2*max][2*max]; int glassold[2*max][2*max];
// Set Video Mode ################################################ extern void setvmode(int); #pragma aux setvmode = \ " int 10h " \ parm [eax] \ modify exact [eax];
// Wait Ret Race ################################################# void wait_retrace() { while ((inp(0x3DA) & 0x08) == 0); while ((inp(0x3DA) & 0x08) != 0); }
// PutPixel ###################################################### void PutPixel(int x,int y,int Color) { if ((x>0)&&(y>0)&&(x<320)&&(y<200)) Scr[x+y*320]=Color; }
// GetPixel ###################################################### int GetPixel(int x,int y) { return(bmp[x+y*320]); }
void main(void) { FILE *f; int i,j,xc,yc,c,yc1,xc1,foffset; float s,x,y,a,b;
setvmode(0x13); f=fopen("1.bmp", "rb"); fseek(f,1024+54,0); fread(&bmp, 1, 64000, f); fseek(f,54,0); fread(&p, 1, 1024, f); fclose(f);
// Готовим палитру for(i=0;i<256;i++) { outp(0x3C8,i); outp(0x3C9,p[(i*4)+2] >> 2); outp(0x3C9,p[(i*4)+1] >> 2); outp(0x3C9,p[(i*4)+0] >> 2); } // Создаем таблицу переходов for (i=-max;i for (j=-max;j { s=sin(PI/2+(PI/2)/(max*2.2)*sqrt(i*i+j*j)); x=(i*s); y=(j*s); glassnew[i+max][j+max]=(int)x+(int)y*320; glassold[i+max][j+max]=(i/2)+(j/2)*320; } do { memcpy((char*)&Scr, (char*)&bmp, 64000); xc=160+100*cos(2*a)*sin(b); yc=100+70*cos(b); foffset=xc+yc*320; for (i=0;i<2*max;i++) for (j=0;j<2*max;j++) { Scr[foffset+glassnew[i][j]]=bmp[foffset+glassold[i][j]]; } // wait_retrace(); memcpy((char*)0xA0000L, (char*)&Scr, 64000); a=a+0.01; b=b+0.01; } while (!kbhit()); getch(); setvmode(0x03); }
8 8 8
| |