home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 1 / PC Actual CD 01.iso / trucos / pascal / pascal.cd < prev    next >
Encoding:
Text File  |  1995-01-04  |  38.4 KB  |  2,292 lines

  1.  
  2. PASCAL
  3.  
  4. GRABAR Y RECUPERAR PANTALLAS DE TEXTO
  5.  
  6. Programando en Turbo Pascal, hay ocasiones en las que se necesita
  7. «salvar» la pantalla con la que estamos trabajando, y restaurarla
  8. después de hacer algo (mostrar un pequeño menú de ayuda, hacer una
  9. pregunta, etc). Esta es la utilidad de estas dos rutinas, la primera
  10. de ellas, llamado «Savescreen», se encarga de guardar la memoria de
  11. video directamente en un archivo. Su formato es el siguiente:
  12.  
  13. Savescreen(Nombre);
  14.  
  15. donde «Nombre» es el nombre del archivo con el que se guardará la
  16. pantalla.
  17.  
  18. El segundo procedimiento se encarga de 'restaurar' la pantalla. Su
  19. formato es el siguiente:
  20.  
  21. Restscreen(Nombre);
  22.  
  23. donde «Nombre» es el nombre del archivo a restaurar.
  24.  
  25. Estos procedimientos están probados, y funcionan para pantallas del tipo
  26. 80 x 25, 16 Colores, es decir para pantallas de texto. El tamaño que se
  27. graba es de 4000 bytes, porque la pantalla es de 80 columnas x 25 filas
  28. = 2000 bytes, pero como cada caracter lleva asociado un atributo, esto
  29. hace un total de 2000 x 2 = 4000 bytes.
  30.  
  31.  
  32. procedure savescreen(__name:string);
  33.  
  34. var
  35.  
  36.  f :file;
  37.  
  38.  p :pointer;
  39.  
  40. begin
  41.  
  42.  assign(f,__name);
  43.  
  44.  rewrite(f);
  45.  
  46.  { abre el fichero. si existe, lo destruye. }
  47.  
  48.  close(f);
  49.  
  50.  { cierra el fichero. }
  51.  
  52.  reset(f,1);
  53.  
  54.  { abre el fichero otra vez. }
  55.  
  56.  p:=ptr($b800,$0000);
  57.  
  58.  { el puntero p^ apunta a la dirección $b800:0000 }
  59.  
  60.  blockwrite(f,p^,4000);
  61.  
  62.  { guarda la pantalla }
  63.  
  64.  close(f);
  65.  
  66. end;
  67.  
  68.  
  69. procedure restscreen(__name:string);
  70.  
  71. var
  72.  
  73.  f :file;
  74.  
  75.  p :pointer;
  76.  
  77. begin
  78.  
  79.  {$i-}
  80.  
  81.  assign(f,__name);
  82.  
  83.  reset(f);
  84.  
  85.  { comprueba si exite el fichero especificado. }
  86.  
  87.  close(f);
  88.  
  89.  {$i+}
  90.  
  91.  if ioresult=0 then begin
  92.  
  93.  assign(f,__name);
  94.  
  95.  reset(f,1);
  96.  
  97.  p:=ptr($b800,$0000);
  98.  
  99.  { el puntero p^ apunta a la dirección $b800:0000 }
  100.  
  101.  blockread(f,p^,4000);
  102.  
  103.  { lee los datos y los pone en pantalla }
  104.  
  105.  close(f);
  106.  
  107.  end;
  108.  
  109. end;
  110.  
  111. Daniel Sánchez Teodoro
  112.  
  113. Granada
  114.  
  115.  
  116.  
  117. NUMEROS CON PUNTOS
  118.  
  119. Estas dos funciones escritas en Pascal permiten la escritura de un
  120. número con los puntos de separación de millares. Este tipo de
  121. funciones tienen gran utilidad en aplicaciones (por ejemplo de
  122. contabilidad) en las que se deseen presentar resultados de cantidades
  123. con cierta calidad.
  124.  
  125. La primera (UsingLong) sirve para números «LongInt» y la segunda
  126. (Usingreal) para números reales y hace uso de la anterior.
  127.  
  128. Function UsingLong (n:LongInt):string;
  129.  
  130. Const
  131.  
  132.  Punto='.';
  133.  
  134. Var
  135.  
  136.  f,Largo : byte;
  137.  
  138.  s : String;
  139.  
  140.  Signo : String[1];
  141.  
  142. Begin
  143.  
  144.  If n<0 Then Signo := '-'
  145.  
  146.  Else
  147.  
  148.  Signo := '';
  149.  
  150.  n:=Abs(n);
  151.  
  152.  Str(n,s);
  153.  
  154.  For f := 1 to 3 do
  155.  
  156.  If Length(s) >= 4*f Then
  157.  
  158.  Insert (Punto,s,Length(s)-f*4+2);
  159.  
  160.  UsingLong:=Signo+s;
  161.  
  162. End;
  163.  
  164. Function UsingReal(r:Real; deci:byte): String;
  165.  
  166. Var
  167.  
  168.  m : Real;
  169.  
  170.  n : LongInt;
  171.  
  172.  s,t : String;
  173.  
  174. Begin
  175.  
  176.  n := Trunc(r);
  177.  
  178.  s := UsingLong(n);
  179.  
  180.  m := Frac(r);
  181.  
  182.  m := Abs(m);
  183.  
  184.  If deci >0 Then
  185.  
  186.  Begin
  187.  
  188.  Str (m:deci+2:deci,t);
  189.  
  190.  t := Copy (t,2,length(t)-1);
  191.  
  192.  s := s+t;
  193.  
  194.  End;
  195.  
  196.  UsingReal := s;
  197.  
  198. End;
  199.  
  200.  
  201. José M. Serrano
  202.  
  203. Lérida
  204.  
  205.  
  206.  
  207. CAMBIAR LA TABLA DE CARACTERES
  208.  
  209. El procedimiento «xchr» permite transformar un carácter en cualquier
  210. otro que nosotros diseñemos. Para ello nos crearemos una tabla de 8
  211. columnas por 16 filas como la del ejemplo y calcularemos los valores
  212. teniendo en cuenta que para cada una de las columnas de una fila son
  213. 128, 64, 32, 16, 8, 4, 2 y 1. Para cada fila sumamos los valores
  214. correspondientes a las columnas que tachemos para crear el carácter.
  215. Un ejemplo:
  216.  
  217.  ........ 00
  218.  
  219.  ........ 00
  220.  
  221.  ..****.. 60
  222.  
  223.  ..****.. 60
  224.  
  225.  ..*..... 32
  226.  
  227.  ..**.... 48
  228.  
  229.  ...**... 24
  230.  
  231.  ....**.. 12
  232.  
  233.  ........ 00
  234.  
  235.  ..****.. 60
  236.  
  237.  ..****.. 60
  238.  
  239.  ........ 00
  240.  
  241.  ...**... 24
  242.  
  243.  ...**... 24
  244.  
  245.  ........ 00
  246.  
  247.  ........ 00
  248.  
  249. Una vez que hemos calculado los bytes correspondientes a las 16 filas
  250. (las cifras representadas a la derecha), los colocamos en un
  251. array de la siguiente forma:
  252.  
  253. MIO :array [0..15] of BYTE= (00, 00, 60, 60, 32, 48, 24, 12, 00, 60,
  254. 60, 00, 24, 24, 0, 0 );
  255.  
  256. Con todos estos datos podemos generar el siguiente programa para
  257. cambiar el juego de caracteres.
  258.  
  259. uses dos;
  260.  
  261. type font16 = array [ 0..15] of byte;
  262.  
  263. const
  264.  
  265.  ONDAS :font16 =
  266.  
  267.  ($94, $84, $48, $30, $00, $C1, $22, $14, $94, $84, $48, $30, $00, $C1,
  268.  $22, $14);
  269.  
  270.  MIO :font16=
  271.  
  272.  (00, 00, 60, 60, 32, 48, 24, 12, 00, 60, 60, 00, 24, 24, 0, 0);
  273.  
  274. procedure xchr(CH:CHAR ;VAR s);
  275.  
  276. var regs:registers;
  277.  
  278. { La variable s no tiene tipo declarado para que usemos bien matrices
  279.  de 16 bytes o de 8 según el tipo de fuente actual }
  280.  
  281. begin
  282.  
  283. regs.dx:=ord(ch);
  284.  
  285. with regs do
  286.  
  287. begin
  288.  
  289.  ah:=$11;
  290.  
  291.  al:=$00;
  292.  
  293.  bh:=16;
  294.  
  295.  bl:=8;
  296.  
  297.  cx:=1;
  298.  
  299.  es:=seg (S);
  300.  
  301.  bp:=ofs (S);
  302.  
  303. end;
  304.  
  305. intr ($10,regs);
  306.  
  307. { Sólo es soportada por EGA, MCGA y VGA (y no CGA o MDA) }
  308.  
  309. end;
  310.  
  311. begin
  312.  
  313.  xchr ('A',ondas);
  314.  
  315.  writeln ('AAAA');
  316.  
  317. end.
  318.  
  319.  
  320. Nota del L.T.: Este programa sólo cambia el código de un carácter,
  321. pero no es difícil (aunque sí laborioso) cambiar totalmente el juego
  322. de caracteres. Simplemente deberemos generar un array para cada uno
  323. de los 255 caracteres. Una buena idea es ponerlo todo de forma que
  324. cargue la tabla de caracteres desde un bucle, para automatizar el
  325. proceso.
  326.  
  327. Alberto Vallejo Martínez
  328.  
  329. Burgos
  330.  
  331.  
  332. DIRECTORIOS «DIRECTOS»
  333.  
  334. A pesar de que el Borland Pascal incluye una orden para crear
  335. directorios («MKDir»), esta rutina incorpora la interesante novedad de
  336. que permite crear múltiples directorios a la vez, unos dentro de
  337. otros, sin tener que crearlos uno por uno.
  338.  
  339. A este procedimiento se le pasa un «string» con el directorio completo
  340. (podemos añadir al resultado de «getdir» el directorio a crear), y dos
  341. variables booleanas que indican si el directorio es imposible de crear
  342. por ser incorrecto sintácticamente, unidad inexistente o bien si ya
  343. existía. Hay que advertir que dichas variables deben estar
  344. inicializadas a «false».
  345.  
  346. PROCEDURE Creardir (dir:String; VAR error, existe:BOOLEAN);
  347.  
  348. VAR dir2:String;
  349.  
  350.  ind,io:Integer;
  351.  
  352.  faux:File;
  353.  
  354. BEGIN
  355.  
  356.  {$i-}
  357.  
  358.  ind:=Length(dir);
  359.  
  360.  dir2:=dir;
  361.  
  362.  IF (ind<>0) AND (dir[ind]<>':') THEN
  363.  
  364.  BEGIN
  365.  
  366.  WHILE (dir2[Length(dir2)] <>'\') AND (Length(dir2)<>0) DO
  367.  
  368.  Delete(dir2,Length(dir2),1);
  369.  
  370.  Delete(dir2,Length(dir2),1);
  371.  
  372.  IF Length(dir2)>0 THEN Creardir(dir2,error,existe)
  373.  
  374.  ELSE error:=true
  375.  
  376.  END
  377.  
  378.  ELSE IF ind=0 THEN error:=true
  379.  
  380.  ELSE BEGIN
  381.  
  382.  Assign(faux,dir+'\prueba.dat');
  383.  
  384.  Rewrite(faux);
  385.  
  386.  IF ioresult=0 THEN BEGIN
  387.  
  388.  Close(faux);
  389.  
  390.  Erase(faux)
  391.  
  392.  END
  393.  
  394.  ELSE error:=true
  395.  
  396.  END;
  397.  
  398.  IF not(error) THEN error:=ind=0;
  399.  
  400.  IF (ind<>0) AND (dir[ind]<>':') AND NOT (error) THEN
  401.  
  402.  BEGIN
  403.  
  404.  IF NOT error THEN mkdir(dir);
  405.  
  406.  io:=ioresult;
  407.  
  408.  IF existe THEN existe:= io=5;
  409.  
  410.  IF NOT (error) THEN error:= (io<>0) AND (io<>5)
  411.  
  412.  END;
  413.  
  414. END;
  415.  
  416. Julio Maiques Pena
  417.  
  418. Valencia
  419.  
  420.  
  421.  
  422. BITES SIGNIFICATIVOS
  423.  
  424. En Pascal no hay ninguna función estándar que nos traduzca los bites
  425. significativos de un valor de tipo binario, algo de gran utilidad si
  426. nos interesa, por ejemplo, manejar los atributos de un fichero. Con
  427. una función en ensamblador, sin embargo, resolvemos el problema en tan
  428. solo unas cuantas líneas. La función es como sigue:
  429.  
  430. Function BiteActivo(BiteBuscado, Lugar:Word):boolean;assembler;
  431.  
  432. asm
  433.  
  434. mov ax, BiteBuscado
  435.  
  436. and ax, Lugar
  437.  
  438. cmp ax,0 {si es 0, no se haya activo}
  439.  
  440. je @1 {false =0}
  441.  
  442. mov ax,1 {true=1}
  443.  
  444. @1:
  445.  
  446. end;
  447.  
  448. Fco. Javier Delgado Martínez
  449.  
  450. Madrid
  451.  
  452.  
  453. SONIDO POR INTERRUPCIONES
  454.  
  455. Este es un truco residente que hace sonar el teclado de forma curiosa.
  456. Con las teclas «+», «-», y con los números 1 al 9, se puede variar el
  457. tono y duración del sonido respectivamente. Sólo suena cuando se
  458. pulsa alguna tecla, para ello el programa mira directamente la tecla
  459. pulsada en el buffer.
  460.  
  461. program sonido;
  462.  
  463. {$M 1024,0,0}
  464.  
  465. uses crt,dos;
  466.  
  467.  var progr:procedure;
  468.  
  469.  regs:registers;
  470.  
  471.  ofs,entrada:word;
  472.  
  473.  mul,mul2:integer;
  474.  
  475. {$F+}
  476.  
  477.  procedure rutina;interrupt;
  478.  
  479.  var b,d:integer;
  480.  
  481. begin
  482.  
  483.  entrada:=memw[$40:$1c];
  484.  
  485.  if entrada<>30 then
  486.  
  487.  begin
  488.  
  489.  entrada:=entrada-2; { letra -2 bytes es tu letra }
  490.  
  491.  end
  492.  
  493.  else entrada:=60;
  494.  
  495.  ofs:=memw[$40:entrada];
  496.  
  497.  b:=lo(ofs); { número de letra }
  498.  
  499.  if b=43 then mul:=mul+1;
  500.  
  501.  if b=45 then mul:=mul-1 ;
  502.  
  503.  if (b>=49) and (b<=57) then mul2:=b-48;
  504.  
  505.  mul:=abs(mul);
  506.  
  507.  for d:=b*100 downto 0 do sound((d*mul div 2)+b);
  508.  
  509.  nosound;
  510.  
  511.  progr;
  512.  
  513. end;
  514.  
  515.  {$F-}
  516.  
  517. begin
  518.  
  519.  mul:=1;
  520.  
  521.  mul2:=1;
  522.  
  523. writeln(' SONIDO v1.00 ');
  524.  
  525. getintvec($9,@progr);
  526.  
  527. setintvec ($9,addr(rutina));
  528.  
  529. keep(0);
  530.  
  531. end.
  532.  
  533. Jorge Juan Aresté Espi
  534.  
  535. Muro (Alicante)
  536.  
  537.  
  538. RUTINAS PARA EL TECLADO
  539.  
  540. Las siguientes rutinas proporcionan un mayor control sobre el teclado.
  541. La primera de ellas, AceleraTeclado, sirve (como su propio nombre
  542. parece indicar) para acelerar considerablemente la respuesta del
  543. teclado. Su utilización es bien sencilla, y puede ser de gran
  544. utilidad para determinados juegos que requieran una rápida respuesta.
  545. Las otras dos, MaskOutKbd y UnMaskKbd tienen como función la de
  546. activar y desactivar el teclado.
  547.  
  548. Procedure AceleraTeclado;
  549.  
  550. assembler; asm
  551.  
  552.  mov ax,$305
  553.  
  554.  xor bx,bx
  555.  
  556.  int 16h
  557.  
  558. end;
  559.  
  560. Procedure MaskOutKbd; Assembler;
  561.  
  562. asm
  563.  
  564.  in al,21
  565.  
  566.  or al,00000010b
  567.  
  568.  out 21h,al
  569.  
  570. end;
  571.  
  572. Procedure UnMaskKbd; Assembler;
  573.  
  574. asm
  575.  
  576.  in al,21
  577.  
  578.  or al,11111101b
  579.  
  580.  out 21h,al
  581.  
  582. end;
  583.  
  584. La siguiente función lee una tecla del teclado o bien del buffer del
  585. teclado, y devuelve una variable numérica de formato Word, de modo que
  586. en el byte más alto obtenemos el código de rastreo y en el byte más
  587. bajo el código ASCII. Para obtener ambos valores podemos emplear las
  588. funciones Hi y Lo, para obtener los bytes más significativos y menos
  589. significativos respectivamente.
  590.  
  591. El uso de ambos valores combinados es interesante pues podemos
  592. distinguir la pulsación de las flechas del cursor, del teclado
  593. numérico, la pulsación de «Alt» o «Ctrl» con otra tecla, etc. También
  594. es interesante el uso del byte de rastreo, pues este dato no
  595. diferencia, dada una tecla en particular, si se ha pulsado mayúscula o
  596. minúscula o en combinación con «Ctrl» o «Alt». En resumen, cada tecla
  597. tiene un código de rastreo asignado. La lista de todos los códigos
  598. obtenidos al pulsar cada tecla es demasiado extensa para incluirla
  599. aquí, pero todo es cuestión de ir probando. Por ejemplo, el código de
  600. rastreo para la letra «A» es el 30 (1E en Hexadecimal), tanto
  601. mayúscula como minúscula, aunque su código ASCII es 65 para la
  602. mayúscula y 97 si es minúscula. Si pulsamos «Ctrl+A» obtenemos 3001,
  603. y si pulsamos «Alt+A» obtenemos 3000.
  604.  
  605. Function LeeTecla : Word; Assembler;
  606.  
  607. Asm
  608.  
  609.  xor ax,ax
  610.  
  611.  int $16
  612.  
  613. End;
  614.  
  615. Definiendo al principio del programa las siguientes variables:
  616.  
  617. Var
  618.  
  619.  TeclaCabeza : Word Absolute 0:$41A;
  620.  
  621.  TeclaCola : Word Absolute 0:$41C;
  622.  
  623. De esta forma, TeclaCabeza contiene el código de la tecla que se
  624. encuentra al principio del buffer del teclado, mientras que en la
  625. variable TeclaCola se almacena el código de la tecla que se encuentra
  626. en la cola del buffer.
  627.  
  628. También podemos utilizar el siguiente procedimiento, que se encarga de
  629. limpiar el buffer de teclado de una forma rápida y efectiva.
  630.  
  631. Procedure LimpiaBuffer;
  632.  
  633. Begin
  634.  
  635.  TeclaCabeza:= TeclaCola;
  636.  
  637. End;
  638.  
  639. Podemos comparar TeclaCabeza con TeclaCola; en caso de obtener valores
  640. diferentes podemos afirmar que se ha pulsado una tecla. De esta forma
  641. obtenemos una nueva y sencilla forma para la función «KeyPressed». Lo
  642. podemos hacer directamente comparando ambos valores mediante un If
  643. TeclaCabeza<>TeclaCola Then.... O podemos emplear la siguiente
  644. función en ensamblador que hace el mismo trabajo.
  645.  
  646. Function TeclaPulsada : Boolean; Assembler;
  647.  
  648. asm
  649.  
  650.  xor ax,ax
  651.  
  652.  mov es,ax
  653.  
  654.  mov ax,[es:TeclaCabeza]
  655.  
  656.  sub ax,[es:TeclaCola]
  657.  
  658.  jz @@1
  659.  
  660.  mov ax,1
  661.  
  662. @@1:
  663.  
  664.  sti
  665.  
  666. end;
  667.  
  668. Hemos de recordar que las funciones y procedimientos que hacen uso del
  669. ensamblador incorporado en Turbo Pascal, sólo podrán ser compiladas en
  670. versiones posteriores a la 6.0, primera versión en que se incorporó
  671. esta capacidad.
  672.  
  673. Santos Herranz Domingo
  674.  
  675. Madrid
  676.  
  677.  
  678.  
  679. ESPACIO EN EL DISCO
  680.  
  681. Cada vez que efectuamos un «dir» de un directorio del disco se nos
  682. muestra la información de los bytes ocupados y los que quedan libres.
  683. Aunque esta información es más que suficiente, gracias a este programa
  684. podremos conseguir un resultado más vistoso de esta información. La
  685. función de este programa es la de crear una barra de porcentaje con la
  686. cantidad del disco duro que tenemos ocupado.
  687.  
  688. Además, no sólo nos muestra el tanto por ciento de disco ocupado, sino
  689. que para mayor información el programa nos indica los bytes totales,
  690. los ocupados y los que nos quedan libres.
  691.  
  692. Program BarDisk;
  693.  
  694. Uses Crt, Dos;
  695.  
  696. Var total, Libre, Tanto: LongInt;
  697.  
  698.  Numero: String;
  699.  
  700.  i: Byte;
  701.  
  702. Function PuntoMil (n: LongInt): String;
  703.  
  704. Var f: Byte;
  705.  
  706.  s: String;
  707.  
  708. Begin
  709.  
  710.  Str(n,s);
  711.  
  712.  For f:=1 to 3 do
  713.  
  714.  If length (s) >= 4*f then
  715.  
  716.  Insert('.',s, Length(s) - f*4+2);
  717.  
  718.  PuntoMil:=s;
  719.  
  720. End;
  721.  
  722. Begin
  723.  
  724.  Total:=DiskSize(0) div 1024;
  725.  
  726.  Libre:=DiskFree(0) div 1024;
  727.  
  728.  Tanto:=((Total-Libre) *100) div Total;
  729.  
  730.  TextColor(3);
  731.  
  732.  GotoXY(24,WhereY);
  733.  
  734.  WriteLn(Tanto,'% de espacio en disco ocupado');
  735.  
  736.  {Dibuja barra y coloca porcentajes}
  737.  
  738.  For i:=3 To 78 do
  739.  
  740.  Begin
  741.  
  742.  GotoXY (i,WhereY);
  743.  
  744.  Write (#176);
  745.  
  746.  End;
  747.  
  748.  textColor(14);
  749.  
  750.  Tanto:= ((Total-Libre)*78) div Total;
  751.  
  752.  For i:=3 to Tanto do
  753.  
  754.  Begin
  755.  
  756.  GotoXY(i,WhereY);
  757.  
  758.  Write(#219);
  759.  
  760.  End;
  761.  
  762.  TextColor(3);
  763.  
  764.  WriteLn;
  765.  
  766.  GotoXY(3,WhereY); Write(#179,'0%');
  767.  
  768.  GotoXY(38,WhereY); Write(#179,'50%');
  769.  
  770.  GotoXY(74,WhereY); WritelN('100%',#179);
  771.  
  772.  WriteLn;
  773.  
  774.  { Coloca datos del disco }
  775.  
  776.  Numero := PuntoMil (DiskSize(0));
  777.  
  778.  WriteLn(#175#32, Numero, ' bytes totales ');
  779.  
  780.  Numero := PuntoMil (DiskSize(0)-DiskFree(0));
  781.  
  782.  WriteLn(#175#32, Numero, ' bytes ocupados');
  783.  
  784.  Numero := PuntoMil (DiskFree(0));
  785.  
  786.  WriteLn(#175#32, Numero, ' bytes libres');
  787.  
  788.  TextColor(7);
  789.  
  790.  WriteLn;
  791.  
  792. End.
  793.  
  794. Juan Antonio Fernández Moreno
  795.  
  796. Huelva
  797.  
  798.  
  799. ZOOM GRAFICO
  800.  
  801. Este programa incluye la rutina «deforma», que permitirá efectuar
  802. ampliaciones y reducciones, y en general cualquier tipo de deformación
  803. de una zona de la pantalla.
  804.  
  805. Para su uso sólo hemos de llamar a «deforma» con las coordenadas x, y
  806. de la esquina superior izquierda de la imagen a deformar; tras éstas,
  807. las coordenadas x, y de la esquina inferior izquierda de la imagen a
  808. deformar. Después de teclear las cuatro coordenadas introducimos las
  809. mismas, pero esta vez dando las coordenadas donde queremos situar la
  810. imagen. Hay que notar que no tienen por qué tener el mismo tamaño, ya
  811. que el procedimiento se encarga de deformar la imagen para adecuarla a
  812. las coordenadas de destino.
  813.  
  814. En el programa de ejemplo podemos ver un ejemplo del uso de la rutina
  815. para efectuar un zoom hacia afuera.
  816.  
  817. program Uso_de_Deforma;
  818.  
  819. uses Crt;
  820.  
  821. type
  822.  
  823.  pantalla = array [0..199,0..319] of byte;
  824.  
  825. var
  826.  
  827.  pantallaPTR : ^pantalla;
  828.  
  829.  z : integer;
  830.  
  831. procedure deforma(x1,y1,x2,y2,x3,y3,x4,y4 : integer);
  832.  
  833. var
  834.  
  835.  x,y,dx1,dy1,dx3,dy3 : integer;
  836.  
  837. begin
  838.  
  839.  dx1:=x2-x1;
  840.  
  841.  dy1:=y2-y1;
  842.  
  843.  dx3:=x4-x3;
  844.  
  845.  dy3:=y4-y3;
  846.  
  847.  for y:=0 to dy3 do
  848.  
  849.  for x:=0 to dx3 do
  850.  
  851. pantallaPTR^[y+y3,x+x3]:=pantallaPTR^[((y*dy1)div dy3)+y1,((x*dx1)div
  852. dx3)+x1];
  853.  
  854.  end;
  855.  
  856. begin
  857.  
  858.  asm
  859.  
  860.  mov ax,13h
  861.  
  862.  int 10h
  863.  
  864.  end;
  865.  
  866.  pantallaPTR := ptr($a000,0); (*este puntero apunta a la pantalla*)
  867.  
  868.  for z:=0 to 100 do
  869.  
  870.  pantallaPTR^[random(29),random(29)]:=random(255);
  871.  
  872.  for z:=10 to 150 do
  873.  
  874.  begin
  875.  
  876.  deforma(0,0,29,29,100,40,100+z,40+z);
  877.  
  878.  delay(50);
  879.  
  880.  end;
  881.  
  882. end.
  883.  
  884. Antonio Ruiz
  885.  
  886. Málaga
  887.  
  888.  
  889.  
  890. INFORMACION SOBRE EL RATON
  891.  
  892. El siguiente programa, realizado en Turbo Pascal, efectúa un completo
  893. test del ratón mostrando la siguiente información: número de botones,
  894. IRQ utilizada, tamaño del buffer de estado, versión del driver, idioma
  895. utilizado y tipo de ratón (serie, bus, etc.). Además, activa el
  896. cursor para que lo podamos ver en pantalla.
  897.  
  898. Todas las llamadas a las distintas funciones del ratón se realizan a
  899. través de la interrupción 33h. Como se puede comprobar, esta
  900. interrupción está muy utilizada en este programa.
  901.  
  902. Program MTest (Mouse_Test);
  903.  
  904. Uses Crt, Dos;
  905.  
  906. Const aTipo: Array [1..5] Of string [8]=('Bus', 'Sere', 'InPort',
  907. 'PS/2', 'HP');
  908.  
  909.  aIdio: Array [0..8] Of string = ('Inglés', 'Francés', 'Holandés',
  910.  'Alemán','Sueco','Finlandés', 'Español','Portugués','Italiano');
  911.  
  912. Var regs:Registers;
  913.  
  914.  Botones: Byte;
  915.  
  916. Begin
  917.  
  918.  Regs.AX:=0;
  919.  
  920.  INTr($33,regs);
  921.  
  922.  WriteLn;
  923.  
  924.  If regs.AX=0 Then
  925.  
  926.  Begin
  927.  
  928.  WriteLn('No se encontró el driver del ratón.');
  929.  
  930.  Halt;
  931.  
  932.  End
  933.  
  934.  Else
  935.  
  936.  Begin
  937.  
  938.  Botones:=regs.BX;
  939.  
  940.  {Dibuja Mouse}
  941.  
  942.  TextColor(15);
  943.  
  944.  WriteLn(#186:6);
  945.  
  946.  WriteLn(#219#177#219#177#219:8);
  947.  
  948.  WriteLn(#219#219#219#219#219:8);
  949.  
  950.  WriteLn('Driver del ratón en memoria.');
  951.  
  952.  WriteLn;
  953.  
  954.  {Coloca datos y activa ratón}
  955.  
  956.  regs.AX:=$24;
  957.  
  958.  INTr($33, regs);
  959.  
  960.  WriteLn('Versión del driver: ', regs.BH, '.', regs.BL);
  961.  
  962.  WriteLn('Tipo del ratón....: ', (aTipo[regs.CH] ));
  963.  
  964.  WriteLn('Número de botones.: ', botones);
  965.  
  966.  WriteLn('Instalado en IRQ..: ', regs.CL);
  967.  
  968.  regs.AX:=$23;
  969.  
  970.  INTr($33,regs);
  971.  
  972.  WriteLn('Idioma............: ', (aIdio[regs.BX]));
  973.  
  974.  regs.AX:=$15;
  975.  
  976.  INTr($33,regs);
  977.  
  978.  WriteLn('Buffer de estado..: ', regs.BX, ' bytes');
  979.  
  980.  Regs.AX:=1;
  981.  
  982.  INTr($33,regs);
  983.  
  984.  Repeat Until KeyPressed;
  985.  
  986.  regs.AX:=2;
  987.  
  988.  INTr($33,regs);
  989.  
  990.  TextColor(7);
  991.  
  992.  WriteLn;
  993.  
  994.  End;
  995.  
  996. End.
  997.  
  998. Juan Antonio Fernández Moreno
  999.  
  1000. Huelva
  1001.  
  1002.  
  1003. VISUALIZADOR DE FICHEROS BMP
  1004.  
  1005. Este es un interesante programa que nos permite visualizar ficheros
  1006. BMP de 256 colores con codificación RGB. Aunque admite ficheros de
  1007. cualquier resolución, en las imágenes mayores de 320 x 200 sólo se
  1008. visualizarán las primeras 320 columnas y las primeras 200 filas; el
  1009. resto no se visualizará.
  1010.  
  1011. Para su ejecución deberemos introducir «VER_BMP nombre_fichero
  1012. [.BMP]». Esta rutina no comprueba la existencia de tarjeta gráfica
  1013. VGA, ni tampoco la existencia del fichero BMP introducido como
  1014. parámetro; de manera que si se introduce un nombre no válido o no se
  1015. dispone de VGA se provocará un error de ejecución.
  1016.  
  1017. Recordemos que sólo visualiza ficheros BMP con codificación RGB y con
  1018. 256 colores, de manera que si una imagen no puede visualizarse será
  1019. por cualquiera de estos tres motivos: bmpfile.bfType distinto de
  1020. CABEZA_BMP (no es un fichero BMP); bmpinfo.biBitCount distinto de 8
  1021. (no es un fichero de 256 colores), o bmpinfo.biCompression distinto de
  1022. 0 (no tiene codificacion RGB).
  1023.  
  1024. Notas acerca de la rutina y los ficheros BMP
  1025.  
  1026. Dadas las diferentes características de VGA y BMP es necesario
  1027. reconvertir la paleta almacenada en un fichero BMP a un formato válido
  1028. para la VGA, ya que los valores que almacena el fichero BMP para cada
  1029. componente de color estan entre 0 y 255, mientras que la VGA sólo
  1030. maneja valores entre 0 y 63 para cada componente de color.
  1031.  
  1032. Por otra parte, la estructura de la paleta de un BMP asigna 4 bytes
  1033. para cada color, almacenando los colores en el siguiente orden: azul,
  1034. verde y rojo; mientras que la paleta que debe ser pasada a los
  1035. registros DAC de la VGA sólo tiene 3 bytes para cada color de la
  1036. paleta y los colores deben ir en el orden inverso, es decir, rojo,
  1037. verde y azul.
  1038.  
  1039. Por último, la longitud de una línea de imagen almacenada en un
  1040. fichero BMP siempre es múltiplo de 4, por lo que una imagen con un
  1041. ancho que no sea múltiplo de dicha cantidad tendrá bytes basura, que
  1042. no deben ser visualizados (de hecho, tendrá tantos bytes basura como
  1043. los necesarios para igualar la longitud al múltiplo de 4 superior más
  1044. próximo).
  1045.  
  1046. Dado que la inicialización del modo de vídeo se hace en ensamblador no
  1047. es necesario disponer del driver BGI correspondiente. Aunque, eso sí,
  1048. para poder compilarlo necesitaremos al menos la versión 6.0 de Turbo
  1049. Pascal.
  1050.  
  1051. Por otra parte, hay que señalar que las líneas:
  1052.  
  1053. cont := port[$3da]; port[$3c0] := $20;
  1054.  
  1055. cont := port[$3da]; port[$3c0] := $20;
  1056.  
  1057. posibilitan que sólo se muestre la imagen una vez que ésta esté entera
  1058. en la pantalla. De ahí que si queremos que la imagen vaya siendo
  1059. dibujada línea a línea, baste con eliminarlas.
  1060.  
  1061. Una última aclaración: las líneas de imagen de un fichero BMP se almacenan
  1062. en orden inverso a como aparecerán en la pantalla, esto es, la primera
  1063. línea de imagen en el fichero se corresponde con la última que aparece en
  1064. pantalla. Es por esto que el bucle en el que se transfiere la imagen del
  1065. archivo a la pantalla vaya de valores mayores a menores.
  1066.  
  1067. Program Ver_BMP;
  1068.  
  1069. Uses
  1070.  
  1071.  crt, dos;
  1072.  
  1073. Const
  1074.  
  1075.  CABEZA_BMP = $4D42;
  1076.  
  1077. Type
  1078.  
  1079.  BitmapFileHeader = Record
  1080.  
  1081.  bfType :word;
  1082.  
  1083.  bfSize :longint;
  1084.  
  1085.  bfReserved1,
  1086.  
  1087.  bfReserved2 :word;
  1088.  
  1089.  bfOffbits :longint;
  1090.  
  1091.  end;
  1092.  
  1093.  BitmapInfoHeader = record
  1094.  
  1095.  biSize, biWidth,
  1096.  
  1097.  biHeight :longint;
  1098.  
  1099.  biPlanes,
  1100.  
  1101.  biBitCount :word;
  1102.  
  1103.  biCompression,
  1104.  
  1105.  biSizeImage,
  1106.  
  1107.  biXpelsperMeter,
  1108.  
  1109.  biYpelsPerMeter,
  1110.  
  1111.  biClrUsed,
  1112.  
  1113.  biClrImportant :longint;
  1114.  
  1115.  end;
  1116.  
  1117.  RGBQuad = record
  1118.  
  1119.  rgbBlue, rgbGreen, rgbRed, rgbReserved :byte;
  1120.  
  1121.  end;
  1122.  
  1123.  rgbDAC = record
  1124.  
  1125.  rgbRed, rgbGreen, rgbBlue :byte;
  1126.  
  1127.  end;
  1128.  
  1129.  RGBQpaleta = array[0..255] of RGBquad;
  1130.  
  1131.  RGBpaleta = array[0..255] of rgbDAC;
  1132.  
  1133.  linea320 = array[0..319] of byte;
  1134.  
  1135. Var
  1136.  
  1137.  fichero :file;
  1138.  
  1139.  name :string;
  1140.  
  1141.  bmpFile :bitmapFileHeader;
  1142.  
  1143.  bmpInfo :bitmapInfoHeader;
  1144.  
  1145.  bmpPalet :RGBQpaleta;
  1146.  
  1147.  Paleta :rgbPaleta;
  1148.  
  1149.  linea :^linea320;
  1150.  
  1151.  suma :byte;
  1152.  
  1153.  scanline, mover, cont :word;
  1154.  
  1155.  regs :registers;
  1156.  
  1157.  buffergraf :array [0..64000] of byte absolute $a000:$00;
  1158.  
  1159. Begin
  1160.  
  1161.  name := paramstr(1);
  1162.  
  1163.  if pos('.',name) < 1 then
  1164.  
  1165.  name := name + '.bmp';
  1166.  
  1167.  assign(fichero, name);
  1168.  
  1169.  reset(fichero, 1);
  1170.  
  1171.  blockread(fichero, bmpfile, sizeof(bmpfile));
  1172.  
  1173.  blockread(fichero, bmpinfo, sizeof(bmpinfo));
  1174.  
  1175.  if (bmpfile.bfType <> CABEZA_BMP) or (bmpinfo.biBitCount <> 8) or
  1176.  
  1177.  (bmpinfo.biCompression <> 0) then
  1178.  
  1179.  writeln ('No se puede Visualizar el fichero')
  1180.  
  1181.  else begin
  1182.  
  1183.  blockread (fichero, bmpPalet[0], sizeof(bmpPalet));
  1184.  
  1185.  for cont := 0 to 255 do begin
  1186.  
  1187.  paleta[cont].rgbRed := bmpPalet[cont].rgbRed div 4;
  1188.  
  1189.  paleta[cont].rgbGreen := bmpPalet[cont].rgbGreen div 4;
  1190.  
  1191.  paleta[cont].rgbBlue := bmpPalet[cont].rgbBlue div 4;
  1192.  
  1193.  end;
  1194.  
  1195.  cont := bmpinfo.biWidth mod 4;
  1196.  
  1197.  case cont of
  1198.  
  1199.  1: suma := 3;
  1200.  
  1201.  2: suma := 2;
  1202.  
  1203.  3: suma := 1;
  1204.  
  1205.  else
  1206.  
  1207.  suma := 0;
  1208.  
  1209.  end;
  1210.  
  1211.  scanline := bmpinfo.biWidth + suma;
  1212.  
  1213.  if bmpinfo.biWidth > 320 then
  1214.  
  1215.  mover := 320
  1216.  
  1217.  else
  1218.  
  1219.  mover := bmpinfo.biWidth;
  1220.  
  1221.  asm
  1222.  
  1223.  mov ax, 0013h
  1224.  
  1225.  int 10h
  1226.  
  1227.  end;
  1228.  
  1229.  regs.ax := $1012;
  1230.  
  1231.  regs.bx := $00;
  1232.  
  1233.  regs.cx := $100;
  1234.  
  1235.  regs.es := seg(paleta[0]);
  1236.  
  1237.  regs.dx := ofs(paleta[0]);
  1238.  
  1239.  intr($10, regs);
  1240.  
  1241.  getmem(linea, scanline);
  1242.  
  1243.  cont := port[$3da];
  1244.  
  1245.  port[$3c0] := $00;
  1246.  
  1247.  if bmpinfo.biheight > 200 then begin
  1248.  
  1249.  seek(fichero, filepos(fichero)+ scanline * (bmpinfo.biheight-200));
  1250.  
  1251.  bmpinfo.biheight := 200
  1252.  
  1253.  end;
  1254.  
  1255.  for cont := (bmpinfo.biheight - 1) downto 0 do begin
  1256.  
  1257.  blockread(fichero, linea^[0], scanline);
  1258.  
  1259.  move (linea^[0], bufferGraf[cont*320], mover);
  1260.  
  1261.  end;
  1262.  
  1263.  cont := port[$3da];
  1264.  
  1265.  port[$3c0] := $20;
  1266.  
  1267.  close(fichero);
  1268.  
  1269.  freemem(linea, scanline);
  1270.  
  1271.  repeat until keypressed;
  1272.  
  1273.  asm
  1274.  
  1275.  mov ax, 0003h
  1276.  
  1277.  int 10h
  1278.  
  1279.  end;
  1280.  
  1281.  end;
  1282.  
  1283. end.
  1284.  
  1285. Carlos Soto García
  1286.  
  1287. Las Rozas (Madrid)
  1288.  
  1289.  
  1290. RUTINAS GRAFICAS
  1291.  
  1292. La introducción a la programación del modo de vídeo 13h de la VGA ha
  1293. tenido gran aceptación entre todos nuestros lectores. Buena prueba de
  1294. ello es que estamos recibiendo gran cantidad de rutinas para este modo
  1295. de vídeo. Un buen ejemplo es la siguiente unidad para Turbo Pascal
  1296. 6.0 ó posterior, que contiene diversas rutinas (la mayoría en
  1297. ensamblador) de gran interés para el mencionado modo de 320x200x256.
  1298.  
  1299. La unidad contiene los siguientes procedimientos:
  1300.  
  1301. LeePcx: Este procedimiento descomprime un fichero en formato
  1302. gráfico PCX de 320x200x256 (con la condición de que el tamaño del
  1303. fichero no exceda de 64 Kbytes) y almacena el resultado en una zona de
  1304. memoria. También devuelve la paleta del fichero.
  1305.  
  1306. MueveGraf: Se encarga de escribir en pantalla un gráfico
  1307. descomprimido con el procedimiento anterior. También sirve para mover
  1308. gráficos que sean una imagen exacta de la memoria de pantalla. Es
  1309. equivalente a la instrucción «move» de Turbo Pascal.
  1310.  
  1311. LeeSprite: Captura una región de la pantalla y la almacena en
  1312. una región de memoria especificada. El formato del gráfico es el
  1313. siguiente: en la posición 0 con un tamaño de una palabra se guarda el
  1314. ancho del dibujo; en la posición 2 con un tamaño de una palabra se
  1315. guarda el alto del dibujo, y a partir de la posición 4 con un tamaño
  1316. de (ancho x alto) bytes se guarda el dibujo grabado por filas.
  1317.  
  1318. PonSprite: Devuelve a la pantalla una región capturada con el
  1319. procedimiento «LeeSprite». Además, permite realizar operaciones
  1320. lógicas entre el dibujo y lo que hay en pantalla. Para seleccionar
  1321. qué operación lógica vamos a usar existen las constantes
  1322. mskNormal, mskXor, mskOr, mskAnd y
  1323. mskNot. Estas constantes vienen dadas en la siguiente tabla
  1324. donde se indican también sus valores numéricos, y las operaciones
  1325. lógicas que se realizan entre los puntos de la pantalla y del
  1326. Sprite.
  1327.  
  1328. MskNormal 0 MOV
  1329.  
  1330. MskXOR 1 XOR
  1331.  
  1332. MskOR 2 OR
  1333.  
  1334. MskAND 3 AND
  1335.  
  1336. MskNOT 4 NOT
  1337.  
  1338. Unit Graficos;
  1339.  
  1340. Interface
  1341.  
  1342. Const
  1343.  
  1344.  {-- Constantes del fundido --}
  1345.  
  1346.  funRojo = 0;
  1347.  
  1348.  funAzul = 1;
  1349.  
  1350.  funVerde = 2;
  1351.  
  1352.  {-- Operaciones lógicas del procedimiento PonSprite --}
  1353.  
  1354.  mskNormal = 0;
  1355.  
  1356.  mskXOR = 1;
  1357.  
  1358.  mskOR = 2;
  1359.  
  1360.  mskAND = 3;
  1361.  
  1362.  mskNOT = 4;
  1363.  
  1364. Type
  1365.  
  1366.  TPaleta = Array[0..767] of Byte;
  1367.  
  1368.  Procedure LeePcx(var Graf;Total:Word;var Pal:TPaleta;var Imagen);
  1369.  
  1370.  Procedure MueveGraf(var Graf);
  1371.  
  1372.  Procedure PonSprite(X,Y:Word;Mask:Byte;var Graf);
  1373.  
  1374.  Procedure LeeSprite(x1,y1,x2,y2:Word;var Graf);
  1375.  
  1376.  Procedure PonPunto(X,Y:Word;Color:Byte);
  1377.  
  1378.  Procedure Escribe(X,Y:Word;Texto:String;Color:Byte);
  1379.  
  1380. Implementation
  1381.  
  1382. Var
  1383.  
  1384.  Seg1F,
  1385.  
  1386.  Ofs1F : Word;
  1387.  
  1388. Procedure LeePcx; Assembler;
  1389.  
  1390. { Descomprime un fichero PCX en formato 320x200x256. Se asume que la
  1391.  
  1392.  información que se pasa como gráfico es correcta. El fichero ha de tener
  1393.  
  1394.  menos de 64k. El dibujo resultante se almacena en la variable IMAGEN y la
  1395.  
  1396.  paleta correspondiente en PAL. }
  1397.  
  1398. Var
  1399.  
  1400.  Cont : Word;
  1401.  
  1402. Asm
  1403.  
  1404.  Push Ds
  1405.  
  1406.  { CONT indica dónde empieza la paleta }
  1407.  
  1408.  Mov Ax,Total
  1409.  
  1410.  Mov Cont,Ax
  1411.  
  1412.  Sub Cont,768
  1413.  
  1414.  { Cada valor de la paleta ha de ser dividido por 4 }
  1415.  
  1416.  Lds Si,Graf { Se cargan dos punteros a la variable GRAF }
  1417.  
  1418.  Les Di,Pal
  1419.  
  1420.  Add Si,Cont { Se colocan donde empieza la paleta }
  1421.  
  1422.  Cld
  1423.  
  1424.  Mov Cx,768 { Hay 256*3 elementos }
  1425.  
  1426.  Mov Bl,4
  1427.  
  1428.  Xor Dx,Dx { Para dividir no se usa DX ni AH }
  1429.  
  1430.  Xor Ah,Ah
  1431.  
  1432. @Divide:
  1433.  
  1434.  Lodsb
  1435.  
  1436.  Xor Ah,Ah
  1437.  
  1438.  Div Bl { Divide cada byte por 4 }
  1439.  
  1440.  Stosb
  1441.  
  1442.  Loop @Divide
  1443.  
  1444.  { Con Es:Di se direccionará la memoria de vídeo }
  1445.  
  1446.  Les Di,Imagen
  1447.  
  1448.  { Se salta la cabecera. Usa Ds:Di para leer de la variable }
  1449.  
  1450.  Lds Si,Graf
  1451.  
  1452.  Add Si,128
  1453.  
  1454.  Mov Dx,Cont
  1455.  
  1456.  { El byte alto del contador no se va a usar }
  1457.  
  1458.  Xor Ch,Ch
  1459.  
  1460. @Bucle:
  1461.  
  1462.  Lodsb { Carga el byte actual }
  1463.  
  1464.  Cmp Al,192 { Si es menor de 192 sólo se dibuja una vez }
  1465.  
  1466.  Jb @NoRepite
  1467.  
  1468.  Sub Al,192 { Calcula cuantas veces se ha de dibujar }
  1469.  
  1470.  Mov Cl,Al
  1471.  
  1472.  Lodsb { Lee el color que se habrá de escribir }
  1473.  
  1474.  Jmp @Escribe
  1475.  
  1476. @NoRepite:
  1477.  
  1478.  Mov Cx,1 { Sólo hay que imprimir un pixel }
  1479.  
  1480. @Escribe:
  1481.  
  1482.  Stosb { Escribe el color }
  1483.  
  1484.  Loop @Escribe { tantas veces como haga falta }
  1485.  
  1486.  Cmp Si,Dx { Comprueba si hemos llegado al final }
  1487.  
  1488.  Jnz @Bucle
  1489.  
  1490.  Pop Ds { Se tiene que restaurar DS }
  1491.  
  1492. End; { PROCEDURE LeePcx }
  1493.  
  1494. Procedure MueveGraf;Assembler;
  1495.  
  1496. Asm
  1497.  
  1498.  Push Ds
  1499.  
  1500.  Lds Si,Graf
  1501.  
  1502.  Mov Ax,0A000h
  1503.  
  1504.  Mov Es,Ax
  1505.  
  1506.  Xor Di,Di
  1507.  
  1508.  Mov Cx,32000
  1509.  
  1510.  Rep Movsw
  1511.  
  1512.  Pop Ds
  1513.  
  1514. End; { PROCEDURE MueveGraf }
  1515.  
  1516. Procedure PonSprite;Assembler;
  1517.  
  1518. { Escribe en pantalla un sprite de los creados por el procedimient LeeSprite,
  1519.  
  1520.  haciendo una operación lógica al escribirlo. }
  1521.  
  1522. Var
  1523.  
  1524.  Ancho,Alto : Word;
  1525.  
  1526. Asm
  1527.  
  1528.  Push Ds
  1529.  
  1530.  Dec X
  1531.  
  1532.  Dec Y
  1533.  
  1534.  Les Di,Graf { Lee el alto y ancho del gráfico }
  1535.  
  1536.  Mov Ax,word ptr [Es:Di]
  1537.  
  1538.  Mov Ancho,Ax { que se encuentran en las dos primeras palabras }
  1539.  
  1540.  Mov Ax,Es:[Di+2]
  1541.  
  1542.  Mov Alto,Ax
  1543.  
  1544.  Lds Si,Graf { Carga la dirección del gráfico }
  1545.  
  1546.  Add Si,4 { El gráfico en sí comienza en [Graf+4] }
  1547.  
  1548.  Mov Ax,320
  1549.  
  1550.  Xor Dx,Dx
  1551.  
  1552.  Mul Y
  1553.  
  1554.  Add Ax,X
  1555.  
  1556.  Mov Di,Ax { Calcula la posición de inicio }
  1557.  
  1558.  Mov Ax,0A000h
  1559.  
  1560.  Mov Es,Ax
  1561.  
  1562.  Mov Cx,Alto { El bucle se ejecutará tantas veces como alto sea }
  1563.  
  1564.  Mov Dl,Mask
  1565.  
  1566. @Repite:
  1567.  
  1568.  Push Cx
  1569.  
  1570.  Mov Cx,Ancho
  1571.  
  1572. @Escribe:
  1573.  
  1574.  Lodsb
  1575.  
  1576. @Normal:
  1577.  
  1578.  Cmp Dl,0
  1579.  
  1580.  Jne @XOR
  1581.  
  1582.  Jmp @FinCase
  1583.  
  1584. @XOR:
  1585.  
  1586.  Cmp Dl,1
  1587.  
  1588.  Jne @OR
  1589.  
  1590.  Xor Al,byte ptr [Es:Di]
  1591.  
  1592.  Jmp @FinCase
  1593.  
  1594. @OR:
  1595.  
  1596.  Cmp Dl,2
  1597.  
  1598.  Jne @AND
  1599.  
  1600.  Or Al,byte ptr [Es:Di]
  1601.  
  1602.  Jmp @FinCase
  1603.  
  1604. @AND:
  1605.  
  1606.  Cmp Dl,3
  1607.  
  1608.  Jne @NOT
  1609.  
  1610.  And Al,byte ptr [Es:Di]
  1611.  
  1612.  Jmp @FinCase
  1613.  
  1614. @NOT:
  1615.  
  1616.  Not Al
  1617.  
  1618.  Jmp @FinCase
  1619.  
  1620. @FinCase:
  1621.  
  1622.  Stosb
  1623.  
  1624.  Loop @Escribe
  1625.  
  1626.  Pop Cx
  1627.  
  1628.  Mov Bx,320 { Salta a la siguiente línea }
  1629.  
  1630.  Sub Bx,Ancho
  1631.  
  1632.  Add Di,Bx
  1633.  
  1634.  Loop @Repite
  1635.  
  1636.  Pop Ds
  1637.  
  1638. End; { PROCEDURE PonSprite }
  1639.  
  1640.  
  1641. Procedure LeeSprite;Assembler;
  1642.  
  1643. { Lee una región de la pantalla y la almacena en un buffer }
  1644.  
  1645. Var
  1646.  
  1647.  Ancho,Alto : Word;
  1648.  
  1649. Asm
  1650.  
  1651.  Push Ds
  1652.  
  1653.  Les Di,Graf
  1654.  
  1655.  Xor Ah,Ah
  1656.  
  1657.  Mov Ax,x2
  1658.  
  1659.  Sub Ax,x1
  1660.  
  1661.  Inc Ax
  1662.  
  1663.  Mov word ptr [Es:Di],Ax
  1664.  
  1665.  Mov Ancho,Ax
  1666.  
  1667.  Mov Ax,y2
  1668.  
  1669.  Sub Ax,y1
  1670.  
  1671.  Inc Ax
  1672.  
  1673.  Mov word ptr [Es:Di+2],Ax
  1674.  
  1675.  Mov Alto,Ax
  1676.  
  1677.  Add Di,4
  1678.  
  1679.  Dec Y1
  1680.  
  1681.  Dec X1
  1682.  
  1683.  Mov Ax,320
  1684.  
  1685.  Xor Dx,Dx
  1686.  
  1687.  Mul Y1
  1688.  
  1689.  Add Ax,X1
  1690.  
  1691.  Mov Si,Ax { Calcula la posición de origen }
  1692.  
  1693.  Mov Ax,0A000h
  1694.  
  1695.  Mov Ds,Ax
  1696.  
  1697.  Mov Cx,Alto
  1698.  
  1699. @Repite:
  1700.  
  1701.  Push Cx
  1702.  
  1703.  Mov Cx,Ancho { Almacena cada línea }
  1704.  
  1705.  Rep Movsb
  1706.  
  1707.  Pop Cx
  1708.  
  1709.  Mov Bx,320 { Salta a la siguiente línea }
  1710.  
  1711.  Sub Bx,Ancho
  1712.  
  1713.  Add Si,Bx
  1714.  
  1715.  Loop @Repite
  1716.  
  1717.  Pop Ds
  1718.  
  1719. End; { PROCEDURE LeeSprite }
  1720.  
  1721. Procedure PonPunto;Assembler;
  1722.  
  1723. { Escribe un punto de un color determinado }
  1724.  
  1725. Asm
  1726.  
  1727.  Dec X
  1728.  
  1729.  Dec Y
  1730.  
  1731.  Xor Dx,Dx
  1732.  
  1733.  Mov Ax,320
  1734.  
  1735.  Mul Y
  1736.  
  1737.  Add Ax,X
  1738.  
  1739.  Mov Di,Ax
  1740.  
  1741.  Mov Ax,0A000h
  1742.  
  1743.  Mov Es,Ax
  1744.  
  1745.  Mov Al,Color
  1746.  
  1747.  Mov Es:[Di],Al
  1748.  
  1749. End; { PROCEDURE PonPunto }
  1750.  
  1751. Procedure Escribe;
  1752.  
  1753. { Usando la tabla que hay en la posición $F000:$FA6E y que contiene
  1754.  
  1755.  los caracteres CGA se escribe un texto. }
  1756.  
  1757. Var
  1758.  
  1759.  Linea : Byte;
  1760.  
  1761.  Byt,
  1762.  
  1763.  Bit,Codigo: Byte;
  1764.  
  1765.  Caracter : String[1];
  1766.  
  1767.  Car,Xx,Yy : Integer;
  1768.  
  1769.  Segm,Ofss : Word;
  1770.  
  1771. Begin
  1772.  
  1773.  Xx:=x;
  1774.  
  1775.  Yy:=y;
  1776.  
  1777.  For Car := 0 to Length(Texto)-1 do
  1778.  
  1779.  Begin
  1780.  
  1781.  Caracter:=Copy(Texto,Car+1,1);
  1782.  
  1783.  Codigo:=Ord(Caracter[1]);
  1784.  
  1785.  { Si el carácter es mayor de 127 no aparece en la tabla estándar. Aparece
  1786.  
  1787.  en una tabla en cuya dirección se encuentra el vector de interrupción
  1788.  
  1789.  1Fh. }
  1790.  
  1791.  If Codigo<128 then
  1792.  
  1793.  Begin
  1794.  
  1795.  Segm:=$F000;
  1796.  
  1797.  Ofss:=$FA6E+Codigo*8;
  1798.  
  1799.  End
  1800.  
  1801.  Else
  1802.  
  1803.  Begin
  1804.  
  1805.  Segm:=Seg1F;
  1806.  
  1807.  Ofss:=Ofs1F+Codigo*8;
  1808.  
  1809.  End;
  1810.  
  1811.  { Escribe el carácter. Escribe las 8 líneas de barrido. }
  1812.  
  1813.  For Byt:=0 to 7 do
  1814.  
  1815.  Begin
  1816.  
  1817.  Linea:=Byte(Ptr(Segm,Ofss+Byt)^);
  1818.  
  1819.  Xx:=x+Car*8;
  1820.  
  1821.  Yy:=Y+Byt;
  1822.  
  1823.  { Cada línea de barrido se compone de 8 pixels }
  1824.  
  1825.  For Bit:=0 to 7 do
  1826.  
  1827.  Begin
  1828.  
  1829.  { No hay que escribir }
  1830.  
  1831.  If Linea < $7F then
  1832.  
  1833.  Xx:=Xx+1
  1834.  
  1835.  Else
  1836.  
  1837.  Begin
  1838.  
  1839.  { Escribe el punto }
  1840.  
  1841.  PonPunto(Xx,Yy,Color);
  1842.  
  1843.  Xx:=Xx+1;
  1844.  
  1845.  Linea:=Linea-$80;
  1846.  
  1847.  End;
  1848.  
  1849.  Linea:=Linea Shl 1;
  1850.  
  1851.  End;
  1852.  
  1853.  End;
  1854.  
  1855.  Yy:=Yy-7;
  1856.  
  1857.  End;
  1858.  
  1859. End; { PROCEDURE Escribe }
  1860.  
  1861.  
  1862. Begin
  1863.  
  1864.  Asm
  1865.  
  1866.  Mov Ah,35h
  1867.  
  1868.  Mov Al,1Fh
  1869.  
  1870.  Int 21h { Calcula la dirección de la tabla de caracteres ASCII }
  1871.  
  1872.  Mov Seg1F,Es
  1873.  
  1874.  Mov Ofs1F,Bx
  1875.  
  1876.  End;
  1877.  
  1878. End.
  1879.  
  1880. Miguel Hernández Martos
  1881.  
  1882. Las Gabias (Granada)
  1883.  
  1884.  
  1885. GRAFICOS FRACTALES
  1886.  
  1887. La función de este truco es generar gráficos fractales, más en
  1888. concreto de los conjuntos de Julia. Si deseáis tener más información
  1889. sobre este tipo de conjuntos os recomendamos leer el mencionado «PC
  1890. Práctico».
  1891.  
  1892. El programa es realmente sencillo, por lo que resulta fácil modificar
  1893. algunos parámetros para conseguir otros efectos y así comprender un
  1894. poco más este tipo de gráficos. Es fácil modificar los colores, el
  1895. tamaño del gráfico en pantalla y la región a visualizar.
  1896.  
  1897. Program Fractal;
  1898.  
  1899. Uses Graph, Crt;
  1900.  
  1901. Const
  1902.  
  1903.  PixelH=150;
  1904.  
  1905.  PixelV=100;
  1906.  
  1907.  { Tamaño en pixels del gráfico en pantalla }
  1908.  
  1909.  xsup=-1.8;
  1910.  
  1911.  ysup=1.8;
  1912.  
  1913.  xinf=-1.8;
  1914.  
  1915.  yinf=1.8;
  1916.  
  1917.  {región del fractal a mostrar }
  1918.  
  1919. Var
  1920.  
  1921.  a,b,DeltaX,DeltaY,NewY2,x,y,x1,x2,y1,y2,SumaCuadrados:Real;
  1922.  
  1923.  cont:Byte;
  1924.  
  1925.  i,j,gd,gm,color:Integer;
  1926.  
  1927. Begin
  1928.  
  1929.  ClrScr;
  1930.  
  1931.  WriteLn ('Es necesario introducir el valor de un número imaginario con
  1932.  notación x+yi');
  1933.  
  1934.  Write('Introduzca el valor de x=> ');
  1935.  
  1936.  ReadLn(a);
  1937.  
  1938.  Write('Introduzca el valor de y=> ');
  1939.  
  1940.  ReadLn(b);
  1941.  
  1942.  gm:=Detect;
  1943.  
  1944.  gd:=0;
  1945.  
  1946.  InitGraph(gd,gm,'');
  1947.  
  1948.  x1:=xsup;
  1949.  
  1950.  y1:=ysup;
  1951.  
  1952.  x2:=xinf;
  1953.  
  1954.  y2:=yinf;
  1955.  
  1956.  DeltaX:=(y1-x1)/PixelH;
  1957.  
  1958.  DeltaY:=(y2-x2)/PixelV;
  1959.  
  1960.  For i:= 1 To PixelH do
  1961.  
  1962.  Begin
  1963.  
  1964.  x1:=x1+DeltaX;
  1965.  
  1966.  NewY2:=y2;
  1967.  
  1968.  For j:=1 To PixelV do
  1969.  
  1970.  Begin
  1971.  
  1972.  NewY2:=NewY2-DeltaY;
  1973.  
  1974.  y:=NewY2;
  1975.  
  1976.  x:=x1;
  1977.  
  1978.  cont:=0;
  1979.  
  1980.  SumaCuadrados:=sqr(x)+sqr(y);
  1981.  
  1982.  While (Cont<50) And (SumaCuadrados<100) Do
  1983.  
  1984.  Begin
  1985.  
  1986.  x:=Sqr(x)-Sqr(y)+a;
  1987.  
  1988.  y:=2*x*b+b;
  1989.  
  1990.  SumaCuadrados:=sqr(x)+sqr(y);
  1991.  
  1992.  inc(cont);
  1993.  
  1994.  End;
  1995.  
  1996. { En este bloque se asignan los colores a los puntos dependiendo de la
  1997. velocidad de escape del punto; se pueden modificar para jugar con el
  1998. gráfico }
  1999.  
  2000.  If SumaCuadrados>100 Then
  2001.  
  2002.  Begin
  2003.  
  2004.  If cont<3 Then color:=11
  2005.  
  2006.  Else If Cont<4 Then Color:=9
  2007.  
  2008.  Else If Cont<6 Then Color:=1
  2009.  
  2010.  Else If Cont<8 Then Color:=13
  2011.  
  2012.  Else If Cont<12 Then Color:=5
  2013.  
  2014.  Else If Cont<15 Then Color:=4
  2015.  
  2016.  Else If Cont<20 Then Color:=12
  2017.  
  2018.  Else If Cont<27 Then Color:=2
  2019.  
  2020.  Else If Cont<35 Then Color:=14
  2021.  
  2022.  Else If Cont<45 Then Color:=7
  2023.  
  2024.  Else Color:=8;
  2025.  
  2026.  PutPixel(i,j,color);
  2027.  
  2028.  End;
  2029.  
  2030.  End;
  2031.  
  2032.  End;
  2033.  
  2034.  ReadLn;
  2035.  
  2036.  CloseGraph;
  2037.  
  2038. End.
  2039.  
  2040. Para el correcto funcionamiento del programa deberemos poner el
  2041. driver BGI en el directorio en que se encuentre almacenado o
  2042. bien cambiar la línea:
  2043.  
  2044. InitGraph(gd,gm,'');
  2045.  
  2046. De forma que entre las comillas ponga el directorio donde se
  2047. encuentra el driver BGI que necesitamos usar.
  2048.  
  2049. Juan Carlos Romero
  2050.  
  2051. Trujillo (Cáceres)
  2052.  
  2053.  
  2054. SCROLL DE PELICULA
  2055.  
  2056. Seguro que más de una vez habéis deseado añadir en vuestros programas
  2057. alguna pantalla de presentación como las que aparecen en las películas
  2058. de cine. Pues bien, ahora es posible gracias al siguiente programa,
  2059. con el que podemos conseguir un impresionante efecto de scroll en modo
  2060. texto con una gran suavidad.
  2061.  
  2062. Se pueden añadir tantas líneas de texto como se deseen, incluso hasta
  2063. llenar toda la pantalla: basta con poner tantos «gotoxy (x,y); write
  2064. ('Texto');» como sean necesarios. Los «delay» sirven para ajustar la
  2065. velocidad: si va demasiado lento basta con disminuir su valor,
  2066. mientras que si funciona muy rápido habrá que incrementarlo.
  2067.  
  2068. USES crt;
  2069.  
  2070. VAR
  2071.  
  2072.  b:word;
  2073.  
  2074. BEGIN
  2075.  
  2076.  ClrScr;
  2077.  
  2078.  Gotoxy(34,13);write('*** PC Actual ***');
  2079.  
  2080.  Gotoxy(33,14);write('Scroll de película');
  2081.  
  2082.  Gotoxy(1,24);
  2083.  
  2084.  REPEAT
  2085.  
  2086.  WHILE (Port[$3DA] AND 8)=0 DO ;
  2087.  
  2088.  Portw[$3D4] := $008;
  2089.  
  2090.  Writeln;
  2091.  
  2092.  Delay(15);
  2093.  
  2094.  FOR b:=0 TO $E DO
  2095.  
  2096.  BEGIN
  2097.  
  2098.  WHILE (Port[$3DA] AND 8)=0 DO ;
  2099.  
  2100.  Portw[$3D4]:=$108+B*256;
  2101.  
  2102.  Delay(15);
  2103.  
  2104.  END;
  2105.  
  2106.  UNTIL KeyPressed;
  2107.  
  2108.  Portw[$3D4]:=$08;
  2109.  
  2110. END.
  2111.  
  2112. Santos Herranz Domingo
  2113.  
  2114. Madrid
  2115.  
  2116.  
  2117.  
  2118. VUELO ESPACIAL
  2119.  
  2120. Seguro que uno de los salvapantallas más utilizados por los usuarios
  2121. habituales de Windows es el «Starfield simulation», ya que combina muy
  2122. acertadamente los ingredientes de sencillez y dinamismo. Pues bien,
  2123. con esta rutina también los usuarios del DOS podrán disfrutar de ese
  2124. conocido vuelo espacial.
  2125.  
  2126. Las aplicaciones de esta utilidad pueden ser diversas. Por ejemplo,
  2127. quienes comienzan a programar juegos de arcade la pueden encontrar
  2128. útil como escenario en el que desarrollar la acción. O quienes no
  2129. dispongan de un salvapantallas para DOS la pueden emplear como tal,
  2130. bien activándola cuando se ausenten, bien modificándola de modo que
  2131. quede residente (a tal fin, os recordamos que en nuestro número de
  2132. enero del 93 premiamos un truco titulado «Rutinas residentes», en el
  2133. que se indicaban los pasos a seguir).
  2134.  
  2135. La «velocidad» de nuestro viaje dependerá de la potencia del ordenador
  2136. sobre el que lo ejecutemos, por lo que a los pasajeros que sufran del
  2137. denominado «vértigo espacial» les puede interesar incluir un Delay (n)
  2138. en cualquier punto del código, donde «n» es un número entero que
  2139. indica un retardo en milisegundos.
  2140.  
  2141. USES Graph, Crt;
  2142.  
  2143. TYPE
  2144.  
  2145.  Pointrec = RECORD
  2146.  
  2147.  sX, sY, ox, oy: LongInt;
  2148.  
  2149.  oapo, apo, c : Byte;
  2150.  
  2151.  END;
  2152.  
  2153. VAR
  2154.  
  2155.  Parr : Array[1..255] Of Pointrec;
  2156.  
  2157.  GD,GM,mx,my,I,cc,j,smx,smy : Integer;
  2158.  
  2159.  kl : LongInt;
  2160.  
  2161.  ch : Char;
  2162.  
  2163.  rx,ry,tx,ty : LongInt;
  2164.  
  2165.  starnum,decv : Byte;
  2166.  
  2167. BEGIN
  2168.  
  2169.  IF paramcount=0 THEN starnum:=120 ELSE val(paramstr(1),starnum,i);
  2170.  
  2171.  IF starnum<30 THEN starnum:=120;
  2172.  
  2173.  DetectGraph(GD,GM);
  2174.  
  2175. {la siguiente línea indica el path donde se sitúan los controladores
  2176. gráficos *.bgi dentro de nuestro disco duro}
  2177.  
  2178.  InitGraph(GD,GM,'d:\bp\bgi');
  2179.  
  2180.  mx:=getmaxx; my:=getmaxy; smx:=mx div 2; smy:=my div 2;
  2181.  
  2182.  decv:=starnum div 30;
  2183.  
  2184.  Randomize;
  2185.  
  2186.  FillChar(Parr,SizeOF(Parr),0);
  2187.  
  2188.  FOR i:=1 TO starnum DO WITH Parr[i] DO
  2189.  
  2190.  BEGIN
  2191.  
  2192.  sx:=(random(Succ(mx))-smx)*80; sy:=(random(Succ(my))-smy)*60;
  2193.  
  2194.  apo:=random(200)+decv;
  2195.  
  2196.  c:=Random(7)+1;
  2197.  
  2198.  ox:=sx; oy:=sy; oapo:=apo;
  2199.  
  2200.  END;
  2201.  
  2202.  REPEAT
  2203.  
  2204.  FOR i:=1 TO starnum DO WITH Parr[i] DO
  2205.  
  2206.  BEGIN
  2207.  
  2208.  oapo:=apo; ox:=sx; oy:=sy;
  2209.  
  2210.  dec(apo,decv);
  2211.  
  2212.  RX:=(sx div SUCC(apo))+smx;
  2213.  
  2214.  RY:=(sy div SUCC(apo))+smy;
  2215.  
  2216.  TX:=(ox div SUCC(oapo))+smx;
  2217.  
  2218.  TY:=(oy div SUCC(oapo))+smy;
  2219.  
  2220.  IF (RX>640) OR (RY>480) OR (RX<0) OR (RY<0) OR (APO<decv) THEN
  2221.  
  2222.  BEGIN
  2223.  
  2224.  sx:=(random(Succ(mx))-smx)*80; sy:=(random(Succ(my))-smy)*60;
  2225.  
  2226.  apo:=200+decv;
  2227.  
  2228.  RX:=(sx div SUCC(apo))+smx; RY:=(sy div SUCC(apo))+smy;
  2229.  
  2230.  END;
  2231.  
  2232.  IF apo>120 THEN cc:=C ELSE cc:=C+8;
  2233.  
  2234.  PutPixel(TX,TY,0); PutPixel(RX,RY,cc);
  2235.  
  2236.  IF OAPO<70 THEN PutPixel(TX+1,TY+1,0);
  2237.  
  2238.  IF APO<70 THEN PutPixel(RX+1,RY+1,cc);
  2239.  
  2240.  IF OAPO<60 THEN PutPixel(TX+1,TY,0);
  2241.  
  2242.  IF APO<60 THEN PutPixel(RX+1,RY,cc);
  2243.  
  2244.  IF OAPO<50 THEN PutPixel(TX,TY+1,0);
  2245.  
  2246.  IF APO<50 THEN PutPixel(RX,RY+1,cc);
  2247.  
  2248.  IF OAPO<40 THEN PutPixel(TX-1,TY-1,0);
  2249.  
  2250.  IF APO<40 THEN PutPixel(RX-1,RY-1,cc);
  2251.  
  2252.  IF OAPO<30 THEN PutPixel(TX+2,TY+2,0);
  2253.  
  2254.  IF APO<30 THEN PutPixel(RX+2,RY+2,cc);
  2255.  
  2256.  IF OAPO<20 THEN BEGIN
  2257.  
  2258.  PutPixel(TX+2,TY-1,0); PutPixel(TX-1,TY+2,0);
  2259.  
  2260.  END;
  2261.  
  2262.  IF APO<20 THEN BEGIN
  2263.  
  2264.  PutPixel(RX+2,RY-1,cc); PutPixel(RX-1,RY+2,cc);
  2265.  
  2266.  END;
  2267.  
  2268.  END;
  2269.  
  2270.  UNTIL KeyPressed;
  2271.  
  2272.  WHILE KeyPressed DO ch:= ReadKey;
  2273.  
  2274.  Closegraph;
  2275.  
  2276. END.
  2277.  
  2278. Antonio Delgado García
  2279.  
  2280. Madrid
  2281.  
  2282. Nota del Laboratorio: El programa funciona ejecutando «stars» o
  2283. «stars n», donde «n» es un parámetro que indica el número de estrellas
  2284. que aparecerán en pantalla. Si se introduce sin parámetro sólo
  2285. aparecerán 120 estrellas. Este programa detecta la tarjeta gráfica y
  2286. se adapta a su resolución.
  2287.  
  2288.  
  2289.  
  2290.  
  2291.  
  2292.