Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

760 lines
22 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: fpipe.cxx
  3. *
  4. * Flex pipes
  5. *
  6. * Copyright (c) 1994 Microsoft Corporation
  7. *
  8. \**************************************************************************/
  9. /* Notes:
  10. - All Draw routines start with current xc at the beginning, and create
  11. a new one at the end. Since it is common to just have 2 xc's for
  12. each prim, xcCur holds the current xc, and xcEnd is available
  13. for the draw routine to use as the end xc.
  14. They also reset xcCur when done
  15. */
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <math.h>
  20. #include <sys/types.h>
  21. #include <time.h>
  22. #include <windows.h>
  23. #include "sspipes.h"
  24. #include "fpipe.h"
  25. #include "eval.h"
  26. // defCylNotch shows the absolute notch for the default cylinder,
  27. // given a direction (notch is always along +x axis)
  28. static GLint defCylNotch[NUM_DIRS] =
  29. { MINUS_Z, PLUS_Z, PLUS_X, PLUS_X, PLUS_X, MINUS_X };
  30. static int GetRelativeDir( int lastDir, int notchVec, int newDir );
  31. /**************************************************************************\
  32. * FLEX_PIPE constructor
  33. *
  34. *
  35. \**************************************************************************/
  36. FLEX_PIPE::FLEX_PIPE( STATE *pState )
  37. : PIPE( pState )
  38. {
  39. float circ;
  40. // Create an EVAL object
  41. nSlices = pState->nSlices;
  42. // No XC's yet, they will be allocated at pipe Start()
  43. xcCur = xcEnd = NULL;
  44. // The EVAL will be used for all pEvals in the pipe, so should be
  45. // set to hold max. possible # of pts for the pipe.
  46. pEval = new EVAL( bTexture );
  47. // Determine pipe tesselation
  48. // For now, this is based on global tesselation factor
  49. //mf: maybe clean up this scheme a bit
  50. // Calculate evalDivSize, a reference value for the size of a UxV division.
  51. // This is used later for calculating texture coords.
  52. circ = CIRCUMFERENCE( pState->radius );
  53. evalDivSize = circ / (float) nSlices;
  54. }
  55. /**************************************************************************\
  56. * ~FLEX_PIPE
  57. *
  58. \**************************************************************************/
  59. FLEX_PIPE::~FLEX_PIPE( )
  60. {
  61. delete pEval;
  62. // delete any XC's
  63. if( xcCur != NULL ) {
  64. if( xcEnd == xcCur )
  65. //mf: so far this can't happen...
  66. xcEnd = NULL; // xcCur and xcEnd can point to same xc !
  67. delete xcCur;
  68. xcCur = NULL;
  69. }
  70. if( xcEnd != NULL ) {
  71. delete xcEnd;
  72. xcEnd = NULL;
  73. }
  74. }
  75. /**************************************************************************\
  76. * REGULAR_FLEX_PIPE constructor
  77. *
  78. \**************************************************************************/
  79. REGULAR_FLEX_PIPE::REGULAR_FLEX_PIPE( STATE *state )
  80. : FLEX_PIPE( state )
  81. {
  82. static float turnFactorRange = 0.1f;
  83. type = TYPE_FLEX_REGULAR;
  84. // figure out turning factor range (0 for min bends, 1 for max bends)
  85. #if 1
  86. float avgTurn = ss_fRand( 0.11f, 0.81f );
  87. // set min and max turn factors, and clamp to 0..1
  88. turnFactorMin =
  89. SS_CLAMP_TO_RANGE( avgTurn - turnFactorRange, 0.0f, 1.0f );
  90. turnFactorMax =
  91. SS_CLAMP_TO_RANGE( avgTurn + turnFactorRange, 0.0f, 1.0f );
  92. #else
  93. // debug: test max bend
  94. turnFactorMin = turnFactorMax = 1.0f;
  95. #endif
  96. // choose straight weighting
  97. // mf:for now, same as npipe - if stays same, put in pipe
  98. if( ! ss_iRand( 20 ) )
  99. weightStraight = ss_iRand2( MAX_WEIGHT_STRAIGHT/4, MAX_WEIGHT_STRAIGHT );
  100. else
  101. weightStraight = ss_iRand( 4 );
  102. }
  103. /**************************************************************************\
  104. * TURNING_FLEX_PIPE constructor
  105. *
  106. \**************************************************************************/
  107. TURNING_FLEX_PIPE::TURNING_FLEX_PIPE( STATE *state )
  108. : FLEX_PIPE( state )
  109. {
  110. type = TYPE_FLEX_TURNING;
  111. }
  112. /******************************Public*Routine******************************\
  113. * SetTexIndex
  114. *
  115. * Set the texture index for this pipe, and calculate texture state dependent
  116. * on texRep values
  117. *
  118. * Dec. 95 [marcfo]
  119. *
  120. \**************************************************************************/
  121. void
  122. FLEX_PIPE::SetTexParams( TEXTURE *pTex, IPOINT2D *pTexRep )
  123. {
  124. if( bTexture ) {
  125. GLfloat t_size;
  126. float circ;
  127. t_start = (GLfloat) pTexRep->y * 1.0f;
  128. t_end = 0.0f;
  129. // calc height (t_size) of one rep of texture around circumference
  130. circ = CIRCUMFERENCE( radius );
  131. t_size = circ / pTexRep->y;
  132. // now calc corresponding width of the texture using its x/y ratio
  133. s_length = t_size / pTex->origAspectRatio;
  134. s_start = s_end = 0.0f;
  135. //mf: this means we are 'standardizing' the texture size and proportions
  136. // on pipe of radius 1.0 for entire program. Might want to recalc this on
  137. // a per-pipe basis ?
  138. }
  139. }
  140. /**************************************************************************\
  141. * ChooseXCProfile
  142. *
  143. * Initialize extruded pipe scheme. This uses a randomly constructed XC, but it
  144. * remains constant throughout the pipe
  145. *
  146. * History
  147. * July 30, 95 : [marcfo]
  148. * - Wrote it
  149. *
  150. \**************************************************************************/
  151. void
  152. FLEX_PIPE::ChooseXCProfile()
  153. {
  154. static float turnFactorRange = 0.1f;
  155. float avgTurn;
  156. float baseRadius = pState->radius;
  157. // initialize evaluator elements:
  158. pEval->numSections = EVAL_XC_CIRC_SECTION_COUNT;
  159. pEval->uOrder = EVAL_ARC_ORDER;
  160. //mf: watch this - maybe should ROUND_UP uDiv
  161. // set uDiv per section (assumed uDiv multiple of numSections)
  162. pEval->uDiv = nSlices / pEval->numSections;
  163. // Setup XC's
  164. // The xc profile remains constant throughout in this case,
  165. // so we only need one xc.
  166. // Choose between elliptical or random cross-sections. Since elliptical
  167. // looks a little better, make it more likely
  168. if( ss_iRand(4) ) // 3/4 of the time
  169. xcCur = new ELLIPTICAL_XC( ss_fRand(1.2f, 2.0f) * baseRadius,
  170. baseRadius );
  171. else
  172. xcCur = new RANDOM4ARC_XC( ss_fRand(1.5f, 2.0f) * baseRadius );
  173. }
  174. /**************************************************************************\
  175. * REGULAR_FLEX_PIPE::Start
  176. *
  177. * Does startup of extruded-XC pipe drawing scheme
  178. *
  179. \**************************************************************************/
  180. void
  181. REGULAR_FLEX_PIPE::Start()
  182. {
  183. NODE_ARRAY *nodes = pState->nodes;
  184. int newDir;
  185. // Set start position
  186. if( !SetStartPos() ) {
  187. status = PIPE_OUT_OF_NODES;
  188. return;
  189. }
  190. // set material
  191. ChooseMaterial();
  192. // set XC profile
  193. ChooseXCProfile();
  194. // push matrix with zTrans and scene rotation
  195. glPushMatrix();
  196. // Translate to current position
  197. TranslateToCurrentPosition();
  198. // set random lastDir
  199. lastDir = ss_iRand( NUM_DIRS );
  200. // get a new node to draw to
  201. newDir = ChooseNewDirection();
  202. if( newDir == DIR_NONE ) {
  203. // draw like one of those tea-pouring thingies...
  204. status = PIPE_STUCK;
  205. DrawTeapot();
  206. glPopMatrix();
  207. return;
  208. } else
  209. status = PIPE_ACTIVE;
  210. align_plusz( newDir ); // get us pointed in right direction
  211. // draw start cap, which will end right at current node
  212. DrawCap( START_CAP );
  213. // set initial notch vector, which is just the default notch, since
  214. // we didn't have to spin the start cap around z
  215. notchVec = defCylNotch[newDir];
  216. zTrans = - pState->view.divSize; // distance back from new node
  217. UpdateCurrentPosition( newDir );
  218. lastDir = newDir;
  219. }
  220. /**************************************************************************\
  221. * TURNING_FLEX_PIPE::Start
  222. *
  223. * Does startup of turning extruded-XC pipe drawing scheme
  224. *
  225. \**************************************************************************/
  226. void
  227. TURNING_FLEX_PIPE::Start( )
  228. {
  229. NODE_ARRAY *nodes = pState->nodes;
  230. // Set start position
  231. if( !SetStartPos() ) {
  232. status = PIPE_OUT_OF_NODES;
  233. return;
  234. }
  235. // Set material
  236. ChooseMaterial();
  237. // Set XC profile
  238. ChooseXCProfile();
  239. // Push matrix with zTrans and scene rotation
  240. glPushMatrix();
  241. // Translate to current position
  242. TranslateToCurrentPosition();
  243. // lastDir has to be set to something valid, in case we get stuck right
  244. // away, cuz Draw() will be called anyways on next iteration, whereupon
  245. // it finds out it really is stuck, AFTER calling ChooseNewTurnDirection,
  246. // which requires valid lastDir. (mf: fix this)
  247. lastDir = ss_iRand( NUM_DIRS );
  248. // Pick a starting direction by finding a neihgbouring empty node
  249. int newDir = nodes->FindClearestDirection( &curPos );
  250. // We don't 'choose' it, or mark it as taken, because ChooseNewDirection
  251. // will always check it anyways
  252. if( newDir == DIR_NONE ) {
  253. // we can't go anywhere
  254. // draw like one of those tea-pouring thingies...
  255. status = PIPE_STUCK;
  256. DrawTeapot();
  257. glPopMatrix();
  258. return;
  259. } else
  260. status = PIPE_ACTIVE;
  261. align_plusz( newDir ); // get us pointed in right direction
  262. // Draw start cap, which will end right at current node
  263. DrawCap( START_CAP );
  264. // Set initial notch vector, which is just the default notch, since
  265. // we didn't have to spin the start cap around z
  266. notchVec = defCylNotch[newDir];
  267. zTrans = 0.0f; // right at current node
  268. lastDir = newDir;
  269. }
  270. /**************************************************************************\
  271. * REGULAR_FLEX_PIPE::Draw
  272. *
  273. * Draws the pipe using a constant random xc that is extruded
  274. *
  275. * Minimum turn radius can vary, since xc is not symmetrical across any
  276. * of its axes. Therefore here we draw using a pipe/elbow sequence, so we
  277. * know what direction we're going in before drawing the elbow. The current
  278. * node is the one we will draw thru next time. Typically, the actual end
  279. * of the pipe is way back of this node, almost at the previous node, due
  280. * to the variable turn radius
  281. *
  282. * History
  283. * July 30, 95 : [marcfo]
  284. * - Wrote it
  285. *
  286. \**************************************************************************/
  287. void
  288. REGULAR_FLEX_PIPE::Draw( )
  289. {
  290. float turnRadius, minTurnRadius;
  291. float pipeLen, maxPipeLen, minPipeLen;
  292. int newDir, relDir;
  293. float maxXCExtent;
  294. NODE_ARRAY *nodes = pState->nodes;
  295. float divSize = pState->view.divSize;
  296. // get new direction
  297. newDir = ChooseNewDirection();
  298. if( newDir == DIR_NONE ) {
  299. status = PIPE_STUCK;
  300. DrawCap( END_CAP );
  301. glPopMatrix();
  302. return;
  303. }
  304. // draw pipe, and if turning, joint
  305. if( newDir != lastDir ) { // turning! - we have to draw joint
  306. // get relative turn, to figure turn radius
  307. relDir = GetRelativeDir( lastDir, notchVec, newDir );
  308. minTurnRadius = xcCur->MinTurnRadius( relDir );
  309. // now calc maximum straight section we can draw before turning
  310. // zTrans is current pos'n of end of pipe, from current node ??
  311. // zTrans is current pos'n of end of pipe, from last node
  312. maxPipeLen = (-zTrans) - minTurnRadius;
  313. // there is also a minimum requirement for the length of the straight
  314. // section, cuz if we turn too soon with a large turn radius, we
  315. // will swing up too close to the next node, and won't be able to
  316. // make one or more of the 4 possible turns from that point
  317. maxXCExtent = xcCur->MaxExtent(); // in case need it again
  318. minPipeLen = maxXCExtent - (divSize + zTrans);
  319. if( minPipeLen < 0.0f )
  320. minPipeLen = 0.0f;
  321. // Choose length of straight section
  322. // (we are translating from turnFactor to 'straightFactor' here)
  323. pipeLen = minPipeLen +
  324. ss_fRand( 1.0f - turnFactorMax, 1.0f - turnFactorMin ) *
  325. (maxPipeLen - minPipeLen);
  326. // turn radius is whatever's left over:
  327. turnRadius = maxPipeLen - pipeLen + minTurnRadius;
  328. // draw straight section
  329. DrawExtrudedXCObject( pipeLen );
  330. zTrans += pipeLen; // not necessary for now, since elbow no use
  331. // draw elbow
  332. // this updates axes, notchVec to position at end of elbow
  333. DrawXCElbow( newDir, turnRadius );
  334. zTrans = -(divSize - turnRadius); // distance back from node
  335. }
  336. else { // no turn
  337. // draw a straight pipe through the current node
  338. // length can vary according to the turnFactors (e.g. for high turn
  339. // factors draw a short pipe, so next turn can be as big as possible)
  340. minPipeLen = -zTrans; // brings us just up to last node
  341. maxPipeLen = minPipeLen + divSize - xcCur->MaxExtent();
  342. // brings us as close as possible to new node
  343. pipeLen = minPipeLen +
  344. ss_fRand( 1.0f - turnFactorMax, 1.0f - turnFactorMin ) *
  345. (maxPipeLen - minPipeLen);
  346. // draw pipe
  347. DrawExtrudedXCObject( pipeLen );
  348. zTrans += (-divSize + pipeLen);
  349. }
  350. UpdateCurrentPosition( newDir );
  351. lastDir = newDir;
  352. }
  353. /**************************************************************************\
  354. * DrawTurningXCPipe
  355. *
  356. * Draws the pipe using only turns
  357. *
  358. * - Go straight if no turns available
  359. *
  360. * History
  361. * Aug 10, 95 : [marcfo]
  362. * - Wrote it
  363. *
  364. \**************************************************************************/
  365. void
  366. TURNING_FLEX_PIPE::Draw()
  367. {
  368. float turnRadius;
  369. int newDir;
  370. NODE_ARRAY *nodes = pState->nodes;
  371. float divSize = pState->view.divSize;
  372. // get new direction
  373. //mf: pipe may have gotten stuck on Start...(we don't check for this)
  374. newDir = nodes->ChooseNewTurnDirection( &curPos, lastDir );
  375. if( newDir == DIR_NONE ) {
  376. status = PIPE_STUCK;
  377. DrawCap( END_CAP );
  378. glPopMatrix();
  379. return;
  380. }
  381. if( newDir == DIR_STRAIGHT ) {
  382. // No turns available - draw straight section and hope for turns
  383. // on next iteration
  384. DrawExtrudedXCObject( divSize );
  385. UpdateCurrentPosition( lastDir );
  386. // ! we have to mark node as taken for this case, since
  387. // ChooseNewTurnDirection doesn't know whether we're taking the
  388. // straight option or not
  389. nodes->NodeVisited( &curPos );
  390. } else {
  391. // draw turning pipe
  392. // since xc is always located right at current node, turn radius
  393. // stays constant at one node division
  394. turnRadius = divSize;
  395. DrawXCElbow( newDir, turnRadius );
  396. // (zTrans stays at 0)
  397. // need to update 2 nodes
  398. UpdateCurrentPosition( lastDir );
  399. UpdateCurrentPosition( newDir );
  400. lastDir = newDir;
  401. }
  402. }
  403. /**************************************************************************\
  404. * DrawXCElbow
  405. *
  406. * Draw elbow from current position through new direction
  407. *
  408. * - Extends current xc around bend
  409. * - Radius of bend is provided - this is distance from xc center to hinge
  410. * point, along newDir. e.g. for 'normal pipes', radius=vc->radius
  411. *
  412. * History
  413. * Jul. 25, 95 : [marcfo]
  414. * - Wrote it
  415. *
  416. \**************************************************************************/
  417. void
  418. FLEX_PIPE::DrawXCElbow( int newDir, float radius )
  419. {
  420. int relDir; // 'relative' direction of turn
  421. float length;
  422. length = (2.0f * PI * radius) / 4.0f; // average length of elbow
  423. // calc vDiv, texture params based on length
  424. //mf: I think we should improve resolution of elbows - more vDiv's
  425. // could rewrite this fn to take a vDivSize
  426. CalcEvalLengthParams( length );
  427. pEval->vOrder = EVAL_ARC_ORDER;
  428. // convert absolute dir to relative dir
  429. relDir = GetRelativeDir( lastDir, notchVec, newDir );
  430. // draw it - call simple bend function
  431. pEval->ProcessXCPrimBendSimple( xcCur, relDir, radius );
  432. // set transf. matrix to new position by translating/rotating/translating
  433. // ! Based on simple elbow
  434. glTranslatef( 0.0f, 0.0f, radius );
  435. switch( relDir ) {
  436. case PLUS_X:
  437. glRotatef( 90.0f, 0.0f, 1.0f, 0.0f );
  438. break;
  439. case MINUS_X:
  440. glRotatef( -90.0f, 0.0f, 1.0f, 0.0f );
  441. break;
  442. case PLUS_Y:
  443. glRotatef( -90.0f, 1.0f, 0.0f, 0.0f );
  444. break;
  445. case MINUS_Y:
  446. glRotatef( 90.0f, 1.0f, 0.0f, 0.0f );
  447. break;
  448. }
  449. glTranslatef( 0.0f, 0.0f, radius );
  450. // update notch vector using old function
  451. notchVec = notchTurn[lastDir][newDir][notchVec];
  452. }
  453. /**************************************************************************\
  454. * DrawExtrudedXCObject
  455. *
  456. * Draws object generated by extruding the current xc
  457. *
  458. * Object starts at xc at origin in z=0 plane, and grows along +z axis
  459. *
  460. * History
  461. * July 5, 95 : [marcfo]
  462. * - Wrote it
  463. *
  464. \**************************************************************************/
  465. void
  466. FLEX_PIPE::DrawExtrudedXCObject( float length )
  467. {
  468. // calc vDiv, and texture coord stuff based on length
  469. // this also calcs pEval texture ctrl pt arrray now
  470. CalcEvalLengthParams( length );
  471. // we can fill in some more stuff:
  472. pEval->vOrder = EVAL_CYLINDER_ORDER;
  473. #if 0
  474. // continuity stuff
  475. prim.contStart = prim.contEnd = CONT_1; // geometric continuity
  476. #endif
  477. // draw it
  478. //mf: this fn doesn't really handle continutity for 2 different xc's, so
  479. // may as well pass it one xc
  480. pEval->ProcessXCPrimLinear( xcCur, xcCur, length );
  481. // update state draw axes position
  482. glTranslatef( 0.0f, 0.0f, length );
  483. }
  484. /**************************************************************************\
  485. * DrawXCCap
  486. *
  487. * Cap the start of the pipe
  488. *
  489. * Needs newDir, so it can orient itself.
  490. * Cap ends at current position with approppriate profile, starts a distance
  491. * 'z' back along newDir.
  492. * Profile is a singularity at start point.
  493. *
  494. * History
  495. * July 22, 95 : [marcfo]
  496. * - Wrote it
  497. *
  498. \**************************************************************************/
  499. void
  500. FLEX_PIPE::DrawCap( int type )
  501. {
  502. float radius;
  503. XC *xc = xcCur;
  504. BOOL bOpening = (type == START_CAP) ? TRUE : FALSE;
  505. float length;
  506. // set radius as average of the bounding box min/max's
  507. radius = ((xc->xRight - xc->xLeft) + (xc->yTop - xc->yBottom)) / 4.0f;
  508. length = (2.0f * PI * radius) / 4.0f; // average length of arc
  509. // calc vDiv, and texture coord stuff based on length
  510. CalcEvalLengthParams( length );
  511. // we can fill in some more stuff:
  512. pEval->vOrder = EVAL_ARC_ORDER;
  513. // draw it
  514. pEval->ProcessXCPrimSingularity( xc, radius, bOpening );
  515. }
  516. /**************************************************************************\
  517. * CalcEvalLengthParams
  518. *
  519. * Calculate pEval values that depend on the length of the extruded object
  520. *
  521. * - calculate vDiv, s_start, s_end, and the texture control net array
  522. *
  523. * History
  524. * July 13, 95 : [marcfo]
  525. * - Wrote it
  526. *
  527. \**************************************************************************/
  528. void
  529. FLEX_PIPE::CalcEvalLengthParams( float length )
  530. {
  531. pEval->vDiv = (int ) SS_ROUND_UP( length / evalDivSize );
  532. // calc texture start and end coords
  533. if( bTexture ) {
  534. GLfloat s_delta;
  535. // Don't let s_end overflow : it should stay in range (0..1.0)
  536. if( s_end > 1.0f )
  537. s_end -= (int) s_end;
  538. s_start = s_end;
  539. s_delta = (length / s_length );
  540. s_end = s_start + s_delta;
  541. // the texture ctrl point array can be calc'd here - it is always
  542. // a simple 2x2 array for each section
  543. pEval->SetTextureControlPoints( s_start, s_end, t_start, t_end );
  544. }
  545. }
  546. /**************************************************************************\
  547. *
  548. * GetRelativeDir
  549. *
  550. * Calculates relative direction of turn from lastDir, notchVec, newDir
  551. *
  552. * - Use look up table for now.
  553. * - Relative direction is from xy-plane, and can be +x,-x,+y,-y
  554. * - In current orientation, +z is along lastDir, +x along notchVec
  555. *
  556. * History
  557. * July 27, 95 : [marcfo]
  558. * - Wrote it
  559. *
  560. \**************************************************************************/
  561. // this array tells you relative turn
  562. // format: relDir[lastDir][notchVec][newDir]
  563. static int relDir[NUM_DIRS][NUM_DIRS][NUM_DIRS] = {
  564. // +x -x +y -y +z -z (newDir)
  565. // lastDir = +x
  566. iXX, iXX, iXX, iXX, iXX, iXX,
  567. iXX, iXX, iXX, iXX, iXX, iXX,
  568. iXX, iXX, PLUS_X, MINUS_X,PLUS_Y, MINUS_Y,
  569. iXX, iXX, MINUS_X,PLUS_X, MINUS_Y,PLUS_Y,
  570. iXX, iXX, MINUS_Y,PLUS_Y, PLUS_X, MINUS_X,
  571. iXX, iXX, PLUS_Y, MINUS_Y,MINUS_X,PLUS_X,
  572. // lastDir = -x
  573. iXX, iXX, iXX, iXX, iXX, iXX,
  574. iXX, iXX, iXX, iXX, iXX, iXX,
  575. iXX, iXX, PLUS_X, MINUS_X,MINUS_Y,PLUS_Y,
  576. iXX, iXX, MINUS_X,PLUS_X, PLUS_Y, MINUS_Y,
  577. iXX, iXX, PLUS_Y, MINUS_Y,PLUS_X, MINUS_X,
  578. iXX, iXX, MINUS_Y,PLUS_Y, MINUS_X,PLUS_X,
  579. // lastDir = +y
  580. PLUS_X, MINUS_X,iXX, iXX, MINUS_Y,PLUS_Y,
  581. MINUS_X,PLUS_X, iXX, iXX, PLUS_Y, MINUS_Y,
  582. iXX, iXX, iXX, iXX, iXX, iXX,
  583. iXX, iXX, iXX, iXX, iXX, iXX,
  584. PLUS_Y, MINUS_Y,iXX, iXX, PLUS_X, MINUS_X,
  585. MINUS_Y,PLUS_Y, iXX, iXX, MINUS_X,PLUS_X,
  586. // lastDir = -y
  587. PLUS_X, MINUS_X,iXX, iXX, PLUS_Y, MINUS_Y,
  588. MINUS_X,PLUS_X, iXX, iXX, MINUS_Y,PLUS_Y,
  589. iXX, iXX, iXX, iXX, iXX, iXX,
  590. iXX, iXX, iXX, iXX, iXX, iXX,
  591. MINUS_Y,PLUS_Y, iXX, iXX, PLUS_X, MINUS_X,
  592. PLUS_Y, MINUS_Y,iXX, iXX, MINUS_X,PLUS_X,
  593. // lastDir = +z
  594. PLUS_X, MINUS_X,PLUS_Y, MINUS_Y,iXX, iXX,
  595. MINUS_X,PLUS_X, MINUS_Y,PLUS_Y, iXX, iXX,
  596. MINUS_Y,PLUS_Y, PLUS_X, MINUS_X,iXX, iXX,
  597. PLUS_Y, MINUS_Y,MINUS_X,PLUS_X, iXX, iXX,
  598. iXX, iXX, iXX, iXX, iXX, iXX,
  599. iXX, iXX, iXX, iXX, iXX, iXX,
  600. // lastDir = -z
  601. PLUS_X, MINUS_X,MINUS_Y,PLUS_Y, iXX, iXX,
  602. MINUS_X,PLUS_X, PLUS_Y, MINUS_Y,iXX, iXX,
  603. PLUS_Y, MINUS_Y,PLUS_X, MINUS_X,iXX, iXX,
  604. MINUS_Y,PLUS_Y, MINUS_X,PLUS_X, iXX, iXX,
  605. iXX, iXX, iXX, iXX, iXX, iXX,
  606. iXX, iXX, iXX, iXX, iXX, iXX
  607. };
  608. static int
  609. GetRelativeDir( int lastDir, int notchVec, int newDir )
  610. {
  611. return( relDir[lastDir][notchVec][newDir] );
  612. }