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.

2115 lines
54 KiB

  1. /**********************************Module*Header*******************************\
  2. * Module Name: Strips.c
  3. *
  4. * Hardware line drawing support routines
  5. *
  6. * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
  7. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
  8. \******************************************************************************/
  9. #include "precomp.h"
  10. #include "gdi.h"
  11. #define STRIP_LOG_LEVEL 6
  12. //-----------------------------------------------------------------------------
  13. //
  14. // BOOL bInitializeStrips
  15. //
  16. // Setup hardware for sucessive calls to strips functions.
  17. //
  18. //-----------------------------------------------------------------------------
  19. BOOL
  20. bInitializeStrips(PDev* ppdev,
  21. ULONG ulSolidColor, // Solid color fill
  22. DWORD dwLogicOp, // Logical Operation to perform
  23. RECTL* prclClip) // Clip region (Or NULL if no clip)
  24. {
  25. DWORD dwColorReg;
  26. BOOL bRC = FALSE;
  27. Surf* psurfDst = ppdev->psurf;
  28. ULONG* pBuffer;
  29. PERMEDIA_DECL;
  30. DBG_GDI((STRIP_LOG_LEVEL + 1, "bInitializeStrips"));
  31. InputBufferReserve(ppdev, 16, &pBuffer);
  32. pBuffer[0] = __Permedia2TagFBWindowBase;
  33. pBuffer[1] = psurfDst->ulPixOffset;
  34. pBuffer += 2;
  35. if ( dwLogicOp == K_LOGICOP_COPY )
  36. {
  37. dwColorReg = __Permedia2TagFBWriteData;
  38. pBuffer[0] = __Permedia2TagLogicalOpMode;
  39. pBuffer[1] = __PERMEDIA_CONSTANT_FB_WRITE;
  40. pBuffer[2] = __Permedia2TagFBReadMode;
  41. pBuffer[3] = PM_FBREADMODE_PARTIAL(psurfDst->ulPackedPP)
  42. | PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE);
  43. pBuffer += 4;
  44. }
  45. else
  46. {
  47. DWORD dwReadMode;
  48. //@@BEGIN_DDKSPLIT
  49. //
  50. // TODO: look into what the heck is going on here
  51. // for now, I'll remove the code because it is not clear to
  52. // me that it will work
  53. //@@END_DDKSPLIT
  54. // Special case for 3DS Max when page flipping. Max uses an XOR'ed GDI
  55. // line within the 3d window. When pageflipping we double write GDI and
  56. // so always write to buffer 0. We need to make sure the frame buffer
  57. // read happens from the currently displayed buffer.
  58. //
  59. dwColorReg = __Permedia2TagConstantColor;
  60. dwReadMode = psurfDst->ulPackedPP | LogicopReadDest[dwLogicOp];
  61. pBuffer[0] = __Permedia2TagColorDDAMode;
  62. pBuffer[1] = __COLOR_DDA_FLAT_SHADE;
  63. pBuffer[2] = __Permedia2TagLogicalOpMode;
  64. pBuffer[3] = P2_ENABLED_LOGICALOP(dwLogicOp);
  65. pBuffer[4] = __Permedia2TagFBReadMode;
  66. pBuffer[5] = dwReadMode;
  67. pBuffer += 6;
  68. //
  69. // We have changed the DDA Mode setting so we must return TRUE so we can
  70. // re-set it later.
  71. //
  72. bRC = TRUE;
  73. }
  74. pBuffer[0] = dwColorReg;
  75. pBuffer[1] = ulSolidColor;
  76. pBuffer += 2;
  77. if ( prclClip )
  78. {
  79. pBuffer[0] = __Permedia2TagScissorMode;
  80. pBuffer[1] = SCREEN_SCISSOR_DEFAULT | USER_SCISSOR_ENABLE;
  81. pBuffer[2] =__Permedia2TagScissorMinXY;
  82. pBuffer[3] = ((prclClip->left) << SCISSOR_XOFFSET)
  83. | ((prclClip->top) << SCISSOR_YOFFSET);
  84. pBuffer[4] =__Permedia2TagScissorMaxXY;
  85. pBuffer[5] = ((prclClip->right) << SCISSOR_XOFFSET)
  86. | ((prclClip->bottom) << SCISSOR_YOFFSET);
  87. pBuffer += 6;
  88. //
  89. // Need to reset scissor mode
  90. //
  91. bRC = TRUE;
  92. }
  93. InputBufferCommit(ppdev, pBuffer);
  94. DBG_GDI((STRIP_LOG_LEVEL + 1, "bInitializeStrips done return %d", bRC));
  95. return(bRC);
  96. }// bInitializeStrips()
  97. //-----------------------------------------------------------------------------
  98. //
  99. // VOID vResetStrips
  100. //
  101. // Resets the hardware to its default state
  102. //
  103. //-----------------------------------------------------------------------------
  104. VOID
  105. vResetStrips(PDev* ppdev)
  106. {
  107. ULONG* pBuffer;
  108. DBG_GDI((STRIP_LOG_LEVEL + 1, "vResetStrips"));
  109. //
  110. // Reset hardware to default state
  111. //
  112. InputBufferReserve(ppdev, 4 , &pBuffer);
  113. pBuffer[0] = __Permedia2TagScissorMode;
  114. pBuffer[1] = SCREEN_SCISSOR_DEFAULT;
  115. pBuffer[2] = __Permedia2TagColorDDAMode;
  116. pBuffer[3] = __PERMEDIA_DISABLE;
  117. pBuffer += 4;
  118. InputBufferCommit(ppdev, pBuffer);
  119. }// vResetStrips()
  120. //-----------------------------------------------------------------------------
  121. //
  122. // BOOL bFastIntegerLine
  123. //
  124. // Integer line drawing.
  125. //
  126. // Returns FALSE if the line can not be drawn due to hardware limitations
  127. //
  128. // NOTE: This algorithm is not completely compliant. Lines > 190 pixels long
  129. // may get some incorrect pixels plotted somewhere along the length.
  130. // If we detect these long lines then we fail the call.
  131. // NOTE: GLICAP_NT_CONFORMANT_LINES will always be set.
  132. //
  133. //-----------------------------------------------------------------------------
  134. BOOL
  135. bFastIntegerLine(PDev* ppdev,
  136. LONG X1,
  137. LONG Y1,
  138. LONG X2,
  139. LONG Y2)
  140. {
  141. LONG dx, dy, adx, ady;
  142. LONG gdx, gdy, count;
  143. ULONG* pBuffer;
  144. PERMEDIA_DECL;
  145. DBG_GDI((STRIP_LOG_LEVEL, "bFastIntegerLine"));
  146. //
  147. // Convert points to INT format
  148. //
  149. X1 >>= 4;
  150. Y1 >>= 4;
  151. X2 >>= 4;
  152. Y2 >>= 4;
  153. //
  154. // Get deltas and absolute deltas
  155. //
  156. if ( (adx = dx = X2 - X1) < 0 )
  157. {
  158. adx = -adx;
  159. }
  160. if ( (ady = dy = Y2 - Y1) < 0 )
  161. {
  162. ady = -ady;
  163. }
  164. if ( adx > ady )
  165. {
  166. //
  167. // X Major line
  168. //
  169. gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  170. if ( ady == 0 )
  171. {
  172. //
  173. // Horizontal lines
  174. //
  175. gdy = 0;
  176. }// if (ady == 0)
  177. else
  178. {
  179. //
  180. // We dont necessarily want to push any lines through Permedia2 that
  181. // might not be conformant
  182. //
  183. if ( (adx > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
  184. &&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
  185. {
  186. return(FALSE);
  187. }
  188. gdy = INTtoFIXED(dy);
  189. //
  190. // Need to explicitly round delta down for -ve deltas.
  191. //
  192. if ( dy < 0 )
  193. {
  194. gdy -= adx - 1;
  195. }
  196. gdy /= adx;
  197. }// if (ady != 0)
  198. count = adx;
  199. }// if ( adx > ady )
  200. else if ( adx < ady )
  201. {
  202. //
  203. // Y Major line
  204. //
  205. gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  206. if ( adx == 0 )
  207. {
  208. //
  209. // Vertical lines
  210. //
  211. gdx = 0;
  212. }
  213. else
  214. {
  215. //
  216. // We dont necessarily want to push any lines through Permedia2 that
  217. // might not be conformant
  218. //
  219. if ( (ady > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
  220. &&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
  221. {
  222. return(FALSE);
  223. }
  224. gdx = INTtoFIXED(dx);
  225. //
  226. // Need to explicitly round delta down for -ve deltas.
  227. //
  228. if ( dx < 0 )
  229. {
  230. gdx -= ady - 1;
  231. }
  232. gdx /= ady;
  233. }
  234. count = ady;
  235. }// if ( adx < ady )
  236. else
  237. {
  238. //
  239. // Special case for 45 degree lines. These are always conformant.
  240. //
  241. gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  242. gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  243. count = adx;
  244. }
  245. InputBufferReserve(ppdev, 16, &pBuffer);
  246. //
  247. // Set up the start point
  248. //
  249. pBuffer[0] = __Permedia2TagStartXDom;
  250. pBuffer[1] = INTtoFIXED(X1) + NEARLY_HALF;
  251. pBuffer[2] = __Permedia2TagStartY;
  252. pBuffer[3] = INTtoFIXED(Y1) + NEARLY_HALF;
  253. pBuffer[4] = __Permedia2TagdXDom;
  254. pBuffer[5] = gdx;
  255. pBuffer[6] = __Permedia2TagdY;
  256. pBuffer[7] = gdy;
  257. pBuffer[8] = __Permedia2TagCount;
  258. pBuffer[9] = count;
  259. pBuffer[10] = __Permedia2TagRender;
  260. pBuffer[11] = __RENDER_LINE_PRIMITIVE;
  261. pBuffer[12] = __Permedia2TagdXDom;
  262. pBuffer[13] = 0;
  263. pBuffer[14] = __Permedia2TagdY;
  264. pBuffer[15] = INTtoFIXED(1);
  265. pBuffer += 16;
  266. InputBufferCommit(ppdev, pBuffer);
  267. DBG_GDI((STRIP_LOG_LEVEL + 1, "bFastIntegerLine Done"));
  268. return(TRUE);
  269. }// bFastIntegerLine()
  270. //-----------------------------------------------------------------------------
  271. //
  272. // BOOL bFastIntegerContinueLine
  273. //
  274. // Integer line drawing through Permedia2.
  275. //
  276. // Returns FALSE if the line can not be drawn due to hardware limitations.
  277. //
  278. // NOTE: This algorithm is not completely compliant. Lines > 190 pixels long
  279. // may get some incorrect pixels plotted somewhere along the length.
  280. // If we detect these long lines then we fail the call.
  281. // NOTE: GLICAP_NT_CONFORMANT_LINES will always be set.
  282. //
  283. //-----------------------------------------------------------------------------
  284. BOOL
  285. bFastIntegerContinueLine(PDev* ppdev,
  286. LONG X1,
  287. LONG Y1,
  288. LONG X2,
  289. LONG Y2)
  290. {
  291. LONG dx, dy, adx, ady;
  292. LONG gdx, gdy, count;
  293. ULONG* pBuffer;
  294. PERMEDIA_DECL;
  295. DBG_GDI((STRIP_LOG_LEVEL + 1, "bFastIntegerContinueLine"));
  296. //
  297. // This assumes that the end point of the previous line is correct.
  298. // The Fraction adjust should be set to nearly a half to remove any
  299. // error from the end point of the previous line.
  300. // Get deltas and absolute deltas from 28.4 format
  301. //
  302. if ( (adx = dx = (X2 - X1) >> 4) < 0 )
  303. {
  304. adx = -adx;
  305. }
  306. if ( (ady = dy = (Y2 - Y1) >> 4) < 0 )
  307. {
  308. ady = -ady;
  309. }
  310. if ( adx > ady )
  311. {
  312. //
  313. // X Major line
  314. //
  315. gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  316. if (ady == 0)
  317. {
  318. //
  319. // Horizontal lines
  320. //
  321. gdy = 0;
  322. }
  323. else
  324. {
  325. //
  326. // We dont necessarily want to push any lines through Permedia2 that
  327. // might not be conformant
  328. //
  329. if ( (adx > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
  330. &&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
  331. {
  332. return(FALSE);
  333. }
  334. gdy = INTtoFIXED(dy);
  335. //
  336. // Need to explicitly round delta down for -ve deltas.
  337. //
  338. if ( dy < 0 )
  339. {
  340. gdy -= adx - 1;
  341. }
  342. gdy /= adx;
  343. }
  344. count = adx;
  345. }// if ( adx > ady )
  346. else if (adx < ady)
  347. {
  348. //
  349. // Y Major line
  350. //
  351. gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  352. if ( adx == 0 )
  353. {
  354. //
  355. // Vertical lines
  356. //
  357. gdx = 0;
  358. }
  359. else
  360. {
  361. //
  362. // We dont necessarily want to push any lines through Permedia2 that
  363. // might not be conformant
  364. //
  365. if ( (ady > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
  366. &&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
  367. {
  368. return(FALSE);
  369. }
  370. gdx = INTtoFIXED(dx);
  371. //
  372. // Need to explicitly round delta down for -ve deltas.
  373. //
  374. if ( dx < 0 )
  375. {
  376. gdx -= ady - 1;
  377. }
  378. gdx /= ady;
  379. }
  380. count = ady;
  381. }
  382. else
  383. {
  384. //
  385. // Special case for 45 degree lines. These are always conformant.
  386. //
  387. if ( ady == 0 )
  388. {
  389. return(TRUE); // adx == ady == 0! Nothing to draw.
  390. }
  391. gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  392. gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
  393. count = adx;
  394. }
  395. InputBufferReserve(ppdev, 10 , &pBuffer);
  396. //
  397. // Set up the start point
  398. //
  399. DBG_GDI((7, "Loading dXDom 0x%x, dY 0x%x, count 0x%x", gdx, gdy, count));
  400. pBuffer[0] = __Permedia2TagdXDom;
  401. pBuffer[1] = gdx;
  402. pBuffer[2] = __Permedia2TagdY;
  403. pBuffer[3] = gdy;
  404. pBuffer[4] = __Permedia2TagContinueNewLine;
  405. pBuffer[5] = count;
  406. //
  407. // Restore dXDom and dY to their defaults
  408. //
  409. pBuffer[6] = __Permedia2TagdXDom;
  410. pBuffer[7] = 0;
  411. pBuffer[8] = __Permedia2TagdY;
  412. pBuffer[9] = INTtoFIXED(1);
  413. pBuffer += 10;
  414. InputBufferCommit(ppdev, pBuffer);
  415. DBG_GDI((STRIP_LOG_LEVEL + 1, "bFastIntegerContinueLine Done"));
  416. return(TRUE);
  417. }// bFastIntegerContinueLine()
  418. //-----------------------------------------------------------------------------
  419. //
  420. // VOID vSolidHorizontal
  421. //
  422. // Draws left-to-right x-major near-horizontal lines using short-stroke
  423. // vectors.
  424. //
  425. //-----------------------------------------------------------------------------
  426. VOID
  427. vSolidHorizontalLine(PDev* ppdev,
  428. STRIP* pStrip,
  429. LINESTATE* pLineState)
  430. {
  431. LONG cStrips;
  432. PLONG pStrips;
  433. LONG iCurrent;
  434. ULONG* pBuffer;
  435. PERMEDIA_DECL;
  436. DBG_GDI((STRIP_LOG_LEVEL, "vSolidHorizontalLine"));
  437. cStrips = pStrip->cStrips;
  438. InputBufferReserve(ppdev, 16, &pBuffer);
  439. //
  440. // Set up the start point
  441. //
  442. pBuffer[0] = __Permedia2TagStartXDom;
  443. pBuffer[1] = INTtoFIXED(pStrip->ptlStart.x);
  444. pBuffer[2] = __Permedia2TagStartY;
  445. pBuffer[3] = INTtoFIXED(pStrip->ptlStart.y);
  446. //
  447. // Set up the deltas for rectangle drawing. Also set Y return value.
  448. //
  449. if ( !(pStrip->flFlips & FL_FLIP_V) )
  450. {
  451. pBuffer[4] = __Permedia2TagdXDom;
  452. pBuffer[5] = INTtoFIXED(0);
  453. pBuffer[6] = __Permedia2TagdXSub;
  454. pBuffer[7] = INTtoFIXED(0);
  455. pBuffer[8] = __Permedia2TagdY;
  456. pBuffer[9] = INTtoFIXED(1);
  457. pStrip->ptlStart.y += cStrips;
  458. }
  459. else
  460. {
  461. pBuffer[4] = __Permedia2TagdXDom;
  462. pBuffer[5] = INTtoFIXED(0);
  463. pBuffer[6] = __Permedia2TagdXSub;
  464. pBuffer[7] = INTtoFIXED(0);
  465. pBuffer[8] = __Permedia2TagdY;
  466. pBuffer[9] = INTtoFIXED(-1);
  467. pStrip->ptlStart.y -= cStrips;
  468. }
  469. pStrips = pStrip->alStrips;
  470. //
  471. // We have to do first strip manually, as we have to use RENDER
  472. // for the first strip, and CONTINUENEW... for the following strips
  473. //
  474. iCurrent = pStrip->ptlStart.x + *pStrips++; // Xsub, Start of next strip
  475. pBuffer[10] = __Permedia2TagStartXSub;
  476. pBuffer[11] = INTtoFIXED(iCurrent);
  477. pBuffer[12] = __Permedia2TagCount;
  478. pBuffer[13] = 1; // Rectangle 1 scanline high
  479. pBuffer[14] = __Permedia2TagRender;
  480. pBuffer[15] = __RENDER_TRAPEZOID_PRIMITIVE;
  481. pBuffer += 16;
  482. InputBufferCommit(ppdev, pBuffer);
  483. if ( --cStrips )
  484. {
  485. while ( cStrips > 1 )
  486. {
  487. //
  488. // First strip of each pair to fill. XSub is valid. Need new Xdom
  489. //
  490. iCurrent += *pStrips++;
  491. InputBufferReserve(ppdev, 8, &pBuffer);
  492. pBuffer[0] = __Permedia2TagStartXDom;
  493. pBuffer[1] = INTtoFIXED(iCurrent);
  494. pBuffer[2] = __Permedia2TagContinueNewDom;
  495. pBuffer[3] = 1;
  496. //
  497. // Second strip of each pair to fill. XDom is valid. Need new XSub
  498. //
  499. iCurrent += *pStrips++;
  500. pBuffer[4] = __Permedia2TagStartXSub;
  501. pBuffer[5] = INTtoFIXED(iCurrent);
  502. pBuffer[6] = __Permedia2TagContinueNewSub;
  503. pBuffer[7] = 1;
  504. pBuffer += 8;
  505. InputBufferCommit(ppdev, pBuffer);
  506. cStrips -=2;
  507. }// while ( cStrips > 1 )
  508. //
  509. // We may have one last line to draw. Xsub will be valid.
  510. //
  511. if ( cStrips )
  512. {
  513. iCurrent += *pStrips++;
  514. InputBufferReserve(ppdev, 4, &pBuffer);
  515. pBuffer[0] = __Permedia2TagStartXDom;
  516. pBuffer[1] = INTtoFIXED(iCurrent);
  517. pBuffer[2] = __Permedia2TagContinueNewDom;
  518. pBuffer[3] = 1;
  519. pBuffer += 4;
  520. InputBufferCommit(ppdev, pBuffer);
  521. }
  522. }// if ( --cStrips )
  523. //
  524. // Return last point. Y already calculated when we knew the direction.
  525. //
  526. pStrip->ptlStart.x = iCurrent;
  527. if ( pStrip->flFlips & FL_FLIP_V )
  528. {
  529. //
  530. // Restore hardware to default state
  531. //
  532. InputBufferReserve(ppdev, 2, &pBuffer);
  533. pBuffer[0] = __Permedia2TagdY;
  534. pBuffer[1] = INTtoFIXED(1);
  535. pBuffer += 2;
  536. InputBufferCommit(ppdev, pBuffer);
  537. }
  538. }// vSolidHorizontalLine()
  539. //-----------------------------------------------------------------------------
  540. //
  541. // VOID vSolidVertical
  542. //
  543. // Draws left-to-right y-major near-vertical lines using short-stroke
  544. // vectors.
  545. //
  546. //-----------------------------------------------------------------------------
  547. VOID
  548. vSolidVerticalLine(PDev* ppdev,
  549. STRIP* pStrip,
  550. LINESTATE* pLineState)
  551. {
  552. LONG cStrips, yDir;
  553. PLONG pStrips;
  554. LONG iCurrent, iLen, iLenSum;
  555. ULONG* pBuffer;
  556. PERMEDIA_DECL;
  557. DBG_GDI((STRIP_LOG_LEVEL, "vSolidVerticalLine"));
  558. cStrips = pStrip->cStrips;
  559. InputBufferReserve(ppdev, 16, &pBuffer);
  560. //
  561. // Set up the start point
  562. //
  563. pBuffer[0] = __Permedia2TagStartXDom;
  564. pBuffer[1] = INTtoFIXED(pStrip->ptlStart.x);
  565. pBuffer[2] = __Permedia2TagStartY;
  566. pBuffer[3] = INTtoFIXED(pStrip->ptlStart.y);
  567. pBuffer[4] = __Permedia2TagdXDom;
  568. pBuffer[5] = INTtoFIXED(0);
  569. pBuffer[6] = __Permedia2TagdXSub;
  570. pBuffer[7] = INTtoFIXED(0);
  571. //
  572. // Set up the deltas for rectangle drawing.
  573. // dxDom, dXSub and dY all are to 0, 0, and 1 by default
  574. //
  575. if ( !(pStrip->flFlips & FL_FLIP_V) )
  576. {
  577. yDir = 1;
  578. }
  579. else
  580. {
  581. yDir = -1;
  582. }
  583. pBuffer[8] = __Permedia2TagdY;
  584. pBuffer[9] = INTtoFIXED(yDir);
  585. pStrips = pStrip->alStrips;
  586. //
  587. // We have to do first strip manually, as we have to use RENDER
  588. // for the first strip, and CONTINUENEW... for the following strips
  589. //
  590. iCurrent = pStrip->ptlStart.x + 1; // Xsub, Start of next strip
  591. iLenSum = (iLen = *pStrips++);
  592. pBuffer[10] = __Permedia2TagStartXSub;
  593. pBuffer[11] = INTtoFIXED(iCurrent);
  594. pBuffer[12] = __Permedia2TagCount;
  595. pBuffer[13] = iLen; // Rectangle 1 scanline high
  596. pBuffer[14] = __Permedia2TagRender;
  597. pBuffer[15] = __RENDER_TRAPEZOID_PRIMITIVE;
  598. pBuffer += 16;
  599. InputBufferCommit(ppdev, pBuffer);
  600. if ( --cStrips )
  601. {
  602. while ( cStrips > 1 )
  603. {
  604. //
  605. // First strip of each pair to fill. XSub is valid. Need new Xdom
  606. //
  607. iCurrent++;
  608. InputBufferReserve(ppdev, 8, &pBuffer);
  609. pBuffer[0] = __Permedia2TagStartXDom;
  610. pBuffer[1] = INTtoFIXED(iCurrent);
  611. iLenSum += (iLen = *pStrips++);
  612. pBuffer[2] = __Permedia2TagContinueNewDom;
  613. pBuffer[3] = iLen;
  614. //
  615. // Second strip of each pair to fill. XDom is valid. Need new XSub
  616. //
  617. iCurrent ++;
  618. pBuffer[4] = __Permedia2TagStartXSub;
  619. pBuffer[5] = INTtoFIXED(iCurrent);
  620. iLenSum += (iLen = *pStrips++);
  621. pBuffer[6] = __Permedia2TagContinueNewSub;
  622. pBuffer[7] = iLen;
  623. pBuffer += 8;
  624. InputBufferCommit(ppdev, pBuffer);
  625. cStrips -=2;
  626. }// while ( cStrips > 1 )
  627. //
  628. // We may have one last line to draw. Xsub will be valid.
  629. //
  630. if ( cStrips )
  631. {
  632. iCurrent ++;
  633. InputBufferReserve(ppdev, 4, &pBuffer);
  634. pBuffer[0] = __Permedia2TagStartXDom;
  635. pBuffer[1] = INTtoFIXED(iCurrent);
  636. iLenSum += (iLen = *pStrips++);
  637. pBuffer[2] = __Permedia2TagContinueNewDom;
  638. pBuffer[3] = iLen;
  639. pBuffer += 4;
  640. InputBufferCommit(ppdev, pBuffer);
  641. }
  642. }// if ( --cStrips )
  643. //
  644. // Restore hardware to default
  645. //
  646. InputBufferReserve(ppdev, 2, &pBuffer);
  647. pBuffer[0] = __Permedia2TagdY;
  648. pBuffer[1] = INTtoFIXED(1);
  649. pBuffer += 2;
  650. InputBufferCommit(ppdev, pBuffer);
  651. //
  652. // Return last point.
  653. //
  654. pStrip->ptlStart.x = iCurrent;
  655. pStrip->ptlStart.y += iLenSum * yDir;
  656. DBG_GDI((STRIP_LOG_LEVEL + 1, "vSolidVerticalLine done"));
  657. }// vSolidVerticalLine()
  658. //-----------------------------------------------------------------------------
  659. //
  660. // VOID vSolidDiagonalVertical
  661. //
  662. // Draws left-to-right y-major near-diagonal lines using short-stroke
  663. // vectors.
  664. //
  665. //-----------------------------------------------------------------------------
  666. VOID
  667. vSolidDiagonalVerticalLine(PDev* ppdev,
  668. STRIP* pStrip,
  669. LINESTATE* pLineState)
  670. {
  671. LONG cStrips, yDir;
  672. PLONG pStrips;
  673. LONG iCurrent, iLen, iLenSum;
  674. ULONG* pBuffer;
  675. PERMEDIA_DECL;
  676. DBG_GDI((STRIP_LOG_LEVEL, "vSolidDiagonalVerticalLine"));
  677. cStrips = pStrip->cStrips;
  678. if ( !(pStrip->flFlips & FL_FLIP_V) )
  679. {
  680. yDir = 1;
  681. }
  682. else
  683. {
  684. yDir = -1;
  685. }
  686. InputBufferReserve(ppdev, 16, &pBuffer);
  687. //
  688. // Set up the deltas for rectangle drawing.
  689. //
  690. pBuffer[0] = __Permedia2TagdXDom;
  691. pBuffer[1] = INTtoFIXED(1);
  692. pBuffer[2] = __Permedia2TagdXSub;
  693. pBuffer[3] = INTtoFIXED(1);
  694. pBuffer[4] = __Permedia2TagdY;
  695. pBuffer[5] = INTtoFIXED(yDir);
  696. pStrips = pStrip->alStrips;
  697. //
  698. // We have to do first strip manually, as we have to use RENDER
  699. // for the first strip, and CONTINUENEW... for the following strips
  700. //
  701. pBuffer[6] = __Permedia2TagStartY;
  702. pBuffer[7] = INTtoFIXED(pStrip->ptlStart.y);
  703. pBuffer[8] = __Permedia2TagStartXDom;
  704. pBuffer[9] = INTtoFIXED(pStrip->ptlStart.x + 1);
  705. pBuffer[10] = __Permedia2TagStartXSub;
  706. pBuffer[11] = INTtoFIXED(pStrip->ptlStart.x);
  707. iLenSum = (iLen = *pStrips++);
  708. iCurrent = pStrip->ptlStart.x + iLen - 1;// Start of next strip
  709. pBuffer[12] = __Permedia2TagCount;
  710. pBuffer[13] = iLen; // Trap iLen scanline high
  711. pBuffer[14] = __Permedia2TagRender;
  712. pBuffer[15] = __RENDER_TRAPEZOID_PRIMITIVE;
  713. pBuffer += 16;
  714. InputBufferCommit(ppdev, pBuffer);
  715. if ( --cStrips )
  716. {
  717. while ( cStrips > 1 )
  718. {
  719. //
  720. // First strip of each pair to fill. XSub is valid. Need new Xdom
  721. //
  722. InputBufferReserve(ppdev, 8, &pBuffer);
  723. pBuffer[0] = __Permedia2TagStartXDom;
  724. pBuffer[1] = INTtoFIXED(iCurrent);
  725. iLenSum += (iLen = *pStrips++);
  726. iCurrent += iLen - 1;
  727. pBuffer[2] = __Permedia2TagContinueNewDom;
  728. pBuffer[3] = iLen;
  729. //
  730. // Second strip of each pair to fill. XDom is valid. Need new XSub
  731. //
  732. pBuffer[4] = __Permedia2TagStartXSub;
  733. pBuffer[5] = INTtoFIXED(iCurrent);
  734. iLenSum += (iLen = *pStrips++);
  735. iCurrent += iLen - 1;
  736. pBuffer[6] = __Permedia2TagContinueNewSub;
  737. pBuffer[7] = iLen;
  738. pBuffer += 8;
  739. InputBufferCommit(ppdev, pBuffer);
  740. cStrips -=2;
  741. }// while ( cStrips > 1 )
  742. //
  743. // We may have one last line to draw. Xsub will be valid.
  744. //
  745. if ( cStrips )
  746. {
  747. InputBufferReserve(ppdev, 4, &pBuffer);
  748. pBuffer[0] = __Permedia2TagStartXDom;
  749. pBuffer[1] = INTtoFIXED(iCurrent);
  750. iLenSum += (iLen = *pStrips++);
  751. iCurrent += iLen - 1;
  752. pBuffer[2] = __Permedia2TagContinueNewDom;
  753. pBuffer[3] = iLen;
  754. pBuffer += 4;
  755. InputBufferCommit(ppdev, pBuffer);
  756. }
  757. }// if ( --cStrips )
  758. InputBufferReserve(ppdev, 6, &pBuffer);
  759. pBuffer[0] = __Permedia2TagdXDom;
  760. pBuffer[1] = 0;
  761. pBuffer[2] = __Permedia2TagdXSub;
  762. pBuffer[3] = 0;
  763. pBuffer[4] = __Permedia2TagdY;
  764. pBuffer[5] = INTtoFIXED(1);
  765. pBuffer += 6;
  766. InputBufferCommit(ppdev, pBuffer);
  767. //
  768. // Return last point.
  769. //
  770. pStrip->ptlStart.x = iCurrent;
  771. pStrip->ptlStart.y += iLenSum * yDir;
  772. DBG_GDI((STRIP_LOG_LEVEL + 1, "vSolidDiagonalVerticalLine done"));
  773. }// vSolidDiagonalVerticalLine()
  774. //-----------------------------------------------------------------------------
  775. //
  776. // VOID vSolidDiagonalHorizontalLine
  777. //
  778. // Draws left-to-right x-major near-diagonal lines using short-stroke
  779. // vectors.
  780. //
  781. //-----------------------------------------------------------------------------
  782. VOID
  783. vSolidDiagonalHorizontalLine(PDev* ppdev,
  784. STRIP* pStrip,
  785. LINESTATE* pLineState)
  786. {
  787. LONG cStrips, yDir, xCurrent, yCurrent, iLen;
  788. PLONG pStrips;
  789. ULONG* pBuffer;
  790. PERMEDIA_DECL;
  791. DBG_GDI((STRIP_LOG_LEVEL, "vSolidDiagonalHorizontalLine"));
  792. // This routine has to be implemented in a different way to the other 3
  793. // solid line drawing functions because the rasterizer unit will not
  794. // produce 2 pixels on the same scanline without a lot of effort in
  795. // producing delta values. In this case, we have to draw a complete new
  796. // primitive for each strip. Therefore, we have to use lines rather than
  797. // trapezoids to generate the required strips. With lines we use 4 messages
  798. // per strip, where trapezoids would use 5.
  799. cStrips = pStrip->cStrips;
  800. if ( !(pStrip->flFlips & FL_FLIP_V) )
  801. {
  802. yDir = 1;
  803. }
  804. else
  805. {
  806. yDir = -1;
  807. }
  808. pStrips = pStrip->alStrips;
  809. xCurrent = pStrip->ptlStart.x;
  810. yCurrent = pStrip->ptlStart.y;
  811. InputBufferReserve(ppdev, 6, &pBuffer);
  812. //
  813. // Set up the deltas for rectangle drawing.
  814. //
  815. pBuffer[0] = __Permedia2TagdXDom;
  816. pBuffer[1] = INTtoFIXED(1);
  817. pBuffer[2] = __Permedia2TagdXSub;
  818. pBuffer[3] = INTtoFIXED(1);
  819. pBuffer[4] = __Permedia2TagdY;
  820. pBuffer[5] = INTtoFIXED(yDir);
  821. pBuffer += 6;
  822. InputBufferCommit(ppdev, pBuffer);
  823. while ( TRUE )
  824. {
  825. //
  826. // Set up the start point
  827. //
  828. InputBufferReserve(ppdev, 8, &pBuffer);
  829. pBuffer[0] = __Permedia2TagStartXDom;
  830. pBuffer[1] = INTtoFIXED(xCurrent);
  831. pBuffer[2] = __Permedia2TagStartY;
  832. pBuffer[3] = INTtoFIXED(yCurrent);
  833. iLen = *pStrips++;
  834. pBuffer[4] = __Permedia2TagCount;
  835. pBuffer[5] = iLen;
  836. pBuffer[6] = __Permedia2TagRender;
  837. pBuffer[7] = __RENDER_LINE_PRIMITIVE;
  838. pBuffer += 8;
  839. InputBufferCommit(ppdev, pBuffer);
  840. xCurrent += iLen;
  841. if ( yDir > 0 )
  842. {
  843. yCurrent += iLen - 1;
  844. }
  845. else
  846. {
  847. yCurrent -= iLen - 1;
  848. }
  849. if ( !(--cStrips) )
  850. {
  851. break;
  852. }
  853. }// while ( TRUE )
  854. InputBufferReserve(ppdev, 6, &pBuffer);
  855. pBuffer[0] = __Permedia2TagdXDom;
  856. pBuffer[1] = 0;
  857. pBuffer[2] = __Permedia2TagdXSub;
  858. pBuffer[3] = 0;
  859. pBuffer[4] = __Permedia2TagdY;
  860. pBuffer[5] = INTtoFIXED(1);
  861. pBuffer += 6;
  862. InputBufferCommit(ppdev, pBuffer);
  863. //
  864. // Return last point.
  865. //
  866. pStrip->ptlStart.x = xCurrent;
  867. pStrip->ptlStart.y = yCurrent;
  868. DBG_GDI((STRIP_LOG_LEVEL + 1, "vSolidDiagonalHorizontalLine done"));
  869. }// vSolidDiagonalHorizontalLine()
  870. //-----------------------------------------------------------------------------
  871. //
  872. // VOID vStyledHorizontalLine()
  873. //
  874. // Takes the list of strips that define the pixels that would be lit for
  875. // a solid line, and breaks them into styling chunks according to the
  876. // styling information that is passed in.
  877. //
  878. // This particular routine handles x-major lines that run left-to-right,
  879. // and are comprised of horizontal strips. It draws the dashes using
  880. // short-stroke vectors.
  881. //
  882. // The performance of this routine could be improved significantly.
  883. //
  884. // Parameters
  885. // ppdev-------PDEV pointer
  886. // pStrip------Strip info. Note: the data in the strip are already in normal
  887. // integer format, not 28.4 format
  888. // pLineState--Line state info
  889. //
  890. //-----------------------------------------------------------------------------
  891. VOID
  892. vStyledHorizontalLine(PDev* ppdev,
  893. STRIP* pStrip,
  894. LINESTATE* pLineState)
  895. {
  896. LONG x;
  897. LONG y;
  898. LONG dy;
  899. LONG* plStrip;
  900. ULONG* pBuffer;
  901. LONG lStripLength;
  902. LONG lTotalNumOfStrips;
  903. LONG lNumPixelRemain;
  904. LONG lCurrentLength;
  905. ULONG bIsGap;
  906. PERMEDIA_DECL;
  907. DBG_GDI((STRIP_LOG_LEVEL, "vStyledHorizontalLine"));
  908. if ( pStrip->flFlips & FL_FLIP_V )
  909. {
  910. dy = -1;
  911. }
  912. else
  913. {
  914. dy = 1;
  915. }
  916. lTotalNumOfStrips = pStrip->cStrips;// Total number of strips we'll do
  917. plStrip = pStrip->alStrips; // Points to current strip
  918. x = pStrip->ptlStart.x; // x position of start of first strip
  919. y = pStrip->ptlStart.y; // y position of start of first strip
  920. //
  921. // Set up the deltas for horizontal line drawing.
  922. //
  923. InputBufferReserve(ppdev, 4, &pBuffer);
  924. pBuffer[0] = __Permedia2TagdXDom;
  925. pBuffer[1] = INTtoFIXED(1);
  926. pBuffer[2] = __Permedia2TagdY;
  927. pBuffer[3] = 0;
  928. pBuffer += 4;
  929. InputBufferCommit(ppdev, pBuffer);
  930. lStripLength = *plStrip; // Number of pixels in first strip
  931. //
  932. // Number of pixels in first strip
  933. //
  934. lNumPixelRemain = pLineState->spRemaining;
  935. //
  936. // ulStyleMask is non-zero if we're in the middle of a 'gap',
  937. // and zero if we're in the middle of a 'dash':
  938. //
  939. bIsGap = pLineState->ulStyleMask;
  940. if ( bIsGap )
  941. {
  942. //
  943. // A gap
  944. //
  945. goto SkipAGap;
  946. }
  947. else
  948. {
  949. //
  950. // A dash
  951. //
  952. goto OutputADash;
  953. }
  954. PrepareToSkipAGap:
  955. //
  956. // Advance in the style-state array, so that we can find the next
  957. // 'dot' that we'll have to display:
  958. //
  959. bIsGap = ~bIsGap;
  960. pLineState->psp++;
  961. if ( pLineState->psp > pLineState->pspEnd )
  962. {
  963. pLineState->psp = pLineState->pspStart;
  964. }
  965. lNumPixelRemain = *pLineState->psp;
  966. //
  967. // If 'lStripLength' is zero, we also need a new strip:
  968. //
  969. if ( lStripLength != 0 )
  970. {
  971. goto SkipAGap;
  972. }
  973. //
  974. // Here, we're in the middle of a 'gap' where we don't have to
  975. // display anything. We simply cycle through all the strips
  976. // we can, keeping track of the current position, until we run
  977. // out of 'gap':
  978. //
  979. while ( TRUE )
  980. {
  981. //
  982. // Each time we loop, we move to a new scan and need a new strip
  983. //
  984. y += dy;
  985. plStrip++;
  986. lTotalNumOfStrips--;
  987. if ( lTotalNumOfStrips == 0 )
  988. {
  989. goto AllDone;
  990. }
  991. lStripLength = *plStrip;
  992. SkipAGap:
  993. lCurrentLength = min(lStripLength, lNumPixelRemain);
  994. lNumPixelRemain -= lCurrentLength;
  995. lStripLength -= lCurrentLength;
  996. x += lCurrentLength;
  997. if ( lNumPixelRemain == 0 )
  998. {
  999. goto PrepareToOutputADash;
  1000. }
  1001. }// while (TRUE)
  1002. PrepareToOutputADash:
  1003. //
  1004. // Advance in the style-state array, so that we can find the next
  1005. // 'dot' that we'll have to display:
  1006. //
  1007. bIsGap = ~bIsGap;
  1008. pLineState->psp++;
  1009. if ( pLineState->psp > pLineState->pspEnd )
  1010. {
  1011. pLineState->psp = pLineState->pspStart;
  1012. }
  1013. lNumPixelRemain = *pLineState->psp;
  1014. //
  1015. // If 'lStripLength' is zero, we also need a new strip.
  1016. //
  1017. if ( lStripLength != 0 )
  1018. {
  1019. //
  1020. // There's more to be done in the current strip, so set 'y'
  1021. // to be the current scan:
  1022. //
  1023. goto OutputADash;
  1024. }
  1025. while ( TRUE )
  1026. {
  1027. //
  1028. // Each time we loop, we move to a new scan and need a new strip:
  1029. //
  1030. y += dy;
  1031. plStrip++;
  1032. lTotalNumOfStrips--;
  1033. if ( lTotalNumOfStrips == 0 )
  1034. {
  1035. goto AllDone;
  1036. }
  1037. lStripLength = *plStrip;
  1038. OutputADash:
  1039. lCurrentLength = min(lStripLength, lNumPixelRemain);
  1040. lNumPixelRemain -= lCurrentLength;
  1041. lStripLength -= lCurrentLength;
  1042. //
  1043. // With Permedia2 we just download the lines to draw
  1044. //
  1045. InputBufferReserve(ppdev, 8, &pBuffer);
  1046. pBuffer[0] = __Permedia2TagStartXDom;
  1047. pBuffer[1] = INTtoFIXED(x);
  1048. pBuffer[2] = __Permedia2TagStartY;
  1049. pBuffer[3] = INTtoFIXED(y);
  1050. pBuffer[4] = __Permedia2TagCount;
  1051. pBuffer[5] = lCurrentLength;
  1052. pBuffer[6] = __Permedia2TagRender;
  1053. pBuffer[7] = __PERMEDIA_LINE_PRIMITIVE;
  1054. pBuffer += 8;
  1055. InputBufferCommit(ppdev, pBuffer);
  1056. x += lCurrentLength;
  1057. if ( lNumPixelRemain == 0 )
  1058. {
  1059. goto PrepareToSkipAGap;
  1060. }
  1061. }// while ( TRUE )
  1062. AllDone:
  1063. //
  1064. // Restore default state
  1065. //
  1066. InputBufferReserve(ppdev, 4, &pBuffer);
  1067. pBuffer[0] = __Permedia2TagdXDom;
  1068. pBuffer[1] = 0;
  1069. pBuffer[2] = __Permedia2TagdY;
  1070. pBuffer[3] = INTtoFIXED(1);
  1071. pBuffer += 4;
  1072. InputBufferCommit(ppdev, pBuffer);
  1073. //
  1074. // Update our state variables so that the next line can continue
  1075. // where we left off:
  1076. //
  1077. pLineState->spRemaining = lNumPixelRemain;
  1078. pLineState->ulStyleMask = bIsGap;
  1079. pStrip->ptlStart.x = x;
  1080. pStrip->ptlStart.y = y;
  1081. DBG_GDI((STRIP_LOG_LEVEL + 1, "vStyledHorizontalLine done"));
  1082. }// vStyledHorizontalLine()
  1083. //-----------------------------------------------------------------------------
  1084. //
  1085. // VOID vStripStyledVertical
  1086. //
  1087. // Takes the list of strips that define the pixels that would be lit for
  1088. // a solid line, and breaks them into styling chunks according to the
  1089. // styling information that is passed in.
  1090. //
  1091. // This particular routine handles y-major lines that run left-to-right,
  1092. // and are comprised of vertical strips. It draws the dashes using
  1093. // short-stroke vectors.
  1094. //
  1095. // The performance of this routine could be improved significantly.
  1096. //
  1097. //-----------------------------------------------------------------------------
  1098. VOID
  1099. vStyledVerticalLine(PDev* ppdev,
  1100. STRIP* pStrip,
  1101. LINESTATE* pLineState)
  1102. {
  1103. LONG x;
  1104. LONG y;
  1105. LONG dy;
  1106. LONG* plStrip;
  1107. LONG cStrips;
  1108. LONG cStyle;
  1109. LONG cStrip;
  1110. LONG cThis;
  1111. ULONG bIsGap;
  1112. ULONG* pBuffer;
  1113. PERMEDIA_DECL;
  1114. DBG_GDI((STRIP_LOG_LEVEL, "vStyledVerticalLine"));
  1115. //@@BEGIN_DDKSPLIT
  1116. //
  1117. // TODO: improve the performance of this routine
  1118. //
  1119. //@@END_DDKSPLIT
  1120. if ( pStrip->flFlips & FL_FLIP_V )
  1121. {
  1122. dy = -1;
  1123. }
  1124. else
  1125. {
  1126. dy = 1;
  1127. }
  1128. cStrips = pStrip->cStrips; // Total number of strips we'll do
  1129. plStrip = pStrip->alStrips; // Points to current strip
  1130. x = pStrip->ptlStart.x; // x position of start of first strip
  1131. y = pStrip->ptlStart.y; // y position of start of first strip
  1132. //
  1133. // Set up the deltas for vertical line drawing.
  1134. //
  1135. InputBufferReserve(ppdev, 6, &pBuffer);
  1136. pBuffer[0] = __Permedia2TagdXDom;
  1137. pBuffer[1] = INTtoFIXED(0);
  1138. pBuffer[2] = __Permedia2TagdXSub;
  1139. pBuffer[3] = INTtoFIXED(0);
  1140. pBuffer[4] = __Permedia2TagdY;
  1141. pBuffer[5] = INTtoFIXED(dy);
  1142. pBuffer += 6;
  1143. InputBufferCommit(ppdev, pBuffer);
  1144. cStrip = *plStrip; // Number of pels in first strip
  1145. cStyle = pLineState->spRemaining; // Number of pels in first 'gap' or 'dash'
  1146. bIsGap = pLineState->ulStyleMask; // Tells whether in a 'gap' or a 'dash'
  1147. // ulStyleMask is non-zero if we're in the middle of a 'gap',
  1148. // and zero if we're in the middle of a 'dash':
  1149. if ( bIsGap )
  1150. {
  1151. goto SkipAGap;
  1152. }
  1153. else
  1154. {
  1155. goto OutputADash;
  1156. }
  1157. PrepareToSkipAGap:
  1158. //
  1159. // Advance in the style-state array, so that we can find the next
  1160. // 'dot' that we'll have to display:
  1161. //
  1162. bIsGap = ~bIsGap;
  1163. pLineState->psp++;
  1164. if ( pLineState->psp > pLineState->pspEnd )
  1165. {
  1166. pLineState->psp = pLineState->pspStart;
  1167. }
  1168. cStyle = *pLineState->psp;
  1169. //
  1170. // If 'cStrip' is zero, we also need a new strip:
  1171. //
  1172. if ( cStrip != 0 )
  1173. {
  1174. goto SkipAGap;
  1175. }
  1176. //
  1177. // Here, we're in the middle of a 'gap' where we don't have to
  1178. // display anything. We simply cycle through all the strips
  1179. // we can, keeping track of the current position, until we run
  1180. // out of 'gap':
  1181. //
  1182. while ( TRUE )
  1183. {
  1184. //
  1185. // Each time we loop, we move to a new column and need a new strip:
  1186. //
  1187. x++;
  1188. plStrip++;
  1189. cStrips--;
  1190. if ( cStrips == 0 )
  1191. {
  1192. goto AllDone;
  1193. }
  1194. cStrip = *plStrip;
  1195. SkipAGap:
  1196. cThis = min(cStrip, cStyle);
  1197. cStyle -= cThis;
  1198. cStrip -= cThis;
  1199. y += (dy > 0) ? cThis : -cThis;
  1200. if ( cStyle == 0 )
  1201. {
  1202. goto PrepareToOutputADash;
  1203. }
  1204. }
  1205. PrepareToOutputADash:
  1206. //
  1207. // Advance in the style-state array, so that we can find the next
  1208. // 'dot' that we'll have to display:
  1209. //
  1210. bIsGap = ~bIsGap;
  1211. pLineState->psp++;
  1212. if ( pLineState->psp > pLineState->pspEnd )
  1213. {
  1214. pLineState->psp = pLineState->pspStart;
  1215. }
  1216. cStyle = *pLineState->psp;
  1217. //
  1218. // If 'cStrip' is zero, we also need a new strip.
  1219. //
  1220. if ( cStrip != 0 )
  1221. {
  1222. goto OutputADash;
  1223. }
  1224. while ( TRUE )
  1225. {
  1226. //
  1227. // Each time we loop, we move to a new column and need a new strip:
  1228. //
  1229. x++;
  1230. plStrip++;
  1231. cStrips--;
  1232. if ( cStrips == 0 )
  1233. {
  1234. goto AllDone;
  1235. }
  1236. cStrip = *plStrip;
  1237. OutputADash:
  1238. cThis = min(cStrip, cStyle);
  1239. cStyle -= cThis;
  1240. cStrip -= cThis;
  1241. //
  1242. // With Permedia2 we just download the lines to draw
  1243. //
  1244. InputBufferReserve(ppdev, 8, &pBuffer);
  1245. pBuffer[0] = __Permedia2TagStartXDom;
  1246. pBuffer[1] = INTtoFIXED(x);
  1247. pBuffer[2] = __Permedia2TagStartY;
  1248. pBuffer[3] = INTtoFIXED(y);
  1249. pBuffer[4] = __Permedia2TagCount;
  1250. pBuffer[5] = cThis;
  1251. pBuffer[6] = __Permedia2TagRender;
  1252. pBuffer[7] = __PERMEDIA_LINE_PRIMITIVE;
  1253. pBuffer += 8;
  1254. InputBufferCommit(ppdev, pBuffer);
  1255. y += (dy > 0) ? cThis : -cThis;
  1256. if ( cStyle == 0 )
  1257. {
  1258. goto PrepareToSkipAGap;
  1259. }
  1260. }// while ( TRUE )
  1261. AllDone:
  1262. //
  1263. // Restore hardware to default state
  1264. //
  1265. InputBufferReserve(ppdev, 2, &pBuffer);
  1266. pBuffer[0] = __Permedia2TagdY;
  1267. pBuffer[1] = INTtoFIXED(1);
  1268. pBuffer += 2;
  1269. InputBufferCommit(ppdev, pBuffer);
  1270. //
  1271. // Update our state variables so that the next line can continue
  1272. // where we left off:
  1273. //
  1274. pLineState->spRemaining = cStyle;
  1275. pLineState->ulStyleMask = bIsGap;
  1276. pStrip->ptlStart.x = x;
  1277. pStrip->ptlStart.y = y;
  1278. }// vStyledVerticalLine()
  1279. //
  1280. // For a given sub-pixel coordinate (x.m, y.n) in 28.4 fixed point
  1281. // format this array is indexed by (m,n) and indicates whether the
  1282. // given sub-pixel is within a GIQ diamond. m coordinates run left
  1283. // to right; n coordinates ru top to bottom so index the array with
  1284. // ((n<<4)+m). The array as seen here really contains 4 quarter
  1285. // diamonds.
  1286. //
  1287. static unsigned char in_diamond[] =
  1288. {
  1289. /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
  1290. /* 0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0 */
  1291. /* 1 */ 1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1, /* 1 */
  1292. /* 2 */ 1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1, /* 2 */
  1293. /* 3 */ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1, /* 3 */
  1294. /* 4 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1, /* 4 */
  1295. /* 5 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 5 */
  1296. /* 6 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6 */
  1297. /* 7 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7 */
  1298. /* 8 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8 */
  1299. /* 9 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9 */
  1300. /* a */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* a */
  1301. /* b */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1, /* b */
  1302. /* c */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1, /* c */
  1303. /* d */ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1, /* d */
  1304. /* e */ 1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1, /* e */
  1305. /* f */ 1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1, /* f */
  1306. /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
  1307. };
  1308. //
  1309. // For lines with abs(slope) != 1 use IN_DIAMOND to determine if an
  1310. // end point is in a diamond. For lines of slope = 1 use IN_S1DIAMOND.
  1311. // For lines of slope = -1 use IN_SM1DIAMOND. The last two are a bit
  1312. // strange. The documentation leaves us with a problem for slope 1
  1313. // lines which run exactly betwen the diamonds. According to the docs
  1314. // such a line can enter a diamond, leave it and enter again. This is
  1315. // plainly rubbish so along the appropriate edge of the diamond we
  1316. // consider a slope 1 line to be inside the diamond. This is the
  1317. // bottom right edge for lines of slope -1 and the bottom left edge for
  1318. // lines of slope 1.
  1319. //
  1320. #define IN_DIAMOND(m, n) (in_diamond[((m) << 4) + (n)])
  1321. #define IN_S1DIAMOND(m, n) ((in_diamond[((m) << 4) + (n)]) || \
  1322. ((m) - (n) == 8))
  1323. #define IN_SM1DIAMOND(m, n) ((in_diamond[((m) << 4) + (n)]) || \
  1324. ((m) + (n) == 8))
  1325. BOOL
  1326. bFastLine(PPDev ppdev,
  1327. LONG fx1,
  1328. LONG fy1,
  1329. LONG fx2,
  1330. LONG fy2)
  1331. {
  1332. register LONG adx, ady, tmp;
  1333. FIX m1, n1, m2, n2;
  1334. LONG dx, dy;
  1335. LONG dX, dY;
  1336. LONG count, startX, startY;
  1337. ULONG* pBuffer;
  1338. PERMEDIA_DECL;
  1339. DBG_GDI((STRIP_LOG_LEVEL, "bFastLine"));
  1340. //
  1341. // This function is only called if we have a line with non integer end points
  1342. // and the unsigned coordinates are no greater than 15.4.
  1343. //
  1344. // We can only guarantee to do lines whose coords need <= 12 bits
  1345. // of integer. This is because to get the delta we must shift
  1346. // by 16 bits. This includes 4 bits of fraction which means if
  1347. // we have more than 12 bits of integer we get overrun on the
  1348. // shift. We could use floating point to give us a better 16
  1349. // bits of integer but this requires an extra set of multiplies
  1350. // and divides in order to convert from 28.4 to fp. In any case
  1351. // we have to have a test to reject coords needing > 16 bits
  1352. // of integer.
  1353. // Actually, we can deal with 16.4 coordinates provided dx and dy
  1354. // never require more than 12 bits of integer.
  1355. // So optimise for the common case where the line is completely
  1356. // on the screen (actually 0 to 2047.f). Since the coords have
  1357. // 4 bits of fraction we note that a 32 bit signed number
  1358. // outside the range 0 to 2047.f will have one of its top 17
  1359. // bits set. So logical or all the coords and test against
  1360. // 0xffff8000. This is about as quick a test as we can get for
  1361. // both ends of the line being on the screen. If this test fails
  1362. // then we can check everything else at a leisurely pace.
  1363. //
  1364. //
  1365. // Get signed and absolute deltas
  1366. //
  1367. if ((adx = dx = fx2 - fx1) < 0)
  1368. {
  1369. adx = -adx;
  1370. }
  1371. if ((ady = dy = fy2 - fy1) < 0)
  1372. {
  1373. ady = -ady;
  1374. }
  1375. //
  1376. // Refuse to draw any lines whose delta is out of range.
  1377. // We have to shift the delta by 16, so we dont want to loose any precision
  1378. //
  1379. if ( (adx | ady) & 0xffff8000 )
  1380. {
  1381. return(FALSE);
  1382. }
  1383. //
  1384. // Fractional bits are used to check if point is in a diamond
  1385. //
  1386. m1 = fx1 & 0xf;
  1387. n1 = fy1 & 0xf;
  1388. m2 = fx2 & 0xf;
  1389. n2 = fy2 & 0xf;
  1390. //
  1391. // The rest of the code is a series of cases. Each one is "called" by a
  1392. // goto. This is simply to keep the nesting down. Main cases are: lines
  1393. // with absolute slope == 1; x-major lines; and y-major lines. We draw
  1394. // lines as they are given rather than always drawing in one direction.
  1395. // This adds extra code but saves the time required to swap the points
  1396. // and adjust for not drawing the end point.
  1397. //
  1398. startX = fx1 << 12;
  1399. startY = fy1 << 12;
  1400. DBG_GDI((7, "GDI Line %x, %x deltas %x, %x", startX, startY, dx, dy));
  1401. if ( adx < ady )
  1402. {
  1403. goto y_major;
  1404. }
  1405. if ( adx > ady )
  1406. {
  1407. goto x_major;
  1408. }
  1409. //
  1410. // All slope 1 lines are sampled in X. i.e. we move the start coord to
  1411. // an integer x and let Permedia2 truncate in y. This is because all GIQ
  1412. // lines are rounded down in y for values exactly half way between two
  1413. // pixels. If we sampled in y then we would have to round up in x for
  1414. // lines of slope 1 and round down in x for other lines. Sampling in x
  1415. // allows us to use the same Permedia2 bias in all cases (0x7fff). We do
  1416. // the x round up or down when we move the start point.
  1417. //
  1418. if ( dx != dy )
  1419. {
  1420. goto slope_minus_1;
  1421. }
  1422. if ( dx < 0 )
  1423. {
  1424. goto slope1_reverse;
  1425. }
  1426. dX = 1 << 16;
  1427. dY = 1 << 16;
  1428. if ( IN_S1DIAMOND(m1, n1) )
  1429. {
  1430. tmp = (startX + 0x8000) & ~0xffff;
  1431. }
  1432. else
  1433. {
  1434. tmp = (startX + 0xffff) & ~0xffff;
  1435. }
  1436. startY += tmp - startX;
  1437. startX = tmp;
  1438. if ( IN_S1DIAMOND(m2, n2) )
  1439. {
  1440. fx2 = (fx2 + 0x8) & ~0xf; // nearest integer
  1441. }
  1442. else
  1443. {
  1444. fx2 = (fx2 + 0xf) & ~0xf; // next integer
  1445. }
  1446. count = (fx2 >> 4) - (startX >> 16);
  1447. goto Draw_Line;
  1448. slope1_reverse:
  1449. dX = -1 << 16;
  1450. dY = -1 << 16;
  1451. if ( IN_S1DIAMOND(m1, n1) )
  1452. {
  1453. tmp = (startX + 0x8000) & ~0xffff;
  1454. }
  1455. else
  1456. {
  1457. tmp = startX & ~0xffff;
  1458. }
  1459. startY += tmp - startX;
  1460. startX = tmp;
  1461. if ( IN_S1DIAMOND(m2, n2) )
  1462. {
  1463. fx2 = (fx2 + 0x8) & ~0xf; // nearest integer
  1464. }
  1465. else
  1466. {
  1467. fx2 &= ~0xf; // previous integer
  1468. }
  1469. count = (startX >> 16) - (fx2 >> 4);
  1470. goto Draw_Line;
  1471. slope_minus_1:
  1472. if ( dx < 0 )
  1473. {
  1474. goto slope_minus_dx;
  1475. }
  1476. //
  1477. // dx > 0, dy < 0
  1478. //
  1479. dX = 1 << 16;
  1480. dY = -1 << 16;
  1481. if (IN_SM1DIAMOND(m1, n1))
  1482. {
  1483. tmp = (startX + 0x7fff) & ~0xffff;
  1484. }
  1485. else
  1486. {
  1487. tmp = (startX + 0xffff) & ~0xffff;
  1488. }
  1489. startY += startX - tmp;
  1490. startX = tmp;
  1491. if (IN_SM1DIAMOND(m2, n2))
  1492. {
  1493. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1494. }
  1495. else
  1496. {
  1497. fx2 = (fx2 + 0xf) & ~0xf; // next integer
  1498. }
  1499. count = (fx2 >> 4) - (startX >> 16);
  1500. goto Draw_Line;
  1501. slope_minus_dx:
  1502. dX = -1 << 16;
  1503. dY = 1 << 16;
  1504. if ( IN_SM1DIAMOND(m1, n1) )
  1505. {
  1506. tmp = (startX + 0x7fff) & ~0xffff;
  1507. }
  1508. else
  1509. {
  1510. tmp = startX & ~0xffff;
  1511. }
  1512. startY += startX - tmp;
  1513. startX = tmp;
  1514. if ( IN_SM1DIAMOND(m2, n2) )
  1515. {
  1516. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1517. }
  1518. else
  1519. {
  1520. fx2 &= ~0xf; // previous integer
  1521. }
  1522. count = (startX >> 16) - (fx2 >> 4);
  1523. goto Draw_Line;
  1524. x_major:
  1525. //
  1526. // Dont necessarily render through Permedia2 if we are worried about
  1527. // conformance.
  1528. //
  1529. if ( (adx > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4))
  1530. &&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES)
  1531. &&(ady != 0) )
  1532. {
  1533. return(FALSE);
  1534. }
  1535. if ( dx < 0 )
  1536. {
  1537. goto right_to_left_x;
  1538. }
  1539. //
  1540. // Line goes left to right. Round up the start x to an integer
  1541. // coordinate. This is the coord of the first diamond that the
  1542. // line crosses. Adjust start y to match this point on the line.
  1543. //
  1544. dX = 1 << 16;
  1545. if ( IN_DIAMOND(m1, n1) )
  1546. {
  1547. tmp = (startX + 0x7fff) & ~0xffff; // nearest integer
  1548. }
  1549. else
  1550. {
  1551. tmp = (startX + 0xffff) & ~0xffff; // next integer
  1552. }
  1553. //
  1554. // We can optimise for horizontal lines
  1555. //
  1556. if ( dy != 0 )
  1557. {
  1558. dY = dy << 16;
  1559. //
  1560. // Need to explicitly round delta down for -ve deltas.
  1561. //
  1562. if ( dy < 0 )
  1563. {
  1564. dY -= adx - 1;
  1565. }
  1566. dY /= adx;
  1567. startY += (((tmp - startX) >> 12) * dY) >> 4;
  1568. }
  1569. else
  1570. {
  1571. dY = 0;
  1572. }
  1573. startX = tmp;
  1574. if ( IN_DIAMOND(m2, n2) )
  1575. {
  1576. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1577. }
  1578. else
  1579. {
  1580. fx2 = (fx2 + 0xf) & ~0xf; // next integer
  1581. }
  1582. count = (fx2 >> 4) - (startX >> 16);
  1583. goto Draw_Line;
  1584. right_to_left_x:
  1585. dX = -1 << 16;
  1586. if ( IN_DIAMOND(m1, n1) )
  1587. {
  1588. tmp = (startX + 0x7fff) & ~0xffff; // nearest integer
  1589. }
  1590. else
  1591. {
  1592. tmp = startX & ~0xffff; // previous integer
  1593. }
  1594. //
  1595. // We can optimise for horizontal lines
  1596. //
  1597. if (dy != 0)
  1598. {
  1599. dY = dy << 16;
  1600. //
  1601. // Need to explicitly round delta down for -ve deltas.
  1602. //
  1603. if ( dy < 0 )
  1604. {
  1605. dY -= adx - 1;
  1606. }
  1607. dY /= adx;
  1608. startY += (((startX - tmp) >> 12) * dY) >> 4;
  1609. }
  1610. else
  1611. {
  1612. dY = 0;
  1613. }
  1614. startX = tmp;
  1615. if ( IN_DIAMOND(m2, n2) )
  1616. {
  1617. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1618. }
  1619. else
  1620. {
  1621. fx2 &= ~0xf; // previous integer
  1622. }
  1623. count = (startX >> 16) - (fx2 >> 4);
  1624. goto Draw_Line;
  1625. y_major:
  1626. //
  1627. // Dont necessarily render through Permedia2 if we are worried
  1628. // about conformance.
  1629. //
  1630. if ( (ady > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4))
  1631. &&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES)
  1632. &&(adx != 0) )
  1633. {
  1634. return(FALSE);
  1635. }
  1636. if ( dy < 0 )
  1637. {
  1638. goto high_to_low_y;
  1639. }
  1640. dY = 1 << 16;
  1641. if ( IN_DIAMOND(m1, n1) )
  1642. {
  1643. tmp = (startY + 0x7fff) & ~0xffff; // nearest integer
  1644. }
  1645. else
  1646. {
  1647. tmp = (startY + 0xffff) & ~0xffff; // next integer
  1648. }
  1649. //
  1650. // We can optimise for vertical lines
  1651. //
  1652. if ( dx != 0 )
  1653. {
  1654. dX = dx << 16;
  1655. //
  1656. // Need to explicitly round delta down for -ve deltas.
  1657. //
  1658. if ( dx < 0 )
  1659. {
  1660. dX -= ady - 1;
  1661. }
  1662. dX /= ady;
  1663. startX += (((tmp - startY) >> 12) * dX) >> 4;
  1664. }
  1665. else
  1666. {
  1667. dX = 0;
  1668. }
  1669. startY = tmp;
  1670. if ( IN_DIAMOND(m2, n2) )
  1671. {
  1672. fy2 = (fy2 + 0x7) & ~0xf; // nearest integer
  1673. }
  1674. else
  1675. {
  1676. fy2 = (fy2 + 0xf) & ~0xf; // next integer
  1677. }
  1678. count = (fy2 >> 4) - (startY >> 16);
  1679. goto Draw_Line;
  1680. high_to_low_y:
  1681. dY = -1 << 16;
  1682. if ( IN_DIAMOND(m1, n1) )
  1683. {
  1684. tmp = (startY + 0x7fff) & ~0xffff; // nearest integer
  1685. }
  1686. else
  1687. {
  1688. tmp = startY & ~0xffff; // previous integer
  1689. }
  1690. //
  1691. // We can optimise for horizontal lines
  1692. //
  1693. if ( dx != 0 )
  1694. {
  1695. dX = dx << 16;
  1696. //
  1697. // Need to explicitly round delta down for -ve deltas.
  1698. //
  1699. if ( dx < 0 )
  1700. {
  1701. dX -= ady - 1;
  1702. }
  1703. dX /= ady;
  1704. startX += (((startY - tmp) >> 12) * dX) >> 4;
  1705. }
  1706. else
  1707. {
  1708. dX = 0;
  1709. }
  1710. startY = tmp;
  1711. if ( IN_DIAMOND(m2, n2) )
  1712. {
  1713. fy2 = (fy2 + 0x7) & ~0xf; // nearest integer
  1714. }
  1715. else
  1716. {
  1717. fy2 &= ~0xf; // previous integer
  1718. }
  1719. count = (startY >> 16) - (fy2 >> 4);
  1720. Draw_Line:
  1721. //
  1722. // We need 6 fifo entries to draw a line
  1723. //
  1724. InputBufferReserve(ppdev, 16, &pBuffer);
  1725. DBG_GDI((7, "Line %x, %x deltas %x, %x Count %x",
  1726. startX + 0x7fff, startY + 0x7fff, dX, dY, count));
  1727. pBuffer[0] = __Permedia2TagStartXDom;
  1728. pBuffer[1] = startX + 0x7fff;
  1729. pBuffer[2] = __Permedia2TagStartY;
  1730. pBuffer[3] = startY + 0x7fff;
  1731. pBuffer[4] = __Permedia2TagdXDom;
  1732. pBuffer[5] = dX;
  1733. pBuffer[6] = __Permedia2TagdY;
  1734. pBuffer[7] = dY;
  1735. pBuffer[8] = __Permedia2TagCount;
  1736. pBuffer[9] = count;
  1737. pBuffer[10] = __Permedia2TagRender;
  1738. pBuffer[11] = __RENDER_LINE_PRIMITIVE;
  1739. //
  1740. // Restore default state
  1741. //
  1742. pBuffer[12] = __Permedia2TagdXDom;
  1743. pBuffer[13] = 0;
  1744. pBuffer[14] = __Permedia2TagdY;
  1745. pBuffer[15] = INTtoFIXED(1);
  1746. pBuffer += 16;
  1747. InputBufferCommit(ppdev, pBuffer);
  1748. return(TRUE);
  1749. }// bFastLine()