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.

499 lines
15 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: eval.cpp
  3. //
  4. // Desc: EVAL class
  5. // Evaluator composed of one or more sections that are evaluated
  6. // separately with OpenGL evaluators
  7. //
  8. // Copyright (c) 1994-2000 Microsoft Corporation
  9. //-----------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. typedef enum
  12. {
  13. X_PLANE = 0,
  14. Y_PLANE,
  15. Z_PLANE
  16. };
  17. #define EVAL_VSIZE 3 // vertex size in floats
  18. #define TMAJOR_ORDER 2
  19. #define TMINOR_ORDER 2
  20. #define VDIM 3
  21. #define TDIM 2
  22. static void RotatePointSet( D3DXVECTOR3 *inPts, int numPts, float angle, int dir,
  23. float radius, D3DXVECTOR3 *outPts );
  24. static void ExtrudePointSetDir( D3DXVECTOR3 *inPts, int numPts, float *acPts,
  25. int dir, D3DXVECTOR3 *outPts );
  26. //-----------------------------------------------------------------------------
  27. // Name: EVAL
  28. // Desc: Evaluator constructor
  29. //-----------------------------------------------------------------------------
  30. EVAL::EVAL( BOOL bTex )
  31. {
  32. m_bTexture = bTex;
  33. // Allocate points buffer
  34. //mf: might want to use less than max in some cases
  35. int size = MAX_USECTIONS * MAX_UORDER * MAX_VORDER * sizeof(D3DXVECTOR3);
  36. m_pts = (D3DXVECTOR3 *) LocalAlloc( LMEM_FIXED, size );
  37. assert( m_pts != NULL && "EVAL constructor\n" );
  38. // Alloc texture points buffer
  39. if( m_bTexture )
  40. {
  41. size = MAX_USECTIONS * TEX_ORDER * TEX_ORDER * sizeof(TEX_POINT2D);
  42. m_texPts = (TEX_POINT2D *) LocalAlloc( LMEM_FIXED, size );
  43. assert( m_texPts != NULL && "EVAL constructor\n" );
  44. }
  45. ResetEvaluator( m_bTexture );
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Name: ~EVAL
  49. // Desc: Evaluator destructor
  50. //-----------------------------------------------------------------------------
  51. EVAL::~EVAL( )
  52. {
  53. LocalFree( m_pts );
  54. if( m_bTexture )
  55. LocalFree( m_texPts );
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Name: Reset
  59. // Desc: Reset evaluator to generate 3d vertices and vertex normals
  60. //-----------------------------------------------------------------------------
  61. void ResetEvaluator( BOOL bTexture )
  62. {
  63. /*
  64. if( bTexture )
  65. {
  66. glEnable( GL_MAP2_TEXTURE_COORD_2 );
  67. }
  68. glEnable( GL_MAP2_VERTEX_3 );
  69. glEnable( GL_AUTO_NORMAL );
  70. glFrontFace( GL_CW ); // cuz
  71. */
  72. // mf: !!! if mixing Normal and Flex, have to watch out for this, cuz normal
  73. // needs CCW
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Name: SetTextureControlPoints
  77. // Desc: Set texture control point net
  78. //
  79. // This sets up 'numSections' sets of texture coordinate control points, based
  80. // on starting and ending s and t values.
  81. //
  82. // s coords run along pipe direction, t coords run around circumference
  83. //-----------------------------------------------------------------------------
  84. void EVAL::SetTextureControlPoints( float s_start, float s_end,
  85. float t_start, float t_end )
  86. {
  87. int i;
  88. TEX_POINT2D *ptexPts = m_texPts;
  89. float t_delta = (t_end - t_start) / m_numSections;
  90. float t = t_start;
  91. // calc ctrl pts for each quadrant
  92. for( i = 0; i < m_numSections; i++, ptexPts += (TDIM*TDIM) )
  93. {
  94. // s, t coords
  95. ptexPts[0].t = ptexPts[2].t = t;
  96. t += t_delta;
  97. ptexPts[1].t = ptexPts[3].t = t;
  98. ptexPts[0].s = ptexPts[1].s = s_start;
  99. ptexPts[2].s = ptexPts[3].s = s_end;
  100. }
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Name: SetVertexCtrlPtsXCTranslate
  104. // Desc: Builds 3D control eval control net from 2 xcObjs displaced along the
  105. // z-axis by 'length'.
  106. //
  107. // First xc used to generate points in z=0 plane.
  108. // Second xc generates points in z=length plane.
  109. // ! Replicates the last point around each u.
  110. //-----------------------------------------------------------------------------
  111. void EVAL::SetVertexCtrlPtsXCTranslate( D3DXVECTOR3 *pts, float length,
  112. XC *xcStart, XC *xcEnd )
  113. {
  114. int i;
  115. D3DXVECTOR2 *ptsStart, *ptsEnd;
  116. D3DXVECTOR3 *pts1, *pts2;
  117. int numPts = xcStart->m_numPts;
  118. numPts++; // due to last point replication
  119. ptsStart = xcStart->m_pts;
  120. ptsEnd = xcEnd->m_pts;
  121. pts1 = pts;
  122. pts2 = pts + numPts;
  123. for( i = 0; i < (numPts-1); i++, pts1++, pts2++ )
  124. {
  125. // copy over x,y from each xc
  126. *( (D3DXVECTOR2 *) pts1) = *ptsStart++;
  127. *( (D3DXVECTOR2 *) pts2) = *ptsEnd++;
  128. // set z for each
  129. pts1->z = 0.0f;
  130. pts2->z = length;
  131. }
  132. // Replicate last point in each u-band
  133. *pts1 = *pts;
  134. *pts2 = *(pts + numPts);
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Name: ProcessXCPrimLinear
  138. // Desc: Processes a prim according to evaluator data
  139. // - Only valid for colinear xc's (along z)
  140. // - XC's may be identical (extrusion). If not identical, may have
  141. // discontinuities at each end.
  142. // - Converts 2D XC pts to 3D pts
  143. //-----------------------------------------------------------------------------
  144. void EVAL::ProcessXCPrimLinear( XC *xcStart, XC *xcEnd, float length )
  145. {
  146. if( length <= 0.0f )
  147. // nuttin' to do
  148. return;
  149. // Build a vertex control net from 2 xcObj's a distance 'length' apart
  150. // this will displace the end xcObj a distance 'length' down the z-axis
  151. SetVertexCtrlPtsXCTranslate( m_pts, length, xcStart, xcEnd );
  152. Evaluate( );
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Name: ProcessXCPrimBendSimple
  156. // Desc: Processes a prim by bending along dir from xcCur
  157. // - dir is relative from xc in x-y plane
  158. // - adds C2 continuity at ends
  159. //-----------------------------------------------------------------------------
  160. void EVAL::ProcessXCPrimBendSimple( XC *xcCur, int dir, float radius )
  161. {
  162. D3DXVECTOR3 *ptsSrc, *ptsDst;
  163. static float acPts[MAX_XC_PTS+1];
  164. int ptSetStride = xcCur->m_numPts + 1; // pt stride for output pts buffer
  165. // We will be creating 4 cross-sectional control point sets here.
  166. // Convert 2D pts in xcCur to 3D pts at z=0 for 1st point set
  167. xcCur->ConvertPtsZ( m_pts, 0.0f );
  168. // Calc 4th point set by rotating 1st set as per dir
  169. ptsDst = m_pts + 3*ptSetStride;
  170. RotatePointSet( m_pts, ptSetStride, 90.0f, dir, radius, ptsDst );
  171. // angles != 90, hard, cuz not easy to extrude 3rd set from 4th
  172. // Next, have to figure out ac values. Need to extend each xc's points
  173. // into bend to generate ac net. For circular bend (and later for general
  174. // case elliptical bend), need to know ac distance from xc for each point.
  175. // This is based on the point's turn radius - a function of its distance
  176. // from the 'hinge' of the turn.
  177. // Can take advantage of symmetry here. Figure for one xc, good for 2nd.
  178. // This assumes 90 deg turn. (also,last point replicated)
  179. xcCur->CalcArcACValues90( dir, radius, acPts );
  180. // 2) extrude each point's ac from xcCur (extrusion in +z)
  181. // apply values to 1st to get 2nd
  182. // MINUS_Z, cuz subtracts *back* from dir
  183. ExtrudePointSetDir( m_pts, ptSetStride, acPts, MINUS_Z,
  184. m_pts + ptSetStride );
  185. // 3) extrude each point's ac from xcEnd (extrusion in -dir)
  186. ptsSrc = m_pts + 3*ptSetStride;
  187. ptsDst = m_pts + 2*ptSetStride;
  188. ExtrudePointSetDir( ptsSrc, ptSetStride, acPts, dir, ptsDst );
  189. Evaluate();
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Name: EVAL::ProcessXCPrimSingularity
  193. // Desc: Processes a prim by joining singularity to an xc
  194. // - Used for closing or opening the pipe
  195. // - If bOpening is true, starts with singularity, otherwise ends with one
  196. // - the xc side is always in z=0 plane
  197. // - singularity side is radius on either side of xc
  198. // - adds C2 continuity at ends (perpendicular to +z at singularity end)
  199. //-----------------------------------------------------------------------------
  200. void EVAL::ProcessXCPrimSingularity( XC *xcCur, float length, BOOL bOpening )
  201. {
  202. D3DXVECTOR3 *ptsSing, *ptsXC;
  203. static float acPts[MAX_XC_PTS+1];
  204. float zSing; // z-value at singularity
  205. int ptSetStride = xcCur->m_numPts + 1; // pt stride for output pts buffer
  206. int i;
  207. XC xcSing(xcCur);
  208. // create singularity xc - which is an extremely scaled-down version
  209. // of xcCur (this prevents any end-artifacts, unless of course we were
  210. // to zoom it ultra-large).
  211. xcSing.Scale( .0005f );
  212. // We will be creating 4 cross-sectional control point sets here.
  213. // mf: 4 is like hard coded; what about for different xc component levels ?
  214. if( bOpening )
  215. {
  216. ptsSing = m_pts;
  217. ptsXC = m_pts + 3*ptSetStride;
  218. }
  219. else
  220. {
  221. ptsSing = m_pts + 3*ptSetStride;
  222. ptsXC = m_pts;
  223. }
  224. // Convert 2D pts in xcCur to 3D pts at 'xc' point set
  225. xcCur->ConvertPtsZ( ptsXC, 0.0f );
  226. // Set z-value for singularity point set
  227. zSing = bOpening ? -length : length;
  228. xcSing.ConvertPtsZ( ptsSing, zSing );
  229. // The arc control for each point is based on a radius value that is
  230. // each xc point's distance from the xc center
  231. xcCur->CalcArcACValuesByDistance( acPts );
  232. // Calculate point set near xc
  233. if( bOpening )
  234. ExtrudePointSetDir( ptsXC, ptSetStride, acPts, PLUS_Z,
  235. ptsXC - ptSetStride );
  236. else
  237. ExtrudePointSetDir( ptsXC, ptSetStride, acPts, MINUS_Z,
  238. ptsXC + ptSetStride );
  239. // Point set near singularity is harder, as the points must generate
  240. // a curve between the singularity and each xc point
  241. // No, easier, just scale each point by universal arc controller !
  242. D3DXVECTOR3* ptsDst = m_pts;
  243. ptsDst = bOpening ? ptsSing + ptSetStride : ptsSing - ptSetStride;
  244. for( i = 0; i < ptSetStride; i ++, ptsDst++ )
  245. {
  246. ptsDst->x = EVAL_CIRC_ARC_CONTROL * ptsXC[i].x;
  247. ptsDst->y = EVAL_CIRC_ARC_CONTROL * ptsXC[i].y;
  248. ptsDst->z = zSing;
  249. }
  250. Evaluate();
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Name: Evaluate
  254. // Desc: Evaluates the EVAL object
  255. // - There may be 1 or more lengthwise sections around an xc
  256. // - u is minor, v major
  257. // - u,t run around circumference, v,s lengthwise
  258. // - Texture maps are 2x2 for each section
  259. // - ! uDiv is per section !
  260. //-----------------------------------------------------------------------------
  261. void EVAL::Evaluate()
  262. {
  263. int i;
  264. D3DXVECTOR3 *ppts = m_pts;
  265. TEX_POINT2D *ptexPts = m_texPts;
  266. // total # pts in cross-section:
  267. int xcPointCount = (m_uOrder-1)*m_numSections + 1;
  268. for( i = 0; i < m_numSections; i ++,
  269. ppts += (m_uOrder-1),
  270. ptexPts += (TEX_ORDER*TEX_ORDER) )
  271. {
  272. /*
  273. // map texture coords
  274. if( bTexture )
  275. {
  276. glMap2f(GL_MAP2_TEXTURE_COORD_2,
  277. 0.0f, 1.0f, TDIM, TEX_ORDER,
  278. 0.0f, 1.0f, TEX_ORDER*TDIM, TEX_ORDER,
  279. (float *) ptexPts );
  280. }
  281. // map vertices
  282. glMa
  283. p2f(GL_MAP2_VERTEX_3,
  284. 0.0f, 1.0f, VDIM, uOrder,
  285. 0.0f, 1.0f, xcPointCount*VDIM, vOrder,
  286. (float *) ppts );
  287. // evaluate
  288. glMapGrid2f(uDiv, 0.0f, 1.0f, ``vDiv, 0.0f, 1.0f);
  289. glEvalMesh2( GL_FILL, 0, uDiv, 0, vDiv);
  290. */
  291. }
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Name: ExtrudePointSetDir
  295. // Desc: Extrude a point set back from the current direction
  296. // Generates C2 continuity at the supplied point set xc, by generating another
  297. // point set back of the first, using supplied subtraction values.
  298. //-----------------------------------------------------------------------------
  299. static void ExtrudePointSetDir( D3DXVECTOR3 *inPts, int numPts, float *acPts, int dir,
  300. D3DXVECTOR3 *outPts )
  301. {
  302. int i;
  303. float sign;
  304. int offset;
  305. switch( dir )
  306. {
  307. case PLUS_X:
  308. offset = 0;
  309. sign = -1.0f;
  310. break;
  311. case MINUS_X:
  312. offset = 0;
  313. sign = 1.0f;
  314. break;
  315. case PLUS_Y:
  316. offset = 1;
  317. sign = -1.0f;
  318. break;
  319. case MINUS_Y:
  320. offset = 1;
  321. sign = 1.0f;
  322. break;
  323. case PLUS_Z:
  324. offset = 2;
  325. sign = -1.0f;
  326. break;
  327. case MINUS_Z:
  328. offset = 2;
  329. sign = 1.0f;
  330. break;
  331. }
  332. for( i = 0; i < numPts; i++, inPts++, outPts++, acPts++ )
  333. {
  334. *outPts = *inPts;
  335. ((float *)outPts)[offset] = ((float *)inPts)[offset] + (sign * (*acPts));
  336. }
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Name: RotatePointSet
  340. // Desc: Rotate point set by angle, according to dir and radius
  341. // - Put points in supplied outPts buffer
  342. //-----------------------------------------------------------------------------
  343. static void RotatePointSet( D3DXVECTOR3 *inPts, int numPts, float angle, int dir,
  344. float radius, D3DXVECTOR3 *outPts )
  345. {
  346. D3DXMATRIX matrix1, matrix2, matrix3;
  347. int i;
  348. D3DXVECTOR3 rot = D3DXVECTOR3(0, 0, 0);
  349. D3DXVECTOR3 anchor = D3DXVECTOR3(0, 0, 0);
  350. // dir rot
  351. // +x 90 y
  352. // -x -90 y
  353. // +y -90 x
  354. // -y 90 x
  355. // convert angle to radians
  356. //mf: as noted in objects.c, we have to take negative angle to make
  357. // it work in familiar 'CCW rotation is positive' mode. The ss_* rotate
  358. // routines must work in the 'CW is +'ve' mode, as axis pointing at you.
  359. angle = SS_DEG_TO_RAD(-angle);
  360. // set axis rotation and anchor point
  361. switch( dir )
  362. {
  363. case PLUS_X:
  364. rot.y = angle;
  365. anchor.x = radius;
  366. break;
  367. case MINUS_X:
  368. rot.y = -angle;
  369. anchor.x = -radius;
  370. break;
  371. case PLUS_Y:
  372. rot.x = -angle;
  373. anchor.y = radius;
  374. break;
  375. case MINUS_Y:
  376. rot.x = angle;
  377. anchor.y = -radius;
  378. break;
  379. }
  380. // translate anchor point to origin
  381. D3DXMatrixIdentity( &matrix1 );
  382. D3DXMatrixTranslation( &matrix1, -anchor.x, -anchor.y, -anchor.z );
  383. // rotate
  384. D3DXMatrixIdentity( &matrix2 );
  385. D3DXMatrixRotationYawPitchRoll( &matrix2, rot.y, rot.x, rot.z ); // TODO: right?
  386. // concat these 2
  387. D3DXMatrixMultiply( &matrix3, &matrix2, &matrix1 );
  388. // translate back
  389. D3DXMatrixIdentity( &matrix2 );
  390. D3DXMatrixTranslation( &matrix2, anchor.x, anchor.y, anchor.z );
  391. // concat these 2
  392. D3DXMatrixMultiply( &matrix1, &matrix2, &matrix3 );
  393. for( i = 0; i < numPts; i ++, outPts++, inPts++ )
  394. {
  395. // D3DXVec3TransformCoord( &tmp, inPts, &matrix1 ); // TODO: which?
  396. D3DXVECTOR4 tmp;
  397. D3DXVec3Transform( &tmp, inPts, &matrix1 );
  398. outPts->x = tmp.x;
  399. outPts->y = tmp.y;
  400. outPts->z = tmp.z;
  401. }
  402. }