home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 March / Chip_1998-03_cd.bin / zkuste / SVET_GEO / GEORAY / GEORAY.ZIP / SOURCE.ZIP / RENDER / RENDER.GOC
Text File  |  1996-03-02  |  21KB  |  622 lines

  1. /***********************************************************************
  2.  *
  3.  * PROJECT:       Raycast
  4.  * FILE:          render.goc
  5.  *
  6.  * AUTHOR:        Marcus Gröber
  7.  *
  8.  ***********************************************************************/
  9.  
  10. //
  11. // Projekt Raycast-Engine
  12. // (C)1995 by Stefan Becker
  13. //
  14. // Render.goc
  15. // Haupt-Render/Zeichen-Routinen
  16. //
  17.  
  18. //
  19. // Geos-Includes:
  20. //
  21.  
  22. @include <stdapp.goh>
  23.  
  24. //
  25. // ANSI-Includes:
  26. //
  27.  
  28. #include    <stdio.h>
  29. #include    <stdlib.h>
  30. #include    <string.h>
  31. #include    <math.h>
  32.  
  33. //
  34. // Eigene Includes:
  35. //
  36.  
  37. @include    "raycast.goh"
  38. #include    "Globals.h"             // Allg. Definitionen
  39.  
  40. void _pascal clear_line_low(char *p,char mask,word hoehe);
  41. void _pascal grey_line_low(char *p,char mask,word hoehe,word evenodd);
  42. void _pascal scale_line_low(char *p,char mask,char *tp,char tmask,
  43.   int ypos,word hoehe);
  44.  
  45. //
  46. // Global Variablen
  47. //
  48.  
  49. struct {
  50.   Bitmap bmp;
  51.   char data[YAUF][(XAUF+7)/8];
  52. } Offscreen;
  53.  
  54. char texture[TEX_SIZE][(TEX_SIZE+7)/8]={
  55.   #include "texture\texture.inc"
  56. };
  57.  
  58. SKIP_TAB    hsc_dx_tab,     // dx/dy-Tabellen für effizienteres Raycasting
  59.             hsc_dy_tab;
  60. SKIP_TAB    vsc_dx_tab,
  61.             vsc_dy_tab;
  62. WINKEL_TAB  x_winkel_tab,   // Tabelle fƒr Richtungsvektoren aller Winkel
  63.             y_winkel_tab;   // (Nötig, um schnell einen Einheitsvektor
  64.                             // dieser Richtung zu ermitteln)
  65.  
  66. MAZE        maze;           // Wird später aus maze_user generiert.
  67.  
  68. // Definition des begehbaren Areals: '*':Wand, ' ':freie Fläche
  69. // Achtung, wird noch vertikal gespiegelt, damit (0,0) links unten ist
  70. MAZE        maze_user =
  71.   {
  72.       "****************", // 15
  73.       "*          *   *", // 14
  74.       "*    *         *", // 13
  75.       "*        *******", // 12
  76.       "*   ******     *", // 11
  77.       "*        *     *", // 10
  78.       "****     *     *", // 9
  79.       "*  *        *  *", // 8
  80.       "*  *           *", // 7
  81.       "*     ****  ****", // 6
  82.       "*  *  *        *", // 5
  83.       "*******   ******", // 4
  84.       "*  ** *        *", // 3
  85.       "*         *    *", // 2
  86.       "*  *          **", // 1 Feld (1,1) muß frei sein (Spieler wird dahin
  87.       "****************"  // 0 mit Blickrichtung nach rechts positioniert!)
  88.   };                      // (0,0) links unten, erster Index ist X
  89.  
  90. //
  91. // Koordinatentransformation für Karten-Modus:
  92. //
  93.  
  94. int tx(int x)           // Punkt aus virt. Welt in Kartenkoordinaten umsetzen
  95. {
  96.     int erg;
  97.  
  98.     erg = (int)( (dword)x * XAUF / MAZE_MAX_X );
  99.     erg = MAX(0,erg);   // Legale Position (sicherheitshalber)
  100.     erg = MIN(XAUF-1,erg);
  101.     return erg;
  102. }
  103.  
  104. int ty(int y)           // Punkt aus virt. Welt in Kartenkoordinaten umsetzen
  105. {
  106.     int erg;
  107.     
  108.     erg = (YAUF-1) - (int)( (dword)y * YAUF / MAZE_MAX_Y );
  109.     erg = MAX(0,erg);   // Legale Position (sicherheitshalber)
  110.     erg = MIN(YAUF-1,erg);
  111.     return erg;
  112. }
  113.  
  114. //
  115. // Kartenmodus darstellen:
  116. //
  117.  
  118. void do_map_raycasting(
  119.   GStateHandle window, int xw,int yw, int plx,int ply, int plw)
  120. {
  121.     int         x,y;                // x/y-Laufvariablen für Felder
  122.     int         p1x,p1y,p2x,p2y;    // Variablen für Spieler-x/y-Punkte
  123.     char        str[80];            // String für "sprintf"
  124.  
  125.     // Voreinstellungen für die Grafik (Geos):
  126.     GrSetAreaMaskSys(window,SDM_100);
  127.     GrSetLineMaskSys(window,SDM_100);
  128.     GrSetLineStyle(window,LS_SOLID,0,NULL,0);
  129.     GrSetLineColor(window,CF_INDEX,C_BLACK,0,0);
  130.  
  131.     // Das Labyrinth hinmalen:
  132.     for(x=0; x<MAZE_X; x++)         // Alle Spalten...
  133.         for(y=0; y<MAZE_Y; y++)     // Alle Zeilen...
  134.         {
  135.             if(maze[x][y] != ' ')   // Ist da eine Wand?
  136.               GrSetAreaColor(window,CF_INDEX,C_BLACK,0,0);
  137.             else
  138.               GrSetAreaColor(window,CF_INDEX,C_WHITE,0,0);
  139.  
  140.             // Kästchen zeichnen (Geos):
  141.             GrFillRect(window,
  142.                 xw+tx(x*TEX_SIZE),yw+ty((y+1)*TEX_SIZE),
  143.                 xw+tx((x+1)*TEX_SIZE),yw+ty(y*TEX_SIZE));
  144.         }
  145.  
  146.     // Den Spieler mit einzeichnen:
  147.     p1x = tx(plx);                              // Aktuelle Spielerposition
  148.     p1y = ty(ply);
  149.     GrFillRect(window,xw+p1x-1,yw+p1y-1,xw+p1x+1,yw+p1y+1);
  150.                                                 // Spieler einzeichnen
  151.     // Linie mit Länge 100 in Blickrichtung einzeichnen.
  152.     p2x = tx(plx + IntegerOf(GrMulWWFixed(x_winkel_tab[plw],MakeWWFixed(100))));
  153.     p2y = ty(ply + IntegerOf(GrMulWWFixed(y_winkel_tab[plw],MakeWWFixed(100))));
  154.     GrDrawLine(window,xw+p1x,yw+p1y,xw+p2x,yw+p2y);
  155.                                                 // Linie zeichnen (Geos)
  156. }
  157.  
  158. //
  159. // Eine skalierte senkrechte Texturlinie malen:
  160. //
  161.  
  162. void draw_scaled_line(int xpos, int txt_xpos, int hoehe)
  163. {
  164.     int ypos;                           // Oberkante der zu zeichnenden Textur
  165.     char mask;
  166.  
  167.     // Höhe sicherheitshalber auf "vernünftige" Grenzen limitieren:
  168.     hoehe = MIN(hoehe,32000);
  169.     hoehe = MAX(1,hoehe);
  170.  
  171.     // Texturposition sicherheitshalber auch auf "vernünftige" Werte limitieren:
  172.     txt_xpos = MAX(0,txt_xpos);
  173.     txt_xpos = MIN(TEX_SIZE-1,txt_xpos);
  174.  
  175.     // Wo muß die Oberkante der Linie im Grafikfenster hin? (0,0) ist links oben.
  176.     ypos = (YAUF/2) - (hoehe/2);        // virtueller Horizont bei YAUF/2
  177.  
  178.     mask=1<<(7-(xpos%8));
  179.  
  180.     if(ypos>0)                          // Draw "sky"
  181.       clear_line_low(&Offscreen.data[0][xpos/8], mask, ypos);
  182.  
  183.     scale_line_low(
  184.       &Offscreen.data[MAX(0,ypos)][xpos/8], mask,
  185.       &texture[0][txt_xpos/8], 1<<(7-(txt_xpos%8)),
  186.       ypos, hoehe);                     // Draw wall
  187.     
  188.     if(ypos+hoehe<YAUF)                 // Draw "floor"
  189.       grey_line_low(
  190.         &Offscreen.data[ypos+hoehe][xpos/8], mask,
  191.         YAUF-(ypos+hoehe), ((ypos+hoehe)^xpos) & 1);
  192. }
  193.  
  194. //
  195. // Berechnen der Entfernung mittels Streckfaktor der orthogonalen Projektion:
  196. //
  197.  
  198. WWFixedAsDWord calc_dist(int x, int y, int plw)
  199. {
  200.     // Geht, da Richtungsvektor (x_winkel_tab,y_winkel_tab) normiert ist.
  201.     return GrMulWWFixed(MakeWWFixed(x),x_winkel_tab[plw]) +
  202.            GrMulWWFixed(MakeWWFixed(y),y_winkel_tab[plw]);
  203. }
  204.  
  205. //
  206. // Ist dieser Punkt eine legale Position im Spielfeld?
  207. //
  208.  
  209. #define legal_pos(_x,_y)\
  210.     ( (_x)>=0 && (_x)<MAZE_MAX_X && (_y)>=0 && (_y)<MAZE_MAX_Y )
  211.  
  212. //
  213. // Horizontalen Scan durchführen:
  214. //
  215.  
  216. int hscan(int *lx, int *ly, int winkel)
  217. {
  218.     WWFixedAsDWord fx,fy;
  219.     WWFixedAsDWord   delta_x,delta_y;
  220.     int     iy,rx,ry;
  221.     int     zy;
  222.  
  223.     // Ist dieser Winkel für horizontales Scannen verwendbar?
  224.     if((hsc_dx_tab[winkel]==0) && (hsc_dy_tab[winkel]==0))
  225.         return FALSE;   // Nein! Illegaler Winkel => Keine Wand!
  226.  
  227.     // Startposition übernehmen:
  228.     fx = MakeWWFixed(*lx); fy = MakeWWFixed(iy=*ly);
  229.  
  230.     // Sehen, daß man zu Beginn auf einer horizontalen Liniengrenze landet:
  231.     if((iy % TEX_SIZE) != 0)
  232.     {
  233.         if((sdword)y_winkel_tab[winkel] > 0)        // Die Linie darüber oder darunter?
  234.         {
  235.             // Wir müssen auf die Linie darüber:
  236.             zy = ((iy / TEX_SIZE) + 1) * TEX_SIZE;  // Y-Koordinate der gewünschten Zeile
  237.         }
  238.         else
  239.         {
  240.             // Wir müssen auf die Linie darunter:
  241.             zy = (iy / TEX_SIZE) * TEX_SIZE;        // Y-Koordinate der gewünschten Zeile
  242.         }
  243.     
  244.         // Schritt auf die nächste Linie durchführen:
  245.         delta_y = MakeWWFixed(zy - iy); // So weit ist es dahin
  246.         delta_x = GrMulWWFixed(
  247.           delta_y,
  248.           GrSDivWWFixed(
  249.             x_winkel_tab[winkel],
  250.             y_winkel_tab[winkel]));     // So weit zur Seite gehen.
  251.         fx += delta_x;                  // Da liegt der neue X-Wert
  252.         fy = MakeWWFixed(zy);           // Da liegt der neue Y-Wert
  253.     }   // if (Aufsetzen)
  254.  
  255.     delta_x = hsc_dx_tab[winkel]; delta_y = hsc_dy_tab[winkel];
  256.  
  257.     // Schnell scannen:
  258.     // So lange man sich noch in virt. Welt befindet...
  259.     while( legal_pos(WWFixedToInt(fx),WWFixedToInt(fy)) )
  260.     {
  261.         // In Rasterposition umrechnen.
  262.         rx = WWFixedToInt(fx) >> TEX_SHIFT; ry = WWFixedToInt(fy) >> TEX_SHIFT;
  263.  
  264.         // Ist da etwas oberhalb und unterhalb der aktuellen hor. Linie?
  265.         if( (maze[rx][ry]!=' ') || (maze[rx][ry-1]!=' ') )
  266.         {
  267.             // Da ist eine Wand!
  268.             *lx = WWFixedToInt(fx); *ly = WWFixedToInt(fy); // Wandposition.
  269.             return TRUE;        // Hier ist eine Wand!
  270.         }   // if
  271.         
  272.         // Nächsten Punkt holen:
  273.         fx += delta_x; fy += delta_y;
  274.     }   // while
  275.  
  276.     // Keine Wand gefunden. Strahl geht ins Leere!
  277.     return FALSE;
  278. }
  279.  
  280. //
  281. // Vertikalen Scan durchführen:
  282. //
  283.  
  284. int vscan(int *lx, int *ly, int winkel)
  285. {
  286.     WWFixedAsDWord fx,fy;
  287.     WWFixedAsDWord x,y,delta_x,delta_y;
  288.     int     ix,rx,ry;
  289.     int     zx;
  290.  
  291.     // Ist dieser Winkel für horizontales Scannen verwendbar?
  292.     if((vsc_dx_tab[winkel]==0) && (vsc_dy_tab[winkel]==0))
  293.         return FALSE;   // Nein! Illegaler Winkel => Keine Wand!
  294.  
  295.     // Startposition übernehmen:
  296.     fx = MakeWWFixed(ix=*lx); fy = MakeWWFixed(*ly);
  297.  
  298.     // Sehen, daß man zu Beginn auf einer vertikalen Linie landet:
  299.     if((ix % TEX_SIZE) != 0)
  300.     {
  301.         if((sdword)x_winkel_tab[winkel] > 0)        // Die Linie rechts oder links?
  302.         {
  303.             // Wir müssen auf die Linie rechts:
  304.             zx = ((ix / TEX_SIZE) + 1) * TEX_SIZE;  // X-Koordinate der gewünschten Spalte
  305.         }
  306.         else
  307.         {
  308.             // Wir müssen auf die Linie links:
  309.             zx = (ix / TEX_SIZE) * TEX_SIZE;        // X-Koordinate der gewünschten Spalte
  310.         }
  311.  
  312.         // Schritt auf die nächste Linie durchführen:
  313.         delta_x = MakeWWFixed(zx - ix); // So weit ist es dahin
  314.         delta_y = GrMulWWFixed(
  315.           delta_x,
  316.           GrSDivWWFixed(
  317.             y_winkel_tab[winkel],
  318.             x_winkel_tab[winkel]));     // So weit nach oben gehen.
  319.         fy += delta_y;                  // Da liegt der neue Y-Wert
  320.         fx = MakeWWFixed(zx);           // Da liegt der neue X-Wert
  321.     }   // if (Aufsetzen)
  322.  
  323.     delta_x = vsc_dx_tab[winkel]; delta_y = vsc_dy_tab[winkel];
  324.  
  325.     // Schnell scannen:
  326.     // So lange man sich noch in der vrt. Welt befindet...
  327.     while( legal_pos(WWFixedToInt(fx),WWFixedToInt(fy)) )
  328.     {                                   
  329.         // In Rasterposition umrechnen:
  330.         rx = WWFixedToInt(fx) >> TEX_SHIFT; ry = WWFixedToInt(fy) >> TEX_SHIFT;
  331.  
  332.         // Ist da etwas linkt und rechts von der senkrechten Linie?
  333.         if( (maze[rx][ry]!=' ') || (maze[rx-1][ry]!=' ') )
  334.         {
  335.             // Ja: Eine Wand ist hier.
  336.             *lx = WWFixedToInt(fx); *ly = WWFixedToInt(fy); // Wandposition.
  337.             return TRUE;        // Hier ist eine Wand!
  338.         }   // if
  339.         
  340.         // Nächsten Punkt holen:
  341.         fx += delta_x; fy += delta_y;
  342.     }   // while
  343.  
  344.     // Nichts gefunden. Strahl geht ins Leere!
  345.     return FALSE;
  346. }
  347.  
  348. //
  349. // Einen Strahl "Raycasten" und eventuellen Auftreffpunkt auf einer Mauer
  350. // samit zugehöriger Texturposition liefern:
  351. // (Arbeitet ohne Bresenham mit der Delta-X/Delta-Y-Methode für max. Geschwindigkeit)
  352. //
  353.  
  354. int cast_one_ray(int plx, int ply, int plw, int winkel, WWFixedAsDWord *dist, int *pat_pos)
  355. {
  356.     int         hwall_hit,vwall_hit;            // Horizontales bzw. vertikales Auftreffen auf Wand?
  357.     int         vx,vy;                          // Auftreffpunkt auf eine vertikale Linie
  358.     int         hx,hy;                          // Auftreffpunkt auf eine horizontale Linie
  359.     WWFixedAsDWord h_dist,v_dist;               // Entfernung des horizontalen und vert. Auftreffpunkts
  360.  
  361.     //
  362.     // Horizontalen Schnellscan durchführen:
  363.     //
  364.     hx = plx; hy = ply;                 // Start bei Spielerposition
  365.     hwall_hit = hscan(&hx,&hy,winkel);  // Treffer auf eine hor. Wand? Wenn ja: wo?
  366.     if(hwall_hit)
  367.       h_dist = calc_dist(hx-plx,hy-ply,plw);
  368.     else
  369.       h_dist = MakeWWFixed(32767);
  370.  
  371.     //
  372.     // Vertikalen Schnellscan durchführen:
  373.     //
  374.     vx = plx; vy = ply;                 // Start bei Spielerposition
  375.     vwall_hit = vscan(&vx,&vy,winkel);  // Treffer auf eine vert. Wand? Wenn ja: wo?
  376.     if(vwall_hit)
  377.       v_dist = calc_dist(vx-plx,vy-ply,plw);
  378.     else
  379.       v_dist = MakeWWFixed(32767);
  380.  
  381.     //
  382.     // Gar kein Treffer?
  383.     //
  384.     if(!vwall_hit && !hwall_hit)
  385.         return FALSE;   // Da ist absolut garnichts!
  386.  
  387.     //
  388.     // Zum Spieler näheren Treffer nehmen:
  389.     //
  390.     if(h_dist<v_dist)               // Horizontaler oder vertikaler Treffer näher?
  391.     {
  392.         *dist = h_dist;             // horizontal war näher
  393.         *pat_pos = hx % TEX_SIZE;   // Diese Texturspalte wird genommen.
  394.     }
  395.     else
  396.     {
  397.         *dist = v_dist;             // vertikal war näher
  398.         *pat_pos = vy % TEX_SIZE;
  399.                                     // Diese Texturspalte wird genommen.
  400.     }
  401.     return TRUE;        // Treffer. Näherer der beiden Schnittpunkte.
  402. }
  403.  
  404. //
  405. // Höhe eines Objekts aus seiner Entfernung berechnen.
  406. // (Wird mit Konstante/Entfernung berechnet.)
  407. //
  408.  
  409. int calc_hoehe(int dist)
  410. {
  411.     // Höhe berechnen:
  412.     dist = ABS(dist);                   // sicherheitshalber!!!
  413.     dist = MIN(dist,MAX_SICHT);         // sicherheitshalber!!!
  414.     return PERSPEKTIVE / (dist+1);      // Zurodnung Entfernung->Wandhöhe
  415. }
  416.  
  417. //
  418. // Haupt-Raycast-Routine (3D-Modus):
  419. //
  420.  
  421. void do_3d_raycasting(int plx, int ply, int plw)
  422. {
  423.     int             wall_x,wall_y;                  // Schnittpunkt mit der Wand
  424.     int             x,winkel,startw,endw;           // Laufvariable, Start-, Endwinkel
  425.     WWFixedAsDWord  dist;                           // Distanz der Wand.
  426.     int             hoehe;                          // Daraus errechnete Höhe der darzustellenden Wand in Pixeln
  427.     int             txt_pos;                        // Zu skalierende Spalte der Textur.
  428.     char            str[80];                        // String für Koordinaten-Ausgabe.
  429.  
  430.     // Start- und Endwinkel für Spieler-Blickwinkel errechnen:
  431.     startw = plw + (XAUF / 2);              // Start-Blickwinkel errechnen
  432.     if(startw >= ANZ_WINKEL)                // Legal?
  433.         startw -= ANZ_WINKEL;               // Nein, muß "modulo" korrigiert werden.
  434.     if(startw < 0)                          // Legal?
  435.         startw += ANZ_WINKEL;               // Nein, muß "modulo" korrigiert werden.
  436.  
  437.     // Raycasting für alle Winkel durchführen:
  438.     x = 0;                                  // Dieser Strahl gehört zur X-Koordinate 0 im generierten Bild
  439.     winkel = startw;                        // Mit dem Startwinkel wird links angefangen
  440.     while(x < XAUF)                         // So lange bis das gesamte Bild berechnet ist
  441.     {
  442.         // Einen Strahl absetzen und ggf. Mauerschnittpunkte ermitteln:
  443.         if(cast_one_ray(plx,ply,plw,winkel,&dist,&txt_pos))
  444.         {
  445.             // Ja, da ist eine Wand. Aus der Entfernung
  446.             // berechnen, wie groß diese dargestellt werden soll:
  447.             hoehe = calc_hoehe(WWFixedToInt(dist));
  448.                                             // Wie hoch muß das Objekt nun sein?
  449.  
  450.             // Skalierte Texturspalte senkrecht zeichnen:
  451.             draw_scaled_line(x,txt_pos,hoehe);
  452.         }
  453.  
  454.         // Schleifenende: (Hier muß x inkrementiert und der Winkel "modulo" erhöht werden)
  455.         x++;                                // Nächste X-Koordinate
  456.         winkel--;                           // Nächster Winkel
  457.         if(winkel < 0)                      // Illegal bzw. Unterlauf?
  458.             winkel += ANZ_WINKEL;           // Korrigieren!
  459.     }   // while
  460. }
  461.  
  462. //
  463. // Routine verzweigt je nach Flagge "my_3d_flag" auf Karten- oder
  464. // 3D-Modus und leitet Zeichenoperationen in eine Offscreen-Bitmap um.
  465. // (Mac-spezifisch)
  466. //
  467.  
  468. void do_raycasting(
  469.   GStateHandle window, int x,int y, int plx,int ply, int plw, Boolean DrawMap)
  470. {
  471.     // 3D- oder Kartensicht?
  472.     if(DrawMap)
  473.         do_map_raycasting(window,x,y,plx,ply,plw);      // Karten-Sicht
  474.     else
  475.     {
  476.         do_3d_raycasting(plx,ply,plw);                  // 3D-Sicht
  477.         GrDrawImage(window,x,y,IBS_1,&Offscreen.bmp);   // Offscreen-Bitmap
  478.     }
  479. }
  480.  
  481. //
  482. // Tabellen initialisieren etc. (für alle Rechnersysteme):
  483. //
  484.  
  485. // Spielfeld vertikal spiegeln. Nötig, damit vorinitialisiertes
  486. // Feld oben "richtig herum" im Quellcode angezeigt wird.
  487.  
  488. void flip_maze(void)
  489. {                       
  490.     int     zeile,spalte;               // Indizes
  491.  
  492.     for(spalte=0; spalte<MAZE_X; spalte++)
  493.         for(zeile=0; zeile<MAZE_Y; zeile++)
  494.             maze[spalte][zeile] = maze_user[MAZE_Y-1-zeile][spalte];
  495.                                         // Daten übernehmen
  496. }
  497.  
  498. void Init_Tabellen(void)        // dx/dy-Tabelle und Winkeltabellen errechnen:
  499. {
  500.  
  501.     WWFixedAsDWord z,d,alpha,d_alpha;
  502.     int         i;              // Laufvariable
  503.  
  504.     //
  505.     // Tabelle für Richtungsvektoren initialisieren:
  506.     //
  507.  
  508.     // Größe eines Winkelschrittes berechnen (360/Winkelanzahl):
  509.     d_alpha = GrSDivWWFixed(MakeWWFixed(360),MakeWWFixed(ANZ_WINKEL));
  510.  
  511.     // Fƒr alle Winkel den zugehörigen Richtungsvektor errechnen.
  512.     // Dabei ist der 0. Winkel bei 0 Grad (entspricht rechts).
  513.     for(alpha=0, i=0; i<ANZ_WINKEL; i++, alpha+=d_alpha)  // Alle Winkel...
  514.     {
  515.         // Punkte auf dem Einheitskreis als Richtungsvektoren:
  516.         x_winkel_tab[i] = GrQuickCosine(alpha);
  517.                                         // Cos gibt die X-Koordinate an
  518.         y_winkel_tab[i] = GrQuickSine(alpha);
  519.                                         // Sin gibt die Y-Koordinate an
  520.     }   // for
  521.  
  522.     //
  523.     // Tabelle fƒr schnelleres dx/dy-Raycasting initialisieren:
  524.     //
  525.     for(i=0; i<ANZ_WINKEL; i++) // Alle Winkel...
  526.     {
  527.         //
  528.         // Tabelle fƒr horizontalen Scan generieren:
  529.         //
  530.         if(y_winkel_tab[i]==0)                      // Degenerierte Richtung fƒr hor. Scan?
  531.             hsc_dx_tab[i] = hsc_dy_tab[i] = 0;      // "Degenerierte" Richtung fƒr hor. Scan!
  532.         else
  533.         {
  534.             hsc_dy_tab[i] =
  535.               MakeWWFixed( ((sdword)y_winkel_tab[i]>0)? TEX_SIZE : -TEX_SIZE );
  536.             d = GrMulWWFixed(
  537.               hsc_dy_tab[i],
  538.               GrSDivWWFixed(
  539.                 x_winkel_tab[i],
  540.                 y_winkel_tab[i]));
  541.             if(ABS(WWFixedToInt(d))>MAX_SICHT)
  542.                 hsc_dx_tab[i] = hsc_dy_tab[i] = 0;  // Dieser Winkel ist auch "degeneriert"!
  543.             else
  544.                 hsc_dx_tab[i] = d;                  // Dieser Wert kann verwendet werden.
  545.         }
  546.         //
  547.         // Tabelle fƒr vertikalen Scan erstellen:
  548.         //
  549.         if(x_winkel_tab[i]==0)                      // Degenerierte Richtung fƒr vert. Scan?
  550.             vsc_dx_tab[i] = vsc_dy_tab[i] = 0;      // "Degenerierte" Richtung fƒr vert. Scan!
  551.         else
  552.         {
  553.             vsc_dx_tab[i] =
  554.               MakeWWFixed( ((sdword)x_winkel_tab[i]>0)? TEX_SIZE : -TEX_SIZE );
  555.             d = GrMulWWFixed(
  556.               vsc_dx_tab[i],
  557.               GrSDivWWFixed(
  558.                 y_winkel_tab[i],
  559.                 x_winkel_tab[i]));
  560.             if(ABS(WWFixedToInt(d))>MAX_SICHT)
  561.                 vsc_dx_tab[i] = vsc_dy_tab[i] = 0;  // Dieser Winkel ist auch "degeneriert"!
  562.             else
  563.                 vsc_dy_tab[i] = d;                  // Dieser Wert kann verwendet werden.
  564.         }
  565.     }   // for
  566.  
  567.     //
  568.     // Spielfeld vertikal spiegeln:
  569.     //
  570.     flip_maze();
  571. }
  572.  
  573. /***********************************************************************
  574.  *              Methods for RaycastClass
  575.  ***********************************************************************/
  576. @classdecl      RaycastClass;
  577.  
  578. @method RaycastClass, MSG_VIS_RECALC_SIZE
  579. {
  580.     return MAKE_SIZE_DWORD(XAUF,YAUF);
  581. }
  582.  
  583. @method RaycastClass, MSG_VIS_DRAW
  584. {
  585.     VisInstance *vself;
  586.  
  587.     vself = ObjDerefVis(oself);
  588.     do_raycasting(
  589.       gstate, vself->VI_bounds.R_left, vself->VI_bounds.R_top,
  590.       pself->RCI_plx, pself->RCI_ply, pself->RCI_plw, pself->RCI_drawMap);
  591. }
  592.  
  593. @method RaycastClass, MSG_RAYCAST_INIT_TABLES
  594. {
  595.     Init_Tabellen();
  596.     Offscreen.bmp.B_width=XAUF;
  597.     Offscreen.bmp.B_height=YAUF;
  598.     Offscreen.bmp.B_compact=BMC_UNCOMPACTED;
  599.     Offscreen.bmp.B_type=BMF_MONO;
  600. }
  601.  
  602. @method RaycastClass, MSG_RAYCAST_SET_MAP_MODE
  603. {
  604.     pself->RCI_drawMap = drawMap;       // Set new mapping mode and redraw
  605.     @send self::MSG_VIS_REDRAW_ENTIRE_OBJECT();
  606. }
  607.  
  608. @method RaycastClass, MSG_RAYCAST_GET_PLAYER
  609. {
  610.     *plx = pself->RCI_plx;              // Return player coordinates
  611.     *ply = pself->RCI_ply;
  612.     *plw = pself->RCI_plw;
  613. }
  614.  
  615. @method RaycastClass, MSG_RAYCAST_SET_PLAYER
  616. {
  617.     pself->RCI_plx = plx;               // Set new player coordinates & redraw
  618.     pself->RCI_ply = ply;
  619.     pself->RCI_plw = plw;
  620.     @send self::MSG_VIS_REDRAW_ENTIRE_OBJECT();
  621. }
  622.