home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 17 / CD_ASCQ_17_101194.iso / vrac / raycst.zip / RAYCAST.CPP < prev    next >
C/C++ Source or Header  |  1994-05-13  |  11KB  |  467 lines

  1. #include <dos.h>
  2. #include <conio.h>
  3. #include <math.h>
  4. #include <stdio.h>
  5. #include <alloc.h>
  6. #include <bios.h>
  7. #include "video.h"
  8.  
  9. #define RAYLENGTH 60
  10. #define MAXLENGTH 220
  11. #define WORLDX 256
  12. #define WORLDY 256
  13. #define WORLDSIZE 65535
  14. // The altitude of the helicopter. (Above ground)
  15. #define USERALT 16
  16. #define BUFSEG FP_SEG(Buffer)
  17. #define BUFOFS FP_OFF(Buffer);
  18.  
  19. struct RGB {
  20.     byte red;
  21.     byte green;
  22.     byte blue;
  23. };
  24.  
  25. unsigned far char* World;
  26. unsigned far char* Color;
  27. unsigned far char* Sky;
  28. unsigned far char* Cockpit;
  29. int sine[1280];
  30. int cosine[1280];
  31. int startpostable [MAXLENGTH+50];
  32. char far* Buffer;
  33. int USERX;
  34. int USERY;
  35. int USERA;
  36.  
  37. void DrawSky (int Angle,int l)
  38. // Draw the sky.
  39. {
  40.   unsigned int BufSeg=BUFSEG;
  41.   unsigned int SkySeg=FP_SEG (Sky);
  42.   asm{
  43.      push es
  44.      push di
  45.      push ds
  46.      push si
  47.  
  48.      mov ax,SkySeg // Set DS:SI to the sky picture
  49.      mov ds,ax
  50.      mov ax,Angle
  51.      add ax,4
  52.      mov si,ax
  53.  
  54.      mov ax,BufSeg // Set ES:DI to the Screen buffer
  55.      mov es,ax
  56.      mov ax,l
  57.      mov di,ax
  58.  
  59.      mov cx,200 // The number of rows
  60.  
  61.      CopyLoop:
  62.      mov al,[ds:si]
  63.      mov [es:di],al
  64.      add di,320
  65.      add si,320
  66.      dec cx
  67.      jnz CopyLoop
  68.  
  69.      pop si
  70.      pop ds
  71.      pop di
  72.      pop es
  73.   };
  74. };
  75.  
  76. void DrawIt(int startpos, int r, int xpos, int OldPos, unsigned char c)
  77. {
  78.     unsigned int BufSeg = FP_SEG (Buffer);
  79.     if ((startpos < 200) && (OldPos <200))
  80.     {
  81.     asm{
  82.         push es
  83.         push di
  84.  
  85.         mov ax,r             // <---- Here
  86.         cmp ax,10
  87.         ja  IsBigger
  88.  
  89.         // If r is less than 25, that is, the ray is closer than 25 units
  90.         // from the viewer, use this method.
  91.         // The reason why I use this method is that you'll get transparent
  92.         // ground otherwise.
  93.         mov ax,BufSeg
  94.         mov es,ax
  95.  
  96.         mov ax,63680
  97.         add ax,xpos
  98.         mov di,ax
  99.  
  100.         mov cx,200  // Set CX to the number of pixels to be written
  101.         sub cx,OldPos //startpos
  102.         jmp near Draw
  103.         // End of r<=25
  104.  
  105.         //If r is greater than 25....
  106.         IsBigger:                   // <---- And here
  107.         mov ax,startpos            // See if we need to draw.
  108.         cmp ax,OldPos
  109.         jng NoDraw   // No. Skip this position.
  110.         mov ax,BufSeg // Set ES:DI to the lowest pixel in the column (StartPos)
  111.         mov es,ax
  112.  
  113.         mov ax,startpos
  114.         mov dx,320
  115.         mul dx
  116.         add ax,xpos
  117.         mov di,ax
  118.  
  119.         mov cx,startpos  // SΣtt CX to the number of pixels to be written
  120.         sub cx,OldPos
  121.         // End of r>25
  122.  
  123.         Draw: // Draw the column
  124.  
  125.         mov al,c  //Set AL to the color of the pixel
  126.  
  127.         DrawLoop:     // And draw it.
  128.         mov [es:di],al
  129.         sub di,320
  130.         dec cx
  131.         jnz DrawLoop
  132.  
  133.         NoDraw:
  134.         pop di
  135.         pop es
  136.      };
  137.   };
  138. };
  139.  
  140. void DrawLine (int xpos)
  141. // This routine draws column xpos on the screen. Xpos ranges from 0 to 319, and
  142. // the whole screen is a quarter of a full circle (1280 degrees in THIS system).
  143. // Using Sine and Cosine values and then interpolating
  144. // between them must be the slowest possible method available.
  145. // Feel free to optimize.
  146. {
  147.   int Alt=(World[(USERY<<8)+USERX]+USERALT); // Get the altitude of the viewer
  148.   int OldPos=199; // Used to speed up drawing
  149.   int Angle=(xpos+USERA)%1280; // The angle of the column
  150.   DrawSky (Angle%320,xpos); // Draw the sky.
  151.  
  152.   int x1=(USERX+(cosine [Angle]));//%WORLDX;
  153.   int y1=(USERY-(sine [Angle]));//%WORLDY;
  154.   int x2=USERX;
  155.   int y2=USERY;
  156.  
  157.   int y_unit,x_unit; // Variables for amount of change
  158.                             //  in x and y
  159.  
  160.   unsigned int offset=y1*256+x1; // Calculate offset into video RAM
  161.  
  162.   int ydiff=y2-y1;   // Calculate difference between
  163.                             //  y coordinates
  164.   if (ydiff<0) // If the line moves in the negative direction
  165.   {
  166.      ydiff=-ydiff;    // ...get absolute value of difference
  167.      y_unit=-256;     // ...and set negative unit in y dimension
  168.   }
  169.   else y_unit=256;   // Else set positive unit in y dimension
  170.  
  171.   int xdiff=x2-x1;    // Calculate difference between x coordinates
  172.   if (xdiff<0)       // If the line moves in the negative direction
  173.   {
  174.       xdiff=-xdiff;    // ...get absolute value of difference
  175.       x_unit=-1;        // ...and set negative unit in x dimension
  176.   }
  177.   else x_unit=1;          // Else set positive unit in y dimension
  178.  
  179.   int error_term=0;            // Initialize error term
  180.   if (xdiff>ydiff) // If difference is bigger in x dimension
  181.   {
  182.      int length=xdiff+1;    // ...prepare to count off in x direction
  183.      for (int i=length; i>0; i--)// Loop through points in x direction
  184.      {
  185.         offset+=x_unit;                // Move offset to next pixel in x direction
  186.         error_term+=ydiff;        // Check to see if move required in y direction
  187.         if (error_term>xdiff)
  188.         {    // If so...
  189.           error_term-=xdiff;        // ...reset error term
  190.           offset+=y_unit;                // ...and move offset to next pixel in y dir.
  191.         };
  192.         // Get the color for the point (x,y) and the right altitude for it.
  193.         byte c=Color [offset];
  194.         long height = ((World [offset]-Alt)<<4)/i;
  195.  
  196.         // Perspective transform
  197.         int startpos = startpostable [i];
  198.         startpos -= height;
  199.  
  200.         // OK, draw it!
  201.         DrawIt (startpos,i,xpos,OldPos,c);
  202.         if (i==26)
  203.           DrawIt (startpos,25,xpos,OldPos,c);
  204.  
  205.         OldPos = startpos;  // Used to speed up rendering.
  206.      };
  207.   }
  208.   else
  209.   {                                // If difference is bigger in
  210.                                 //  y dimension
  211.      int length=ydiff+1;    // ...prepare to count off in
  212.                                 //  y direction
  213.      for (int i=length; i>0; i--)
  214.      {    // Loop through points in y direction
  215.         offset+=y_unit;                // Move offset to next pixel
  216.                                      //  in y direction
  217.         error_term+=xdiff;    // Check to see if move
  218.                                      //  required in x direction
  219.         if (error_term>0)
  220.         {        // If so...
  221.           error_term-=ydiff;    // ...reset error term
  222.           offset+=x_unit;            // ...and move offset to next pixel in x dir.
  223.         };
  224.         // Get the color for the point (x,y) and the right altitude for it.
  225.         byte c=Color [offset];
  226.         long height = ((World [offset]-Alt)<<4)/i;
  227.  
  228.         // Perspective transform
  229.         int startpos = startpostable [i];
  230.         startpos -= height;
  231.  
  232.         // OK, draw it!
  233.         DrawIt (startpos,i,xpos,OldPos,c);
  234.         if (i==26)
  235.           DrawIt (startpos,25,xpos,OldPos,c);
  236.  
  237.         OldPos = startpos;  // Used to speed up rendering.
  238.      };
  239.   };
  240. };
  241.  
  242. void InitSinCos(void)
  243. // Setup Sine and cosine tables.
  244. {
  245.     printf ("InitSinCos :");
  246.     for (int a=0;a<1280;a++)
  247.     {
  248.         float A=a;
  249.         A=A/(320/0.5); // A divided by 320/FOV in radians
  250.         A=A*M_PI;
  251.         sine [a]=sin (A)*100;
  252.         cosine [a]=cos (A)*100;
  253.         if ((a%100)==0) printf (">");
  254.     };
  255. };
  256.  
  257. void InitStartPosTable(void)
  258. // Speed up prespective transformations by using lookup tables.
  259. {
  260.     printf ("\nInit Startpos :");
  261.     for (int i=1;i<(RAYLENGTH+50);i++)
  262.     {
  263.         startpostable [i] =500/i+80;
  264.         // The number 80 above is the y position of the horizon.
  265.         // To simulate tilting the helicopter forward, decrease it to 20 or 40
  266.         // increase it to tilt backwards.
  267.         if ((i%10)==0) printf (">");
  268.     };
  269. };
  270.  
  271. void DupCols(void)
  272. // If you only draw every other column, duplicate the columns here.
  273. {
  274.     unsigned int BufSeg=BUFSEG;
  275.     asm{
  276.         push es
  277.         push di
  278.         push ds
  279.         push si
  280.  
  281.         mov ax,BufSeg // DS:SI = Buffer
  282.         mov ds,ax
  283.         mov ax,0
  284.         mov si,ax
  285.  
  286.         mov ax,BufSeg // ES:DI = Buffern+1
  287.         mov es,ax
  288.         mov ax,1
  289.         mov di,ax
  290.  
  291.         mov cx,32000 // Set CX to the number of WORDS in the Buffer
  292.  
  293.         CopyLoop:
  294.         mov al,[ds:si]
  295.         add si,2
  296.         mov [es:di],al
  297.         add di,2
  298.         dec cx
  299.         jnz CopyLoop
  300.  
  301.         pop si
  302.         pop ds
  303.         pop di
  304.         pop es
  305.     };
  306. };
  307.  
  308. void BlitBuffer (void)
  309. // Move the buffer to the screen at A000:0000.
  310. {
  311.     unsigned int BufSeg=BUFSEG;
  312.     asm{
  313.         push es
  314.         push di
  315.         push ds
  316.         push si
  317.  
  318.         mov ax,BufSeg // Set DS:SI to the buffer
  319.         mov ds,ax
  320.         mov ax,0
  321.         mov si,ax
  322.  
  323.         mov ax,0xA000 // Set ES:DI to the screen
  324.         mov es,ax
  325.         mov ax,0
  326.         mov di,ax
  327.  
  328.         mov cx,32000 // Set cx to the number of WORDS
  329.  
  330.         cld
  331.         rep movsw
  332.  
  333.         pop si
  334.         pop ds
  335.         pop di
  336.         pop es
  337.     };
  338. };
  339.  
  340. void DrawCockpit(void)
  341. // Blit the instrument panel image.
  342. {
  343.     unsigned int BufSeg=BUFSEG;
  344.     unsigned int CockpitSeg=FP_SEG (Cockpit);
  345.     asm{
  346.         push es
  347.         push di
  348.         push ds
  349.         push si
  350.  
  351.         mov ax,CockpitSeg // Set DS:SI to pint to the instrument panel image
  352.         mov ds,ax
  353.         mov ax,8
  354.         mov si,ax
  355.  
  356.         mov ax,BufSeg // Set ES:DI to point to the Buffer
  357.         mov es,ax
  358.         mov ax,0
  359.         mov di,ax
  360.  
  361.         mov cx,63999 // Set cx to the number of BYTES
  362.  
  363.         cld
  364.  
  365.         DrawLoop:
  366.         lodsb
  367.         cmp al,9
  368.         jz Transparent
  369.         stosb
  370.         jmp near Done
  371.         Transparent:
  372.         inc di
  373.         Done:
  374.         dec cx
  375.         jnz DrawLoop
  376.  
  377.         lodsb
  378.         stosb
  379.  
  380.         pop si
  381.         pop ds
  382.         pop di
  383.         pop es
  384.     };
  385. };
  386.  
  387. #pragma argsused
  388. void main (int argc, char *argv[])
  389. {
  390.     InitSinCos();
  391.     InitStartPosTable();
  392.     Buffer = (byte far*) farmalloc (64000);
  393.  
  394.     printf ("\nReading data files....");
  395.  
  396.     FILE *Data = fopen ("ALTITUDE.BMP","rb");
  397.     World = (unsigned char far*) farmalloc (WORLDSIZE);
  398.     fseek (Data,1078,SEEK_SET);
  399.     fread ((void*)World,WORLDSIZE,1,Data);
  400.     fclose (Data);
  401.  
  402.     Data=fopen ("COLOR.BMP","rb");
  403.     Color = (unsigned char far*) farmalloc (WORLDSIZE);
  404.     fseek (Data,1078,SEEK_SET);
  405.     fread ((void*)Color,WORLDSIZE,1,Data);
  406.     fclose (Data);
  407.  
  408.     Data=fopen ("SKY.BMP","rb");
  409.     Sky = (unsigned char far*) farmalloc (64000);
  410.     fseek (Data,1078,SEEK_SET);
  411.     fread ((void*)Sky,64000,1,Data);
  412.     fclose (Data);
  413.  
  414.     Data=fopen ("CPIT.BMP","rb");
  415.     Cockpit = (unsigned char far*) farmalloc (64000);
  416.     fseek (Data,1078,SEEK_SET);
  417.     fread ((void*)Cockpit,64000,1,Data);
  418.     fclose (Data);
  419.  
  420.     VidOn();
  421.  
  422.     palLoad ("RAYCAST.COL");
  423.     palSet();
  424.  
  425.     USERX=100; // Starting position
  426.     USERY=100;
  427.     USERA=960; // Starting angle.
  428.  
  429.     long starttime=biostime (0,0);
  430.     int frames=0;
  431.  
  432. /* The program currently draws *every* column.
  433.     To speed things up (Comanche "big pixels"), implement the changes. */
  434.     while (!kbhit())
  435.     {
  436.         for (int l=0;l<320;l++)  // Replace l++ with l+=2.
  437.         {
  438.             DrawLine (l);
  439.         };
  440. //        DupCols();      // Remove the comment sign ("//")
  441.         DrawCockpit();
  442.         BlitBuffer();
  443.         USERX++;
  444.         USERY++;
  445. //        USERA++;        // UnComment this line to rotate.
  446. //        USERA%=1280;    // If you rotate, you need this line.
  447.         USERX=USERX%WORLDX;
  448.         USERY=USERY%WORLDY;
  449.         frames++;
  450.     };
  451.     starttime=biostime (0,0)-starttime;
  452.  
  453.     getch();
  454.     farfree ((void *)Color);
  455.     farfree ((void *)World);
  456.     farfree ((void *)Buffer);
  457.     farfree ((void *)Sky);
  458.     farfree ((void *)Cockpit);
  459.     VidOff();
  460.     int FPS=(frames*10)/((starttime*10)/182);
  461.     int AFT=((starttime*1000)/182)/frames;
  462.     // FPS if frames per second times 10, so a FPS of 27 means 2.7 frames per second.
  463.     // AFT is the average frame time in 1/100s of a second.
  464.     printf ("FPS=%d    AFT=%d/100\nPress any key....",FPS,AFT);
  465.     getch();
  466. };
  467.