Programming: Статьи
Графические эффекты: линза
Источник:
Реализация 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<max;i++)
for (j=-max;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);
}
При перепечатке любого материала
с сайта, видимая ссылка на источник www.warayg.narod.ru
и все имена, ссылки авторов обязательны.
© 2005
|