Leaked source code of windows server 2003
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.

532 lines
22 KiB

  1. /*============================================================================
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: catrom.cpp
  6. * Content: Implementation for Catmull-Rom splines
  7. *
  8. ****************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. //-----------------------------------------------------------------------------
  12. // RefDev::ProcessCatRomSpline
  13. //-----------------------------------------------------------------------------
  14. HRESULT RefDev::ProcessCatRomSpline( DWORD dwOffW, DWORD dwOffH,
  15. DWORD dwWidth, DWORD dwHeight,
  16. DWORD dwStride,
  17. FLOAT *pPrimSegments )
  18. {
  19. int u_range = dwWidth - 3;
  20. int v_range = dwHeight - 3;
  21. if(u_range <= 0 || v_range <= 0)
  22. {
  23. DPFERR("A Catmull-Rom spline needs at least 16 control points");
  24. return DDERR_INVALIDPARAMS;
  25. }
  26. RDCatRomSpline catrom;
  27. unsigned M[4], N[4];
  28. unsigned u_segs, v_segs, u_start, v_start;
  29. if(pPrimSegments != 0)
  30. {
  31. u_segs = unsigned(double(unsigned(pPrimSegments[0]) + unsigned(pPrimSegments[2])) / 2.0 + 0.5);
  32. v_segs = unsigned(double(unsigned(pPrimSegments[1]) + unsigned(pPrimSegments[3])) / 2.0 + 0.5);
  33. if(u_segs == 0)
  34. {
  35. u_segs = 1;
  36. }
  37. if(v_segs == 0)
  38. {
  39. v_segs = 1;
  40. }
  41. if(unsigned(pPrimSegments[0]) != unsigned(pPrimSegments[2]) || unsigned(pPrimSegments[1]) != unsigned(pPrimSegments[3]))
  42. {
  43. // First, gulp, the irregular outside
  44. // To make life easier, we don't want to deal with the case when u_segs or v_segs is one
  45. // This ensures that there is at least one inside point
  46. if(u_segs == 1)
  47. {
  48. u_segs = 2;
  49. }
  50. if(v_segs == 1)
  51. {
  52. v_segs = 2;
  53. }
  54. // Start with top edge
  55. unsigned segs = unsigned(pPrimSegments[0]);
  56. unsigned k_outer = 0;
  57. unsigned k_inner = 1;
  58. unsigned outer_inc = u_segs - 2;
  59. unsigned inner_inc = segs;
  60. unsigned outer = 0;
  61. unsigned inner = 0;
  62. double u0, v0, u1, v1, u2, v2, tu0, tv0, tu1, tv1, tu2, tv2;
  63. while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer < segs))
  64. {
  65. if(inner < outer)
  66. {
  67. _ASSERT(k_inner < u_segs - 1, "Error in logic");
  68. u0 = double(u_range * k_inner) / double(u_segs) + 3.0;
  69. v0 = double(v_range) / double(v_segs) + 3.0;
  70. u1 = double(u_range * k_outer) / double(segs) + 3.0;
  71. v1 = 0.0;
  72. u2 = double(u_range * (k_inner + 1)) / double(u_segs) + 3.0;
  73. v2 = v0;
  74. tu0 = double(k_inner) / double(u_segs);
  75. tv0 = 1.0 / double(v_segs);
  76. tu1 = double(k_outer) / double(segs);
  77. tv1 = 0.0;
  78. tu2 = double(k_inner + 1) / double(u_segs);
  79. tv2 = tv0;
  80. M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  81. u0 -= floor(u0);
  82. if((u_range * k_outer) % segs == 0)
  83. {
  84. M[1] = unsigned(u1) - 4;
  85. u1 = 1.0;
  86. }
  87. else
  88. {
  89. M[1] = unsigned(u1) - 3; // unsigned(u1) == floor(u1)
  90. u1 -= floor(u1);
  91. }
  92. M[2] = unsigned(u2) - 3; // unsigned(u2) == floor(u2)
  93. u2 -= floor(u2);
  94. N[2] = N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  95. v2 = v0 = v0 - floor(v0);
  96. N[1] = 0;
  97. ++k_inner;
  98. inner += inner_inc;
  99. }
  100. else
  101. {
  102. _ASSERT(k_outer < segs, "Error in logic");
  103. u0 = double(u_range * k_inner) / double(u_segs) + 3.0;
  104. v0 = double(v_range) / double(v_segs) + 3.0;
  105. u1 = double(u_range * k_outer) / double(segs) + 3.0;
  106. v1 = 0.0;
  107. u2 = double(u_range * (k_outer + 1)) / double(segs) + 3.0;
  108. v2 = v1;
  109. tu0 = double(k_inner) / double(u_segs);
  110. tv0 = 1.0 / double(v_segs);
  111. tu1 = double(k_outer) / double(segs);
  112. tv1 = 0.0;
  113. tu2 = double(k_outer + 1) / double(segs);
  114. tv2 = tv1;
  115. if((u_range * k_inner) % u_segs == 0)
  116. {
  117. M[0] = unsigned(u0) - 4;
  118. u0 = 1.0;
  119. }
  120. else
  121. {
  122. M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  123. u0 -= floor(u0);
  124. }
  125. M[1] = unsigned(u1) - 3; // unsigned(u1) == floor(u1)
  126. u1 -= floor(u1);
  127. if((u_range * (k_outer + 1)) % segs == 0)
  128. {
  129. M[2] = unsigned(u2) - 4;
  130. u2 = 1.0;
  131. }
  132. else
  133. {
  134. M[2] = unsigned(u2) - 3; // unsigned(u2) == floor(u2)
  135. u2 -= floor(u2);
  136. }
  137. N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  138. v0 -= floor(v0);
  139. N[2] = N[1] = 0;
  140. ++k_outer;
  141. outer += outer_inc;
  142. }
  143. HRESULT hr = DrawTessTri(catrom, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2, tu0, tv0, tu1, tv1, tu2, tv2, false, false, false);
  144. if(FAILED(hr))
  145. {
  146. return hr;
  147. }
  148. }
  149. // bottom edge
  150. segs = unsigned(pPrimSegments[2]);
  151. k_outer = segs;
  152. k_inner = u_segs - 1;
  153. inner_inc = segs;
  154. outer = 0;
  155. inner = 0;
  156. while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer > 0))
  157. {
  158. if(inner < outer)
  159. {
  160. _ASSERT(k_inner > 1, "Error in logic");
  161. u0 = double(u_range * k_inner) / double(u_segs) + 3.0;
  162. v0 = double(v_range * (v_segs - 1)) / double(v_segs) + 3.0;
  163. u1 = double(u_range * k_outer) / double(segs) + 3.0;
  164. v1 = double(v_range + 3);
  165. u2 = double(u_range * (k_inner - 1)) / double(u_segs) + 3.0;
  166. v2 = v0;
  167. tu0 = double(k_inner) / double(u_segs);
  168. tv0 = double(v_segs - 1) / double(v_segs);
  169. tu1 = double(k_outer) / double(segs);
  170. tv1 = 1.0;
  171. tu2 = double(k_inner - 1) / double(u_segs);
  172. tv2 = tv0;
  173. M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  174. u0 -= floor(u0);
  175. if((u_range * k_outer) % segs == 0)
  176. {
  177. M[1] = unsigned(u1) - 4;
  178. u1 = 1.0;
  179. }
  180. else
  181. {
  182. M[1] = unsigned(u1) - 3; // unsigned(u1) == floor(u1)
  183. u1 -= floor(u1);
  184. }
  185. M[2] = unsigned(u2) - 3; // unsigned(u2) == floor(u2)
  186. u2 -= floor(u2);
  187. N[2] = N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  188. v2 = v0 = v0 - floor(v0);
  189. N[1] = dwHeight - 4;
  190. v1 = 1.0;
  191. --k_inner;
  192. inner += inner_inc;
  193. }
  194. else
  195. {
  196. _ASSERT(k_outer > 0, "Error in logic");
  197. u0 = double(u_range * k_inner) / double(u_segs) + 3.0;
  198. v0 = double(v_range * (v_segs - 1)) / double(v_segs) + 3.0;
  199. u1 = double(u_range * k_outer) / double(segs) + 3.0;
  200. v1 = double(v_range + 3);
  201. u2 = double(u_range * (k_outer - 1)) / double(segs) + 3.0;
  202. v2 = v1;
  203. tu0 = double(k_inner) / double(u_segs);
  204. tv0 = double(v_segs - 1) / double(v_segs);
  205. tu1 = double(k_outer) / double(segs);
  206. tv1 = 1.0;
  207. tu2 = double(k_outer - 1) / double(segs);
  208. tv2 = tv1;
  209. M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  210. u0 -= floor(u0);
  211. if((u_range * k_outer) % segs == 0)
  212. {
  213. M[1] = unsigned(u1) - 4;
  214. u1 = 1.0;
  215. }
  216. else
  217. {
  218. M[1] = unsigned(u1) - 3; // unsigned(u1) == floor(u1)
  219. u1 -= floor(u1);
  220. }
  221. M[2] = unsigned(u2) - 3; // unsigned(u2) == floor(u2)
  222. u2 -= floor(u2);
  223. N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  224. v0 -= floor(v0);
  225. N[2] = N[1] = dwHeight - 4;
  226. v2 = v1 = 1.0;
  227. --k_outer;
  228. outer += outer_inc;
  229. }
  230. HRESULT hr = DrawTessTri(catrom, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2, tu0, tv0, tu1, tv1, tu2, tv2, false, false, false);
  231. if(FAILED(hr))
  232. {
  233. return hr;
  234. }
  235. }
  236. // right edge
  237. segs = unsigned(pPrimSegments[1]);
  238. k_outer = 0;
  239. k_inner = 1;
  240. outer_inc = v_segs - 2;
  241. inner_inc = segs;
  242. outer = 0;
  243. inner = 0;
  244. while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer < segs))
  245. {
  246. if(inner < outer)
  247. {
  248. _ASSERT(k_inner < v_segs - 1, "Error in logic");
  249. u0 = double(u_range * (u_segs - 1)) / double(u_segs) + 3.0;
  250. v0 = double(v_range * k_inner) / double(v_segs) + 3.0;
  251. u1 = double(u_range + 3);
  252. v1 = double(v_range * k_outer) / double(segs) + 3.0;
  253. u2 = u0;
  254. v2 = double(v_range * (k_inner + 1)) / double(v_segs) + 3.0;
  255. tu0 = double(u_segs - 1) / double(u_segs);
  256. tv0 = double(k_inner) / double(v_segs);
  257. tu1 = 1.0;
  258. tv1 = double(k_outer) / double(segs);
  259. tu2 = tu0;
  260. tv2 = double(k_inner + 1) / double(v_segs);
  261. M[2] = M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  262. u2 = u0 = u0 - floor(u0);
  263. M[1] = dwWidth - 4;
  264. u1 = 1.0;
  265. N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  266. v0 -= floor(v0);
  267. if((v_range * k_outer) % segs == 0)
  268. {
  269. N[1] = unsigned(v1) - 4;
  270. v1 = 1.0;
  271. }
  272. else
  273. {
  274. N[1] = unsigned(v1) - 3; // unsigned(v1) == floor(v1)
  275. v1 -= floor(v1);
  276. }
  277. N[2] = unsigned(v2) - 3; // unsigned(v2) == floor(v2)
  278. v2 -= floor(v2);
  279. ++k_inner;
  280. inner += inner_inc;
  281. }
  282. else
  283. {
  284. _ASSERT(k_outer < segs, "Error in logic");
  285. u0 = double(u_range * (u_segs - 1)) / double(u_segs) + 3.0;
  286. v0 = double(v_range * k_inner) / double(v_segs) + 3.0;
  287. u1 = double(u_range + 3);
  288. v1 = double(v_range * k_outer) / double(segs) + 3.0;
  289. u2 = u1;
  290. v2 = double(v_range * (k_outer + 1)) / double(segs) + 3.0;
  291. tu0 = double(u_segs - 1) / double(u_segs);
  292. tv0 = double(k_inner) / double(v_segs);
  293. tu1 = 1.0;
  294. tv1 = double(k_outer) / double(segs);
  295. tu2 = tu1;
  296. tv2 = double(k_outer + 1) / double(segs);
  297. M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  298. u0 -= floor(u0);
  299. M[2] = M[1] = dwWidth - 4;
  300. u2 = u1 = 1.0;
  301. if((v_range * k_inner) % v_segs == 0)
  302. {
  303. N[0] = unsigned(v0) - 4;
  304. v0 = 1.0;
  305. }
  306. else
  307. {
  308. N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  309. v0 -= floor(v0);
  310. }
  311. N[1] = unsigned(v1) - 3; // unsigned(v1) == floor(v1)
  312. v1 -= floor(v1);
  313. if((v_range * (k_outer + 1)) % segs == 0)
  314. {
  315. N[2] = unsigned(v2) - 4;
  316. v2 = 1.0;
  317. }
  318. else
  319. {
  320. N[2] = unsigned(v2) - 3; // unsigned(v2) == floor(v2)
  321. v2 -= floor(v2);
  322. }
  323. ++k_outer;
  324. outer += outer_inc;
  325. }
  326. HRESULT hr = DrawTessTri(catrom, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2, tu0, tv0, tu1, tv1, tu2, tv2, false, false, false);
  327. if(FAILED(hr))
  328. {
  329. return hr;
  330. }
  331. }
  332. // left edge
  333. segs = unsigned(pPrimSegments[3]);
  334. k_outer = segs;
  335. k_inner = v_segs - 1;
  336. inner_inc = segs;
  337. outer = 0;
  338. inner = 0;
  339. while(outer_inc != 0 ? (inner != inner_inc * outer_inc || outer != inner_inc * outer_inc) : (k_outer > 0))
  340. {
  341. if(inner < outer)
  342. {
  343. _ASSERT(k_inner > 1, "Error in logic");
  344. u0 = double(u_range) / double(u_segs) + 3.0;
  345. v0 = double(v_range * k_inner) / double(v_segs) + 3.0;
  346. u1 = 0.0;
  347. v1 = double(v_range * k_outer) / double(segs) + 3.0;
  348. u2 = u0;
  349. v2 = double(v_range * (k_inner - 1)) / double(v_segs) + 3.0;
  350. tu0 = 1.0 / double(u_segs);
  351. tv0 = double(k_inner) / double(v_segs);
  352. tu1 = 0.0;
  353. tv1 = double(k_outer) / double(segs);
  354. tu2 = tu0;
  355. tv2 = double(k_inner - 1) / double(v_segs);
  356. M[2] = M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  357. u2 = u0 = u0 - floor(u0);
  358. M[1] = 0;
  359. N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  360. v0 -= floor(v0);
  361. if((v_range * k_outer) % segs == 0)
  362. {
  363. N[1] = unsigned(v1) - 4;
  364. v1 = 1.0;
  365. }
  366. else
  367. {
  368. N[1] = unsigned(v1) - 3; // unsigned(v1) == floor(v1)
  369. v1 -= floor(v1);
  370. }
  371. N[2] = unsigned(v2) - 3; // unsigned(v2) == floor(v2)
  372. v2 -= floor(v2);
  373. --k_inner;
  374. inner += inner_inc;
  375. }
  376. else
  377. {
  378. _ASSERT(k_outer > 0, "Error in logic");
  379. u0 = double(u_range) / double(u_segs) + 3.0;
  380. v0 = double(v_range * k_inner) / double(v_segs) + 3.0;
  381. u1 = 0.0;
  382. v1 = double(v_range * k_outer) / double(segs) + 3.0;
  383. u2 = u1;
  384. v2 = double(v_range * (k_outer - 1)) / double(segs) + 3.0;
  385. tu0 = 1.0 / double(u_segs);
  386. tv0 = double(k_inner) / double(v_segs);
  387. tu1 = 0.0;
  388. tv1 = double(k_outer) / double(segs);
  389. tu2 = tu1;
  390. tv2 = double(k_outer - 1) / double(segs);
  391. M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  392. u0 -= floor(u0);
  393. M[2] = M[1] = 0;
  394. N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  395. v0 -= floor(v0);
  396. if((v_range * k_outer) % segs == 0)
  397. {
  398. N[1] = unsigned(v1) - 4;
  399. v1 = 1.0;
  400. }
  401. else
  402. {
  403. N[1] = unsigned(v1) - 3; // unsigned(v1) == floor(v1)
  404. v1 -= floor(v1);
  405. }
  406. N[2] = unsigned(v2) - 3; // unsigned(v2) == floor(v2)
  407. v2 -= floor(v2);
  408. --k_outer;
  409. outer += outer_inc;
  410. }
  411. HRESULT hr = DrawTessTri(catrom, dwOffW, dwOffH, dwStride, M, N, u0, v0, u1, v1, u2, v2, tu0, tv0, tu1, tv1, tu2, tv2, false, false, false);
  412. if(FAILED(hr))
  413. {
  414. return hr;
  415. }
  416. }
  417. // Now do the regular interior
  418. u_start = 1;
  419. v_start = 1;
  420. }
  421. else
  422. {
  423. // It can be done regularly
  424. u_start = 0;
  425. v_start = 0;
  426. }
  427. }
  428. else
  429. {
  430. unsigned segs = unsigned(GetRSf()[D3DRS_PATCHSEGMENTS]);
  431. if(segs == 0)
  432. {
  433. segs = 1;
  434. }
  435. u_start = 0;
  436. v_start = 0;
  437. u_segs = segs;
  438. v_segs = segs;
  439. }
  440. for(unsigned i = v_start; i < v_segs - v_start; ++i)
  441. {
  442. double v0 = double(v_range * i) / double(v_segs) + 3.0;
  443. double v1 = double(v_range * (i + 1)) / double(v_segs) + 3.0;
  444. N[1] = N[0] = unsigned(v0) - 3; // unsigned(v0) == floor(v0)
  445. if((v_range * (i + 1)) % v_segs == 0)
  446. {
  447. N[3] = N[2] = unsigned(v1) - 4;
  448. v1 = 1.0;
  449. }
  450. else
  451. {
  452. N[3] = N[2] = unsigned(v1) - 3; // unsigned(v1) == floor(v1)
  453. v1 -= floor(v1);
  454. }
  455. for(unsigned j = u_start; j < u_segs - u_start; ++j)
  456. {
  457. double u0 = (u_range * double(j)) / double(u_segs) + 3.0;
  458. double u1 = (u_range * double(j + 1)) / double(u_segs) + 3.0;
  459. M[3] = M[0] = unsigned(u0) - 3; // unsigned(u0) == floor(u0)
  460. if((u_range * (j + 1)) % u_segs == 0)
  461. {
  462. M[2] = M[1] = unsigned(u1) - 4;
  463. u1 = 1.0;
  464. }
  465. else
  466. {
  467. M[2] = M[1] = unsigned(u1) - 3; // unsigned(u1) == floor(u1)
  468. u1 -= floor(u1);
  469. }
  470. HRESULT hr = DrawTessQuad(catrom, dwOffW, dwOffH, dwStride, M, N,
  471. u0 - floor(u0), v0 - floor(v0), u1, v1,
  472. double(j) / double(u_segs), double(i) / double(v_segs),
  473. double(j + 1) / double(u_segs), double(i + 1) / double(v_segs),
  474. false);
  475. if(FAILED(hr))
  476. {
  477. return hr;
  478. }
  479. }
  480. }
  481. return S_OK;
  482. }
  483. //-----------------------------------------------------------------------------
  484. // RDCatRomSpline::Basis
  485. //-----------------------------------------------------------------------------
  486. double RDCatRomSpline::Basis(unsigned i, unsigned k, double t) const
  487. {
  488. static const double lut[4][4] = {{-1.0/2.0, 3.0/2.0, -3.0/2.0, 1.0/2.0},
  489. {1.0, -5.0/2.0, 2.0, -1.0/2.0},
  490. {-1.0/2.0, 0.0, 1.0/2.0, 0.0},
  491. {0.0, 1.0, 0.0, 0.0}};
  492. _ASSERT(i < 4, "Catmull-Rom spline can be only cubic");
  493. return t * t * t * lut[0][i] + t * t * lut[1][i] + t * lut[2][i] + lut[3][i];
  494. }
  495. //-----------------------------------------------------------------------------
  496. // RDCatRomSpline::BasisPrime
  497. //-----------------------------------------------------------------------------
  498. double RDCatRomSpline::BasisPrime(unsigned i, unsigned k, double t) const
  499. {
  500. static const double lut[3][4] = {{-3.0/2.0, 9.0/2.0, -9.0/2.0, 3.0/2.0},
  501. {2.0, -5.0, 4.0, -1.0},
  502. {-1.0/2.0, 0.0, 1.0/2.0, 0.0}};
  503. _ASSERT(i < 4, "Catmull-Rom spline can be only cubic");
  504. return t * t * lut[0][i] + t * lut[1][i] + lut[2][i];
  505. }