home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia Fácil 56 / INF1297.iso / SOFCAS / EDUCA / EVSIM11.ZIP / EV.C < prev    next >
C/C++ Source or Header  |  1996-04-27  |  67KB  |  1,839 lines

  1.  
  2. /*───────────────────────────────────────────────────────────────────\
  3. │                                                                    │
  4. │                               EV 1.1                               │
  5. │                                                                    │
  6. │   PROGRAMA DE SIMULACION GRAFICA DE CAMPOS     (Borland C++  2.0+  │
  7. │   Y POTENCIALES ELECTRICOS Y GRAVITATORIOS     y Turbo Assembler)  │
  8. │                                                                    │
  9. │      (C) 1996  José J. Muñoz García   (hobster@gui.uva.es)         │
  10. │                & Ciriaco G. de Celis  (ciri@gui.uva.es)            │
  11. │                                                                    │
  12. │         Incluir en un fichero de proyecto con EV-SYS.ASM           │
  13. │        El modelo de memoria debe ser necesariamente LARGE          │
  14. │                                                                    │
  15. │   Nota: Puede ser necesario editar Options/Transfer/TurboAssembler │
  16. │         y activar la opción /m5 en la línea de comandos, para      │
  17. │         evitar mensajes de error. Alternativamente, se puede       │
  18. │         introducir ev-sys.obj en lugar de ev-sys.asm en el fichero │
  19. │         de proyecto, obteniéndolo antes con TASM ev-sys /m5 /mx    │
  20. │                                                                    │
  21. \───────────────────────────────────────────────────────────────────*/
  22.  
  23.  
  24.   /* FICHEROS DE CABECERA */
  25.  
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <conio.h>
  29. #include <dos.h>
  30. #include <alloc.h>
  31. #include <string.h>
  32. #include <math.h>
  33.  
  34. unsigned _stklen = 32768;
  35.  
  36.  
  37.   /* CONSTANTES */
  38.  
  39. #define PRESERVAR    1
  40. #define RESTAURAR    2
  41. #define MOSTRAR      3
  42. #define MODO80       4
  43. #define RESALTAR     5
  44. #define MAX_E      100
  45. #define CAMPO        0
  46. #define POTENCIAL    1
  47. #define ELECTRICO    1
  48. #define GRAVITATORIO 2
  49.  
  50. #define M800x600x16      0x102         /* modos VESA de 16c */
  51. #define M800x600x16_S3   0x202
  52. #define M1024x768x16     0x104
  53. #define M1024x768x16_S3  0x204
  54. #define M1280x1024x16    0x106
  55. #define M1280x1024x16_S3 0x208
  56.  
  57.  
  58.   /* TIPOS */
  59.  
  60. typedef enum {CONF, EDIT, LINE, CAMP, POT, INFO, SALIR, IDIOMA} Opciones;
  61.  
  62. typedef struct {
  63.   int   tipo;                /* puede ser ELECTRICO o GRAVITATORIO */
  64.   int   puntuales;           /* número de cargas o masas */
  65.   float puntual [MAX_E][3];  /* (X, Y) de las cargas/masas; valor */
  66.   float xrango, yrango;      /* rango del plano */
  67.   float ajuste;              /* para representación en 256 colores */
  68.   int   lineas;              /* para representación en 16 colores */
  69.   } Sistema;
  70.  
  71. typedef struct {
  72.   char  fabricante;
  73.   char  version;
  74.   char  compresion;
  75.   char  bitspixel;
  76.   short xmin, ymin, xmax, ymax;
  77.   short hdpi, vdpi;
  78.   char  paleta[48];
  79.   char  reservado;
  80.   char  planos;
  81.   short byteslinea;
  82.   short infopaleta;
  83.   short hpantalla;
  84.   short vpantalla;
  85.   char  resto[54];
  86.   } CabeceraPCX;
  87.  
  88.  
  89.   /* PROTOTIPOS */
  90.  
  91. extern void VGAModeX (int);
  92. extern void setpix (int, int, int);
  93. extern void set16pix (int, int, int);
  94. extern void set4pix (int, int, int);
  95. extern void lineahoriz (int, int, int, int);
  96. extern void recta (int, int, int, int, int, int);
  97. extern void setpage (int);
  98. extern void showpage (int);
  99. extern void Xprcar (int, int, int, int, int, int, int, int);
  100. extern int  prcar (int, int, int, int, int);
  101. extern void PintaBitMap (char *, int, int, int, int, int, int, int, int);
  102. extern void MoveVram (void *, void *, int);
  103. extern int  getpix (int, int);
  104. extern int  NoHayTecla (void);
  105. extern void interrupt NuevaInt24 (void);
  106. extern int  segvideo;
  107. extern char far *FuenteInfo;
  108.  
  109. void main (int *, char **),
  110.      Vram (int),
  111.      SetMode (unsigned),
  112.      PaletaEV (void),
  113.      PaletaMenu (void),
  114.      PaletaConf (void),
  115.      Xprcad (char *, int, int, int, int, int, int, int),
  116.      PintaOpcionMenu (Opciones, int),
  117.      PintaOpcionConf (int, int),
  118.      Configurar (int *, int *, int *, int *),
  119.      Ventana (int, int, int, int, int, int),
  120.      Cuadro (int),
  121.      Puntuales (Sistema *, float, float),
  122.      EmulaCursor (int, int, int),
  123.      Cursor (int, int),
  124.      Editar (Sistema *),
  125.      Ayuda (void),
  126.      Grafica256 (Sistema *, int, int),
  127.      Grafica16 (Sistema *, int, int, int),
  128.      Pausa (int, int),
  129.      About (void);
  130.  
  131. int  prcad (char *, int, int, int, int),
  132.      getpix16 (int, int),
  133.      AnimaCursor (int *, int *, float, float),
  134.      input (char *, int, int, int, int, int, int, int),
  135.      PintaModos (int, int),
  136.      SalvaPantalla (int, int),
  137.      PintaEoV (Sistema *, int, int),
  138.      TrazaCampo (Sistema *datos, int, int, int),
  139.      ExisteVGA (void),             /* Detectar VGA */
  140.      TestVESA (void),              /* Detectar soporte VESA */
  141.      ExisteModoVESA (unsigned),    /* Comprobar si un modo es soportado */
  142.      GetBest16 (int *, int *),     /* Obtener mejor modo de 16c */
  143.      HablaSp (void);
  144.  
  145. Opciones Menu (void);
  146.  
  147.  
  148.   /* VARIABLES */
  149.  
  150. int sp = 1,        /* 1 = mensajes en español */
  151.     sonido = 1;    /* 1 = sonido activo       */
  152.  
  153.  
  154.   /* TOLERANCIA A FALLOS (ESTA FUNCION NO DEBERIA EJECUTARSE NUNCA) */
  155.  
  156. int matherr (struct exception *a)
  157. {
  158.   SetMode (0x12);
  159.   prcad ("Error interno de cálculo irrecuperable.", 0, 0, 15, 0);
  160.   prcad ("Pulse una tecla para intentar continuar...", 0, 16, 15, 0);
  161.   while (kbhit()) getch(); if (!getch()) getch();
  162.  
  163.   a->retval = 0;
  164.   main (0, NULL);
  165.   exit (129);
  166.   return 1;
  167. }
  168.  
  169.  
  170.   /* PRESERVAR O RESTAURAR LA PANTALLA DE TEXTO */
  171.  
  172. void Vram (int operacion)
  173. {
  174.   static scr_ok, modo, pag, cx, cy, colorbits;
  175.   static long tam;
  176.   static char *scrbuf;
  177.   union REGS regs;
  178.  
  179.   if (operacion==PRESERVAR) {
  180.     scr_ok=0;
  181.     modo=peekb(0x40, 0x49) & 0x7F;
  182.     if (peekb(0x40, 0x84) < 24) pokeb(0x40, 0x84, 24);
  183.     pag=peekb(0x40,0x62);
  184.     cx=peekb(0x40,0x50+pag*2); cy=peekb(0x40,0x51+pag*2);
  185.     colorbits=peek(0x40, 0x10) & 0x30;
  186.     tam = 2L * (peekb(0x40, 0x84) + 1) * peek (0x40, 0x4A);
  187.     if (tam > 32768L) tam=32768L;
  188.     if ((modo<=3)||(modo==7)) {
  189.       if ((scrbuf=farmalloc(tam))!=NULL) {
  190.         scr_ok=1;
  191.         movedata ((modo==7) ? 0xb000: 0xb800,
  192.                   (modo==7) ? 0     : peek(0x40, 0x4e),
  193.                   FP_SEG(scrbuf), FP_OFF(scrbuf), tam);
  194.         }
  195.       }
  196.     if ((modo!=3) && (modo!=7)) textmode ((modo!=7) ? C80:MONO);
  197.     }
  198.     else if ((operacion==RESTAURAR) || (operacion==MOSTRAR)) {
  199.       poke (0x40, 0x10, peek(0x40, 0x10) & 0xFFCF | colorbits);
  200.       if (modo != (peekb(0x40, 0x49) & 0x7F)) {
  201.           regs.x.ax=modo; int86 (0x10, ®s, ®s);
  202.           }
  203.         else {
  204.           regs.x.ax=0x1003; regs.x.bx=1;
  205.           int86 (0x10, ®s, ®s);
  206.           }
  207.       regs.x.ax=0x500+pag; int86 (0x10, ®s, ®s);
  208.       regs.x.ax=0x200; regs.x.bx=pag<<8;
  209.       regs.h.dh=cy; regs.h.dl=cx; int86 (0x10, ®s, ®s);
  210.       if (scr_ok) {
  211.           movedata (FP_SEG(scrbuf), FP_OFF(scrbuf),
  212.                     (modo==7) ? 0xb000 : 0xb800,
  213.                     (modo==7) ? 0      : peek(0x40, 0x4e), tam);
  214.           if (operacion==RESTAURAR) farfree(scrbuf);
  215.           }
  216.       }
  217.     else if ((operacion==MODO80)) {
  218.       poke (0x40, 0x10, peek(0x40, 0x10) & 0xFFCF | colorbits);
  219.       if (((peekb(0x40, 0x49) & 0x7F) == 0x13) || ((modo!=3) && (modo!=7)))
  220.         textmode ((modo!=7) ? C80:MONO);
  221.       if ((scr_ok) && ((modo==2) || (modo==3) || (modo==7)))
  222.         movedata (FP_SEG(scrbuf), FP_OFF(scrbuf),
  223.                   (modo==7) ? 0xb000 : 0xb800,
  224.                   (modo==7) ? 0      : peek(0x40, 0x4e), tam);
  225.       }
  226. }
  227.  
  228.  
  229.   /* COMPROBAR QUE EXISTE VGA */
  230.  
  231. int ExisteVGA()
  232. {
  233.   struct REGPACK r;
  234.  
  235.   r.r_ax=0x1A00; intr (0x10, &r);
  236.   return ((r.r_ax & 0xFF)==0x1A);
  237. }
  238.  
  239.  
  240.   /* COMPROBAR QUE EXISTE SOPORTE VESA */
  241.  
  242. int TestVESA (void)
  243. {
  244.   struct REGPACK r;
  245.   char far *mem;
  246.   unsigned vesa;
  247.  
  248.   mem = farmalloc (256L);
  249.   r.r_es = FP_SEG (mem);  r.r_di = FP_OFF (mem);
  250.   r.r_ax = 0x4F00; intr (0x10, &r);
  251.   mem[4]=0; if (strcmp (mem, "VESA")==0) vesa=1; else vesa=0;
  252.   farfree (mem);
  253.   return (vesa);
  254. }
  255.  
  256.  
  257.   /* COMPROBAR LA EXISTENCIA DE UN MODO GRAFICO VESA */
  258.  
  259. int ExisteModoVESA (unsigned modo)
  260. {
  261.   struct REGPACK r;
  262.   unsigned far *mem, far *array;
  263.  
  264.   mem = farmalloc (256L);
  265.   r.r_es = FP_SEG (mem);  r.r_di = FP_OFF (mem);
  266.   r.r_ax=0x4F00; intr (0x10, &r);
  267.   array = MK_FP (mem[8], mem[7]);
  268.   farfree (mem);
  269.  
  270.   while ((*array!=0xFFFF) && (*array!=modo)) array++;
  271.   return (*array==modo);
  272. }
  273.  
  274.  
  275.   /* ESTABLECER UN MODO GRAFICO VESA U ORDINARIO */
  276.  
  277. void SetMode (unsigned modo)
  278. {
  279.   struct REGPACK r;
  280.   long far *mem;
  281.  
  282.   if (modo < 0x100) {
  283.       r.r_ax=0x0012;
  284.       intr (0x10, &r);
  285.       }
  286.     else {
  287.       mem = farmalloc (256L);
  288.       r.r_es = FP_SEG (mem);  r.r_di = FP_OFF (mem);
  289.       r.r_ax = 0x4F01; r.r_cx = modo; intr (0x10, &r);
  290.       farfree (mem);
  291.       r.r_ax=0x4F02; r.r_bx=modo; intr (0x10, &r);
  292.       }
  293. }
  294.  
  295.  
  296.   /* OBTENER EL VALOR DE UN PIXEL EN UN MODO VESA U ORDINARIO */
  297.  
  298. int getpix16 (int cx, int cy)
  299. {
  300.   union REGS r;
  301.  
  302.   r.x.ax = 0x0D00;
  303.   r.x.bx = 0;
  304.   r.x.cx = cx;
  305.   r.x.dx = cy;
  306.  
  307.   int86 (0x10, &r, &r);
  308.  
  309.   return (r.h.al);
  310. }
  311.  
  312.  
  313.   /* BUSCAR EL MODO DE 16 COLORES DE MAYOR RESOLUCION (HASTA 1024x768) */
  314.  
  315. int GetBest16 (int *maxx, int *maxy)
  316. {
  317.   if (TestVESA()) {
  318.     *maxx=1024; *maxy=768;
  319.     if (ExisteModoVESA (M1024x768x16))     return (M1024x768x16);
  320.     if (ExisteModoVESA (M1024x768x16_S3))  return (M1024x768x16_S3);
  321.     *maxx=800; *maxy=600;
  322.     if (ExisteModoVESA (M800x600x16))      return (M800x600x16);
  323.     if (ExisteModoVESA (M800x600x16_S3))   return (M800x600x16_S3);
  324.     }
  325.   *maxx=640; *maxy=480;
  326.   return (0x12);
  327. }
  328.  
  329.  
  330.   /* ESTABLECER LA PALETA PARA EL MODULO DEL CAMPO O EL POTENCIAL */
  331.  
  332. void PaletaEV()
  333. {
  334.   unsigned char  dac[256][3];
  335.   union    REGS  r;
  336.   struct   SREGS s;
  337.   register       p;
  338.  
  339.   for (p=191; p>127; p--) {
  340.     dac[p][0]=0;
  341.     dac[p][1]=0;
  342.     dac[p][2]=191-p;
  343.     }
  344.  
  345.   for (p=192; p<256; p++) {
  346.     dac[p][0]=p-192;
  347.     dac[p][1]=0;
  348.     dac[p][2]=0;
  349.     }
  350.  
  351.   r.x.ax=0x1012; r.x.bx=128; r.x.cx=128;
  352.   s.es=FP_SEG(dac); r.x.dx=FP_OFF(&dac[r.x.bx]);
  353.   int86x (0x10, &r, &r, &s);
  354. }
  355.  
  356.  
  357.   /* ESTABLECER LA PALETA PARA EL MENU */
  358.  
  359. void PaletaMenu()
  360. {
  361.   unsigned char  dac[256][3];
  362.   union    REGS  r;
  363.   struct   SREGS s;
  364.   register       i;
  365.  
  366.   for (i=128; i<192; i++) {
  367.     dac[i][0]=0;
  368.     dac[i][1]=0;
  369.     dac[i][2]=i-128;
  370.     }
  371.  
  372.   for (i=208; i<256; i++) {
  373.     dac[i][0]=255-i+16;
  374.     dac[i][1]=0;
  375.     dac[i][2]=((255-i+16) >> 1) + 8;
  376.     }
  377.  
  378.   for (i=192; i<208; i++) {
  379.     dac[i][0]=(208-i) * 3 + 15;
  380.     dac[i][1]=(208-i) * 3 + 15;
  381.     dac[i][2]=0;
  382.     }
  383.  
  384.   for (i=64; i<128; i++) {
  385.     dac[i][0]=0;
  386.     dac[i][1]=127-i;
  387.     dac[i][2]=0;
  388.     }
  389.  
  390.   for (i=32; i<64; i++) {
  391.     dac[i][0]=0;
  392.     dac[i][1]=0;
  393.     dac[i][2]=(64-i)*3/2+15;
  394.     }
  395.  
  396.   dac[20][0]=0;
  397.   dac[20][1]=0;
  398.   dac[20][2]=63;
  399.  
  400.   dac[21][0]=8;
  401.   dac[21][1]=40;
  402.   dac[21][2]=16;
  403.  
  404.   r.x.ax=0x1012; r.x.bx=20; r.x.cx=236;
  405.   s.es=FP_SEG(dac); r.x.dx=FP_OFF(&dac[r.x.bx]);
  406.   int86x (0x10, &r, &r, &s);
  407. }
  408.  
  409.  
  410.   /* ESTABLECER LA PALETA PARA LA CONFIGURACION */
  411.  
  412. void PaletaConf()
  413. {
  414.   unsigned char  dac[256][3];
  415.   union    REGS  r;
  416.   struct   SREGS s;
  417.   register       i;
  418.  
  419.   for (i=128; i<192; i++) {
  420.     dac[i][0]=i-128;
  421.     dac[i][1]=(i-128) >> 1;
  422.     dac[i][2]=0;
  423.     }
  424.  
  425.   for (i=200; i<256; i++) {
  426.     dac[i][0]=0;
  427.     dac[i][1]=(255-i)+8;
  428.     dac[i][2]=0;
  429.     }
  430.  
  431.   dac[199][0]=dac[199][1]=dac[199][2]=63;
  432.   dac[198][0]=dac[198][1]=0; dac[198][2]=63;
  433.   dac[197][0]=dac[197][1]=63; dac[197][2]=0;
  434.   dac[196][0]=63; dac[196][1]=0; dac[196][2]=63;
  435.  
  436.   r.x.ax=0x1012; r.x.bx=128; r.x.cx=128;
  437.   s.es=FP_SEG(dac); r.x.dx=FP_OFF(&dac[r.x.bx]);
  438.   int86x (0x10, &r, &r, &s);
  439. }
  440.  
  441.  
  442.   /* IMPRIMIR CADENA DE CARACTERES EN MODO X */
  443.  
  444. void Xprcad (char *cad, int x, int y, int largo, int alto,
  445.             int tinta, int papel, int escala)
  446. {
  447.   while (*cad) {
  448.     Xprcar (*cad, x, y, largo, alto, tinta, papel, escala);
  449.     x+=largo*8;
  450.     cad++;
  451.     }
  452. }
  453.  
  454.  
  455.   /* IMPRIMIR CADENA DE CARACTERES EN MODO GRAFICO DE 16 COLORES */
  456.  
  457. int prcad (char *cad, int x, int y, int tinta, int papel)
  458. {
  459.   static cx=0, cy=0;
  460.  
  461.   if (x!=-1) cx=x, cy=y;
  462.  
  463.   while (*cad) {
  464.     cx += prcar (*cad, cx, cy, tinta, papel);
  465.     cad++;
  466.     if (cx > 632) cx=0, cy+=16;
  467.     }
  468.  
  469.   if (y==-1) cy+=16, cx=0;
  470.  
  471.   return (cy*256+cx);
  472. }
  473.  
  474.  
  475.   /* LEER CADENA DE CARACTERES POR TECLADO EN MODO 640x480x16 */
  476.  
  477. void EmulaCursor (int x, int y, int insercion)
  478. {
  479.   register i;
  480.  
  481.   outport (0x3CE, 0x1803);
  482.   for (i = insercion? 13:0; i<15; i++) recta (x, y+i, x+8, y+i, 15, 1);
  483.   outport (0x3CE, 0x0003);
  484. }
  485.  
  486.  
  487. int input (char *cad, int modo, int maxcar, int x, int y, int tinta, int papel, int papeli)
  488. {
  489.   int    t, i, px, primeravez=1, cx, xx;
  490.   static insercion=1;
  491.   char   *p, tamcars[80];
  492.  
  493.   px = strlen (cad);
  494.  
  495.   p=cad; cx=x; while (*p) cx += (tamcars[p-cad] = prcar (*p++, cx, y, tinta, papeli));
  496.   xx = cx;
  497.   for (i=px; i<maxcar; i++) cx += (tamcars[i] = prcar (255, cx, y, tinta, papel));
  498.   EmulaCursor (xx, y, insercion);
  499.  
  500.   do {
  501.     if (!(t=getch())) t = getch() << 8;
  502.     if ((primeravez) && (t!=8) && (t!=13) && (t!=27) && (t<256)) cad[0]=px=0;
  503.     primeravez=0;
  504.     switch (t) {
  505.       case 0x4B00: if (px) px--; break;
  506.       case 0x4D00: if (px < strlen(cad)) px++; break;
  507.       case 8:      if (px)
  508.                      for (i=--px; i<=strlen(cad); i++) cad[i]=cad[i+1];
  509.                    break;
  510.       case 0x5300: for (i=px; i<=strlen(cad); i++) cad[i]=cad[i+1]; break;
  511.       case 0x4700: px=0; break;
  512.       case 0x4F00: px = strlen(cad); break;
  513.       case 0x5200: EmulaCursor (xx, y, insercion);
  514.                    insercion ^= 1;
  515.                    EmulaCursor (xx, y, insercion);
  516.       default:     if(
  517.                        (t>=32) && (t<256) && (
  518.                          (modo==0) ||
  519.                          ((modo==1) && (t>='0') && (t<='9')) ||
  520.                          ((modo==2) && (
  521.                            ((t>='0') && (t<='9')) ||  /* Modo 0: Asc */
  522.                            ((t>='a') && (t<='f')) ||  /* Modo 1: Dec */
  523.                            ((t>='A') && (t<='F'))     /* Modo 2: Hex */
  524.                            )
  525.                          )
  526.                        )
  527.                      )
  528.                      if (!insercion) {
  529.                          if (px < maxcar) {
  530.                            cad[strlen(cad)+1]=0;
  531.                            cad[px++]=t;
  532.                            }
  533.                          }
  534.                        else
  535.                          if (strlen(cad) < maxcar) {
  536.                            for (i=strlen(cad); i>=px; i--) cad[i+1]=cad[i];
  537.                            cad[i+1]=t; px++;
  538.                            }
  539.                    break;
  540.       }
  541.     EmulaCursor (xx, y, insercion);
  542.     p=cad; cx=x; while (*p) cx += (tamcars[p-cad] = prcar (*p++, cx, y, tinta, papel));
  543.     for (i=strlen(cad); i<maxcar; i++) cx += (tamcars[i] = prcar (255, cx, y, tinta, papel));
  544.     for (xx=x, i=1; i<=px; i++) xx += tamcars[i];
  545.     EmulaCursor (xx, y, insercion);
  546.   } while ((t!=13) && (t!=27));
  547.  
  548.   EmulaCursor (xx, y, insercion);
  549.  
  550.   if ((t==13) && (strlen(cad)==0)) t=27;  /* campo vacío -> ESC */
  551.  
  552.   return (t==13);
  553. }
  554.  
  555.  
  556.   /* Grabar pantalla gráfica en formato PCX. En el caso de las
  557.      pantallas 320x400 y 320x480 se dobla imaginariamente la
  558.      resolución horizontal (320->640) para mejorar la relación
  559.      de aspecto que presentarán por defecto.                    */
  560.  
  561. int SalvaPantalla (int maxx, int maxy)
  562. {
  563.   CabeceraPCX    cab;
  564.   FILE           *f;
  565.   void interrupt (*ViejaInt24) (void);
  566.   int            cx, cy, pixel, antpixel, pixveces, offset, error,
  567.                  doblar, i, m320;
  568.   static   char  nombre[13]="EV-CAP00.PCX";
  569.   unsigned char  buffer [2049];
  570.   union    REGS  r;
  571.   struct   SREGS s;
  572.  
  573.   if (sonido) for (i=2000; i<2400; i+=40) {
  574.     sound (i);     delay (10);
  575.     sound (i+200); delay (10);
  576.     }
  577.   nosound();
  578.  
  579.   m320   = (maxx==320);
  580.   doblar = (m320 && (maxy>240));
  581.  
  582.   memset (&cab, 0, sizeof(CabeceraPCX));  /* Cabecera estándar PCX */
  583.   cab.fabricante =  10;
  584.   cab.version    =   5;
  585.   cab.compresion =   1;
  586.   cab.bitspixel  =   8;
  587.   cab.xmax       = maxx-1; if (doblar) cab.xmax = maxx*2 - 1;
  588.   cab.ymax       = maxy-1;
  589.   cab.planos     =   1;
  590.   cab.byteslinea = cab.xmax+1;
  591.   cab.infopaleta =   1;
  592.  
  593.   ViejaInt24=getvect(0x24);
  594.   setvect (0x24, NuevaInt24);   /* evitar error crítico */
  595.  
  596.   if ((f=fopen(nombre, "wb")) == NULL) return (1);
  597.   if (fwrite (&cab, 1, sizeof(CabeceraPCX), f) == 0) {
  598.     fclose (f);
  599.     return (1);
  600.     }
  601.  
  602.   offset   = 0;
  603.   pixveces = 1;
  604.   if (maxx==320)
  605.       antpixel = getpix (0, 0);
  606.     else
  607.       antpixel = getpix16 (0, 0);  /* B y N */
  608.   cx = 1;
  609.   cy = 0;
  610.  
  611.   do {
  612.       do {
  613.           if (m320)
  614.               pixel = getpix (cx, cy);
  615.             else
  616.               pixel = getpix16 (cx, cy);
  617.           if ((pixel == antpixel) && ((pixveces<31) || ((pixveces<63) && !doblar)))
  618.                   pixveces++;
  619.               else {
  620.                   if ((pixveces==1) && !doblar && (antpixel<0xC0))
  621.                       buffer[offset++]=antpixel;
  622.                     else {
  623.                       if (doblar)
  624.                           buffer [offset++] = 0xC0 | (pixveces << 1); /* ancho x2 */
  625.                         else
  626.                           buffer [offset++] = 0xC0 | pixveces;
  627.                       buffer [offset++] = antpixel;
  628.                       }
  629.                   antpixel = pixel;
  630.                   pixveces = 1;
  631.                   }
  632.           if (offset >= 2048) {
  633.               if (fwrite (buffer, 1, offset, f) != offset) {
  634.                 fclose (f);
  635.                 return (1);
  636.                 }
  637.               offset = 0;
  638.               }
  639.           cx ++;
  640.       } while (cx < maxx);
  641.       if (m320) lineahoriz (0, cy, 80, 0); else recta (0, cy, maxx, cy, 0, 0);
  642.       cx = 0;
  643.       cy++;
  644.   } while (cy < maxy);
  645.  
  646.   if (fwrite (buffer, 1, offset, f) != offset) {
  647.     fclose (f);
  648.     return (1);
  649.     }
  650.  
  651.   offset = 0;
  652.   if (pixveces>1) {
  653.     if (doblar)
  654.         buffer [offset++] = 0xC0 | (pixveces << 1); /* ancho x2 */
  655.       else
  656.         buffer [offset++] = 0xC0 | pixveces;
  657.     buffer [offset++] = antpixel;
  658.     }
  659.   buffer [offset++] = 0xC1;
  660.   buffer [offset++] = pixel;
  661.  
  662.   buffer [offset++] = 0x0C;  /* paleta de 256 colores */
  663.  
  664.   r.x.ax = 0x1017; r.x.bx = 0; r.x.cx = 256;
  665.   s.es = FP_SEG (&buffer[offset]); r.x.dx = FP_OFF (&buffer[offset]);
  666.   int86x (0x10, &r, &r, &s);    /* obtener paleta */
  667.  
  668.   for (cx = 0; cx < 768; cx++)
  669.     buffer [offset++] <<= 2;          /* 64 -> 256 */
  670.  
  671.   if (fwrite (buffer, 1, offset, f) != offset) {
  672.     fclose (f);
  673.     return (1);
  674.     }
  675.  
  676.   if (sonido) for (i=2400; i>2000; i-=40) {
  677.     sound (i);     delay (10);
  678.     sound (i+200); delay (10);
  679.     }
  680.   nosound();
  681.  
  682.   nombre[7]++; if (nombre[7] > '9') nombre[7]='0', nombre[6]++;
  683.  
  684.   i = (fclose(f) == EOF);
  685.  
  686.   setvect (0x24, ViejaInt24);
  687.  
  688.   return (i);
  689. }
  690.  
  691.  
  692.   /* TRAZAR LA GRAFICA DEL MODULO DEL CAMPO O DEL POTENCIAL */
  693.  
  694. int PintaEoV (Sistema *datos, int ypixels, int EoV)
  695. {
  696.   register x, y;
  697.   double   cx, cy, EV, coc, cx0, cy0, cte;
  698.   int      xx2, yy2, xinc, punt, tec, xpixels=320;
  699.  
  700.   if (!datos->puntuales) {
  701.     Xprcad (sp?"¡No hay datos! ":"    No data!   ",
  702.       44, ypixels/5, 2, ypixels/80, 15, 0xFF, 0);
  703.     Xprcad (sp?"Elige primero la opción de Editar":"   Select first the Edit option  ",
  704.       24, ypixels/2, 1, 1, 15, 0xFF, 0);
  705.     Xprcad (sp?"Pulsa una tecla...":"  Press any key...", 92, ypixels*2/3, 1, 2, 15, 0xFF, 0);
  706.     return ('P');
  707.     }
  708.  
  709.   if (datos->tipo == ELECTRICO) cte=8.987551e9; else cte=6.67259e-11;
  710.  
  711.   xx2 = xpixels >> 1;  yy2 = ypixels >> 1;
  712.  
  713.   /* primera pasada: resolución real
  714.      de 80x120, 80x100, 80x60 ó 80x50: 1/16 de los pixels */
  715.  
  716.   for (y=0; (y<ypixels) && NoHayTecla(); y+=4)
  717.     for (x=0; (x<xpixels) && NoHayTecla(); x+=4) {
  718.       EV = 0.0;
  719.       for (punt = 0; punt < datos->puntuales; punt++) {
  720.         cx = datos->xrango * (x - xx2) / xpixels;
  721.         cy = datos->yrango * (ypixels - 1 - y - yy2) / ypixels;
  722.         cx0 = datos->puntual [punt][0] - cx;
  723.         cy0 = datos->puntual [punt][1] - cy;
  724.         coc = cx0 * cx0 + cy0 * cy0;
  725.         if (EoV) coc = sqrt (coc);   /* r² -> campo, r -> potencial */
  726.         if (coc < 1e-10) coc=1e-10;  /* evitar división por cero */
  727.         EV += cte * datos->puntual[punt][2] / coc;
  728.         }
  729.  
  730.       if (EV>1.0) EV = pow (datos->ajuste, log (EV));  /* reducción logarítmica */
  731.         else if (EV<-1.0) EV = - pow (datos->ajuste, log (-EV)); else EV = 0.0;
  732.  
  733.       if (EV > 63.) EV = 63.; else if (EV < -63.) EV = -63.;
  734.       set16pix (x, y, (int) EV + 192);
  735.       }
  736.  
  737.   /* segunda pasada: resolución real
  738.      de 160x240, 160x200, 160x120 ó 160x100: 3/16 de los pixels */
  739.  
  740.   for (y=0; (y<ypixels) && NoHayTecla(); y+=2) {
  741.     if (y % 4) { x=0; xinc=2; } else { x=2; xinc=4; }
  742.     for (; (x<xpixels) && NoHayTecla(); x+=xinc) {
  743.       EV = 0.0;
  744.       for (punt = 0; punt < datos->puntuales; punt++) {
  745.         cx = datos->xrango * (x - xx2) / xpixels;
  746.         cy = datos->yrango * (ypixels - 1 - y - yy2) / ypixels;
  747.         cx0 = datos->puntual [punt][0] - cx;
  748.         cy0 = datos->puntual [punt][1] - cy;
  749.         coc = cx0 * cx0 + cy0 * cy0;
  750.         if (EoV) coc = sqrt (coc);
  751.         if (coc < 1e-10) coc=1e-10;
  752.         EV += cte * datos->puntual[punt][2] / coc;
  753.         }
  754.  
  755.       if (EV>1.0) EV = pow (datos->ajuste, log (EV));  /* reducción logarítmica */
  756.         else if (EV<-1.0) EV = - pow (datos->ajuste, log (-EV)); else EV = 0.0;
  757.  
  758.       if (EV > 63.) EV = 63.; else if (EV < -63.) EV = -63.;
  759.       set4pix (x, y, (int) EV + 192);
  760.       }
  761.     }
  762.  
  763.   /* última pasada: resolución real
  764.      de 320x480, 360x400, 320x240 ó 320x200: 12/16 de los pixels */
  765.  
  766.   for (y=0; (y<ypixels) && NoHayTecla(); y++) {
  767.     if (y % 2) { x=0; xinc=1; } else { x=1; xinc=2; }
  768.     for (; (x<xpixels) && NoHayTecla(); x+=xinc) {
  769.       EV = 0.0;
  770.       for (punt = 0; punt < datos->puntuales; punt++) {
  771.         cx = datos->xrango * (x - xx2) / xpixels;
  772.         cy = datos->yrango * (ypixels - 1 - y - yy2) / ypixels;
  773.         cx0 = datos->puntual [punt][0] - cx;
  774.         cy0 = datos->puntual [punt][1] - cy;
  775.         coc = cx0 * cx0 + cy0 * cy0;
  776.         if (EoV) coc = sqrt (coc);
  777.         if (coc < 1e-10) coc=1e-10;
  778.         EV += cte * datos->puntual[punt][2] / coc;
  779.         }
  780.  
  781.       if (EV>1.0) EV = pow (datos->ajuste, log (EV));  /* reducción logarítmica */
  782.         else if (EV<-1.0) EV = - pow (datos->ajuste, log (-EV)); else EV = 0.0;
  783.  
  784.       if (EV > 63.) EV = 63.; else if (EV < -63.) EV = -63.;
  785.       setpix (x, y, (int) EV + 192);
  786.       }
  787.     }
  788.  
  789.   if (kbhit()) { tec=getch(); if (!tec) tec=getch() << 8; } else tec=0;
  790.   return (tec);
  791. }
  792.  
  793.  
  794.   /* TRAZAR LA GRAFICA DE LAS LINEAS DE CAMPO */
  795.  
  796. int TrazaCampo (Sistema *datos, int xpixels, int ypixels, int color)
  797. {
  798.   double   PI=3.1415926536, angulo, nlin, maxc, Ei, Ex, Ey, absEy, absEx,
  799.            xi, yi, xf, yf, ix, iy, coc, xinc, yinc, cte,
  800.            alto2pasos, ancho2pasos, pasos2, ancho2, alto2, nancho2, nalto2,
  801.            xpixelsancho, ypixelsalto, xpixels2, ypixels2;
  802.   int      carga, cargas, i, tec, pasos=100, EntraEnOtraCarga,
  803.            signo, deveras, x0, y0, x1, y1;
  804.  
  805.   if (!datos->puntuales) {
  806.     if (sp)
  807.         printf("\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t  ¡No hay datos!\n\n"
  808.                "\t\t\tElige primero la opción de Editar\n\n"
  809.                "\t\t\t\tPulsa una tecla...");
  810.       else
  811.         printf("\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t     No data!   \n\n"
  812.                "\t\t\t   Select first the Edit option\n\n"
  813.                "\t\t\t\t Press any key...");
  814.     return (0);
  815.     }
  816.  
  817.   if (datos->tipo == ELECTRICO) cte=8.987551e9; else cte=6.67259e-11;
  818.  
  819.   /* valores fijos precalculados para acelerar cálculos */
  820.  
  821.   pasos2 = 2*pasos;
  822.   alto2pasos = datos->yrango/2/pasos;  ancho2pasos = datos->xrango/2/pasos;
  823.   ancho2 = datos->xrango/2;  nancho2 = -datos->xrango/2;
  824.   alto2 = datos->yrango/2;  nalto2 = -datos->yrango/2;
  825.   xpixelsancho = xpixels / datos->xrango;  xpixels2 = xpixels / 2;
  826.   ypixelsalto = ypixels / datos->yrango;  ypixels2 = ypixels / 2;
  827.  
  828.   maxc = fabs(datos->puntual[0][2]);
  829.   for (carga=1; carga < datos->puntuales; carga++)
  830.     if (maxc < fabs(datos->puntual[carga][2]))
  831.       maxc = fabs(datos->puntual[carga][2]);
  832.   if (maxc > 1e-99) nlin = datos->lineas / maxc; else nlin=0;
  833.  
  834.   for (carga=0; (carga < datos->puntuales) && (!kbhit()); carga++) {
  835.     if (datos->puntual[carga][2] == 0.0) signo=1; else
  836.       signo = fabs(datos->puntual[carga][2]) / datos->puntual[carga][2];
  837.     cargas = fabs(datos->puntual[carga][2]) * nlin;
  838.     if (cargas)
  839.       for (angulo=0.1; (angulo < 2*PI+0.1) && (!kbhit()); angulo += PI/cargas) {
  840.         for (deveras = (signo==-1)?0:1; deveras < 2; deveras++) {
  841.           xi = cos (angulo) * datos->xrango/pasos + datos->puntual[carga][0];
  842.           yi = sin (angulo) * datos->yrango/pasos + datos->puntual[carga][1]; /* (x, y) iniciales */
  843.           EntraEnOtraCarga=0;
  844.           while (!EntraEnOtraCarga) {
  845.             Ex = Ey = 0.0;
  846.             for (i=0; i<datos->puntuales; i++) {
  847.               ix = xi - datos->puntual[i][0];
  848.               iy = yi - datos->puntual[i][1];
  849.               coc = ix * ix + iy * iy;     /* r² */
  850.               if (coc < 1e-99) coc=1e-99;
  851.               Ei = cte * datos->puntual[i][2] / coc;
  852.               coc = sqrt (coc);
  853.               Ex += Ei * (ix / coc);
  854.               Ey += Ei * (iy / coc);
  855.               }
  856.             absEy = fabs (Ey);
  857.             if (absEy < 1e-99) xinc=0.; else xinc = (Ex * datos->yrango) / (absEy * pasos2);
  858.             if (fabs(xinc) <= ancho2pasos)
  859.                 if (Ey >= 0) yinc = alto2pasos; else yinc = -alto2pasos;
  860.               else {
  861.                 absEx = fabs (Ex);
  862.                 if (absEx < 1e-99) yinc=0.; else yinc = (Ey * datos->xrango) / (absEx * pasos2);
  863.                 if (fabs(yinc) <= alto2pasos)
  864.                     if (Ex >= 0) xinc = ancho2pasos; else xinc = -ancho2pasos;
  865.                 }
  866.             xf = xi + xinc * signo;
  867.             yf = yi + yinc * signo;
  868.             if ((xf < nancho2) ||
  869.                 (xf >  ancho2) ||
  870.                 (yf <  nalto2) ||
  871.                 (yf >   alto2))   break;  /* fuera de la pantalla */
  872.             if (deveras) recta (xi * xpixelsancho + xpixels2,
  873.                                 ypixels2 - yi * ypixelsalto,
  874.                                 xf * xpixelsancho + xpixels2,
  875.                                 ypixels2 - yf * ypixelsalto,
  876.                                 color, 0);
  877.             for (i=0; (i<datos->puntuales) && !EntraEnOtraCarga; i++) {
  878.               if ((fabs (xf - datos->puntual[i][0]) < ancho2pasos) &&
  879.                 (fabs (yf - datos->puntual[i][1]) < alto2pasos)) EntraEnOtraCarga=1;
  880.               }
  881.             xi = xf; yi = yf;
  882.             }
  883.           if (EntraEnOtraCarga) break;
  884.           }
  885.         }
  886.       }
  887.  
  888.   if (kbhit()) {
  889.       tec=getch(); if (!tec) tec=getch() << 8;
  890.       }
  891.     else {
  892.       tec=0;
  893.       for (carga=0; carga < datos->puntuales; carga++)
  894.         for (angulo=0.; angulo < PI; angulo += PI/180) {
  895.           ix = cos (angulo) * datos->xrango/pasos;
  896.           iy = 1.5 * sin (angulo) * datos->yrango/pasos;
  897.           x0 = x1 = (datos->puntual[carga][0] + ix) * xpixelsancho + xpixels2;
  898.           y0 = ypixels2 - (datos->puntual[carga][1] + iy) * ypixelsalto;
  899.           y1 = ypixels2 - (datos->puntual[carga][1] - iy) * ypixelsalto;
  900.           if (x0 < 0) x0=0; if (x0>=xpixels) x0=xpixels-1;
  901.           if (x1 < 0) x1=0; if (x1>=xpixels) x1=xpixels-1;
  902.           if (y0 < 0) y0=0; if (y0>=ypixels) y0=ypixels-1;
  903.           if (y1 < 0) y1=0; if (y1>=ypixels) y1=ypixels-1;
  904.           recta (x0, y0, x1, y1,
  905.                  (datos->puntual[carga][2] >= 0)? 12:9, 0);
  906.           }
  907.       }
  908.  
  909.   return (tec);
  910. }
  911.  
  912.  
  913.   /* PINTAR OPCION DEL MENU PRINCIPAL */
  914.  
  915. void PintaOpcionMenu (Opciones opcion, int modo)
  916. {
  917.   int a, b, c, cy, co, i;
  918.  
  919.   if (modo==RESALTAR)
  920.       a=32, b=21, c=1;
  921.     else {
  922.       a=64, b=0xFF, c=3;
  923.       cy = opcion * 32 + 144;
  924.       for (i=cy; i<cy+32; i++) {
  925.         if (i < 200) co=i/4+142; else co=(399-i)/4+142;
  926.         lineahoriz (3, i, 76, co);
  927.         }
  928.       }
  929.  
  930.   switch (opcion) {
  931.     case CONF:   Xprcad (sp?" Configuración ":" Configuration ", 12, 144, 1, 2, a, b, c);
  932.                  break;
  933.     case EDIT:   Xprcad (sp?" Editar sistema de cargas o masas ":" Edit a mass or load system ", 12, 176, 1, 2, a, b, c);
  934.                  break;
  935.     case LINE:   Xprcad (sp?" Líneas de campo eléct./gravit. ":" Draw elec./grav. field lines ", 12, 208, 1, 2, a, b, c);
  936.                  break;
  937.     case CAMP:   Xprcad (sp?" Gráfica del módulo del vector campo ":" Draw field vector length ", 12, 240, 1, 2, a, b, c);
  938.                  break;
  939.     case POT:    Xprcad (sp?" Gráfica del potencial ":" Draw potential value ", 12, 272, 1, 2, a, b, c);
  940.                  break;
  941.     case INFO:   Xprcad (sp?" Información ":" Information ", 12, 304, 1, 2, a, b, c);
  942.                  break;
  943.     case SALIR:  Xprcad (sp?" Salir ":" Exit ", 12, 336, 1, 2, a, b, c);
  944.     case IDIOMA: Xprcad (sp?" F9 English ":" F9 Español ", 212, 360, 1, 1, 20, 0xFF, 0);
  945.                  break;
  946.     }
  947. }
  948.  
  949.  
  950.   /* MENU PRINCIPAL DEL PROGRAMA */
  951.  
  952. Opciones Menu()
  953. {
  954.   register        i, j, y;
  955.   static Opciones op=IDIOMA, antop=CONF;
  956.   int             tec;
  957.  
  958.   VGAModeX (400);  /* Modo 320x400x256 para el menú principal */
  959.   PaletaMenu();
  960.  
  961.   for (i=142, y=0; i<192; i++)
  962.     for (j=0; j<4; j++, y++) {
  963.       lineahoriz (0, y, 80, i);
  964.       lineahoriz (0, 399-y, 80, i);
  965.       }
  966.  
  967.   Xprcad ("EV", 12, -4, 5, 10, 196, 0xFF, 1);
  968.   Xprcad ("1.1", 92, 68, 2, 4, 196, 0xFF, 2);
  969.  
  970.   Xprcad ("(C) 1996:", 190, 44, 1, 1, 192, 0xFF, 2);
  971.   Xprcad ("José J. Muñoz García", 150, 64, 1, 1, 208, 0xFF, -2);
  972.   Xprcad ("Ciriaco G. de Celis",  154, 84, 1, 1, 192, 0xFF, 2);
  973.  
  974.   if (op==IDIOMA) op=antop;  if (op < 0) op=-op;
  975.  
  976.   for (antop=CONF; antop <= IDIOMA; antop++)
  977.     PintaOpcionMenu (antop, RESTAURAR);
  978.  
  979.   do {
  980.     while (kbhit()) getch();
  981.     PintaOpcionMenu (op, RESALTAR);
  982.     tec = getch(); if (!tec) tec = getch() << 8;
  983.     antop = op;
  984.     switch (tec) {
  985.       case 0x3B00: op=INFO; tec=13; break;
  986.       case 0x4800: if (op > CONF) op--; else op=SALIR; break;
  987.       case 32:
  988.       case 0x5000: if (op < SALIR) op++; else op=CONF; break;
  989.       case 0x4700:
  990.       case 0x4900: op=CONF; break;
  991.       case 0x4F00:
  992.       case 0x5100: op=SALIR; break;
  993.       case 27:     if (op!=SALIR) op=SALIR; else tec=13; break;
  994.       case 0x2D00: op=SALIR; tec=13; break;
  995.       case 0x4300: op=IDIOMA; tec=13; break;
  996.       case 0x4400: SalvaPantalla (320, 400); op = -op; tec=13; break;
  997.       }
  998.     if (op!=antop) PintaOpcionMenu (antop, RESTAURAR);
  999.   } while (tec != 13);
  1000.  
  1001.   return (op);
  1002. }
  1003.  
  1004.  
  1005.   /* PINTAR OPCIONES DE CONFIGURACION */
  1006.  
  1007. void PintaOpcionConf (int opcion, int modo)
  1008. {
  1009.   int a, b, c, cx, cy, co, i;
  1010.  
  1011.   if (modo==RESALTAR)
  1012.       a=0, b=199, c=0;
  1013.     else {
  1014.       a=199, b=0xFF, c=0, cx=8;
  1015.       if (opcion < 4) cy = opcion * 23 + 79;
  1016.         else if (opcion < 8) cy = opcion * 23 + 110;
  1017.         else cy = 306, cx = 16;
  1018.       for (i=cy; i<cy+24; i++) {
  1019.         if (i < 200) co=i/4+142; else co=(399-i)/4+142;
  1020.         lineahoriz (cx, i, 46, co);
  1021.         }
  1022.       }
  1023.  
  1024.   switch (opcion) {
  1025.     case 0: Xprcad (sp?" 640*480   (VGA normal)":" 640*480   (normal VGA)", 32, 79, 1, 1, a, b, c);
  1026.             break;
  1027.     case 1: Xprcad (" 800*600   (VESA)", 32, 102, 1, 1, a, b, c);
  1028.             break;
  1029.     case 2: Xprcad (" 1024*768  (VESA)", 32, 125, 1, 1, a, b, c);
  1030.             break;
  1031.     case 3: Xprcad (" 1280*1024 (VESA)", 32, 148, 1, 1, a, b, c);
  1032.             break;
  1033.     case 4: Xprcad (sp?" 320*200   (VGA normal)":" 320*200   (normal VGA)", 32, 206, 1, 1, a, b, c);
  1034.             break;
  1035.     case 5: Xprcad (sp?" 320*240   (VGA normal)":" 320*240   (normal VGA)", 32, 229, 1, 1, a, b, c);
  1036.             break;
  1037.     case 6: Xprcad (sp?" 320*400   (VGA normal)":" 320*400   (normal VGA)", 32, 252, 1, 1, a, b, c);
  1038.             break;
  1039.     case 7: Xprcad (sp?" 320*480   (VGA normal)":" 320*480   (normal VGA)", 32, 275, 1, 1, a, b, c);
  1040.             break;
  1041.     case 8: Xprcad (sonido?(sp?" Activo      ":" Enabled  "):(sp?" Desactivado ":" Disabled "), 72, 306, 1, 1, a, b, c);
  1042.             break;
  1043.     }
  1044. }
  1045.  
  1046.  
  1047.   /* INDICAR MODOS GRAFICOS SELECCIONADOS */
  1048.  
  1049. int PintaModos (int modo16, int modo256)
  1050. {
  1051.   int m16, m256, cy, co;
  1052.  
  1053.   switch (modo16) {
  1054.     case M800x600x16:
  1055.     case M800x600x16_S3:   m16 = 1; break;
  1056.     case M1024x768x16:
  1057.     case M1024x768x16_S3:  m16 = 2; break;
  1058.     case M1280x1024x16:
  1059.     case M1280x1024x16_S3: m16 = 3; break;
  1060.     default:               m16 = 0; break;
  1061.     }
  1062.  
  1063.   switch (modo256) {
  1064.     case 200: m256 = 0; break;
  1065.     case 240: m256 = 1; break;
  1066.     case 400: m256 = 2; break;
  1067.     case 480: m256 = 3; break;
  1068.     }
  1069.  
  1070.   for (cy=79; cy<175; cy++) {
  1071.     if (cy < 200) co=cy/4+142; else co=(399-cy)/4+142;
  1072.     lineahoriz (5, cy, 2, co);
  1073.     }
  1074.   Xprcar ('√', 20, m16 * 23 + 79, 1, 1, 197, 0xFF, 0);
  1075.  
  1076.   for (cy=206; cy<302; cy++) {
  1077.     if (cy < 200) co=cy/4+142; else co=(399-cy)/4+142;
  1078.     lineahoriz (5, cy, 2, co);
  1079.     }
  1080.   Xprcar ('√', 20, m256 * 23 + 206, 1, 1, 197, 0xFF, 0);
  1081.  
  1082.   return (m16 | (m256 << 8));
  1083. }
  1084.  
  1085.  
  1086.   /* CONFIGURAR */
  1087.  
  1088. void Configurar (int *modo16, int *xpix16, int *ypix16, int *modo256)
  1089. {
  1090.   register i, j, y;
  1091.   static   op=-1;
  1092.   int      antop, v1, v2, v3;
  1093.   int      tec;
  1094.  
  1095.   VGAModeX (400);  /* Modo 320x400x256 para el menú principal */
  1096.   PaletaConf();
  1097.  
  1098.   for (i=142, y=0; i<192; i++)
  1099.     for (j=0; j<4; j++, y++) {
  1100.       lineahoriz (0, y, 80, i);
  1101.       lineahoriz (0, 399-y, 80, i);
  1102.       }
  1103.  
  1104.   Xprcad (sp?"CONFIGURACION":"CONFIGURATION", 108, 6, 1, 3, 192, 0xFF, 3);
  1105.  
  1106.   Xprcad (sp?"Modo gráfico ( 16 colores)":"Graphics mode ( 16 colors)", 12, 56, 1, 1, 0, 0xFF, 0);
  1107.   Xprcad (sp?"Modo gráfico (256 colores)":"Graphics mode (256 colors)", 12, 183, 1, 1, 0, 0xFF, 0);
  1108.   Xprcad (sp?"Soportado":"Supported", 236, 56, 1, 1, 198, 0xFF, 0);
  1109.   Xprcad (sp?"Soportado":"Supported", 236, 183, 1, 1, 198, 0xFF, 0);
  1110.   Xprcad (sp?"Sonido:":"Sound: ", 12, 306, 1, 1, 0, 0xFF, 0);
  1111.   Xprcad (sp?"Cursores \030 \031  Recorrer modos":"Cursors \030 \031   Point modes", 40, 332, 1, 1, 196, 0xFF, 0);
  1112.   Xprcad (sp?"Espacio       Seleccionar modo":"Space         Select mode", 40, 352, 1, 1, 196, 0xFF, 0);
  1113.   Xprcad (sp?"INTRO o ESC   Fin configuración":"ENTER or ESC  End of configuration", 40, 372, 1, 1, 196, 0xFF, 0);
  1114.  
  1115.   for (antop=0; antop <= 8; antop++) PintaOpcionConf (antop, RESTAURAR);
  1116.  
  1117.   i = PintaModos (*modo16, *modo256);
  1118.  
  1119.   if (op==-1) op = i & 0xFF;
  1120.  
  1121.   v1 = ExisteModoVESA (M800x600x16) || ExisteModoVESA (M800x600x16_S3);
  1122.   v2 = ExisteModoVESA (M1024x768x16) || ExisteModoVESA (M1024x768x16_S3);
  1123.   v3 = ExisteModoVESA (M1280x1024x16) || ExisteModoVESA (M1280x1024x16_S3);
  1124.  
  1125.   Xprcad (sp?"Sí":"Yes", 264, 79, 1, 1, 198, 0xFF, 0);
  1126.   Xprcad (v1?(sp?"Sí":"Yes"):"No", 264, 102, 1, 1, 198, 0xFF, 0);
  1127.   Xprcad (v2?(sp?"Sí":"Yes"):"No", 264, 125, 1, 1, 198, 0xFF, 0);
  1128.   Xprcad (v3?(sp?"??":"??"):"No", 264, 148, 1, 1, 198, 0xFF, 0);
  1129.   Xprcad (sp?"Sí":"Yes", 264, 206, 1, 1, 198, 0xFF, 0);
  1130.   Xprcad (sp?"Sí":"Yes", 264, 229, 1, 1, 198, 0xFF, 0);
  1131.   Xprcad (sp?"Sí":"Yes", 264, 252, 1, 1, 198, 0xFF, 0);
  1132.   Xprcad (sp?"Sí":"Yes", 264, 275, 1, 1, 198, 0xFF, 0);
  1133.  
  1134.   do {
  1135.     PintaOpcionConf (op, RESALTAR);
  1136.     tec = getch(); if (!tec) tec = getch() << 8;
  1137.     antop = op;
  1138.     switch (tec) {
  1139.       case 0x4400: SalvaPantalla (320, 400);
  1140.                    tec = 27;
  1141.                    break;
  1142.       case 0x4800: if (op > 0) op--; else op=8;
  1143.                    if ((op==3) && (!v3)) op--;
  1144.                    if ((op==2) && (!v2)) op--;
  1145.                    if ((op==1) && (!v1)) op--;
  1146.                    break;
  1147.       case 0x2D00:
  1148.       case 13:     tec=27;
  1149.       case 32:
  1150.         switch (op) {
  1151.           case 0: *xpix16=640; *ypix16=480; *modo16=0x12; break;
  1152.           case 1: *xpix16=800; *ypix16=600; if (ExisteModoVESA (M800x600x16)) *modo16=M800x600x16; else *modo16=M800x600x16_S3; break;
  1153.           case 2: *xpix16=1024; *ypix16=768; if (ExisteModoVESA (M1024x768x16)) *modo16=M1024x768x16; else *modo16=M1024x768x16_S3; break;
  1154.           case 3: *xpix16=1280; *ypix16=1024; if (ExisteModoVESA (M1280x1024x16)) *modo16=M1280x1024x16; else *modo16=M1280x1024x16_S3; break;
  1155.           case 4: *modo256=200; break;
  1156.           case 5: *modo256=240; break;
  1157.           case 6: *modo256=400; break;
  1158.           case 7: *modo256=480; break;
  1159.           case 8: sonido ^= 1;  break;
  1160.           }
  1161.         PintaModos (*modo16, *modo256);
  1162.         break;
  1163.       case 0x5000: if (op < 8) op++; else op=0;
  1164.                    if ((op==1) && (!v1)) op++;
  1165.                    if ((op==2) && (!v2)) op++;
  1166.                    if ((op==3) && (!v3)) op++;
  1167.                    break;
  1168.       case 0x4700:
  1169.       case 0x4900: op=0; break;
  1170.       case 0x4F00:
  1171.       case 0x5100: op=8; break;
  1172.       }
  1173.     if (op!=antop) PintaOpcionConf (antop, RESTAURAR);
  1174.   } while (tec !=27);
  1175. }
  1176.  
  1177.  
  1178.   /* DIBUJAR UNA VENTANA EN MODO 640x480x16 */
  1179.  
  1180. void Ventana (int x, int y, int largo, int alto, int fondo, int marco)
  1181. {
  1182.   register i;
  1183.  
  1184.   for (i=y-9; i < y+alto+9; i++) recta (x-9, i, x+largo+9, i, fondo, 1);
  1185.  
  1186.   recta (x-5, y-5, x+5+largo, y-5, marco, 1);
  1187.   recta (x-5, y+alto+4, x+5+largo, y+alto+4, marco, 1);
  1188.   recta (x-5, y-5, x-5, y+alto+5, marco, 1);
  1189.   recta (x+5+largo, y-5, x+5+largo, y+alto+5, marco, 1);
  1190. }
  1191.  
  1192.  
  1193.   /* PINTAR RECUADRO INFERIOR Y EJES (EDITOR DE CARGAS O MASAS) */
  1194.  
  1195. void Cuadro (int tipo)
  1196. {
  1197.   int i;
  1198.  
  1199.   prcad ("X              Y              ", 7, 412, 6, 0);
  1200.   prcad ("=", 19, 412, 6, 0);
  1201.   prcad ("=", 140, 412, 6, 0);
  1202.   if (tipo==ELECTRICO)
  1203.       prcad (sp?" SISTEMA DE CARGAS":" ELECTRIC LOADS S.", 250, 412, 10, 0);
  1204.     else
  1205.       prcad (sp?" SISTEMA DE MASAS ":" GRAV. MASS SYSTEM", 250, 412, 10, 0);
  1206.   prcad (sp?"  Usar ":"  Use  ", -1, 0, 7, 0);
  1207.   prcad ("\033", -1, 0, 14, 4);  prcad (" ", -1, 0, 10, 0);
  1208.   prcad ("\030", -1, 0, 14, 4);  prcad (" ", -1, 0, 10, 0);
  1209.   prcad ("\031", -1, 0, 14, 4);  prcad (" ", -1, 0, 10, 0);
  1210.   prcad ("\032", -1, 0, 14, 4);  prcad (" ", -1, 0, 10, 0);
  1211.   prcad (sp?"INTRO":"ENTER", -1, 0, 14, 4);
  1212.   prcad ("  ", -1, 0, 15, 0);
  1213.   prcad ("ESC", -1, 0, 14, 4);
  1214.   prcad (sp?" Fin":" End ", -1, 0, 7, 0);
  1215.  
  1216.   prcad ("F4", 5, 440, 14, 4);
  1217.   if (tipo==ELECTRICO)
  1218.       prcad (sp?" Cambiar cargas -> masas   ":" Change from load to mass  ", -1, 0, 9, 0);
  1219.     else
  1220.       prcad (sp?" Cambiar masas -> cargas   ":" Change from mass to load  ", -1, 0, 9, 0);
  1221.  
  1222.   prcad ("F5", -1, 0, 14, 4);  prcad (sp?" Borrar pantalla (empezar)  ":" Clear screen (to begin)    ", -1, 0, 9, 0);
  1223.   prcad ("F6", -1, 0, 14, 4);
  1224.   if (tipo==ELECTRICO)
  1225.       prcad (sp?" Editar una carga":" Edit one load   ", -1, 0, 9, 0);
  1226.     else
  1227.       prcad (sp?" Editar una masa ":" Edit one mass   ", -1, 0, 9, 0);
  1228.  
  1229.   prcad ("F7", 5, 460, 14, 4); prcad (sp?" Acercar  ":" Zoom in  ", -1, 0, 9, 0);
  1230.   prcad ("F8", -1, 0, 14, 4);  prcad (sp?" Alejar   ":" Zoom out ", -1, 0, 9, 0);
  1231.   prcad ("F9", -1, 0, 14, 4);  prcad (sp?" Nuevo rango   ":" New range     ", -1, 0, 9, 0);
  1232.   prcad ("F2", -1, 0, 14, 4);  prcad (sp?" Grabar a disco  ":" Save to disk    ", -1, 0, 9, 0);
  1233.   prcad ("F3", -1, 0, 14, 4);  prcad (sp?" Cargar de disco":" Load from disk ", -1, 0, 9, 0);
  1234.  
  1235.   recta (0, 406, 639, 406, 3, 1);
  1236.   recta (0, 433, 639, 433, 3, 1);
  1237.   recta (0, 479, 639, 479, 3, 1);
  1238.   recta (0, 406, 0, 479, 3, 1);
  1239.   recta (639, 406, 639, 479, 3, 1);
  1240.   recta (564, 406, 564, 433, 3, 1);
  1241.   recta (403, 406, 403, 433, 3, 1);
  1242.   recta (250, 406, 250, 433, 3, 1);
  1243.  
  1244.   recta (0, 199, 639, 199, 5, 1);
  1245.   recta (0, 200, 639, 200, 5, 1);
  1246.   recta (318, 0, 318, 399, 5, 1);
  1247.   recta (319, 0, 319, 399, 5, 1);
  1248.  
  1249.   for (i=638; i>0; i-=32) {
  1250.     recta (i, 197, i, 203, 5, 1);
  1251.     recta (i+1, 197, i+1, 203, 5, 1);
  1252.     }
  1253.  
  1254.   for (i=7; i<400; i+=32) {
  1255.     recta (316, i, 322, i, 5, 1);
  1256.     recta (316, i+1, 322, i+1, 5, 1);
  1257.     }
  1258. }
  1259.  
  1260.  
  1261.   /* PINTAR CURSOR (EDITOR DE CARGAS O MASAS) */
  1262.  
  1263. void Cursor (int x, int y)
  1264. {
  1265.   outport (0x3CE, 0x1803);  /* activar modo XOR de escritura en vídeo */
  1266.  
  1267.   recta (x+3, y+1, x+9, y+1, 15, 1);
  1268.   recta (x+2, y, x+10, y, 15, 1);
  1269.   recta (x+3, y-1, x+9, y-1, 15, 1);
  1270.  
  1271.   recta (x-3, y+1, x-9, y+1, 15, 1);
  1272.   recta (x-2, y, x-10, y, 15, 1);
  1273.   recta (x-3, y-1, x-9, y-1, 15, 1);
  1274.  
  1275.   recta (x-1, y+3, x-1, y+9, 15, 1);
  1276.   recta (x, y+2, x, y+10, 15, 1);
  1277.   recta (x+1, y+3, x+1, y+9, 15, 1);
  1278.  
  1279.   recta (x-1, y-3, x-1, y-9, 15, 1);
  1280.   recta (x, y-2, x, y-10, 15, 1);
  1281.   recta (x+1, y-3, x+1, y-9, 15, 1);
  1282.  
  1283.   outport (0x3CE, 0x0003);  /* desactivar modo de escritura XOR */
  1284. }
  1285.  
  1286.  
  1287.   /* MOVER EL CURSOR (EDITOR DE CARGAS O MASAS) */
  1288.  
  1289. int AnimaCursor (int *cx, int *cy, float xr, float yr)
  1290. {
  1291.   int           tecla, xx, yy, accion=0, salto=1, tm, incr, maxincr, tics, i;
  1292.   char          cad[12];
  1293.   unsigned long *cbios = MK_FP (0x40, 0x6C),
  1294.                 tiempos[11];
  1295.  
  1296.   xx = *cx; yy = *cy;
  1297.  
  1298.   for (i=tm=0; i<11; i++) tiempos[i]=maxincr=18;
  1299.  
  1300.   Cursor (xx, yy);
  1301.  
  1302.   while (!accion) {
  1303.     sprintf (cad, "%.3E", (xx-319)*xr/620);
  1304.     while (strlen(cad)<11) strcat (cad, "\377");
  1305.     prcad (cad, 32, 412, 12, 0);
  1306.     sprintf (cad, "%.3E", (200-yy)*yr/380);
  1307.     while (strlen(cad)<11) strcat (cad, "\377");
  1308.     prcad (cad, 153, 412, 12, 0);
  1309.  
  1310.     tecla = getch(); if (!tecla) tecla = getch() << 8;
  1311.  
  1312.     tiempos [tm++] = *cbios; if (tm > 10) tm=0;
  1313.     for (i=1, tics=0; i<11; i++) {
  1314.       incr=tiempos[i]-tiempos[i-1]; if (incr > maxincr) maxincr=incr;
  1315.       tics+=incr;
  1316.       }
  1317.     if ((tics < 19) && (maxincr < 10)) salto++; else salto=1, maxincr=0;
  1318.  
  1319.     switch (tecla) {
  1320.       case 0x4800: if (yy > 9+salto) yy -= salto;  else yy=389;  break;
  1321.       case 0x5000: if (yy < 390-salto) yy += salto; else yy=10;  break;
  1322.       case 0x4D00: if (xx < 630-salto) xx += salto; else xx=10;  break;
  1323.       case 0x4B00: if (xx > 9+salto) xx -= salto;  else xx=629;  break;
  1324.       case 13:
  1325.       case 27:
  1326.       case 0x3B00:
  1327.       case 0x3C00:
  1328.       case 0x3D00:
  1329.       case 0x3E00:
  1330.       case 0x3F00:
  1331.       case 0x4000:
  1332.       case 0x4100:
  1333.       case 0x4200:
  1334.       case 0x2D00:
  1335.       case 0x4300:
  1336.       case 0x4400: accion=1; break;
  1337.       }
  1338.     Cursor (*cx, *cy);    /* Borrar cursor previo */
  1339.     Cursor (xx, yy);      /* Pintar el nuevo */
  1340.     *cx = xx; *cy = yy;
  1341.   }
  1342.  
  1343.   Cursor (xx, yy);        /* Borrar cursor al salir */
  1344.   return (tecla);
  1345. }
  1346.  
  1347.  
  1348.   /* PINTAR CARGAS O MASAS PUNTUALES */
  1349.  
  1350. void Puntuales (Sistema *datos, float xr, float yr)
  1351. {
  1352.   int  i, j, x, y, posit;
  1353.   char cad[20];
  1354.  
  1355.   outport (0x3CE, 0x1803);  /* activar modo XOR de escritura en vídeo */
  1356.  
  1357.   for (i=0; i < datos->puntuales; i++) {
  1358.     x = datos->puntual[i][0] / xr * 620 + 319;
  1359.     y = 200 - datos->puntual[i][1] / yr * 380;
  1360.     if ((x < 630) && (x > 8) && (y < 390) && (y > 9)) {
  1361.       posit = (datos->puntual[i][2] >= 0);
  1362.       prcar (posit?'+':'-', x-3, y-7, posit?12:9, 0);
  1363.       for (j = x-5; j < x+6; j++) recta (j, y+5, j, y-6, posit?12:9, 1);
  1364.       sprintf (cad, "%.3E", datos->puntual[i][2]);
  1365.       x = x-40; y = y+10; if (x<0) x=0; if (x>556) x=556; if (y>393) y=393;
  1366.       prcad (cad, x, y, 7, 0);
  1367.       }
  1368.     }
  1369.  
  1370.   outport (0x3CE, 0x0003);  /* desactivar modo de escritura XOR */
  1371. }
  1372.  
  1373.  
  1374.   /* AYUDA DEL EDITOR */
  1375.  
  1376. void Ayuda()
  1377. {
  1378.   int t=15, p=2;
  1379.  
  1380.   Ventana (70, 56, 400, 112, p, t);
  1381.   if (sp) {
  1382.       prcad ("Utilice los cursores y pulse INTRO para colocar", 80,  64, t, p);
  1383.       prcad ("las cargas o las masas.  Los  sistemas de masas", 80,  80, t, p);
  1384.       prcad ("sólo pueden contener masas,  y  los sistemas de", 80,  96, t, p);
  1385.       prcad ("cargas sólo cargas.  Consulte  el  apartado  de", 80, 112, t, p);
  1386.       prcad ("información en el menú principal  para  recibir", 80, 128, t, p);
  1387.       prcad ("orientación acerca de los valores recomendados.", 80, 144, t, p);
  1388.       }
  1389.     else {
  1390.       prcad ("Use the cursor keys and press RETURN to set the", 80,  64, t, p);
  1391.       prcad ("loads and mass.  The mass systems can only hold", 80,  80, t, p);
  1392.       prcad ("mass, and the load systems can only hold loads.", 80,  96, t, p);
  1393.       prcad ("Select the information option in the main  menu", 80, 112, t, p);
  1394.       prcad ("to read some tips about the recommended  values", 80, 128, t, p);
  1395.       prcad ("for load and mass.", 80, 144, t, p);
  1396.       }
  1397.   if (!getch()) getch();
  1398. }
  1399.  
  1400.  
  1401.   /* EDITAR CARGAS O MASAS PUNTUALES */
  1402.  
  1403. void Editar (Sistema *datos)
  1404. {
  1405.   void interrupt (*ViejaInt24) (void);
  1406.   static cx=400, cy=150, primeravez=1, xx, yy;
  1407.   int    tecla, tec, salir=0, i, j, tpok;
  1408.   static char cadp[20], cadrx[20], cadry[20], tipo[20],
  1409.          fichero[60]="EV-01.DAT", cadc[20];
  1410.   char   c0, c1, cad[4];
  1411.   float  valor;
  1412.   FILE   *f;
  1413.  
  1414.   ViejaInt24=getvect(0x24);
  1415.   setvect (0x24, NuevaInt24);   /* evitar error crítico */
  1416.  
  1417.   SetMode (0x12);       /* 640x480x16 */
  1418.   Cuadro (datos->tipo);
  1419.   Puntuales (datos, datos->xrango, datos->yrango);
  1420.  
  1421.   if (primeravez) {
  1422.     Ayuda();
  1423.     SetMode (0x12);
  1424.     Cuadro (datos->tipo);
  1425.     Puntuales (datos, datos->xrango, datos->yrango);
  1426.     primeravez = 0;
  1427.     }
  1428.  
  1429.   while (!salir)
  1430.     switch (AnimaCursor (&cx, &cy, datos->xrango, datos->yrango)) {
  1431.       case 0x3B00: Ayuda();
  1432.                    SetMode (0x12);
  1433.                    Cuadro (datos->tipo);
  1434.                    Puntuales (datos, datos->xrango, datos->yrango);
  1435.                    break;
  1436.       case 0x3C00: Ventana (80, 80, 428, 56, 1, 15);
  1437.                    prcad   (sp?"GRABAR SISTEMA EN DISCO":" SAVE A SYSTEM ON DISK ", 200, 88, 15, 1);
  1438.                    prcad   (sp?"Nombre: ":" Name:  ", 88, 112, 15, 1);
  1439.                    if (input (fichero, 0, 40, 152, 112, 15, 1, 3)) {
  1440.                      if ((f=fopen(fichero, "wt")) == NULL) {
  1441.                          prcad   (sp?"                  ¡ERROR DE DISCO!                 ":"                     DISK ERROR!                   ", 88, 112, 15, 1);
  1442.                          if (!getch()) getch();
  1443.                          }
  1444.                        else {
  1445.                          fprintf (f, (datos->tipo==1)?"EV10-ELECTRICO\n":"EV10-GRAVITATORIO\n");
  1446.                          fprintf (f, "%d %d %d %.8E\n%.3E %.3E\n%d\n", cx, cy, datos->lineas,
  1447.                            datos->ajuste, datos->xrango, datos->yrango,datos->puntuales);
  1448.                          for (i=0; i < datos->puntuales; i++)
  1449.                            fprintf (f, "%.3E %.3E %.3E\n", datos->puntual[i][0],
  1450.                              datos->puntual[i][1], datos->puntual[i][2]);
  1451.                          fclose (f);
  1452.                          }
  1453.                      }
  1454.                    SetMode (0x12);
  1455.                    Cuadro (datos->tipo);
  1456.                    Puntuales (datos, datos->xrango, datos->yrango);
  1457.                    break;
  1458.       case 0x3D00: Ventana (80, 80, 428, 56, 1, 15);
  1459.                    prcad   (sp?"CARGAR SISTEMA DE DISCO":"LOAD A SYSTEM FROM DISK", 200, 88, 15, 1);
  1460.                    prcad   (sp?"Nombre: ":" Name:  ", 88, 112, 15, 1);
  1461.                    if (input (fichero, 0, 40, 152, 112, 15, 1, 3)) {
  1462.                      if ((f=fopen(fichero, "rt")) == NULL) {
  1463.                          prcad   (sp?"                  ¡ERROR DE DISCO!                 ":"                     DISK ERROR!                   ", 88, 112, 15, 1);
  1464.                          if (!getch()) getch();
  1465.                          }
  1466.                        else {
  1467.                          fgets (tipo, 19, f); tpok=1;
  1468.                          if (strstr(tipo, "EV10-ELECTRICO")!=NULL) datos->tipo=ELECTRICO;
  1469.                            else if (strstr(tipo, "EV10-GRAVITATORIO")!=NULL) datos->tipo=GRAVITATORIO;
  1470.                            else tpok=0;
  1471.                          if (tpok) {
  1472.                              fscanf (f, "%d %d %d %f\n%f %f\n%d\n", &cx, &cy, &datos->lineas, &datos->ajuste,
  1473.                                &datos->xrango, &datos->yrango, &datos->puntuales);
  1474.                              for (i=0; i < datos->puntuales; i++)
  1475.                                fscanf (f, "%f %f %f\n", &datos->puntual[i][0],
  1476.                                  &datos->puntual[i][1], &datos->puntual[i][2]);
  1477.                              fclose (f);
  1478.                              }
  1479.                            else {
  1480.                              prcad   (sp?"           FORMATO DE FICHERO DESCONOCIDO          ":"                UNKNOWN FILE FORMAT                ", 88, 112, 15, 1);
  1481.                              if (!getch()) getch();
  1482.                              }
  1483.                          }
  1484.                      }
  1485.                    SetMode (0x12);
  1486.                    Cuadro (datos->tipo);
  1487.                    Puntuales (datos, datos->xrango, datos->yrango);
  1488.                    break;
  1489.       case 0x3E00: Puntuales (datos, datos->xrango, datos->yrango);
  1490.                    if (datos->tipo==ELECTRICO)
  1491.                        datos->tipo=GRAVITATORIO;
  1492.                      else
  1493.                        datos->tipo=ELECTRICO;
  1494.                    Cuadro (datos->tipo);
  1495.                    datos->puntuales = cadp[0] = 0;
  1496.                    break;
  1497.       case 0x3F00: Puntuales (datos, datos->xrango, datos->yrango);
  1498.                    datos->puntuales = cadp[0] = 0;
  1499.                    datos->xrango = 2.5;
  1500.                    datos->yrango = 2.0;
  1501.                    break;
  1502.       case 0x4000: for (i=0; i < datos->puntuales; i++) {
  1503.                      xx = datos->puntual[i][0] / datos->xrango * 620 + 319;
  1504.                      yy = 200 - datos->puntual[i][1] / datos->yrango * 380;
  1505.                      c0 = (i+1)/10 + '0'; c1 = ((i+1) % 10) + '0';
  1506.                      if (c0!='0') prcar (c0, xx-11, yy-24, 15, 0);
  1507.                      prcar (c1, xx-3, yy-24, 15, 0);
  1508.                      }
  1509.                    Ventana (170, 430, 300, 16, 1, 15);
  1510.                    if (datos->tipo==ELECTRICO)
  1511.                        prcad (sp?"Carga":" Load", 178, 430, 15, 1);
  1512.                      else
  1513.                        prcad (sp?"Masa":"Mass", 178, 430, 15, 1);
  1514.                    prcad (sp?" a modificar:":"  to  modify:", -1, 0, 15, 1);
  1515.                    cad[0]=0;
  1516.                    if (input (cad, 1, 3, 330, 430, 15, 1, 3)) {
  1517.                      i = atoi (cad);
  1518.                      if (i && (i <= datos->puntuales)) {
  1519.                        prcad (sp?"Nuevo valor (Q eliminar):":" New value (Q remove it):", 178, 430, 15, 1);
  1520.                        if (input (cadc, 0, 10, 385, 430, 15, 1, 3))
  1521.                          if ((cadc[0]=='q') || (cadc[0]=='Q')) {
  1522.                              while (i <= datos->puntuales)
  1523.                                for (i++, j=0; j<3; j++)
  1524.                                  datos->puntual[i][j] = datos->puntual[i+1][j];
  1525.                              datos->puntuales--;
  1526.                              }
  1527.                            else if ((atof(cadc)!=0.0) || (cadc[0]=='0'))
  1528.                              datos->puntual[i-1][2] = atof(cadc);
  1529.                        }
  1530.                      }
  1531.                    SetMode (0x12);
  1532.                    Cuadro (datos->tipo);
  1533.                    Puntuales (datos, datos->xrango, datos->yrango);
  1534.                    break;
  1535.       case 0x4100: Puntuales (datos, datos->xrango, datos->yrango);
  1536.                    datos->xrango /= 1.1; datos->yrango /= 1.1;
  1537.                    cx = (cx - 319) * 1.1 + 319;
  1538.                    cy = 200 - (200 - cy ) * 1.1;
  1539.                    if (cx>629) cx = 629;  if (cx < 10) cx = 10;
  1540.                    if (cy>389) cy = 389;  if (cy < 10) cy = 10;
  1541.                    Puntuales (datos, datos->xrango, datos->yrango);
  1542.                    break;
  1543.       case 0x4200: Puntuales (datos, datos->xrango, datos->yrango);
  1544.                    datos->xrango *= 1.1; datos->yrango *= 1.1;
  1545.                    cx = (cx - 319) / 1.1 + 319;
  1546.                    cy = 200 - (200 - cy ) / 1.1;
  1547.                    Puntuales (datos, datos->xrango, datos->yrango);
  1548.                    break;
  1549.       case 0x4300: Ventana (150, 152, 340, 90, 1, 15);
  1550.                    prcad   (sp?"Nuevo RANGO del plano":"  New RANGE of plane ", 230, 160, 15, 1);
  1551.                    prcad   (sp?"Anchura del eje X (metros): ":" Width of X axis (meters):  ", 158, 192, 15, 1);
  1552.                    if (input (cadrx, 0, 10, 390, 192, 15, 1, 3))
  1553.                      if ((valor = atof (cadrx)) > 0.0) {
  1554.                        cx = (cx - 319) * (datos->xrango / valor) + 319;
  1555.                        if (cx>629) cx = 629;  if (cx < 10) cx = 10;
  1556.                        datos->xrango = valor;
  1557.                        prcad (sp?"Anchura del eje Y (metros): ":" Width of Y axis (meters):  ", 158, 208, 15, 1);
  1558.                        if (input (cadry, 0, 10, 390, 208, 15, 1, 3))
  1559.                          if ((valor = atof (cadry)) > 0.0) {
  1560.                            cy = 200 - (200 - cy ) * (datos->yrango / valor);
  1561.                            if (cy>389) cy = 389;  if (cy < 10) cy = 10;
  1562.                            datos->yrango = valor;
  1563.                            }
  1564.                        }
  1565.                    SetMode (0x12);
  1566.                    Cuadro (datos->tipo);
  1567.                    Puntuales (datos, datos->xrango, datos->yrango);
  1568.                    break;
  1569.       case 0x4400: Cursor (cx, cy);
  1570.                    SalvaPantalla (640, 480);
  1571.                    Cuadro (datos->tipo);
  1572.                    Puntuales (datos, datos->xrango, datos->yrango);
  1573.                    break;
  1574.       case 13:     xx = cx-150; yy = cy-8;
  1575.                    if (xx>340) xx=340; if (xx<10) xx=10;
  1576.                    if (yy>375) yy=375; if (yy<10) yy=10;
  1577.                    Ventana (xx, yy, 290, 16, 1, 15);
  1578.                    prcad   (sp?"Valor de la ":"  Value for ", xx, yy, 15, 1);
  1579.                    prcad   ((datos->tipo==ELECTRICO)?(sp?"carga (Cul): ":"load (Cul):  "):(sp?"masa (Kg): ":"mass (Kg): "), -1, 0, 15, 1);
  1580.                    if (input (cadp, 0, 10, xx+200, yy, 15, 1, 3)) {
  1581.                      valor = atof (cadp);
  1582.                      if ((valor >= 0.0) || ((valor < 0.0) && (datos->tipo==ELECTRICO)))
  1583.                        if ((valor != 0.0) || (cadp[0]=='0')) {
  1584.                          datos->puntual[datos->puntuales][0] = (cx-319) * datos->xrango / 620;
  1585.                          datos->puntual[datos->puntuales][1] = (200-cy) * datos->yrango / 380;
  1586.                          datos->puntual[datos->puntuales][2] = valor;
  1587.                          datos->ajuste=2.71828182;
  1588.                          datos->lineas=50;
  1589.                          datos->puntuales ++;
  1590.                          }
  1591.                      }
  1592.                    SetMode (0x12);
  1593.                    Cuadro (datos->tipo);
  1594.                    Puntuales (datos, datos->xrango, datos->yrango);
  1595.                    break;
  1596.       case 27:
  1597.       case 0x2D00: salir=1;                                    break;
  1598.       }
  1599.  
  1600.   setvect (0x24, ViejaInt24);
  1601. }
  1602.  
  1603.  
  1604.   /* OPCION DE INFORMACION */
  1605.  
  1606. void About()
  1607. {
  1608.   int c1=9, c2=11, c3=12, c4=14;
  1609.  
  1610.   SetMode (0x12);       /* 640x480x16 */
  1611.  
  1612.   if (sp) {
  1613.       prcad (" INFORMACION ", 254, 0, 14, 4);
  1614.       prcad ("", -1, -1, c1, 0);
  1615.       prcad ("", -1, -1, c1, 0);
  1616.       prcad ("  Este programa traza las líneas de campo (modo 16 colores) de un conjunto de", -1, -1, c1, 0);
  1617.       prcad ("cargas o masas puntuales introducido en la opción de  editar.  También  puede", -1, -1, c1, 0);
  1618.       prcad ("dibujar una representación del módulo del vector campo y del potencial  (modo", -1, -1, c1, 0);
  1619.       prcad ("256 colores).\377Se puede utilizar el rango del plano deseado\377(por defecto,\377unos", -1, -1, c1, 0);
  1620.       prcad ("dos metros de largo y alto) y colocar las cargas o masas en cualquier punto.", -1, -1, c1, 0);
  1621.       prcad ("", -1, -1, c1, 0);
  1622.       prcad ("  Para esas distancias,  son recomendables cargas de nanoculombios (ej. 1e-9)", -1, -1, c2, 0);
  1623.       prcad ("y, tratándose de masas, alrededor de 100 millones de toneladas (ej. 1e11 Kg),", -1, -1, c2, 0);
  1624.       prcad ("otra opción sería modificar el rango propuesto por  defecto.  Se  permite  la", -1, -1, c2, 0);
  1625.       prcad ("introducción de datos en notación científica.", -1, -1, c2, 0);
  1626.       prcad ("", -1, -1, c2, 0);
  1627.       prcad ("  Una vez completado el dibujo, un sonido lo notificará.  Se puede pulsar (+)", -1, -1, c2, 0);
  1628.       prcad ("y (-) para cambiar la intensidad/número de líneas [(*) para restaurar] y  F10", -1, -1, c2, 0);
  1629.       prcad ("para grabar la pantalla en formato PCX,  con\377nombre EV-CAP00.PCX y sucesivos", -1, -1, c2, 0);
  1630.       prcad ("(en los modos 320x400 y 320x480  se\377simula el doble de resolución horizontal", -1, -1, c2, 0);
  1631.       prcad ("para no deformar la relación de aspecto).  La  pulsación  de  cualquier  otra", -1, -1, c2, 0);
  1632.       prcad ("tecla durante o después del proceso de dibujo volverá al menú.", -1, -1, c2, 0);
  1633.       prcad ("", -1, -1, c2, 0);
  1634.       prcad ("  El programa funciona en cualquier PC con  VGA,  si bien es muy recomendable", -1, -1, c3, 0);
  1635.       prcad ("una máquina con coprocesador o un 486-DX o superior. \377Si  la  tarjeta\377gráfica", -1, -1, c3, 0);
  1636.       prcad ("cumple el estándar VESA, podría ser posible alcanzar  1280x1024  puntos en la", -1, -1, c3, 0);
  1637.       prcad ("gráfica de las líneas  de  campo  (si\377el monitor lo soporta). \377La  opción  de", -1, -1, c3, 0);
  1638.       prcad ("configuración permite una flexibilidad total.", -1, -1, c3, 0);
  1639.       prcad ("", -1, -1, c3, 0);
  1640.       prcad ("  EV es un proyecto de software\377científico-educativo  desarrollado  por  José", -1, -1, c4, 0);
  1641.       prcad ("Javier Muñoz García  (Internet E-Mail: hobster@gui.uva.es)  y  Ciriaco\377García", -1, -1, c4, 0);
  1642.       prcad ("de Celis (ciri@gui.uva.es).  La última  versión  de este programa normalmente", -1, -1, c4, 0);
  1643.       prcad ("estará disponible entre otros,\377en ftp://ftp.gui.uva.es/pub/pc/gui/evsim??.zip", -1, -1, c4, 0); }
  1644.     else {
  1645.       prcad (" INFORMATION ", 254, 0, 14, 4);
  1646.       prcad ("", -1, -1, c1, 0);
  1647.       prcad ("", -1, -1, c1, 0);
  1648.       prcad ("  This program draws the field lines of a set of puntual  electric  loads  or", -1, -1, c1, 0);
  1649.       prcad ("gravitational mass introduced by the edit option  (16 colours mode).  It  can", -1, -1, c1, 0);
  1650.       prcad ("also draw a representation of field vector length and the potential (256 col.", -1, -1, c1, 0);
  1651.       prcad ("mode). It is possible to use the desired range of the plane (by default, near", -1, -1, c1, 0);
  1652.       prcad ("to 2 meters width) and to place the loads or mass at any coordinates.", -1, -1, c1, 0);
  1653.       prcad ("", -1, -1, c1, 0);
  1654.       prcad ("  Using such distances,  there  are  recomended nanoculombium loads (vg 1e-9)", -1, -1, c2, 0);
  1655.       prcad ("and, using mass,  close to 100 million of tons\377(for example, 1e11 Kg);  other", -1, -1, c2, 0);
  1656.       prcad ("option would be to modify the proposed range.\377It\377is allowed to introduce data", -1, -1, c2, 0);
  1657.       prcad ("in scientific notation.", -1, -1, c2, 0);
  1658.       prcad ("", -1, -1, c2, 0);
  1659.       prcad ("  Once the draw is completed, a sound will notify it. It is possible to press", -1, -1, c2, 0);
  1660.       prcad ("(+) and (-) to change the intensity/number of lines\377[(*)\377to\377restore defaults]", -1, -1, c2, 0);
  1661.       prcad ("and F10 to save the screen in a PCX file. The screens are saved starting with", -1, -1, c2, 0);
  1662.       prcad ("EV-CAP00.PCX and so on.  Under the 320x400 and 320x480 graphic\377modes,  it\377is", -1, -1, c2, 0);
  1663.       prcad ("simulated a double horizontal resolution\377(to keep the\377aspect ratio).\377To\377press", -1, -1, c2, 0);
  1664.       prcad ("any other key while drawing process is in progress would stop it.", -1, -1, c2, 0);
  1665.       prcad ("", -1, -1, c2, 0);
  1666.       prcad ("  The program works in any PC provided with VGA graphics,  but it is a lot of", -1, -1, c3, 0);
  1667.       prcad ("recommendable a system with mathematic coprocessor or a 486-DX or better.  If", -1, -1, c3, 0);
  1668.       prcad ("the CGA card supports VESA, it would be possible to reach 1280x1024 pixels in", -1, -1, c3, 0);
  1669.       prcad ("the field lines\377graphic  (if  the  monitor  supports\377it). \377The  configuration",-1, -1, c3, 0);
  1670.       prcad ("option allows a total flexibility.", -1, -1, c3, 0);
  1671.       prcad ("", -1, -1, c3, 0);
  1672.       prcad ("  EV is a scientific-educative  software  proyect  developed  by  José Javier", -1, -1, c4, 0);
  1673.       prcad ("Muñoz García  (Internet\377E-Mail:\377hobster@gui.uva.es)  and  by  Ciriaco  García", -1, -1, c4, 0);
  1674.       prcad ("de Celis (ciri@gui.uva.es).  The  latest version of this program should to be", -1, -1, c4, 0);
  1675.       prcad ("available, among other sites, in ftp://ftp.gui.uva.es/pub/pc/gui/evsim??.zip", -1, -1, c4, 0);
  1676.       }
  1677.  
  1678.   Pausa (640, 480);
  1679. }
  1680.  
  1681.  
  1682.   /* PAUSA */
  1683.  
  1684. void Pausa (int xpix, int ypix)
  1685. {
  1686.   int tec;
  1687.  
  1688.   tec=getch(); if (!tec) tec=getch() << 8;
  1689.   if (tec==0x4400)
  1690.     SalvaPantalla (xpix, ypix);  /* F10 */
  1691. }
  1692.  
  1693.  
  1694.   /* GRAFICA EN 16 COLORES DE LAS LINEAS DE CAMPO */
  1695.  
  1696. void Grafica16 (Sistema *datos, int modo16, int xpixels, int ypixels)
  1697. {
  1698.   int    i, tecla, color=10,
  1699.          salir = 0;
  1700.  
  1701.   while (!salir) {
  1702.     SetMode (modo16);
  1703.     tecla = TrazaCampo (datos, xpixels, ypixels, color);
  1704.     if (!tecla) {
  1705.       if (sonido) for (i=1500; i<2000; i+=25) {
  1706.         sound (i);     delay (10);
  1707.         sound (i+200); delay (10);
  1708.         }
  1709.       nosound();
  1710.       tecla=getch(); if (!tecla) tecla=getch() << 8;
  1711.       }
  1712.     switch (tecla) {
  1713.       case 0x4800: color++; if (color>15) color=1; break;
  1714.       case 0x5000: color--; if (color<1) color=15; break;
  1715.       case '+':    datos->lineas +=5;
  1716.                    if (sonido) { sound ((datos->lineas)*25+750); delay (50); nosound(); }
  1717.                    break;
  1718.       case '-':    datos->lineas -=5; if (datos->lineas < 5) datos->lineas = 5;
  1719.                    if (sonido) { sound ((datos->lineas)*25+750); delay (50); nosound(); }
  1720.                    break;
  1721.       case '*':    datos->lineas = 50;
  1722.                    if (sonido) {
  1723.                      sound (2500); delay (200); nosound(); delay (75);
  1724.                      sound (2500); delay (200); nosound();
  1725.                      }
  1726.                    break;
  1727.       case 'P':
  1728.       case 'p':    if (!getch()) getch(); salir=1; break;
  1729.       case 0x4400: SalvaPantalla (xpixels, ypixels);
  1730.                    break;
  1731.       default:     salir++;
  1732.       }
  1733.     }
  1734. }
  1735.  
  1736.  
  1737.   /* GRAFICA EN 256 COLORES DEL MODULO DEL CAMPO O DEL POTENCIAL */
  1738.  
  1739. void Grafica256 (Sistema *datos, int ypixels, int EoV)
  1740. {
  1741.   int          i, tecla,
  1742.                salir = 0;
  1743.  
  1744.   VGAModeX (ypixels);
  1745.   PaletaEV();
  1746.   while (!salir) {
  1747.     tecla = PintaEoV (datos, ypixels, EoV);
  1748.     if (!tecla) {
  1749.       if (sonido) for (i=1500; i<2000; i+=25) {
  1750.         sound (i);     delay (10);
  1751.         sound (i+200); delay (10);
  1752.         }
  1753.       nosound();
  1754.       tecla=getch(); if (!tecla) tecla=getch() << 8;
  1755.       }
  1756.     switch (tecla) {
  1757.       case '+':    datos->ajuste += 0.05;
  1758.                    if (sonido) { sound (((datos->ajuste)-2.71828182)*749+2000); delay (50); nosound(); }
  1759.                    break;
  1760.       case '-':    datos->ajuste -= 0.05; if (datos->ajuste < 0.05) datos->ajuste = 0.05;
  1761.                    if (sonido) { sound (((datos->ajuste)-2.71828182)*749+2000); delay (50); nosound(); }
  1762.                    break;
  1763.       case '*':    datos->ajuste = 2.71828182;
  1764.                    if (sonido) {
  1765.                      sound (2500); delay (200); nosound(); delay (75);
  1766.                      sound (2500); delay (200); nosound();
  1767.                      }
  1768.                    break;
  1769.       case 'P':
  1770.       case 'p':    if (!getch()) getch(); salir=1; break;
  1771.       case 0x4400: SalvaPantalla (320, ypixels);
  1772.                    break;
  1773.       default:     salir++;
  1774.       }
  1775.     }
  1776. }
  1777.  
  1778.  
  1779.   /* DEVOLVER 1 SI MENSAJES EN CASTELLANO */
  1780.  
  1781. int HablaSp()
  1782. {
  1783.   union REGS r; struct SREGS s;
  1784.   char info[2048];
  1785.   int i, idioma, spl[]={54, 591, 57, 506, 56, 593, 503, 34, 63, 502,
  1786.              504, 212, 52, 505, 507, 595, 51, 80, 508, 598, 58, 3, 0};
  1787.  
  1788.   idioma=0;          /* supuesto el inglés */
  1789.  
  1790.   if (_osmajor>=3) {
  1791.     r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
  1792.     intdosx (&r, &r, &s);
  1793.     i=0; while (spl[i++]) if (spl[i-1]==r.x.bx) idioma=1;
  1794.     }
  1795.  
  1796.   return (idioma);
  1797. }
  1798.  
  1799.  
  1800.   /* PROGRAMA PRINCIPAL */
  1801.  
  1802. void main()
  1803. {
  1804.   int     terminar=0, modo16, xpix16, ypix16, modo256=480;
  1805.   Sistema datos;
  1806.  
  1807.   sp = HablaSp();
  1808.  
  1809.   datos.puntuales=0;  /* sin datos al principio */
  1810.   datos.xrango = 2.5;
  1811.   datos.yrango = 2.0;
  1812.   datos.tipo=ELECTRICO;
  1813.  
  1814.   if (!ExisteVGA()) {
  1815.     if (sp)
  1816.         fprintf(stderr, "\nError: Necesarios gráficos VGA o superiores.\n");
  1817.       else
  1818.         fprintf(stderr, "\nError: Needs VGA graphics or better.\n");
  1819.     exit (1);
  1820.     }
  1821.  
  1822.   modo16  = GetBest16 (&xpix16, &ypix16);
  1823.  
  1824.   Vram (PRESERVAR);  /* preservar pantalla previa al programa */
  1825.  
  1826.   do switch (Menu()) {
  1827.     case CONF:       Configurar (&modo16, &xpix16, &ypix16, &modo256); break;
  1828.     case EDIT:       Editar (&datos);                                  break;
  1829.     case LINE:       Grafica16 (&datos, modo16, xpix16, ypix16);       break;
  1830.     case CAMP:       Grafica256 (&datos, modo256, CAMPO);              break;
  1831.     case POT:        Grafica256 (&datos, modo256, POTENCIAL);          break;
  1832.     case INFO:       About();                                          break;
  1833.     case SALIR:      terminar++;                                       break;
  1834.     case IDIOMA:     sp ^= 1;                                          break;
  1835.   } while (!terminar);
  1836.  
  1837.   Vram (RESTAURAR);  /* restaurar pantalla previa al programa */
  1838. }
  1839.