home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / 3DENGINE.ZIP / Raycast.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-16  |  19.8 KB  |  646 lines

  1. // Filnamn: RAYCAST.CPP
  2. // Datum: 1996-02-20
  3. // Info: Innehåller funktioner för raycasting.
  4. //=========================================================================
  5. //
  6. // INCLUDES
  7. //
  8. //=========================================================================
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <math.h>
  12. #include "raycast.h"
  13. #include "pcx.h"
  14. #include "dos.h"
  15. #include "ray.h"
  16. #include "trig.h"
  17. #include "fixpoint.h"
  18. #include "objdraw.h"
  19.  
  20. //=========================================================================
  21. //
  22. // External variables:
  23. //
  24. //=========================================================================
  25. extern unsigned char far *texturelist[NUMTEXTURES];
  26. extern objtype obj[NUMOBJECTS];
  27. extern map_type objmap, walls, ceiling, flor;
  28.  
  29. //=========================================================================
  30. //
  31. // GLOBAL CONSTANTS & VARIABLES.
  32. //
  33. //=========================================================================
  34. int VIEWPORT_LEFT=0;          // Dimensions of viewport
  35. int VIEWPORT_RIGHT=319;
  36. int VIEWPORT_TOP=0;
  37. int VIEWPORT_BOT=169;
  38. int VIEWPORT_HEIGHT=VIEWPORT_BOT-VIEWPORT_TOP+1;
  39. int VERT_CENTER=VIEWPORT_TOP+VIEWPORT_HEIGHT/2;
  40. int VIEWPORT_WIDTH=VIEWPORT_RIGHT-VIEWPORT_LEFT+1;
  41. int HORIZ_CENTER=VIEWPORT_LEFT+VIEWPORT_WIDTH/2;
  42. unsigned char *screen_buffer;        // Off screen buffer
  43. unsigned char bottoms[320],tops[320];  // Lookup table containing wall height
  44. extern int objptr[16][16];                    // Array holding objects' positions
  45. unsigned int dist[320];                        // Pre-calculated distances
  46. int visible[16][16];                            // Visibility array
  47. int objlist[MAXOBJECTS];                    // Array holding sorted objects
  48. unsigned char litetable[MAXLIGHT+1][PALETTESIZE]; // Color array
  49. float wallangle[320];
  50. int distance_table[MAXDISTANCE];
  51. int wheight[MAXDISTANCE];
  52. unsigned char *litelevel=new unsigned char[MAXDISTANCE];
  53. unsigned char *texturelist[15];
  54. int column_angle1, column_angle2;
  55. long viewing_angle=130;
  56. long ambient_level=10;
  57. long xview=6*64+32;
  58. long yview=6*64+32;
  59. long nextx;
  60. long nexty;
  61. door doors[10];
  62. int xmaze,ymaze;     // Map location of ray collision
  63. char MAX_DOORS;
  64.  
  65. // Coordinates for viewport size
  66. vp_size viewport_size[5] = {{0, 0, 319, 169},
  67.                                      {20, 15, 299, 154},
  68.                                      {45, 30, 270, 139},
  69.                                      {75, 45, 244, 124},
  70.                                      {110, 60, 209, 109}};
  71.  
  72. /*
  73. ===================
  74. = getdistance()
  75. = Calculates distance from player
  76. = to wall intersection.
  77. = Uses inline function for maximum
  78. = speed.
  79. ===================
  80. */
  81. inline int getdistance(long degrees,int column_angle,long x,long y)
  82. {
  83.   long trig,fix_ny,fix_nx;
  84.   int distance;
  85.  
  86.   int c=degrees>>9;
  87.   if (((c&3)==0)||((c&3)==3))
  88.      distance=abs(fixdiv((y-((long)yview<<SHIFT))>>SHIFT,
  89.       COS(degrees-((c<<10)<<1)))*cos_table[column_angle]>>SHIFT);
  90.   else
  91.      distance=abs(fixdiv((x-((long)xview<<SHIFT))>>SHIFT,
  92.       SIN(degrees-((c<<10)<<1)))*cos_table[column_angle]>>SHIFT);
  93.   return(distance);
  94. }
  95.  
  96.  
  97.  
  98. /*
  99. =============================
  100. =
  101. = draw_maze()
  102. = Hjärnan i raycasting-motorn. Gör det
  103. = egentliga grovjobbet.
  104. =
  105. =============================
  106. */
  107. void draw_maze(unsigned char far **textmaps, unsigned char **objects)
  108.  
  109. // Draws a raycast image in the viewport of the maze represented
  110. // in array MAP[], as seen from position XVIEW, YVIEW by a
  111. // viewer looking at angle VIEWING_ANGLE where angle 0 is due
  112. // north.
  113.  
  114. {
  115.     // Variable declarations:
  116.     int sy,offset;       // Pixel y position and offset
  117.     long fix_xd,fix_yd;         // Distance to next wall in x and y
  118.     int grid_x,grid_y;   // Coordinates of x and y grid lines
  119.     long fix_xcross_x,fix_xcross_y; // Ray intersection coordinates
  120.     long fix_ycross_x,fix_ycross_y;
  121.     unsigned int xdist,ydist; // Distance to x and y grid lines
  122.     int distance;  // Distance to wall along ray
  123.     int tmcolumn;        // Column in texture map
  124.     int top,bot;
  125.     long fix_yratio;
  126.     int degrees, viewer_height = 32;
  127.     int column_angle;
  128.     int index;
  129.     long far *clock = (long far *)0x0000046CL; // Pointer to internal timer
  130.  
  131.     for (int ysquare=0; ysquare<16; ysquare++)
  132.         for (int xsquare=0; xsquare<16; xsquare++)
  133.             visible[xsquare][ysquare]=0;
  134.  
  135.     // Loop through all columns of pixels in viewport:
  136.     for (int column=VIEWPORT_LEFT; column<=VIEWPORT_RIGHT; column++)
  137.     {
  138.         // Calculate horizontal angle of ray relative to
  139.         //  center ray:
  140.         column_angle=wallangle[column];
  141.         if (column_angle<0) column_angle+=NUMBER_OF_DEGREES;
  142.         if (column_angle>NUMBER_OF_DEGREES-1) column_angle-=NUMBER_OF_DEGREES;
  143.  
  144.         // Calculate angle of ray relative to maze coordinates
  145.         degrees=viewing_angle+column_angle;
  146.         if (degrees>NUMBER_OF_DEGREES-1) degrees-=NUMBER_OF_DEGREES;
  147.  
  148.         // Rotate endpoint of ray to viewing angle:
  149.         int x2 = fixmul(-256L<<SHIFT,SIN(degrees))>>SHIFT;
  150.         int y2 = fixmul(256L<<SHIFT,COS(degrees))>>SHIFT;
  151.  
  152.         // Translate relative to viewer's position:
  153.         x2+=xview;
  154.         y2+=yview;
  155.  
  156.         // Initialize ray at viewer's position:
  157.         long fix_x=(long)xview<<SHIFT;
  158.         long fix_y=(long)yview<<SHIFT;
  159.  
  160.         // Find difference in x,y coordinates along ray:
  161.         long xdiff=x2-xview;
  162.         long ydiff=y2-yview;
  163.  
  164.         // Cheat to avoid divide-by-zero error:
  165.         if (xdiff==0) xdiff=1;
  166.         if (ydiff==0) ydiff=1;
  167.  
  168.         // Get slope of ray:
  169.         long fix_slope = fixdiv((long)ydiff<<SHIFT,(long)xdiff<<SHIFT);
  170.  
  171.         // Cast ray from grid line to grid line:
  172.         for (;;)
  173.         {
  174.  
  175.             // If ray direction positive in x, get next x grid line:
  176.             if (xdiff>0) grid_x=((fix_x>>SHIFT) & 0xffc0) + 64;
  177.  
  178.             // If ray direction negative in x, get last x grid line:
  179.             else grid_x=((fix_x>>SHIFT) & 0xffc0) - 1;
  180.  
  181.             // If ray direction positive in y, get next y grid line:
  182.             if (ydiff>0) grid_y=((fix_y>>SHIFT) & 0xffc0) + 64;
  183.  
  184.             // If ray direction negative in y, get last y grid line:
  185.             else grid_y=((fix_y>>SHIFT) & 0xffc0) - 1;
  186.  
  187.             // Get x,y coordinates where ray crosses x grid line:
  188.             fix_xcross_x = (long) grid_x << SHIFT;
  189.             fix_xcross_y = fix_y + fixmul(fix_slope,((long)grid_x<<SHIFT)-fix_x);
  190.  
  191.             // Get x,y coordinates where ray crosses y grid line:
  192.             fix_ycross_x=fix_x+fixdiv((((long)grid_y<<SHIFT)-fix_y),fix_slope);
  193.             fix_ycross_y=(long)grid_y<<SHIFT;
  194.  
  195.             // Get distance to x grid line:
  196.             distance=getdistance(degrees,column_angle,fix_xcross_x,fix_xcross_y);
  197.             xdist=distance;
  198.  
  199.             // Get distance to y grid line:
  200.             distance=getdistance(degrees,column_angle,fix_ycross_x,fix_ycross_y);
  201.             ydist=distance;
  202.  
  203.             // If x grid line is closer...
  204.             if (xdist<ydist)
  205.             {
  206.  
  207.                 // Calculate maze grid coordinates of square:
  208.                 xmaze=fix_xcross_x>>22;
  209.                 ymaze=fix_xcross_y>>22;
  210.  
  211.                 // Set x and y to point of ray intersection:
  212.                 fix_x=fix_xcross_x;
  213.                 fix_y=fix_xcross_y;
  214.  
  215.                 // Find relevant column of texture map:
  216.                 tmcolumn = (fix_y>>SHIFT) & 0x3f;
  217.  
  218.                 // Is there a maze cube here? If so, stop looping:
  219.                 if (walls[xmaze][ymaze])
  220.                 {
  221.                     // Did the ray hit a door?
  222.                     if (walls[xmaze][ymaze] == 4)
  223.                     {
  224.                         // If so, find that door:
  225.                         index = GetDoorID(xmaze, ymaze);
  226.  
  227.                         // Should this part of the door be rendered?
  228.                         tmcolumn -= doors[index].position;
  229.  
  230.                         // If so, break out of the iteration...
  231.                         if ((tmcolumn << 6) < doors[index].position) break;
  232.                     }
  233.                     else break;
  234.                 }
  235.                 else visible[xmaze][ymaze] = -1;
  236.             }
  237.             else
  238.             { // If y grid line is closer:
  239.  
  240.                 // Calculate maze grid coordinates of square:
  241.                 xmaze=fix_ycross_x>>22;
  242.                 ymaze=fix_ycross_y>>22;
  243.  
  244.                 // Set x and y to point of ray intersection:
  245.                 fix_x=fix_ycross_x;
  246.                 fix_y=fix_ycross_y;
  247.  
  248.                 // Find relevant column of texture map:
  249.                 tmcolumn = (fix_x>>SHIFT) & 0x3f;
  250.  
  251.                 // Is there a maze cube here? If so, stop looping:
  252.                 if (walls[xmaze][ymaze])
  253.                 {
  254.                     // Did the ray hit a door?
  255.                     if (walls[xmaze][ymaze] == 4)
  256.                     {
  257.                         // If so, find the door in the table
  258.                         index = GetDoorID(xmaze, ymaze);
  259.  
  260.                         // Should this part of the door be rendered?
  261.                         tmcolumn -= doors[index].position;
  262.  
  263.                         // If so, break out of the iteration...
  264.                         if ((tmcolumn << 6) < doors[index].position) break;
  265.                     }
  266.                     else
  267.                         break;
  268.                 }
  269.                 else visible[xmaze][ymaze] = -1;
  270.             }
  271.         }
  272.  
  273.         // Get distance from viewer to intersection point:
  274.         distance=getdistance(degrees,column_angle,fix_x,fix_y);
  275.  
  276.         if (distance==0) distance=1;
  277. //        if (walls[xmaze][ymaze] == 4) distance += 32;
  278.  
  279.         dist[column]=distance;
  280.  
  281.         // Calculate visible height of wall:
  282.         int height = wheight[distance];
  283.         if (!height) height=1;
  284.  
  285.         // Calculate bottom of wall on screen:
  286.         bot = distance_table[distance];
  287.  
  288.         // Calculate top of wall on screen:
  289.         top = bot - height + 1;
  290.  
  291.         // Initialize temporary offset into texture map:
  292.         int t=(tmcolumn<<6)+IMAGE_HEIGHT;
  293.  
  294.         // If top of current vertical line is outside of
  295.         // viewport, clip it:
  296.         long dheight=height;
  297.         long iheight=IMAGE_HEIGHT;
  298.         long fix_yratio=fixdiv((long)WALL_HEIGHT<<SHIFT,(long)height<<SHIFT);
  299.         if (top < VIEWPORT_TOP) {
  300.             int diff=VIEWPORT_TOP-top;
  301.             dheight-=diff;
  302.             iheight -= (diff*fix_yratio)>>SHIFT;
  303.             top=VIEWPORT_TOP;
  304.         }
  305.         if (bot >= VIEWPORT_BOT) {
  306.             int diff=bot-VIEWPORT_BOT;
  307.             dheight -= diff;
  308.             iheight -= diff*fix_yratio>>SHIFT;
  309.             t-=(diff*fix_yratio)>>SHIFT;
  310.             bot=VIEWPORT_BOT + 1;
  311.         }
  312.  
  313.         // Save top and bottom in arrays:
  314.         tops[column]=top;
  315.         bottoms[column]=bot;
  316.  
  317.         // Point to video memory offset for top of line:
  318.         offset = (bot<<8)+(bot<<6) + column;
  319.  
  320.         // Which graphics tile are we using?
  321.         int tile=walls[xmaze][ymaze]-1;
  322.  
  323.         long fix_increment=fixdiv(iheight<<SHIFT,dheight<<SHIFT);
  324.         int level=litelevel[distance]+ambient_level;
  325.         if (level>MAXLIGHT) level=MAXLIGHT;
  326.         drawwall(&(screen_buffer[offset]),&(textmaps[tile][t]),dheight,
  327.                      fix_increment,&(litetable[level][0]));
  328.  
  329.     }
  330.  
  331.     // The whole door is now rendered, let's open it some more...
  332.     if (doors[index].state == DOOR_OPENING) doors[index].position -= doors[index].speed;
  333.  
  334.     // If the door is closing, close it some more!
  335.     if (doors[index].state == DOOR_CLOSING) doors[index].position += doors[index].speed;
  336.  
  337.     // If no part of the door is visible, then the door must be open, huh?
  338.     if (doors[index].position <= 4032 && doors[index].state == DOOR_OPENING)
  339.     {
  340.         doors[index].state = DOOR_OPEN;
  341.         doors[index].time = *clock;   // Get current time
  342.     }
  343.  
  344.     // If door is closed, then indicate this by setting door state properly...
  345.     if (doors[index].position >= 4096 && doors[index].state == DOOR_CLOSING)
  346.         doors[index].state = DOOR_CLOSED;
  347.  
  348.     // Check current time. If 60 clock ticks (about 40 seconds) has passed
  349.     // since the door was entirely open, then start closing it...
  350.     if (doors[index].state == DOOR_OPEN)
  351.         if (*clock - doors[index].time > 60) doors[index].state = DOOR_CLOSING;
  352.  
  353.  
  354.     // Step through floor pixels:
  355.  
  356.     for (int row=VERT_CENTER+5; row<=VIEWPORT_BOT; row++) {
  357.  
  358.         // Calculate horizontal angle of leftmost column relative to
  359.         //  center ray:
  360.         column_angle = column_angle1;
  361.         if (column_angle<0) column_angle+=NUMBER_OF_DEGREES;
  362.         if (column_angle>NUMBER_OF_DEGREES-1) column_angle-=NUMBER_OF_DEGREES;
  363.  
  364.         // Calculate angle of ray relative to maze coordinates
  365.         int degrees=viewing_angle+column_angle;
  366.         if (degrees>NUMBER_OF_DEGREES-1) degrees-=NUMBER_OF_DEGREES;
  367.  
  368.         // Get ratio of viewer's height to pixel height:
  369.         long fix_ratio=fixdiv((long)viewer_height<<SHIFT,(long)(row-VERT_CENTER)<<SHIFT);
  370.  
  371.         // Get distance to visible pixel:
  372.         long fix_distance=fixdiv((fix_ratio<<7)+(fix_ratio<<6),COS(column_angle));
  373.  
  374.         // Rotate distance to ray angle:
  375.         int left_x = - (fixmul(fix_distance,SIN(degrees))>>SHIFT);
  376.         int left_y = fixmul(fix_distance,COS(degrees))>>SHIFT;
  377.  
  378.         // Translate relative to viewer coordinates:
  379.         left_x+=xview;
  380.         left_y+=yview;
  381.  
  382.         // Calculate horizontal angle of rightmost column relative to
  383.         //  center ray:
  384.         column_angle = column_angle2;
  385.         if (column_angle<0) column_angle+=NUMBER_OF_DEGREES;
  386.         if (column_angle>NUMBER_OF_DEGREES-1) column_angle-=NUMBER_OF_DEGREES;
  387.  
  388.         // Calculate angle of ray relative to maze coordinates
  389.         degrees=viewing_angle+column_angle;
  390.         if (degrees>NUMBER_OF_DEGREES-1) degrees-=NUMBER_OF_DEGREES;
  391.  
  392.         // Get ratio of viewer's height to pixel height:
  393. //        fix_ratio=fixdiv((long)viewer_height<<SHIFT,(long)(row-VERT_CENTER)<<SHIFT);
  394.  
  395.         // Get distance to visible pixel:
  396. //        fix_distance=fixdiv((fix_ratio<<7)+(fix_ratio<<6),COS(column_angle));
  397.  
  398.         // Rotate distance to ray angle:
  399.         int right_x = - (fixmul(fix_distance,SIN(degrees))>>SHIFT);
  400.         int right_y = fixmul(fix_distance,COS(degrees))>>SHIFT;
  401.  
  402.         // Translate relative to viewer coordinates:
  403.         right_x+=xview;
  404.         right_y+=yview;
  405.  
  406.         // Calculate stepping increment:
  407.         long fix_x_increment=fixdiv((long)(right_x-left_x)<<SHIFT,
  408.                                      (long)(VIEWPORT_RIGHT-VIEWPORT_LEFT)<<SHIFT);
  409.         long fix_y_increment=fixdiv((long)(right_y-left_y)<<SHIFT,
  410.                                      (long)(VIEWPORT_RIGHT-VIEWPORT_LEFT)<<SHIFT);
  411.         long fix_x=(long)left_x<<SHIFT;
  412.         long fix_y=(long)left_y<<SHIFT;
  413.  
  414.         int level=litelevel[fix_distance>>SHIFT]+ambient_level;
  415.         if (level>MAXLIGHT) level=MAXLIGHT;
  416.  
  417.         drawfloorrow(row,&(screen_buffer[(row<<8)+(row<<6)+VIEWPORT_LEFT]),
  418.                          &(texturelist[0]),&flor[0][0],
  419.                          &(litetable[level][0]),
  420.                          &(bottoms[VIEWPORT_LEFT]),fix_x_increment,
  421.                          fix_y_increment,fix_x,fix_y,VIEWPORT_WIDTH);
  422.      }
  423.  
  424.      // Step through ceiling pixels:
  425.  
  426.      for (row=VERT_CENTER-5; row>=VIEWPORT_TOP; --row) {
  427.  
  428.         // Calculate horizontal angle of leftmost column relative to
  429.         //  center ray:
  430.         int column_angle = column_angle1;
  431.         if (column_angle<0) column_angle+=NUMBER_OF_DEGREES;
  432.         if (column_angle>NUMBER_OF_DEGREES-1) column_angle-=NUMBER_OF_DEGREES;
  433.  
  434.         // Calculate angle of ray relative to maze coordinates
  435.         int degrees=viewing_angle+column_angle;
  436.         if (degrees>NUMBER_OF_DEGREES-1) degrees-=NUMBER_OF_DEGREES;
  437.  
  438.         // Get ratio of viewer's height to pixel height:
  439.         long fix_ratio=fixdiv((long)(WALL_HEIGHT-viewer_height)<<SHIFT,
  440.                           (long)(VERT_CENTER-row)<<SHIFT);
  441.  
  442.         // Get distance to visible pixel:
  443.         long fix_distance=fixdiv((fix_ratio<<7)+(fix_ratio<<6),COS(column_angle));
  444.  
  445.         // Rotate distance to ray angle:
  446.         int left_x = - (fixmul(fix_distance,SIN(degrees))>>SHIFT);
  447.         int left_y = fixmul(fix_distance,COS(degrees))>>SHIFT;
  448.  
  449.         // Translate relative to viewer coordinates:
  450.         left_x+=xview;
  451.         left_y+=yview;
  452.  
  453.         // Calculate horizontal angle of rightmost column relative to
  454.         //  center ray:
  455.         column_angle= column_angle2;
  456.         if (column_angle<0) column_angle+=NUMBER_OF_DEGREES;
  457.         if (column_angle>NUMBER_OF_DEGREES-1) column_angle-=NUMBER_OF_DEGREES;
  458.  
  459.         // Calculate angle of ray relative to maze coordinates
  460.         degrees=viewing_angle+column_angle;
  461.         if (degrees>NUMBER_OF_DEGREES-1) degrees-=NUMBER_OF_DEGREES;
  462.  
  463.         // Get ratio of viewer's height to pixel height:
  464. //        fix_ratio=fixdiv((long)(WALL_HEIGHT-viewer_height)<<SHIFT,(long)(VERT_CENTER-row)<<SHIFT);
  465.  
  466.         // Get distance to visible pixel:
  467. //        fix_distance=fixdiv((fix_ratio<<7)+(fix_ratio<<6),COS(column_angle));
  468.  
  469.         // Rotate distance to ray angle:
  470.         int right_x = - (fixmul(fix_distance,SIN(degrees))>>SHIFT);
  471.         int right_y = fixmul(fix_distance,COS(degrees))>>SHIFT;
  472.  
  473.         // Translate relative to viewer coordinates:
  474.         right_x+=xview;
  475.         right_y+=yview;
  476.  
  477.         // Calculate stepping increment:
  478.         long fix_x_increment=fixdiv((long)(right_x-left_x)<<SHIFT,
  479.                                      (long)(VIEWPORT_RIGHT-VIEWPORT_LEFT)<<SHIFT);
  480.         long fix_y_increment=fixdiv((long)(right_y-left_y)<<SHIFT,
  481.                                      (long)(VIEWPORT_RIGHT-VIEWPORT_LEFT)<<SHIFT);
  482.         long fix_x=(long)left_x<<SHIFT;
  483.         long fix_y=(long)left_y<<SHIFT;
  484.  
  485.         int level=litelevel[fix_distance>>SHIFT]+ambient_level;
  486.         if (level>MAXLIGHT) level=MAXLIGHT;
  487.  
  488.         drawceilrow(row,&(screen_buffer[(row<<8)+(row<<6)+VIEWPORT_LEFT]),
  489.                         &(texturelist[0]),&ceiling[0][0],
  490.                         &(litetable[level][0]),
  491.                         &(tops[VIEWPORT_LEFT]),fix_x_increment,
  492.                         fix_y_increment,fix_x,fix_y,VIEWPORT_WIDTH);
  493.      }
  494.  
  495.   int numobjs=0;
  496.   for (xsquare=0; xsquare<16; xsquare++) {
  497.      for (ysquare=0; ysquare<16; ysquare++) {
  498.         if (visible[xsquare][ysquare]) {
  499.           int objnum=objmap[xsquare][ysquare];
  500.           if (objnum) {  // If fixed object
  501.              --objnum;
  502.              int x=obj[objnum].mazex-xview;
  503.              int y=obj[objnum].mazey-yview;
  504.              int alignx=(x*COS(-viewing_angle)
  505.                      - y*SIN(-viewing_angle))>>16;
  506.              int aligny=(x*SIN(-viewing_angle)
  507.                      + y*COS(-viewing_angle))>>16;
  508.              if (aligny>=0) {
  509.                 distance=sqrt((long)alignx*alignx+(long)aligny*aligny);
  510.                 int projx=-(long)alignx*VIEWER_DISTANCE/distance+HORIZ_CENTER;
  511.                 obj[objnum].wdraw=obj[objnum].wbit*VIEWER_DISTANCE/
  512.                       distance;
  513.                 obj[objnum].hdraw=obj[objnum].hbit*VIEWER_DISTANCE/
  514.                       distance;
  515.                 obj[objnum].screenx=projx-(obj[objnum].wdraw >> 1);
  516.                 obj[objnum].screeny=VERT_CENTER-(obj[objnum].hdraw >> 1);
  517.                 obj[objnum].distance=distance;
  518.                 objlist[numobjs++]=objnum;
  519.              } // End if
  520.           } // End if
  521.         } // End if
  522.      } // End for
  523.   } // End for
  524.   if (numobjs) {
  525.      int swap=-1;
  526.      while (swap) {
  527.         swap=0;
  528.         for (int i=0; i<(numobjs-1); i++) {
  529.           if (obj[objlist[i]].distance<obj[objlist[i+1]].distance) {
  530.              int temp=objlist[i];
  531.              objlist[i]=objlist[i+1];
  532.              objlist[i+1]=temp;
  533.              swap=-1;
  534.           }  // End if
  535.         }  // End for
  536.      }  // End while
  537.   }  // End if
  538.   for (int i=0; i<numobjs; i++) {
  539.      int level=litelevel[distance]+ambient_level;
  540.      if (level>MAXLIGHT) level=MAXLIGHT;
  541.      drawobject(&(obj[objlist[i]]),distance,&(litetable[level][0]),
  542.                     &(objects[objlist[i]][0]));
  543.   } // End for
  544. }
  545.  
  546. /*
  547. =============================
  548. =
  549. = Init_Engine()
  550. = Initializes the raycasting engine
  551. = and sets up look up tables etc.
  552. =============================
  553. */
  554.  
  555. void Init_Engine(unsigned char **textures, int num_textures)
  556. {
  557.     FILE *handle;
  558.  
  559.     // Load lightsourcing tables:
  560.     if ((handle=fopen("ltable.dat","rb"))==NULL) {
  561.         perror("Error");
  562.         exit;
  563.         }
  564.     fread(litetable,MAXLIGHT+1,PALETTESIZE,handle);
  565.     fclose(handle);
  566.  
  567.     // Calculate light intensities for all possible
  568.     // distances:
  569.     for (int distance=1; distance<MAXDISTANCE; distance++) {
  570.         float ratio=(float)MAXLIGHT/distance*3;
  571.         if (ratio>1.0) ratio=1.0;
  572.         litelevel[distance]=ratio*MAXLIGHT;
  573.     }
  574.  
  575.     for (int i = 0; i < 320; i++)
  576.         wallangle[i] = atan((float)(i-160)/VIEWER_DISTANCE)*652.2293;
  577.  
  578.     // Create texture list array:
  579.     for (i=0; i < num_textures; i++)
  580.     {
  581.         texturelist[i]=&(textures[i][0]);
  582.     }
  583.  
  584.     for (i = 0; i < MAXDISTANCE; i++)
  585.         distance_table[i] = 6144 / (i + 1) + VERT_CENTER;
  586.     for (i = 0; i < MAXDISTANCE; i++)
  587.         wheight[i] = 12288 / (i + 1);
  588.  
  589.     CalcViewport(0);
  590.  
  591.     i = 0;
  592.  
  593.     // Create door info.
  594.     for (int x = 0; x < GRIDSIZE; x++)
  595.         for (int y = 0; y < GRIDSIZE; y++)
  596.         {
  597.             if (walls[x][y] == 4)
  598.             {
  599.                 doors[i].xpos = x;
  600.                 doors[i].ypos = y;
  601.                 doors[i].position = 4096;
  602.                 doors[i].speed = 8;
  603.                 i++;
  604.             }
  605.         }
  606.     MAX_DOORS = i;
  607. }
  608.  
  609. /*
  610. =============================
  611. = CalcViewport(int num)
  612. = Calculates new screen coordinates
  613. = for viewport
  614. =============================
  615. */
  616. void CalcViewport(int num)
  617. {
  618.     VIEWPORT_LEFT=viewport_size[num].x1;          // Dimensions of viewport
  619.     VIEWPORT_RIGHT=viewport_size[num].x2;
  620.     VIEWPORT_TOP=viewport_size[num].y1;
  621.     VIEWPORT_BOT=viewport_size[num].y2;
  622.     VIEWPORT_HEIGHT=VIEWPORT_BOT-VIEWPORT_TOP+1;
  623.     VERT_CENTER=VIEWPORT_TOP+(VIEWPORT_HEIGHT >> 1);
  624.     VIEWPORT_WIDTH=VIEWPORT_RIGHT-VIEWPORT_LEFT + 1;
  625.     HORIZ_CENTER=VIEWPORT_LEFT+(VIEWPORT_WIDTH >> 1);
  626.     column_angle1 = atan((float)(VIEWPORT_LEFT-HORIZ_CENTER)
  627.                          / VIEWER_DISTANCE)*(NUMBER_OF_DEGREES / 6.28);
  628.  
  629.     column_angle2 = atan((float)(VIEWPORT_RIGHT-HORIZ_CENTER)
  630.                          / VIEWER_DISTANCE)*(NUMBER_OF_DEGREES / 6.28);
  631. }
  632.  
  633. /*
  634. =============================
  635.  
  636. int GetDoorID(void)
  637. Returns door index at coordinates xmaze,ymaze
  638.  
  639. =============================
  640. */
  641. int GetDoorID(int xpos, int ypos)
  642. {
  643.     for (char i = 0; i < MAX_DOORS; i++)
  644.         if (doors[i].xpos == xpos && doors[i].ypos == ypos) return(i);
  645. }
  646.