+++ /dev/null
-/* Catacomb 3-D Source Code\r
- * Copyright (C) 1993-2014 Flat Rock Software\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
- */\r
-\r
-// C3_TRACE.C\r
-\r
-#include "C3_DEF.H"\r
-#pragma hdrstop\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL CONSTANTS\r
-\r
-=============================================================================\r
-*/\r
-\r
-\r
-//\r
-// TESTWALLVISABLE will set the global variable wallvisable to 1 or 0\r
-// depending on if tile.x,tile.y,wallon is visable from focal point\r
-//\r
-#define TESTWALLVISABLE { \\r
- if (tile.y<focal.y) \\r
- voffset = 0; \\r
- else if (tile.y==focal.y) \\r
- voffset = 3; \\r
- else \\r
- voffset = 6; \\r
- if (tile.x==focal.x) \\r
- voffset ++; \\r
- else if (tile.x>focal.x) \\r
- voffset += 2; \\r
- wallvisable = visable[voffset][wallon]; }\r
-\r
-\r
-/*\r
-=============================================================================\r
-\r
- GLOBAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-boolean aborttrace;\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-unsigned wallvisable,voffset;\r
-\r
-\r
-fixed edgex,edgey;\r
-\r
-int wallon;\r
-int basecolor;\r
-\r
-walltype *oldwall;\r
-\r
-//\r
-// offsets from upper left corner of a tile to the left and right edges of\r
-// a given wall (NORTH-WEST)\r
-//\r
-fixed point1x[4] = {GLOBAL1,GLOBAL1,0 ,0 };\r
-fixed point1y[4] = {0 ,GLOBAL1,GLOBAL1,0 };\r
-\r
-fixed point2x[4] = {0 ,GLOBAL1,GLOBAL1,0 };\r
-fixed point2y[4] = {0 ,0 ,GLOBAL1 ,GLOBAL1};\r
-\r
-\r
-//\r
-// offset from tile.x,tile.y of the tile that shares wallon side\r
-// (side is not visable if it is shared)\r
-//\r
-int sharex[4] = { 0, 1, 0,-1};\r
-int sharey[4] = {-1, 0, 1, 0};\r
-\r
-//\r
-// amount to move tile.x,tile.y to follow wallon to another tile\r
-//\r
-int followx[4] = {-1, 0, 1, 0};\r
-int followy[4] = { 0,-1, 0, 1};\r
-\r
-//\r
-// cornerwall gives the wall on the same tile to start following when the\r
-// wall ends at an empty tile (go around an edge on same tile)\r
-// turnwall gives the wall on tile.x+sharex,tile.y+sharey to start following\r
-// when the wall hits another tile (right angle corner)\r
-//\r
-int cornerwall[4] = {WEST,NORTH,EAST,SOUTH};\r
-int turnwall[4] = {EAST,SOUTH,WEST,NORTH};\r
-\r
-//\r
-// wall visabilities in reletive locations\r
-// -,- 0,- +,-\r
-// -,0 0,0 +,0\r
-// -,+ 0,+ +,+\r
-//\r
-int visable[9][4] =\r
-{\r
- {0,1,1,0}, {0,0,1,0}, {0,0,1,1},\r
- {0,1,0,0}, {0,0,0,0}, {0,0,0,1},\r
- {1,1,0,0}, {1,0,0,0}, {1,0,0,1}\r
-};\r
-\r
-int startwall[9] = {2,2,3, 1,0,3, 1,0,0};\r
-int backupwall[9] = {3,3,0, 2,0,0, 2,1,1};\r
-\r
-\r
-int walllength;\r
-\r
-/*\r
-=============================================================================\r
-\r
- FUNCTIONS\r
-\r
-=============================================================================\r
-*/\r
-\r
-/*\r
-========================\r
-=\r
-= FollowTrace\r
-=\r
-========================\r
-*/\r
-\r
-int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max)\r
-{\r
- int tx,ty,otx,oty;\r
- long absdx,absdy,xstep,ystep;\r
-\r
- tx = tracex>>TILESHIFT;\r
- ty = tracey>>TILESHIFT;\r
-\r
- spotvis[tx][ty] = true;\r
-\r
- absdx=LABS(deltax);\r
- absdy=LABS(deltay);\r
-\r
- if (absdx>absdy)\r
- {\r
- ystep = (deltay<<8)/(absdx>>8);\r
-\r
- if (!ystep)\r
- ystep = deltay>0 ? 1 : -1;\r
-\r
- oty = (tracey+ystep)>>TILESHIFT;\r
- if (deltax>0)\r
- {\r
-//###############\r
-//\r
-// step x by +1\r
-//\r
-//###############\r
- do\r
- {\r
- tx++;\r
- spotvis[tx][ty] = true;\r
- tracey+=ystep;\r
- ty = tracey>>TILESHIFT;\r
-\r
- if (ty!=oty)\r
- {\r
- if (tilemap[tx-1][ty])\r
- {\r
- tile.x = tx-1;\r
- tile.y = ty;\r
- return 1;\r
- }\r
- oty = ty;\r
- }\r
- if (tilemap[tx][ty])\r
- {\r
- tile.x = tx;\r
- tile.y = ty;\r
- return 1;\r
- }\r
- } while (--max);\r
- return 0;\r
- }\r
- else\r
- {\r
-//###############\r
-//\r
-// step x by -1\r
-//\r
-//###############\r
- do\r
- {\r
- tx--;\r
- spotvis[tx][ty] = true;\r
- tracey+=ystep;\r
- ty = tracey>>TILESHIFT;\r
-\r
- if (ty!=oty)\r
- {\r
- if (tilemap[tx][oty])\r
- {\r
- tile.x = tx;\r
- tile.y = oty;\r
- return 1;\r
- }\r
- oty = ty;\r
- }\r
- if (tilemap[tx][ty])\r
- {\r
- tile.x = tx;\r
- tile.y = ty;\r
- return 1;\r
- }\r
- } while (--max);\r
- return 0;\r
-\r
- }\r
- }\r
- else\r
- {\r
- xstep = (deltax<<8)/(absdy>>8);\r
- if (!xstep)\r
- xstep = deltax>0 ? 1 : -1;\r
-\r
-\r
- otx = (tracex+xstep)>>TILESHIFT;\r
- if (deltay>0)\r
- {\r
-//###############\r
-//\r
-// step y by +1\r
-//\r
-//###############\r
- do\r
- {\r
- ty++;\r
- spotvis[tx][ty] = true;\r
- tracex+=xstep;\r
- tx = tracex>>TILESHIFT;\r
-\r
- if (tx!=otx)\r
- {\r
- if (tilemap[tx][ty-1])\r
- {\r
- tile.x = tx;\r
- tile.y = ty-1;\r
- return 1;\r
- }\r
- otx = tx;\r
- }\r
- if (tilemap[tx][ty])\r
- {\r
- tile.x = tx;\r
- tile.y = ty;\r
- return 1;\r
- }\r
- } while (--max);\r
- return 0;\r
- }\r
- else\r
- {\r
-//###############\r
-//\r
-// step y by -1\r
-//\r
-//###############\r
- do\r
- {\r
- ty--;\r
- spotvis[tx][ty] = true;\r
- tracex+=xstep;\r
- tx = tracex>>TILESHIFT;\r
-\r
- if (tx!=otx)\r
- {\r
- if (tilemap[otx][ty])\r
- {\r
- tile.x = otx;\r
- tile.y = ty;\r
- return 1;\r
- }\r
- otx = tx;\r
- }\r
- if (tilemap[tx][ty])\r
- {\r
- tile.x = tx;\r
- tile.y = ty;\r
- return 1;\r
- }\r
- } while (--max);\r
- return 0;\r
- }\r
-\r
- }\r
-\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= BackTrace\r
-=\r
-= Traces backwards from edgex,edgey to viewx,viewy to see if a closer\r
-= tile obscures the given point. If it does, it finishes the wall and\r
-= starts a new one.\r
-= Returns true if a tile is hit.\r
-= Call with a 1 to have it automatically finish the current wall\r
-=\r
-=================\r
-*/\r
-\r
-int BackTrace (int finish)\r
-{\r
- fixed tracex,tracey;\r
- long deltax,deltay,absdx,absdy;\r
- int steps,otx,oty,testx,testheight,offset,wall;\r
-\r
- deltax = viewx-edgex;\r
- deltay = viewy-edgey;\r
-\r
- absdx = LABS(deltax);\r
- absdy = LABS(deltay);\r
-\r
- if (absdx>absdy)\r
- steps = ABS(focal.x-(edgex>>TILESHIFT))-1;\r
- else\r
- steps = ABS(focal.y-(edgey>>TILESHIFT))-1;\r
-\r
- if (steps<=0)\r
- return 0;\r
-\r
- otx = tile.x;\r
- oty = tile.y;\r
- if (!FollowTrace(edgex,edgey,deltax,deltay,steps))\r
- return 0;\r
-\r
-//\r
-// if the start wall is behind the focal point, the trace went too far back\r
-//\r
- if (ABS(tile.x-focal.x)<2 && ABS(tile.y-focal.y)<2) // too close\r
- {\r
- if (tile.x == focal.x && tile.y == focal.y)\r
- {\r
- tile.x = otx;\r
- tile.y = oty;\r
- return 0;\r
- }\r
-\r
- if (tile.x<focal.x)\r
- {\r
- if (tile.y<focal.y)\r
- wall = SOUTH;\r
- else\r
- wall = EAST;\r
- }\r
- else if (tile.x==focal.x)\r
- {\r
- if (tile.y<focal.y)\r
- wall = SOUTH;\r
- else\r
- wall = NORTH;\r
- }\r
- else\r
- {\r
- if (tile.y<=focal.y)\r
- wall = WEST;\r
- else\r
- wall = NORTH;\r
- }\r
-\r
- //\r
- // rotate the X value to see if it is behind the view plane\r
- //\r
- if (TransformX (((long)tile.x<<16)+point1x[wall],\r
- ((long)tile.y<<16)+point1y[wall]) < FOCALLENGTH)\r
- {\r
- tile.x = otx;\r
- tile.y = oty;\r
- return 0;\r
- }\r
- }\r
-\r
-//\r
-// if the old wall is still behind a closer wall, ignore the back trace\r
-// and continue on (dealing with limited precision...)\r
-//\r
- if (finish && !FinishWall ()) // the wall is still behind a forward wall\r
- {\r
- tile.x = otx;\r
- tile.y = oty;\r
- rightwall->x1 = oldwall->x2; // common edge with last wall\r
- rightwall->height1 = oldwall->height2;\r
- return 0;\r
- }\r
-\r
-\r
-//\r
-// back up along the intersecting face to find the rightmost wall\r
-//\r
-\r
- if (tile.y<focal.y)\r
- offset = 0;\r
- else if (tile.y==focal.y)\r
- offset = 3;\r
- else\r
- offset = 6;\r
- if (tile.x==focal.x)\r
- offset ++;\r
- else if (tile.x>focal.x)\r
- offset += 2;\r
-\r
- wallon = backupwall[offset];\r
-\r
- while (tilemap[tile.x][tile.y])\r
- {\r
- tile.x += followx[wallon];\r
- tile.y += followy[wallon];\r
- };\r
-\r
- tile.x -= followx[wallon];\r
- tile.y -= followy[wallon];\r
-\r
- wallon = cornerwall[wallon]; // turn to first visable face\r
-\r
- edgex = ((long)tile.x<<16);\r
- edgey = ((long)tile.y<<16);\r
-\r
- TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
- &rightwall->x1,&rightwall->height1);\r
-\r
- basecolor = tilemap[tile.x][tile.y];\r
-\r
- return 1;\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= ForwardTrace\r
-=\r
-= Traces forwards from edgex,edgey along the line from viewx,viewy until\r
-= a solid tile is hit. Sets tile.x,tile.y\r
-=\r
-=================\r
-*/\r
-\r
-void ForwardTrace (void)\r
-{\r
- int offset;\r
- fixed tracex,tracey;\r
- long deltax,deltay;\r
-\r
- deltax = edgex-viewx;\r
- deltay = edgey-viewy;\r
-\r
- FollowTrace(edgex,edgey,deltax,deltay,0);\r
-\r
- if (tile.y<focal.y)\r
- offset = 0;\r
- else if (tile.y==focal.y)\r
- offset = 3;\r
- else\r
- offset = 6;\r
- if (tile.x==focal.x)\r
- offset ++;\r
- else if (tile.x>focal.x)\r
- offset += 2;\r
-\r
- wallon = startwall[offset];\r
-\r
-//\r
-// start the new wall\r
-//\r
- edgex = ((long)tile.x<<16);\r
- edgey = ((long)tile.y<<16);\r
-\r
-//\r
-// if entire first wall is invisable, corner\r
-//\r
- TransformPoint (edgex+point2x[wallon],edgey+point2y[wallon],\r
- &rightwall->x2,&rightwall->height2);\r
-\r
- if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]]\r
- || rightwall->x2 < (rightwall-1)->x2 )\r
- wallon = cornerwall [wallon];\r
-\r
-//\r
-// transform first point\r
-//\r
-\r
- TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
- &rightwall->x1,&rightwall->height1);\r
-\r
- basecolor = tilemap[tile.x][tile.y];\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= FinishWall\r
-=\r
-= Transforms edgex,edgey as the next point of the current wall\r
-= and sticks it in the wall list\r
-=\r
-=================\r
-*/\r
-\r
-int FinishWall (void)\r
-{\r
- char num[20];\r
-\r
- oldwall = rightwall;\r
-\r
- rightwall->color = basecolor;\r
-\r
- TransformPoint (edgex,edgey,&rightwall->x2,&rightwall->height2);\r
-\r
- if (rightwall->x2 <= (rightwall-1)->x2+2\r
- && rightwall->height2 < (rightwall-1)->height2 )\r
- return 0;\r
-\r
- rightwall->walllength = walllength;\r
-\r
- switch (wallon)\r
- {\r
- case north:\r
- case south:\r
- rightwall->side = 0;\r
- rightwall->planecoord = edgey;\r
- break;\r
-\r
- case west:\r
- case east:\r
- rightwall->side = 1;\r
- rightwall->planecoord = edgex;\r
- break;\r
- }\r
-\r
- walllength = 1;\r
-\r
- rightwall++;\r
-\r
- return 1;\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= InsideCorner\r
-=\r
-=================\r
-*/\r
-\r
-void InsideCorner (void)\r
-{\r
- int offset;\r
-\r
- //\r
- // the wall turned -90 degrees, so draw what we have, move to the new tile,\r
- // change wallon, change color, and continue following.\r
- //\r
- FinishWall ();\r
-\r
- tile.x += sharex[wallon];\r
- tile.y += sharey[wallon];\r
-\r
- wallon = turnwall[wallon];\r
-\r
- //\r
- // if the new wall is visable, continue following it. Otherwise\r
- // follow it backwards until it turns\r
- //\r
- TESTWALLVISABLE;\r
-\r
- if (wallvisable)\r
- {\r
- //\r
- // just turn to the next wall and continue\r
- //\r
- rightwall->x1 = oldwall->x2; // common edge with last wall\r
- rightwall->height1 = oldwall->height2;\r
- basecolor = tilemap[tile.x][tile.y];\r
- return; // continue from here\r
- }\r
-\r
- //\r
- // back follow the invisable wall until it turns, then follow that\r
- //\r
- do\r
- {\r
- tile.x += followx[wallon];\r
- tile.y += followy[wallon];\r
- } while (tilemap[tile.x][tile.y]);\r
-\r
- tile.x -= followx[wallon];\r
- tile.y -= followy[wallon];\r
-\r
- wallon = cornerwall[wallon]; // turn to first visable face\r
-\r
- edgex = ((long)tile.x<<16)+point1x[wallon];\r
- edgey = ((long)tile.y<<16)+point1y[wallon];\r
-\r
- if (!BackTrace(0)) // backtrace without finishing a wall\r
- {\r
- TransformPoint (edgex,edgey,&rightwall->x1,&rightwall->height1);\r
- basecolor = tilemap[tile.x][tile.y];\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= OutsideCorner\r
-=\r
-=================\r
-*/\r
-\r
-void OutsideCorner (void)\r
-{\r
- int offset;\r
-\r
- //\r
- // edge is the outside edge of a corner, so draw the current wall and\r
- // turn the corner (+90 degrees)\r
- //\r
- FinishWall ();\r
-\r
- tile.x -= followx[wallon]; // backup to the real tile\r
- tile.y -= followy[wallon];\r
- wallon = cornerwall[wallon];\r
-\r
- //\r
- // if the new wall is visable, continue following it. Otherwise\r
- // trace a ray from the corner to find a wall in the distance to\r
- // follow\r
- //\r
- TESTWALLVISABLE;\r
-\r
- if (wallvisable)\r
- {\r
- //\r
- // the new wall is visable, so just continue on\r
- //\r
- rightwall->x1 = oldwall->x2; // common edge with last wall\r
- rightwall->height1 = oldwall->height2;\r
- return; // still on same tile, so color is ok\r
- }\r
-\r
-//\r
-// start from a new tile further away\r
-//\r
- ForwardTrace(); // find the next wall further back\r
-\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= FollowWalls\r
-=\r
-= Starts a wall edge at the leftmost edge of tile.x,tile.y and follows it\r
-= until something else is seen or the entire view area is covered\r
-=\r
-=================\r
-*/\r
-\r
-void FollowWalls (void)\r
-{\r
- int height,newcolor,offset,wall;\r
-\r
-//####################\r
-//\r
-// figure leftmost wall of new tile\r
-//\r
-//####################\r
-\r
-restart:\r
-\r
- walllength = 1;\r
-\r
- if (tile.y<focal.y)\r
- offset = 0;\r
- else if (tile.y==focal.y)\r
- offset = 3;\r
- else\r
- offset = 6;\r
- if (tile.x==focal.x)\r
- offset ++;\r
- else if (tile.x>focal.x)\r
- offset += 2;\r
-\r
- wallon = startwall[offset];\r
-\r
-//\r
-// if the start wall is inside a block, skip it by cornering to the second wall\r
-//\r
- if ( tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])\r
- wallon = cornerwall [wallon];\r
-\r
-//\r
-// transform first edge to screen coordinates\r
-//\r
- edgex = ((long)tile.x<<16);\r
- edgey = ((long)tile.y<<16);\r
-\r
- TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],\r
- &rightwall->x1,&rightwall->height1);\r
-\r
- basecolor = tilemap[tile.x][tile.y];\r
-\r
-//##################\r
-//\r
-// follow the wall as long as possible\r
-//\r
-//##################\r
-\r
-advance:\r
-\r
- do // while ( tile.x != right.x || tile.y != right.y)\r
- {\r
-//\r
-// check for conditions that shouldn't happed...\r
-//\r
- if (rightwall->x1 > VIEWXH) // somehow missed right tile...\r
- return;\r
-\r
- if (rightwall == &walls[DANGERHIGH])\r
- {\r
- //\r
- // somethiing got messed up! Correct by thrusting ahead...\r
- //\r
- VW_ColorBorder(6);\r
- bordertime = 60;\r
- Thrust(player->angle,TILEGLOBAL/4);\r
- player->angle+=5;\r
- if (player->angle>ANGLES)\r
- player->angle-=ANGLES;\r
- aborttrace = true;\r
- return;\r
-\r
-#if 0\r
- strcpy (str,"Wall list overflow at LE:");\r
- itoa(mapon+1,str2,10);\r
- strcat (str,str2);\r
- strcat (str," X:");\r
- ltoa(objlist[0].x,str2,10);\r
- strcat (str,str2);\r
- strcat (str," Y:");\r
- ltoa(objlist[0].y,str2,10);\r
- strcat (str,str2);\r
- strcat (str," AN:");\r
- itoa(objlist[0].angle,str2,10);\r
- strcat (str,str2);\r
-\r
- Quit (str);\r
-#endif\r
- }\r
-\r
-//\r
-// proceed along wall\r
-//\r
-\r
- edgex = ((long)tile.x<<16)+point2x[wallon];\r
- edgey = ((long)tile.y<<16)+point2y[wallon];\r
-\r
- if (BackTrace(1)) // went behind a closer wall\r
- continue;\r
-\r
- //\r
- // advance to next tile along wall\r
- //\r
- tile.x += followx[wallon];\r
- tile.y += followy[wallon];\r
-\r
- if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])\r
- {\r
- InsideCorner (); // turn at a corner\r
- continue;\r
- }\r
-\r
- newcolor = tilemap[tile.x][tile.y];\r
-\r
- if (!newcolor) // turn around an edge\r
- {\r
- OutsideCorner ();\r
- continue;\r
- }\r
-\r
- if (newcolor != basecolor)\r
- {\r
- //\r
- // wall changed color, so draw what we have and continue following\r
- //\r
- FinishWall ();\r
- rightwall->x1 = oldwall->x2; // new wall shares this edge\r
- rightwall->height1 = oldwall->height2;\r
- basecolor = newcolor;\r
-\r
- continue;\r
- }\r
- walllength++;\r
- } while (tile.x != right.x || tile.y != right.y);\r
-\r
-\r
-\r
-//######################\r
-//\r
-// draw the last tile\r
-//\r
-//######################\r
-\r
- edgex = ((long)tile.x<<16)+point2x[wallon];\r
- edgey = ((long)tile.y<<16)+point2y[wallon];\r
- FinishWall();\r
-\r
- wallon = cornerwall[wallon];\r
-\r
- //\r
- // if the corner wall is visable, draw it\r
- //\r
- TESTWALLVISABLE;\r
-\r
- if (wallvisable)\r
- {\r
- rightwall->x1 = oldwall->x2; // common edge with last wall\r
- rightwall->height1 = oldwall->height2;\r
- edgex = ((long)tile.x<<16)+point2x[wallon];\r
- edgey = ((long)tile.y<<16)+point2y[wallon];\r
- FinishWall();\r
- }\r
-\r
-}\r
-\r
-//===========================================================================\r