home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hot Shareware 32
/
hot34.iso
/
ficheros
/
VDOC
/
NOME6.ZIP
/
REGALOS
/
VECTFIRE.ARJ
/
VECTFIRE
/
VECTFIRE.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1997-07-23
|
24KB
|
730 lines
{$F-,O-,A+,G+,Q-,R-,S+,I+,V+,B-,X+,P-,T-,D+,L+,N+,E-}
{ESTA ES LA 2º VERSION DEL EFECTO FUEGO. EL PROCEDIMIENTO HA SIDO MEJORADO
POR SANTIAGO ROMERO AKA [NoP]. Pues sean para el todos los meritos!!!.
-Nombre del programa:VECTFIRE.EXE
-Lenguaje:Pascal.
-Compilador:Turbo Pascal v7.0 (16 bits)
-Librerias que se usan:ninguna.
-Archivos externos:BLUR.SCR:imagen de fondo en formato crudo.
BLUR.PAL:paleta de dicha imagen.
-Autor:Jose Antonio Dieguez Alonso. AKA [Se7eN]. Miembro de Capsule Corporation.
-Direccion@:Rambla Marina nº 366-8º-1º. CP:08907 Hospitalet del Llobregat (BARNA)
-Que hace?:Pues bien, chicos y chicas. Aqui teneis el famoso efecto llamado
BlurMotion. Y vosotros direis BLUR que?. Sinceramente, creo que es uno de
los efectos mas impresionantes para el poco codigo que ocupa, ya que no
hay enormes trozos en ensamblador (grrr!!! ensamblador, que chungo!!! ;-)
y la velocidad es tremendamente suave. Dicho efecto esta basado en una pa-
leta especialmete preparada. El efecto en cuestion realiza un degradado
descendente de la paleta. Bien, y vosotros direis, pues que bien, y que
puedo hacer con esto?. Pues aqui estoy yo para daros ideas!!! ;-). Segu-
ramente abreis visto alguna vez un cubo o un toroide rotando, hecho a base
de lineas (modo wireframe). Seguramente abreis visto que dicho cubo o
toroide empezaba a arder. Pues bien, ese efecto de fuego sobre el cubo
es nada mas y nada menos que aplicar el efecto BlurMotion a dicho poliedro.
Y vosotros estareis pensando,.....si que debe ser dificil hacer ese efecto..
Pues nada mas lejos de la realidad. El efecto en cuestion son unas 20 lineas
en ASM, pero el truco esta en la paleta preparada. Mira al final de este
fichero y encontraras mas informacion. ;-)
-Posibles mejoras:Rotar un poligono con el mismo efecto pero sobre una
imagen de fondo dentro de la zona donde arde el poligono y no como en este
ejemplo, donde el poligono arde pero con un fondo siempre del mismo color
(en este caso negro).
-Nota:la rutina de rotacion del poliedro es la que se incluyo en la revista
PCmania, aunque los procedimientos que dibujan las lineas estan hechas en
ASM para una mayor velocidad.
///////////////////////////////////////////////////////////////////////////}
PROGRAM VECTFIRE;
{//////////////////////////////////////////////////////////////////////////}
{///////////// definicion de constantes, variables y tipos ////////////////}
CONST
VIDEO:WORD=$0A000; {segmento de video de la VGA}
velx=4; {velocidad de giro en las coordenadas x,y,z}
vely=2;
velz=3;
TYPE
est_puntos = ARRAY [1..500,0..2] of integer; {coordenadas X,Y,Z de los puntos}
est_lineas = ARRAY [1..1000,0..1] of integer;
VAR
Total_puntos : integer;
Total_lineas : integer;
donut : est_puntos;
Rotado : est_puntos;
lineas : est_lineas;
xdeg,ydeg,zdeg : word; {incrementos en los ejes}
xoff,yoff,zoff : integer; {posiciones relativas}
sen,cosen : ARRAY [0..360] of integer; {tablas para los senos y cosenos}
Mezclas : Pointer; {puntero donde se ''QEMARA'' el donut}
segm : word; {segmento para el puntero anterior}
{//////////// fin de declaracion de constantes,variables y tipos///////////}
{//////////////////////////////////////////////////////////////////////////}
function keypressed : boolean; assembler;
{//////////////////////////////////////////////////////////////////////////}
{devuelve TRUE si se ha pulsado una tecla. Asi nos ahorramos tener que
incluir la unit CRT}
asm
mov ah,0bh
int 21h
and al,0feh
end;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Set_vga; ASSEMBLER;
{//////////////////////////////////////////////////////////////////////////}
{pasa a modo13h, es decir a 320 x 200 a 256 colores}
ASM
mov ax,13h
int 10h
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Set_text; ASSEMBLER;
{//////////////////////////////////////////////////////////////////////////}
{pasa a modo texto, 80 x 25 columnas}
ASM
mov ax,3h
int 10h
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE SetColor(Nr,R,G,B:Byte);
{//////////////////////////////////////////////////////////////////////////}
{Actualiza el color Nr, con las componentes R (ROJA), G (VERDE) y B (AZUL)
indicadas}
BEGIN
Port[$3C8]:=Nr;
Port[$3C9]:=R;
Port[$3C9]:=G;
Port[$3C9]:=B;
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE CargaPaleta(Fichero_Pal:String);
{//////////////////////////////////////////////////////////////////////////}
{carga y establece la paleta que se encuentra en el fichero *.PAL}
VAR
FichPal:File;
RGB:ARRAY[0..255,1..3] OF Byte;
I:Byte;
BEGIN
Assign(FichPal,Fichero_Pal+'.PAL');
Reset(FichPal,1);
BlockRead(FichPal,RGB,768);
FOR I:=0 TO 255 DO SetColor(I,RGB[I,1],RGB[I,2],RGB[I,3]);
Close(FichPal);
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE CargaCrudo(nombre:string);
{//////////////////////////////////////////////////////////////////////////}
{carga el dibujo de formato lineal.Se aprovecha el mismo puntero Mezclas
para cargar el dibujo, ya que no se va almacenar para nada y solamente se
va ha volcar a video}
VAR
FichCrudo:File;
BEGIN
Assign(FichCrudo,nombre+'.SCR');
Reset(FichCrudo,1);
BlockRead(FichCrudo,mezclas^,64000);
move(mezclas^,mem[Video:0],64000); {muestra la imagen en pantalla}
Close(FichCrudo);
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE WaitRetrace; ASSEMBLER;
{//////////////////////////////////////////////////////////////////////////}
{espera al retrazado vertical del monitor. Se usa para eliminar el parpadeo
y sincronizar el volcado a video}
ASM
mov dx,3DAh
@l1:
in al,dx
and al,08h
jnz @l1
@l2:
in al,dx
and al,08h
jz @l2
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE PutPixel (SegDes:Word;X,Y:Integer;Color:byte);assembler;
{//////////////////////////////////////////////////////////////////////////}
{se pone un pixel en el segmento (SegDes) indicado. si el segmento es $A000
lo colocamos directamente en la pantalla}
Asm
cmp X,0 {si los valores estan fuera de los limites}
jl @@End {de 320 x 200 no se pinta el pixel}
cmp Y,0
jl @@End
cmp X,319
jg @@End
cmp Y,199
jg @@End
mov ax,SegDes
mov es,ax
mov al,Color
mov di,Y
mov bx,X
mov dx,di
xchg dh,dl
shl di,6
add di,dx
add di,bx
mov es:[di],al
@@End:
End;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE DrawLineH(SegDes,X1,X2,Y1:Word; Color:Byte);assembler;
{//////////////////////////////////////////////////////////////////////////}
{se dibuja una linea horizontal en segmento indicado}
Asm
mov ax,SegDes
mov es,ax
mov ax,y1
mov di,ax
shl di,1
shl di,1
add di,ax
mov cl,6
shl di,cl
mov bx,x1
mov dx,x2
cmp bx,dx
jl @@1
xchg bx,dx
@@1:
inc dx
add di,bx
mov cx,dx
sub cx,bx
shr cx,1
mov al,Color
mov ah,al
ror bx,1
jnb @@2
mov es:[di],al
inc di
ror dx,1
jnb @@3
dec cx
@@3:
rol dx,1
@@2:
rep stosw
ror dx,1
jnb @@4
mov es:[di],al
inc di
@@4:
End;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE DrawLineV(SegDes,X1,Y1,Y2:Word; Color:Byte);assembler;
{//////////////////////////////////////////////////////////////////////////}
{se dibuja una.....SI..una linea vertical en el segmento indicado :-) }
Asm
mov ax,x1
mov bx,y1
mov dx,y2
cmp bx,dx
jl @@1
xchg bx,dx
@@1:
mov di,bx
shl di,1
shl di,1
add di,bx
mov cl,6
shl di,cl
add di,ax
mov cx,SegDes
mov es,cx
mov cx,dx
sub cx,bx
inc cx
mov al,Color
mov bx,319
@@2:
mov es:[di],al
inc di
add di,bx
loop @@2
End;
{//////////////////////////////////////////////////////////////////////////}
Procedure DrawLine(SegDes:Word;X1,Y1,X2,Y2:Integer; Color:Byte);assembler;
{//////////////////////////////////////////////////////////////////////////}
{se dibuja una linea en el segemnto indicado. Se usan los procedimientos
Putpixel, drawlineH y drawlineV.}
Asm
mov al,Color
xor ah,ah
mov si,ax
mov ax,x1
cmp ax,319
ja @@TheEnd
mov bx,x2
cmp bx,319
ja @@TheEnd
mov cx,y1
cmp cx,199
ja @@TheEnd
mov dx,y2
cmp dx,199
ja @@TheEnd
cmp ax,bx
jnz @@Horizontal
cmp cx,dx
jnz @@vertical
push SegDes
push ax
push cx
push si
call Putpixel
jmp @@TheEnd
@@Horizontal:
cmp cx,dx
jnz @@Horizontal2
push SegDes
push ax
push bx
push cx
push si
call DrawLineH
jmp @@TheEnd
@@Vertical:
push SegDes
push ax
push cx
push dx
push si
call DrawLineV
jmp @@TheEnd
@@Horizontal2:
cmp cx,dx
jbe @@1
xchg cx,dx
xchg ax,bx
@@1:
mov di,cx
shl di,1
shl di,1
add di,cx
push si
mov si,bx
mov bx,dx
sub bx,cx
mov cl,06
shl di,cl
add di,ax
mov dx,si
pop si
sub dx,ax
mov ax,SegDes
mov es,ax
mov ax,si
push bp
or dx,0
jge @@Jmp1
neg dx
cmp dx,bx
jbe @@Jmp3
mov cx,dx
inc cx
mov si,dx
shr si,1
std
mov bp,320
@@1c:
stosb
@@1b:
or si,si
jge @@1a
add di,bp
add si,dx
jmp @@1b
@@1a:
sub si,bx
loop @@1c
jmp @@TheEnd2
@@Jmp3:
mov cx,bx
inc cx
mov si,bx
neg si
sar si,1
cld
mov bp,319
@@2c:
stosb
@@2b:
or si,si
jl @@2a
sub si,bx
dec di
jmp @@2b
@@2a:
add di,bp
add si,dx
loop @@2c
jmp @@TheEnd2
@@Jmp1:
cmp dx,bx
jbe @@Jmp4
mov cx,dx
inc cx
mov si,dx
shr si,1
cld
mov bp,320
@@3c:
stosb
@@3b:
or si,si
jge @@3a
add di,bp
add si,dx
jmp @@3b
@@3a:
sub si,bx
loop @@3c
jmp @@TheEnd2
@@Jmp4:
mov cx,bx
inc cx
mov si,bx
neg si
sar si,1
std
mov bp,321
@@4c:
stosb
@@4b:
or si,si
jl @@4a
sub si,bx
inc di
jmp @@4b
@@4a:
add di,bp
add si,dx
loop @@4c
@@TheEnd2:
pop bp
cld
@@TheEnd:
End;
{//////////////////////////////////////////////////////////////////////////}
procedure Quemar_fuego; assembler;
{//////////////////////////////////////////////////////////////////////////}
{aqui esta la primera parte del efecto BlurMotion}
asm
mov ax, SEGM {realizamos los cambios en la pantalla virtual}
mov es, ax
mov di, 95 {origen desde la zona izquierda de la pantalla}
mov dx, 130 {ancho del buffer}
mov cx, 165 {alto del buffer}
@FireLoop :
xor ax,ax
mov al,es:[di]
add al,es:[di+1] {1er pixel de la izq}
adc ah,0
add al,es:[di-1] {1er pixel de la dch}
adc ah,0
add al,es:[di+320] {pixel de abajo}
adc ah,0
shr ax,2
jz @zero
dec ax
@Zero :
mov es:[di-320],al
inc di
dec dx
jnz @FireLoop
mov dx,130
add di, 320-130
dec cx
jnz @FireLoop
end;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Poner_Fuego(SegOrg,SegDes:Word);assembler;
{//////////////////////////////////////////////////////////////////////////}
{y aqui esta el efecto BlurMotion en cuestion. Se ha de indicar en que
pantalla se quema (SegOrg) y en que pantalla se van a visualizar los
cambios (SegDes)}
Asm
PUSH DS
MOV AX, SegOrg
MOV DS, AX { El segmento origen y el segmento destino}
MOV AX, SegDes { destino para copiar desde DS:SI }
MOV ES, AX { a ES:DI con MOVSx }
mov dx, 165 { nº de veces a repetir el bucle }
Mov si, 95 {origen del buffer}
Mov Di, 95
@bucle:
Mov cx, 130/2 {El fuego se hace en 130 pixels de ancho}
{ y se divide / 2 por el MOVSW }
Rep movsw
ADD DI, 190
ADD SI, 190 {320-130=190}
dec dx
jnz @bucle { repetir el bucle DX veces (165). }
pop ds
end;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Crea_donut(radio1,radio2,partes1,partes2:integer);
{//////////////////////////////////////////////////////////////////////////}
{crea un donut (u otra figura en funcion de los parametros pasados)}
var
cont1,cont2 : integer;
circulo : array[1..25,0..2] of integer;
xtemp : longint;
begin
if partes1*partes2>500 then exit; {si hay demasiados puntos,sale}
total_lineas:=0;
total_puntos:=partes1*partes2;
for cont1:=1 to partes1 do begin
circulo[cont1,0]:=radio1*sen[360*cont1 div partes1]+radio2*256;
circulo[cont1,1]:=radio1*cosen[360*cont1 div partes1];
end;
for cont2:=1 to partes2 do
for cont1:=1 to partes1 do begin
xtemp:=circulo[cont1,0];
donut[(cont2-1)*partes1+cont1,0]:=xtemp*cosen[360*cont2 div partes2] div 256;
donut[(cont2-1)*partes1+cont1,1]:=circulo[cont1,1];
donut[(cont2-1)*partes1+cont1,2]:=xtemp*sen[360*cont2 div partes2] div 256;
inc(total_lineas);
lineas[total_lineas,0]:=(cont2-1)*partes1+cont1;
lineas[total_lineas,1]:=(cont2-1)*partes1+(cont1 mod partes1)+1;
inc(total_lineas);
lineas[total_lineas,0]:=(cont2-1)*partes1+cont1;
lineas[total_lineas,1]:=(((cont2-1)*partes1+(cont1)+partes1-1)mod (total_puntos))+1;
end;
end;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Crea_tablas;
{//////////////////////////////////////////////////////////////////////////}
{crea las tablas necesarias para la rotacion}
VAR
xpos,ypos : integer;
cont : integer;
BEGIN
xoff:=160; {centro de giro en el eje X (la mitad de la pantalla}
yoff:=100; {centro de giro en el eje Y (la mitad de la pantalla}
zoff:=64; {distancia, alejamiento,}
total_puntos:=0;
for cont:=0 to 360 do
BEGIN
sen[cont]:=round(256*sin(pi*2*cont/360));
cosen[cont]:=round(256*cos(pi*2*cont/360));
END;
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Gira_Donut(Xrot,Yrot,Zrot:integer);
{//////////////////////////////////////////////////////////////////////////}
{gira el donut segun los incrementos pasados}
VAR
cont : integer;
xtemp,
ytemp,
ztemp : longint;
BEGIN
for cont:=1 to total_puntos do
BEGIN
rotado[cont,0]:=Donut[cont,0];
rotado[cont,1]:=Donut[cont,1];
rotado[cont,2]:=Donut[cont,2];
if xrot<>0 then
BEGIN
ytemp:=rotado[cont,1];
ztemp:=rotado[cont,2];
rotado[cont,1]:=(ytemp*cosen[xrot]-ztemp*sen[xrot])div 256;
rotado[cont,2]:=(ytemp*sen[xrot]+ztemp*cosen[xrot])div 256;
END;
if yrot<>0 then
BEGIN
xtemp:=rotado[cont,0];
ztemp:=rotado[cont,2];
rotado[cont,0]:=(ztemp*sen[yrot]+xtemp*cosen[yrot])div 256;
rotado[cont,2]:=(ztemp*cosen[yrot]-xtemp*sen[yrot])div 256;
END;
if zrot<>0 then
BEGIN
xtemp:=rotado[cont,0];
ytemp:=rotado[cont,1];
rotado[cont,0]:=(xtemp*cosen[zrot]-ytemp*sen[zrot])div 256;
rotado[cont,1]:=(xtemp*sen[zrot]+ytemp*cosen[zrot])div 256;
END;
END;
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Pon_lineas;
{//////////////////////////////////////////////////////////////////////////}
{dibuja el donut en modo wireframe, es decir, pinta las lineas del donut}
VAR
cont : integer;
punto1,punto2 : integer;
xfin1,yfin1 : integer;
xfin2,yfin2 : integer;
zz: integer;
col :byte;
BEGIN
for cont:=1 to total_lineas do
BEGIN
punto1:=lineas[cont,0];
punto2:=lineas[cont,1];
xfin1:=xoff+rotado[punto1,0]div (zoff+rotado[punto1,2]div 256);
yfin1:=yoff+rotado[punto1,1]div (zoff+rotado[punto1,2]div 256);
xfin2:=xoff+rotado[punto2,0]div (zoff+rotado[punto2,2]div 256);
yfin2:=yoff+rotado[punto2,1]div (zoff+rotado[punto2,2]div 256);
zz := zoff-rotado[punto2,2] div 64;
Col := round (zz/2); {el color maximo de la paleta de fuego es
el 63, aqui se hace un difuminado para que las lineas de fondo
se pinten con un color mas bajo, asi parece que arden menos}
DrawLine(Segm,xfin1,yfin1,xfin2,yfin2,col);
{ DrawLine(Segm,xfin1,yfin1,xfin2,yfin2,63); {si pones esta linea
en lugar de la anterior todas las aristas arderan con el maximo color de
la paleta}
END;
END;
{//////////////////////////////////////////////////////////////////////////}
PROCEDURE Fill64K (SegDes:Word;Data:Byte);assembler;
{//////////////////////////////////////////////////////////////////////////}
{borra (o mejor dicho), rellena un segmento con el byte especificado. Se usa
para ''borrar'' el segmento ocupado por el puntero mezclas}
Asm
mov ax,SegDes
mov es,ax
xor di,di
mov al,Data
mov ah,al
mov cx,32000
rep stosw
End;
{//////////////////////////////////////////////////////////////////////////}
{//////////////////////////////////////////////////////////////////////////}
{//////////////////////////////////////////////////////////////////////////}
{//////////////////////////// PROGRAMA PRINCIPAL //////////////////////////}
BEGIN
crea_tablas; {crea las tablas con senos y cosenos
necesarios para la rotacion}
crea_donut(5,9,10,10); {nos genera el poliedro}
set_vga; {pasa a modo13h}
GetMem(Mezclas, 64000); {reserva memoria para el puntero}
segm:=seg(mezclas^); {obtiene su segmento}
Fill64k(segm,0); {borro el contenido del segmento}
cargaPaleta('fondo'); {cargo la paleta}
cargaCrudo('fondo'); {cargo el dibujo de fondo}
REPEAT {************* Bucle principal ***********}
gira_Donut(xdeg,ydeg,zdeg);
waitretrace;
pon_lineas; {dibuja el donut}
quemar_fuego; {aplica el efecto BlurMotion}
poner_fuego( segM, VIDEO ); {visualiza el efecto}
xdeg:=(xdeg+velx)mod 360; {incrementa las coordenadas de
giro del donut}
ydeg:=(ydeg+vely)mod 360;
zdeg:=(zdeg+velz)mod 360;
UNTIL keypressed; {************ fin bucle principal ********}
{como puedes ver NO se borra la pantalla virtual (segM) ya que si se
hace un FILL64K(segm,0) no se acumularia el fuego y el efecto no saldria}
set_text; {vuelve a modo texto}
FreeMem(Mezclas, 64000); {libera la memoria ocupada por el
puntero}
END. {fin del codigo fuente}
{//////////////////////////////////////////////////////////////////////////}
{//////////////////////////////////////////////////////////////////////////}
Para realizar este efecto tienes que utilizar una paleta adecuada. Mira el
archivo BLUR.PAL y veras como son los primeros 64 valores.
Si no tienes un visualizador de paletas puedes cargar el archivo PALETA.PCX
y mirar su paleta. Dicha paleta es la que contiene el archivo BLUR.PAL.
Los primeros 64 valores valores forman la paleta del fuego
(comienza con el negro, luego pasa al rojo y finalmente al amarillo}.
**** Pues bien, para hacer este efecto tienes que pintar las
lineas del poligono con un color entre el 0 y 63, si el color esta mas cercano
a 63 el difuminado sera mayor (parece que arde mas) y si el color es mas cerca-
no a 0 el difuminado sera menor (arde menos).****
Bueno, para optimizar se ha usado un buffer, en lugar de toda la pantalla.
mira este dibujo y lo entenderas mejor:
------------------------------------ *
| | | * | *
| | aqui se | * | *
| | mueve | 165 | *
|*** 95 *** | el poli- | * | *
| | gono. | * | 200
| ------------ * | *
| ****130**** | *
| | *
------------------------------------ *
****************320*****************
Es decir es un buffer de 130 x 165 pixels y comienza a partir
de la columna 95. Si usas un poligono mas grande solo tendras
que ajustar el buffer a tus necesidades.
Pero lo mejor de usar un buffer, aparte de que ganas en velocidad,
es que muestras una imagen en pantalla en la zona donde no actua
el buffer (p.e.mostrando un dibujo) y ya se queda en pantalla y
no necesitas copiarlo (COPY64k) ni nada por el estilo.
Bueno, espero que que lo hayaIs pillado. Pues nada, a QUEMAR!!!!
nota:la rutina de rotacion es de la PCmania, aunque yo he incluido
las rutinas para dibujar lineas en ASM, para que vaya mas rapido
aun.
nota2:OLVIDAD LA 1ª version!!!!!!!
nota3:Si al ejecutar el archivo VECTFIRE.EXE da error y no se
ejecuta es debido a que los archivos que usa (el BLUR.SCR y el
BLUR.PAL) estan con el atributo de solo lectura, (+R), para so-
lucionar este problema debes quitar este atributo a todos los
archivos (ya que por defecto todos los archivos contenidos en el
CD-ROM tienen el atributo de solo lectura) meditante la orden
ATTRIB -R +A *.*
Si tienes fuentes de Pascal o Assembler y te gustaria intercambiar conocimientos
puedes tambien ponerte en contacto conmigo.....Espero vuestras cartas....;-D
Mi direccion es la siguiente:
Jose Antonio DIEGUEZ ALONSO
Rambla Marina nº 366-8º-1ª
08907 Hospitalet del Llobregat
BARCELONA
UN SALUDO. Hasta pronto