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.

461 lines
14 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: npipe.cpp
  3. //
  4. // Desc: Normal pipes code
  5. //
  6. // Copyright (c) 1994-2000 Microsoft Corporation
  7. //-----------------------------------------------------------------------------
  8. #include "stdafx.h"
  9. static void align_notch( int newDir, int notch );
  10. static void align_plusy( int oldDir, int newDir );
  11. // defCylNotch shows where the notch for the default cylinder will be,
  12. // in absolute coords, once we do an align_plusz
  13. static int defCylNotch[NUM_DIRS] =
  14. { PLUS_Y, PLUS_Y, MINUS_Z, PLUS_Z, PLUS_Y, PLUS_Y };
  15. //-----------------------------------------------------------------------------
  16. // Name: NORMAL_PIPE constructor
  17. // Desc:
  18. //-----------------------------------------------------------------------------
  19. NORMAL_PIPE::NORMAL_PIPE( STATE *pState ) : PIPE( pState )
  20. {
  21. m_type = TYPE_NORMAL;
  22. m_pNState = pState->m_pNState;
  23. // choose weighting of going straight
  24. if( ! CPipesScreensaver::iRand( 20 ) )
  25. m_weightStraight = CPipesScreensaver::iRand2( MAX_WEIGHT_STRAIGHT/4, MAX_WEIGHT_STRAIGHT );
  26. else
  27. m_weightStraight = 1 + CPipesScreensaver::iRand( 4 );
  28. }
  29. //-----------------------------------------------------------------------------
  30. // Name: Start
  31. // Desc: Start drawing a new normal pipe
  32. // - Draw a start cap and short pipe in new direction
  33. //-----------------------------------------------------------------------------
  34. void NORMAL_PIPE::Start()
  35. {
  36. int newDir;
  37. // Set start position
  38. if( !SetStartPos() )
  39. {
  40. m_status = PIPE_OUT_OF_NODES;
  41. return;
  42. }
  43. // set a material
  44. ChooseMaterial();
  45. m_pState->m_pd3dDevice->SetTexture( 0, m_pState->m_textureInfo[0].pTexture );
  46. m_pState->m_pd3dDevice->SetMaterial( m_pMat );
  47. // push matrix that has initial zTrans and rotation
  48. m_pWorldMatrixStack->Push();
  49. // Translate to current position
  50. TranslateToCurrentPosition();
  51. // Pick a random lastDir
  52. m_lastDir = CPipesScreensaver::iRand( NUM_DIRS );
  53. newDir = ChooseNewDirection();
  54. if( newDir == DIR_NONE )
  55. {
  56. // pipe is stuck at the start node, draw nothing
  57. m_status = PIPE_STUCK;
  58. m_pWorldMatrixStack->Pop();
  59. return;
  60. }
  61. else
  62. {
  63. m_status = PIPE_ACTIVE;
  64. }
  65. // set initial notch vector
  66. m_notchVec = defCylNotch[newDir];
  67. DrawStartCap( newDir );
  68. // move ahead 1.0*r to draw pipe
  69. m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
  70. // draw short pipe
  71. align_notch( newDir, m_notchVec );
  72. m_pNState->m_pShortPipe->Draw( m_pWorldMatrixStack->GetTop() );
  73. m_pWorldMatrixStack->Pop();
  74. UpdateCurrentPosition( newDir );
  75. m_lastDir = newDir;
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Name: Draw
  79. // Desc: - if turning, draws a joint and a short cylinder, otherwise
  80. // draws a long cylinder.
  81. // - the 'current node' is set as the one we draw thru the NEXT
  82. // time around.
  83. //-----------------------------------------------------------------------------
  84. void NORMAL_PIPE::Draw()
  85. {
  86. int newDir;
  87. m_pState->m_pd3dDevice->SetTexture( 0, m_pState->m_textureInfo[0].pTexture );
  88. m_pState->m_pd3dDevice->SetMaterial( m_pMat );
  89. newDir = ChooseNewDirection();
  90. if( newDir == DIR_NONE )
  91. {
  92. // no empty nodes - nowhere to go
  93. DrawEndCap();
  94. m_status = PIPE_STUCK;
  95. return;
  96. }
  97. // push matrix that has initial zTrans and rotation
  98. m_pWorldMatrixStack->Push();
  99. // Translate to current position
  100. TranslateToCurrentPosition();
  101. // draw joint if necessary, and pipe
  102. if( newDir != m_lastDir )
  103. {
  104. // turning! - we have to draw joint
  105. DrawJoint( newDir );
  106. // draw short pipe
  107. align_notch( newDir, m_notchVec );
  108. m_pNState->m_pShortPipe->Draw( m_pWorldMatrixStack->GetTop() );
  109. }
  110. else
  111. {
  112. // no turn -- draw long pipe, from point 1.0*r back
  113. align_plusz( newDir );
  114. align_notch( newDir, m_notchVec );
  115. m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, -m_radius );
  116. m_pNState->m_pLongPipe->Draw( m_pWorldMatrixStack->GetTop() );
  117. }
  118. m_pWorldMatrixStack->Pop();
  119. UpdateCurrentPosition( newDir );
  120. m_lastDir = newDir;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Name: DrawStartCap
  124. // Desc: Cap the start of the pipe with a ball
  125. //-----------------------------------------------------------------------------
  126. void NORMAL_PIPE::DrawStartCap( int newDir )
  127. {
  128. if( m_pState->m_bUseTexture )
  129. {
  130. align_plusz( newDir );
  131. m_pNState->m_pBallCap->Draw( m_pWorldMatrixStack->GetTop() );
  132. }
  133. else
  134. {
  135. // draw big ball in default orientation
  136. m_pNState->m_pBigBall->Draw( m_pWorldMatrixStack->GetTop() );
  137. align_plusz( newDir );
  138. }
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Name: DrawEndCap():
  142. // Desc: - Draws a ball, used to cap end of a pipe
  143. //-----------------------------------------------------------------------------
  144. void NORMAL_PIPE::DrawEndCap()
  145. {
  146. m_pWorldMatrixStack->Push();
  147. // Translate to current position
  148. TranslateToCurrentPosition();
  149. if( m_pState->m_bUseTexture )
  150. {
  151. align_plusz( m_lastDir );
  152. align_notch( m_lastDir, m_notchVec );
  153. m_pNState->m_pBallCap->Draw( m_pWorldMatrixStack->GetTop() );
  154. }
  155. else
  156. {
  157. m_pNState->m_pBigBall->Draw( m_pWorldMatrixStack->GetTop() );
  158. }
  159. m_pWorldMatrixStack->Pop();
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Name:
  163. // Desc: this array supplies the sequence of elbow notch vectors, given
  164. // oldDir and newDir (0's are don't cares)
  165. // it is also used to determine the ending notch of an elbow
  166. //-----------------------------------------------------------------------------
  167. static int notchElbDir[NUM_DIRS][NUM_DIRS][4] =
  168. {
  169. // oldDir = +x
  170. iXX, iXX, iXX, iXX,
  171. iXX, iXX, iXX, iXX,
  172. PLUS_Y, MINUS_Z, MINUS_Y, PLUS_Z,
  173. MINUS_Y, PLUS_Z, PLUS_Y, MINUS_Z,
  174. PLUS_Z, PLUS_Y, MINUS_Z, MINUS_Y,
  175. MINUS_Z, MINUS_Y, PLUS_Z, PLUS_Y,
  176. // oldDir = -x
  177. iXX, iXX, iXX, iXX,
  178. iXX, iXX, iXX, iXX,
  179. PLUS_Y, PLUS_Z, MINUS_Y, MINUS_Z,
  180. MINUS_Y, MINUS_Z, PLUS_Y, PLUS_Z,
  181. PLUS_Z, MINUS_Y, MINUS_Z, PLUS_Y,
  182. MINUS_Z, PLUS_Y, PLUS_Z, MINUS_Y,
  183. // oldDir = +y
  184. PLUS_X, PLUS_Z, MINUS_X, MINUS_Z,
  185. MINUS_X, MINUS_Z, PLUS_X, PLUS_Z,
  186. iXX, iXX, iXX, iXX,
  187. iXX, iXX, iXX, iXX,
  188. PLUS_Z, MINUS_X, MINUS_Z, PLUS_X,
  189. MINUS_Z, PLUS_X, PLUS_Z, MINUS_X,
  190. // oldDir = -y
  191. PLUS_X, MINUS_Z, MINUS_X, PLUS_Z,
  192. MINUS_X, PLUS_Z, PLUS_X, MINUS_Z,
  193. iXX, iXX, iXX, iXX,
  194. iXX, iXX, iXX, iXX,
  195. PLUS_Z, PLUS_X, MINUS_Z, MINUS_X,
  196. MINUS_Z, MINUS_X, PLUS_Z, PLUS_X,
  197. // oldDir = +z
  198. PLUS_X, MINUS_Y, MINUS_X, PLUS_Y,
  199. MINUS_X, PLUS_Y, PLUS_X, MINUS_Y,
  200. PLUS_Y, PLUS_X, MINUS_Y, MINUS_X,
  201. MINUS_Y, MINUS_X, PLUS_Y, PLUS_X,
  202. iXX, iXX, iXX, iXX,
  203. iXX, iXX, iXX, iXX,
  204. // oldDir = -z
  205. PLUS_X, PLUS_Y, MINUS_X, MINUS_Y,
  206. MINUS_X, MINUS_Y, PLUS_X, PLUS_Y,
  207. PLUS_Y, MINUS_X, MINUS_Y, PLUS_X,
  208. MINUS_Y, PLUS_X, PLUS_Y, MINUS_X,
  209. iXX, iXX, iXX, iXX,
  210. iXX, iXX, iXX, iXX
  211. };
  212. //-----------------------------------------------------------------------------
  213. // Name: ChooseElbow
  214. // Desc: - Decides which elbow to draw
  215. // - The beginning of each elbow is aligned along +y, and we have
  216. // to choose the one with the notch in correct position
  217. // - The 'primary' start notch (elbow[0]) is in same direction as
  218. // newDir, and successive elbows rotate this notch CCW around +y
  219. //-----------------------------------------------------------------------------
  220. int NORMAL_PIPE::ChooseElbow( int oldDir, int newDir )
  221. {
  222. int i;
  223. // precomputed table supplies correct elbow orientation
  224. for( i=0; i<4; i++ )
  225. {
  226. if( notchElbDir[oldDir][newDir][i] == m_notchVec )
  227. return i;
  228. }
  229. // we shouldn't arrive here
  230. return -1;
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Name: DrawJoint
  234. // Desc: Draw a joint between 2 pipes
  235. //-----------------------------------------------------------------------------
  236. void NORMAL_PIPE::DrawJoint( int newDir )
  237. {
  238. int jointType;
  239. int iBend;
  240. jointType = m_pNState->ChooseJointType();
  241. #if PIPES_DEBUG
  242. if( newDir == oppositeDir[lastDir] )
  243. OutputDebugString( "Warning: opposite dir chosen!\n" );
  244. #endif
  245. switch( jointType )
  246. {
  247. case BALL_JOINT:
  248. {
  249. if( m_pState->m_bUseTexture )
  250. {
  251. // use special texture-friendly ballJoints
  252. align_plusz( newDir );
  253. m_pWorldMatrixStack->Push();
  254. align_plusy( m_lastDir, newDir );
  255. // translate forward 1.0*r along +z to get set for drawing elbow
  256. m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
  257. // decide which elbow orientation to use
  258. iBend = ChooseElbow( m_lastDir, newDir );
  259. m_pNState->m_pBallJoints[iBend]->Draw( m_pWorldMatrixStack->GetTop() );
  260. m_pWorldMatrixStack->Pop();
  261. }
  262. else
  263. {
  264. // draw big ball in default orientation
  265. m_pNState->m_pBigBall->Draw( m_pWorldMatrixStack->GetTop() );
  266. align_plusz( newDir );
  267. }
  268. // move ahead 1.0*r to draw pipe
  269. m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
  270. break;
  271. }
  272. case ELBOW_JOINT:
  273. default:
  274. {
  275. align_plusz( newDir );
  276. // the align_plusy() here will mess up
  277. // our notch calcs, so we push-pop
  278. m_pWorldMatrixStack->Push();
  279. align_plusy( m_lastDir, newDir );
  280. // translate forward 1.0*r along +z to get set for drawing elbow
  281. m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
  282. // decide which elbow orientation to use
  283. iBend = ChooseElbow( m_lastDir, newDir );
  284. if( iBend == -1 )
  285. {
  286. #if PIPES_DEBUG
  287. OutputDebugString( "Bad result from ChooseElbow()\n" );
  288. #endif
  289. iBend = 0; // recover
  290. }
  291. m_pNState->m_pElbows[iBend]->Draw( m_pWorldMatrixStack->GetTop() );
  292. m_pWorldMatrixStack->Pop();
  293. m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
  294. break;
  295. }
  296. }
  297. // update the current notch vector
  298. m_notchVec = notchTurn[m_lastDir][newDir][m_notchVec];
  299. #if PIPES_DEBUG
  300. if( m_notchVec == iXX )
  301. OutputDebugString( "notchTurn gave bad value\n" );
  302. #endif
  303. }
  304. //-----------------------------------------------------------------------------
  305. // Name: align_plusy
  306. // Desc: - Assuming +z axis is already aligned with newDir, align
  307. // +y axis BACK along lastDir
  308. //-----------------------------------------------------------------------------
  309. void NORMAL_PIPE::align_plusy( int oldDir, int newDir )
  310. {
  311. static D3DXVECTOR3 zAxis = D3DXVECTOR3(0.0f,0.0f,1.0f);
  312. static float RotZ[NUM_DIRS][NUM_DIRS] =
  313. {
  314. 0.0f, 0.0f, 90.0f, 90.0f, 90.0f, -90.0f,
  315. 0.0f, 0.0f, -90.0f, -90.0f, -90.0f, 90.0f,
  316. 180.0f, 180.0f, 0.0f, 0.0f, 180.0f, 180.0f,
  317. 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
  318. -90.0f, 90.0f, 0.0f, 180.0f, 0.0f, 0.0f,
  319. 90.0f, -90.0f, 180.0f, 0.0f, 0.0f, 0.0f
  320. };
  321. float rotz = RotZ[oldDir][newDir];
  322. if( rotz != 0.0f )
  323. m_pWorldMatrixStack->RotateAxisLocal( &zAxis, SS_DEG_TO_RAD(rotz) );
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Name: align_notch
  327. // Desc: - a cylinder is notched, and we have to line this up
  328. // with the previous primitive's notch which is maintained as
  329. // notchVec.
  330. // - this adds a rotation around z to achieve this
  331. //-----------------------------------------------------------------------------
  332. void NORMAL_PIPE::align_notch( int newDir, int notch )
  333. {
  334. float rotz;
  335. int curNotch;
  336. // figure out where notch is presently after +z alignment
  337. curNotch = defCylNotch[newDir];
  338. // (don't need this now we have lut)
  339. // given a dir, determine how much to rotate cylinder around z to match notches
  340. // format is [newDir][notchVec]
  341. static float alignNotchRot[NUM_DIRS][NUM_DIRS] =
  342. {
  343. fXX, fXX, 0.0f, 180.0f, 90.0f, -90.0f,
  344. fXX, fXX, 0.0f, 180.0f, -90.0f, 90.0f,
  345. -90.0f, 90.0f, fXX, fXX, 180.0f, 0.0f,
  346. -90.0f, 90.0f, fXX, fXX, 0.0f, 180.0f,
  347. -90.0f, 90.0f, 0.0f, 180.0f, fXX, fXX,
  348. 90.0f, -90.0f, 0.0f, 180.0f, fXX, fXX
  349. };
  350. // look up rotation value in table
  351. rotz = alignNotchRot[newDir][notch];
  352. #if PIPES_DEBUG
  353. if( rotz == fXX )
  354. {
  355. printf( "align_notch(): unexpected value\n" );
  356. return;
  357. }
  358. #endif
  359. static D3DXVECTOR3 zAxis = D3DXVECTOR3(0.0f,0.0f,1.0f);
  360. if( rotz != 0.0f )
  361. m_pWorldMatrixStack->RotateAxisLocal( &zAxis, SS_DEG_TO_RAD(rotz) );
  362. }