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.

1656 lines
45 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: pxrxstrp.c
  8. *
  9. * Content:
  10. *
  11. //@@BEGIN_DDKSPLIT
  12. * All the line code in this driver amounts to a big bag of dirt. Someday,
  13. * I'm going to rewrite it all. Not today, though (sigh)...
  14. * Original comment!. Rewritten for GLINT. Styled lines could do with more
  15. * work, but Solid lines should be about as optimal as possible without
  16. * rewriting the algorithm that calls these functions.
  17. //@@END_DDKSPLIT
  18. *
  19. * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  20. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
  21. \*****************************************************************************/
  22. #include "precomp.h"
  23. #include "pxrx.h"
  24. /**************************************************************************\
  25. *
  26. * BOOL pxrxInitStrips
  27. *
  28. \**************************************************************************/
  29. BOOL pxrxInitStrips(
  30. PPDEV ppdev,
  31. ULONG ulColor,
  32. DWORD logicOp,
  33. RECTL *prclClip )
  34. {
  35. DWORD config2D;
  36. BOOL bInvalidateScissor = FALSE;
  37. GLINT_DECL;
  38. VALIDATE_DD_CONTEXT;
  39. SET_WRITE_BUFFERS;
  40. WAIT_PXRX_DMA_TAGS( 7 );
  41. if( logicOp == __GLINT_LOGICOP_COPY )
  42. {
  43. config2D = __CONFIG2D_CONSTANTSRC |
  44. __CONFIG2D_FBWRITE;
  45. }
  46. else
  47. {
  48. config2D = __CONFIG2D_LOGOP_FORE(logicOp) |
  49. __CONFIG2D_CONSTANTSRC |
  50. __CONFIG2D_FBWRITE;
  51. if( LogicopReadDest[logicOp] )
  52. {
  53. config2D |= __CONFIG2D_FBDESTREAD;
  54. SET_READ_BUFFERS;
  55. }
  56. }
  57. LOAD_FOREGROUNDCOLOUR( ulColor );
  58. if( prclClip )
  59. {
  60. config2D |= __CONFIG2D_USERSCISSOR;
  61. QUEUE_PXRX_DMA_TAG( __GlintTagScissorMinXY,
  62. MAKEDWORD_XY(prclClip->left, prclClip->top ) );
  63. QUEUE_PXRX_DMA_TAG( __GlintTagScissorMaxXY,
  64. MAKEDWORD_XY(prclClip->right, prclClip->bottom) );
  65. if(ppdev->cPelSize == GLINTDEPTH32)
  66. {
  67. bInvalidateScissor = TRUE;
  68. }
  69. }
  70. LOAD_CONFIG2D( config2D );
  71. SEND_PXRX_DMA_BATCH;
  72. glintInfo->savedConfig2D = config2D;
  73. glintInfo->savedLOP = logicOp;
  74. glintInfo->savedCol = ulColor;
  75. glintInfo->savedClip = prclClip;
  76. DISPDBG((DBGLVL, "pxrxInitStrips done"));
  77. return (bInvalidateScissor);
  78. }
  79. /**************************************************************************\
  80. *
  81. * VOID pxrxResetStrips
  82. *
  83. \**************************************************************************/
  84. VOID pxrxResetStrips(
  85. PPDEV ppdev )
  86. {
  87. GLINT_DECL;
  88. DISPDBG((DBGLVL, "pxrxResetStrips called"));
  89. // Reset the scissor maximums:
  90. WAIT_PXRX_DMA_TAGS( 1 );
  91. QUEUE_PXRX_DMA_TAG( __GlintTagScissorMaxXY, 0x7FFF7FFF );
  92. SEND_PXRX_DMA_BATCH;
  93. }
  94. /**************************************************************************\
  95. *
  96. * VOID pxrxIntegerLine
  97. *
  98. \**************************************************************************/
  99. BOOL pxrxIntegerLine(
  100. PPDEV ppdev,
  101. LONG X1,
  102. LONG Y1,
  103. LONG X2,
  104. LONG Y2 )
  105. {
  106. LONG dx, dy, adx, ady;
  107. GLINT_DECL;
  108. // Convert points to INT format:
  109. X1 >>= 4;
  110. Y1 >>= 4;
  111. X2 >>= 4;
  112. Y2 >>= 4;
  113. if( (adx = dx = X2 - X1) < 0 )
  114. {
  115. adx = -adx;
  116. }
  117. if( (ady = dy = Y2 - Y1) < 0 )
  118. {
  119. ady = -ady;
  120. }
  121. WAIT_PXRX_DMA_TAGS( 3+2 );
  122. if( adx > ady )
  123. {
  124. // X major line:
  125. if( ady == dy )
  126. {
  127. // +ve minor delta
  128. if((ady) &&
  129. (adx != ady) &&
  130. (adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
  131. {
  132. DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
  133. return FALSE;
  134. }
  135. DISPDBG((DBGLVL, "pxrxIntegerLine: [X +] delta = (%d, %d), "
  136. "bias = (0x%08x)",
  137. dx, dy, P3_LINES_BIAS_P));
  138. QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_P );
  139. }
  140. else
  141. {
  142. // -ve minor delta
  143. if( (ady) &&
  144. (adx != ady) &&
  145. (adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
  146. {
  147. DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
  148. return FALSE;
  149. }
  150. DISPDBG((DBGLVL, "pxrxIntegerLine: [X -] delta = (%d, %d), "
  151. "bias = (0x%08x)",
  152. dx, dy, P3_LINES_BIAS_N));
  153. QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_N );
  154. }
  155. }
  156. else
  157. {
  158. // Y major line:
  159. if( adx == dx )
  160. {
  161. // +ve minor delta
  162. if( (adx) &&
  163. (adx != ady) &&
  164. (ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
  165. {
  166. DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
  167. return FALSE;
  168. }
  169. DISPDBG((DBGLVL, "pxrxIntegerLine: [Y +] delta = (%d, %d), "
  170. "bias = (0x%08x)",
  171. dx, dy, P3_LINES_BIAS_P));
  172. QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_P );
  173. }
  174. else
  175. {
  176. // -ve minor delta
  177. if( (adx) &&
  178. (adx != ady) &&
  179. (ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
  180. {
  181. DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
  182. return FALSE;
  183. }
  184. DISPDBG((DBGLVL, "pxrxIntegerLine: [Y -] delta = (%d, %d), "
  185. "bias = (0x%08x)",
  186. dx, dy, P3_LINES_BIAS_N));
  187. QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_N );
  188. }
  189. }
  190. QUEUE_PXRX_DMA_INDEX3( __DeltaTagLineCoord0,
  191. __DeltaTagLineCoord1,
  192. __DeltaTagDrawLine2D01 );
  193. QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X1, Y1) );
  194. QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
  195. QUEUE_PXRX_DMA_DWORD( 0 );
  196. SEND_PXRX_DMA_BATCH;
  197. glintInfo->lastLine = 1;
  198. DISPDBG((DBGLVL, "pxrxIntegerLine done"));
  199. return TRUE;
  200. }
  201. /**************************************************************************\
  202. *
  203. * BOOL pxrxContinueLine
  204. *
  205. \**************************************************************************/
  206. BOOL pxrxContinueLine(
  207. PPDEV ppdev,
  208. LONG X1,
  209. LONG Y1,
  210. LONG X2,
  211. LONG Y2 )
  212. {
  213. LONG dx, dy, adx, ady;
  214. GLINT_DECL;
  215. // Convert points to INT format:
  216. X1 >>= 4;
  217. Y1 >>= 4;
  218. X2 >>= 4;
  219. Y2 >>= 4;
  220. if( (adx = dx = X2 - X1) < 0 )
  221. {
  222. adx = -adx;
  223. }
  224. if( (ady = dy = Y2 - Y1) < 0 )
  225. {
  226. ady = -ady;
  227. }
  228. WAIT_PXRX_DMA_TAGS( 3+2 );
  229. if( adx > ady )
  230. {
  231. // X major line:
  232. if( ady == dy )
  233. {
  234. // +ve minor delta
  235. if( (ady) &&
  236. (adx != ady) &&
  237. (adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
  238. {
  239. DISPDBG((DBGLVL, "pxrxContinueLine failed"));
  240. return FALSE;
  241. }
  242. DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
  243. "bias = (0x%08x), last = %d",
  244. dx, dy, P3_LINES_BIAS_P, glintInfo->lastLine));
  245. QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_P );
  246. }
  247. else
  248. {
  249. // -ve minor delta
  250. if( (ady) &&
  251. (adx != ady) &&
  252. (adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
  253. {
  254. DISPDBG((DBGLVL, "pxrxContinueLine failed"));
  255. return FALSE;
  256. }
  257. DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
  258. "bias = (0x%08x), last = %d",
  259. dx, dy, P3_LINES_BIAS_N, glintInfo->lastLine));
  260. QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_N );
  261. }
  262. }
  263. else
  264. {
  265. // Y major line:
  266. if( adx == dx )
  267. {
  268. // +ve minor delta
  269. if( (adx) &&
  270. (adx != ady) &&
  271. (ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
  272. {
  273. DISPDBG((DBGLVL, "pxrxContinueLine failed"));
  274. return FALSE;
  275. }
  276. DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
  277. "bias = (0x%08x), last = %d",
  278. dx, dy, P3_LINES_BIAS_P, glintInfo->lastLine));
  279. QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_P );
  280. }
  281. else
  282. {
  283. // -ve minor delta
  284. if( (adx) &&
  285. (adx != ady) &&
  286. (ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
  287. {
  288. DISPDBG((DBGLVL, "pxrxContinueLine failed"));
  289. return FALSE;
  290. }
  291. DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
  292. "bias = (0x%08x), last = %d",
  293. dx, dy, P3_LINES_BIAS_N, glintInfo->lastLine));
  294. QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_N );
  295. }
  296. }
  297. if( glintInfo->lastLine == 0 )
  298. {
  299. QUEUE_PXRX_DMA_INDEX2( __DeltaTagLineCoord1,
  300. __DeltaTagDrawLine2D01 );
  301. QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
  302. QUEUE_PXRX_DMA_DWORD( 0 );
  303. glintInfo->lastLine = 1;
  304. }
  305. else if( glintInfo->lastLine == 1 )
  306. {
  307. QUEUE_PXRX_DMA_INDEX2( __DeltaTagLineCoord0,
  308. __DeltaTagDrawLine2D10 );
  309. QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
  310. QUEUE_PXRX_DMA_DWORD( 0 );
  311. glintInfo->lastLine = 0;
  312. }
  313. else
  314. {
  315. // lastline == 2
  316. QUEUE_PXRX_DMA_INDEX3( __DeltaTagLineCoord0,
  317. __DeltaTagLineCoord1,
  318. __DeltaTagDrawLine2D01 );
  319. QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X1, Y1) );
  320. QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
  321. QUEUE_PXRX_DMA_DWORD( 0 );
  322. glintInfo->lastLine = 1;
  323. }
  324. SEND_PXRX_DMA_BATCH;
  325. DISPDBG((DBGLVL, "pxrxContinueLine done"));
  326. return TRUE;
  327. }
  328. /******************************Public*Routine******************************\
  329. * VOID vPXRXSolidHorizontalLine
  330. *
  331. * Draws left-to-right x-major near-horizontal lines using short-stroke
  332. * vectors.
  333. *
  334. \**************************************************************************/
  335. VOID vPXRXSolidHorizontalLine(
  336. PDEV *ppdev,
  337. STRIP *pStrip,
  338. LINESTATE *pLineState )
  339. {
  340. LONG cStrips;
  341. PLONG pStrips;
  342. LONG iCurrent;
  343. GLINT_DECL;
  344. cStrips = pStrip->cStrips;
  345. WAIT_PXRX_DMA_TAGS( 10 );
  346. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, 0 );
  347. QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, 0 );
  348. // Set up the start point
  349. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(pStrip->ptlStart.x) );
  350. QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(pStrip->ptlStart.y) );
  351. // Set up the deltas for rectangle drawing. Also set Y return value.
  352. if( !(pStrip->flFlips & FL_FLIP_V) )
  353. {
  354. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(1) );
  355. pStrip->ptlStart.y += cStrips;
  356. }
  357. else
  358. {
  359. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(-1) );
  360. pStrip->ptlStart.y -= cStrips;
  361. }
  362. pStrips = pStrip->alStrips;
  363. // We have to do first strip manually, as we have to use RENDER
  364. // for the first strip, and CONTINUENEW... for the following strips
  365. iCurrent = pStrip->ptlStart.x + *pStrips++; // Xsub, Start of next strip
  366. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
  367. QUEUE_PXRX_DMA_TAG( __GlintTagCount, 1 );// Rectangle 1 scanline high
  368. QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_TRAPEZOID_PRIMITIVE );
  369. if( --cStrips )
  370. {
  371. while( cStrips > 1 )
  372. {
  373. // First strip of each pair to fill. XSub is valid. Need new Xdom
  374. iCurrent += *pStrips++;
  375. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
  376. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, 1 );
  377. WAIT_PXRX_DMA_TAGS( 2 + 2 );
  378. // Second strip of each pair to fill. XDom is valid. Need new XSub
  379. iCurrent += *pStrips++;
  380. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
  381. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, 1 );
  382. cStrips -=2;
  383. }
  384. // We may have one last line to draw. Xsub will be valid.
  385. if( cStrips )
  386. {
  387. iCurrent += *pStrips++;
  388. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
  389. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, 1 );
  390. }
  391. }
  392. SEND_PXRX_DMA_BATCH;
  393. // Return last point. Y already calculated when we knew the direction.
  394. pStrip->ptlStart.x = iCurrent;
  395. }
  396. /******************************Public*Routine******************************\
  397. * VOID vPXRXSolidVertical
  398. *
  399. * Draws left-to-right y-major near-vertical lines using short-stroke
  400. * vectors.
  401. *
  402. \**************************************************************************/
  403. VOID vPXRXSolidVerticalLine(
  404. PDEV *ppdev,
  405. STRIP *pStrip,
  406. LINESTATE *pLineState )
  407. {
  408. LONG cStrips, yDir;
  409. PLONG pStrips;
  410. LONG iCurrent, iLen, iLenSum;
  411. GLINT_DECL;
  412. cStrips = pStrip->cStrips;
  413. WAIT_PXRX_DMA_TAGS( 10 );
  414. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, 0 );
  415. QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, 0 );
  416. // Set up the start point
  417. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(pStrip->ptlStart.x) );
  418. QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(pStrip->ptlStart.y) );
  419. // Set up the deltas for rectangle drawing.
  420. if( !(pStrip->flFlips & FL_FLIP_V) )
  421. {
  422. yDir = 1;
  423. }
  424. else
  425. {
  426. yDir = -1;
  427. }
  428. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(yDir) );
  429. pStrips = pStrip->alStrips;
  430. // We have to do first strip manually, as we have to use RENDER
  431. // for the first strip, and CONTINUENEW... for the following strips
  432. iCurrent = pStrip->ptlStart.x + 1; // Xsub, Start of next strip
  433. iLenSum = (iLen = *pStrips++);
  434. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
  435. QUEUE_PXRX_DMA_TAG( __GlintTagCount, iLen ); // Rectangle 1 scanline high
  436. QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_TRAPEZOID_PRIMITIVE );
  437. if( --cStrips )
  438. {
  439. while( cStrips > 1 )
  440. {
  441. // First strip of each pair to fill. XSub is valid. Need new Xdom
  442. iCurrent++;
  443. iLenSum += (iLen = *pStrips++);
  444. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
  445. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, iLen );
  446. WAIT_PXRX_DMA_TAGS( 2 + 2 );
  447. // Second strip of each pair to fill. XDom is valid. Need new XSub
  448. iCurrent++;
  449. iLenSum += (iLen = *pStrips++);
  450. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
  451. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, iLen );
  452. cStrips -=2;
  453. }
  454. // We may have one last line to draw. Xsub will be valid.
  455. if( cStrips )
  456. {
  457. iCurrent++;
  458. iLenSum += (iLen = *pStrips++);
  459. QUEUE_PXRX_DMA_TAG(__GlintTagStartXDom, INTtoFIXED(iCurrent));
  460. QUEUE_PXRX_DMA_TAG(__GlintTagContinueNewDom, iLen);
  461. }
  462. }
  463. SEND_PXRX_DMA_BATCH;
  464. // Return last point.
  465. pStrip->ptlStart.x = iCurrent;
  466. pStrip->ptlStart.y += iLenSum * yDir;
  467. }
  468. /******************************Public*Routine******************************\
  469. * VOID vPXRXSolidDiagonalVertical
  470. *
  471. * Draws left-to-right y-major near-diagonal lines using short-stroke
  472. * vectors.
  473. *
  474. \**************************************************************************/
  475. VOID vPXRXSolidDiagonalVerticalLine(
  476. PDEV *ppdev,
  477. STRIP *pStrip,
  478. LINESTATE *pLineState )
  479. {
  480. LONG cStrips, yDir;
  481. PLONG pStrips;
  482. LONG iCurrent, iLen, iLenSum;
  483. GLINT_DECL;
  484. cStrips = pStrip->cStrips;
  485. if( !(pStrip->flFlips & FL_FLIP_V) )
  486. {
  487. yDir = 1;
  488. }
  489. else
  490. {
  491. yDir = -1;
  492. }
  493. WAIT_PXRX_DMA_TAGS( 10 );
  494. // Set up the deltas for rectangle drawing.
  495. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, INTtoFIXED(1) );
  496. QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, INTtoFIXED(1) );
  497. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(yDir) );
  498. pStrips = pStrip->alStrips;
  499. // We have to do first strip manually, as we have to use RENDER
  500. // for the first strip, and CONTINUENEW... for the following strips
  501. QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(pStrip->ptlStart.y) );
  502. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(pStrip->ptlStart.x+1) );
  503. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(pStrip->ptlStart.x) );
  504. iLenSum = (iLen = *pStrips++);
  505. iCurrent = pStrip->ptlStart.x + iLen - 1; // Start of next strip
  506. QUEUE_PXRX_DMA_TAG( __GlintTagCount, iLen); // Trap iLen scanline high
  507. QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_TRAPEZOID_PRIMITIVE);
  508. if( --cStrips )
  509. {
  510. while( cStrips > 1 )
  511. {
  512. // First strip of each pair to fill. XSub is valid. Need new Xdom
  513. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
  514. iLenSum += (iLen = *pStrips++);
  515. iCurrent += iLen - 1;
  516. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, iLen );
  517. WAIT_PXRX_DMA_TAGS( 2 + 2 );
  518. // Second strip of each pair to fill. XDom is valid. Need new XSub
  519. QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
  520. iLenSum += (iLen = *pStrips++);
  521. iCurrent += iLen - 1;
  522. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, iLen );
  523. cStrips -=2;
  524. }
  525. // We may have one last line to draw. Xsub will be valid.
  526. if (cStrips)
  527. {
  528. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
  529. iLenSum += (iLen = *pStrips++);
  530. iCurrent += iLen - 1;
  531. QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, iLen );
  532. }
  533. }
  534. SEND_PXRX_DMA_BATCH;
  535. // Return last point.
  536. pStrip->ptlStart.x = iCurrent;
  537. pStrip->ptlStart.y += iLenSum * yDir;
  538. }
  539. /******************************Public*Routine******************************\
  540. * VOID vPXRXSolidDiagonalHorizontalLine
  541. *
  542. * Draws left-to-right x-major near-diagonal lines using short-stroke
  543. * vectors.
  544. *
  545. \**************************************************************************/
  546. VOID vPXRXSolidDiagonalHorizontalLine(
  547. PDEV *ppdev,
  548. STRIP *pStrip,
  549. LINESTATE *pLineState )
  550. {
  551. LONG cStrips, yDir, xCurrent, yCurrent, iLen;
  552. PLONG pStrips;
  553. GLINT_DECL;
  554. // This routine has to be implemented in a different way to the other 3
  555. // solid line drawing functions because the rasterizer unit will not
  556. // produce 2 pixels on the same scanline without a lot of effort in
  557. // producing delta values. In this case, we have to draw a complete new
  558. // primitive for each strip. Therefore, we have to use lines rather than
  559. // trapezoids to generate the required strips. With lines we use 4 messages
  560. // per strip, where trapezoids would use 5.
  561. cStrips = pStrip->cStrips;
  562. if( !(pStrip->flFlips & FL_FLIP_V) )
  563. {
  564. yDir = 1;
  565. }
  566. else
  567. {
  568. yDir = -1;
  569. }
  570. pStrips = pStrip->alStrips;
  571. xCurrent = pStrip->ptlStart.x;
  572. yCurrent = pStrip->ptlStart.y;
  573. WAIT_PXRX_DMA_TAGS( 3 + 4 );
  574. // Set up the deltas for rectangle drawing.
  575. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, INTtoFIXED(1) );
  576. QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, INTtoFIXED(1) );
  577. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(yDir) );
  578. while( TRUE )
  579. {
  580. // Set up the start point
  581. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(xCurrent) );
  582. QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(yCurrent) );
  583. iLen = *pStrips++;
  584. QUEUE_PXRX_DMA_TAG( __GlintTagCount, iLen );
  585. QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_LINE_PRIMITIVE );
  586. xCurrent += iLen;
  587. if( yDir > 0 )
  588. {
  589. yCurrent += iLen - 1;
  590. }
  591. else
  592. {
  593. yCurrent -= iLen - 1;
  594. }
  595. if( !(--cStrips) )
  596. {
  597. break;
  598. }
  599. WAIT_PXRX_DMA_TAGS( 4 );
  600. }
  601. SEND_PXRX_DMA_BATCH;
  602. // Return last point.
  603. pStrip->ptlStart.x = xCurrent;
  604. pStrip->ptlStart.y = yCurrent;
  605. }
  606. /******************************Public*Routine******************************\
  607. * VOID vPXRXStyledHorizontal
  608. *
  609. * Takes the list of strips that define the pixels that would be lit for
  610. * a solid line, and breaks them into styling chunks according to the
  611. * styling information that is passed in.
  612. *
  613. * This particular routine handles x-major lines that run left-to-right,
  614. * and are comprised of horizontal strips. It draws the dashes using
  615. * short-stroke vectors.
  616. *
  617. * The performance of this routine could be improved significantly if
  618. * anyone cared enough about styled lines improve it.
  619. *
  620. \**************************************************************************/
  621. VOID vPXRXStyledHorizontalLine(
  622. PDEV *ppdev,
  623. STRIP *pstrip,
  624. LINESTATE *pls )
  625. {
  626. LONG x;
  627. LONG y;
  628. LONG dy;
  629. LONG* plStrip;
  630. LONG cStrips;
  631. LONG cStyle;
  632. LONG cStrip;
  633. LONG cThis;
  634. ULONG bIsGap;
  635. GLINT_DECL;
  636. //@@BEGIN_DDKSPLIT
  637. // This routine does some quite complex things with patterns. For ease of
  638. // implementation on GLINT, I have just changed the relevant parts. This,
  639. // therefore, is definitly not an optimal solution. However, styled lines
  640. // are really not that important. If anyone feels inclined to do more work
  641. // here, then fine! XXXX
  642. //@@END_DDKSPLIT
  643. if( pstrip->flFlips & FL_FLIP_V )
  644. {
  645. dy = -1;
  646. }
  647. else
  648. {
  649. dy = 1;
  650. }
  651. cStrips = pstrip->cStrips; // Total number of strips we'll do
  652. plStrip = pstrip->alStrips; // Points to current strip
  653. x = pstrip->ptlStart.x; // x position of start of first strip
  654. y = pstrip->ptlStart.y; // y position of start of first strip
  655. // Set up the deltas for horizontal line drawing.
  656. WAIT_PXRX_DMA_TAGS( 2 );
  657. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, INTtoFIXED(1) );
  658. QUEUE_PXRX_DMA_TAG( __GlintTagdY, 0 );
  659. cStrip = *plStrip; // Number of pels in first strip
  660. cStyle = pls->spRemaining; // Number of pels in first 'gap' or 'dash'
  661. bIsGap = pls->ulStyleMask; // Tells whether in a 'gap' or a 'dash'
  662. // ulStyleMask is non-zero if we're in the middle of a 'gap',
  663. // and zero if we're in the middle of a 'dash':
  664. if( bIsGap )
  665. {
  666. goto SkipAGap;
  667. }
  668. else
  669. {
  670. goto OutputADash;
  671. }
  672. PrepareToSkipAGap:
  673. // Advance in the style-state array, so that we can find the next
  674. // 'dot' that we'll have to display:
  675. bIsGap = ~bIsGap;
  676. pls->psp++;
  677. if (pls->psp > pls->pspEnd)
  678. {
  679. pls->psp = pls->pspStart;
  680. }
  681. cStyle = *pls->psp;
  682. // If 'cStrip' is zero, we also need a new strip:
  683. if (cStrip != 0)
  684. {
  685. goto SkipAGap;
  686. }
  687. // Here, we're in the middle of a 'gap' where we don't have to
  688. // display anything. We simply cycle through all the strips
  689. // we can, keeping track of the current position, until we run
  690. // out of 'gap':
  691. while (TRUE)
  692. {
  693. // Each time we loop, we move to a new scan and need a new strip:
  694. y += dy;
  695. plStrip++;
  696. cStrips--;
  697. if (cStrips == 0)
  698. {
  699. goto AllDone;
  700. }
  701. cStrip = *plStrip;
  702. SkipAGap:
  703. cThis = min(cStrip, cStyle);
  704. cStyle -= cThis;
  705. cStrip -= cThis;
  706. x += cThis;
  707. if (cStyle == 0)
  708. {
  709. goto PrepareToOutputADash;
  710. }
  711. }
  712. PrepareToOutputADash:
  713. // Advance in the style-state array, so that we can find the next
  714. // 'dot' that we'll have to display:
  715. bIsGap = ~bIsGap;
  716. pls->psp++;
  717. if (pls->psp > pls->pspEnd)
  718. {
  719. pls->psp = pls->pspStart;
  720. }
  721. cStyle = *pls->psp;
  722. // If 'cStrip' is zero, we also need a new strip.
  723. if (cStrip != 0)
  724. {
  725. // There's more to be done in the current strip, so set 'y'
  726. // to be the current scan:
  727. goto OutputADash;
  728. }
  729. while( TRUE )
  730. {
  731. // Each time we loop, we move to a new scan and need a new strip:
  732. y += dy;
  733. plStrip++;
  734. cStrips--;
  735. if( cStrips == 0 )
  736. {
  737. goto AllDone;
  738. }
  739. cStrip = *plStrip;
  740. OutputADash:
  741. cThis = min(cStrip, cStyle);
  742. cStyle -= cThis;
  743. cStrip -= cThis;
  744. // With glint we just download the lines to draw
  745. WAIT_PXRX_DMA_TAGS( 4 );
  746. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(x) );
  747. QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(y) );
  748. QUEUE_PXRX_DMA_TAG( __GlintTagCount, cThis );
  749. QUEUE_PXRX_DMA_TAG( __GlintTagRender, __GLINT_LINE_PRIMITIVE );
  750. x += cThis;
  751. if( cStyle == 0 )
  752. {
  753. goto PrepareToSkipAGap;
  754. }
  755. }
  756. AllDone:
  757. SEND_PXRX_DMA_BATCH;
  758. // Update our state variables so that the next line can continue
  759. // where we left off:
  760. pls->spRemaining = cStyle;
  761. pls->ulStyleMask = bIsGap;
  762. pstrip->ptlStart.x = x;
  763. pstrip->ptlStart.y = y;
  764. }
  765. /******************************Public*Routine******************************\
  766. * VOID vPXRXStyledVertical
  767. *
  768. * Takes the list of strips that define the pixels that would be lit for
  769. * a solid line, and breaks them into styling chunks according to the
  770. * styling information that is passed in.
  771. *
  772. * This particular routine handles y-major lines that run left-to-right,
  773. * and are comprised of vertical strips. It draws the dashes using
  774. * short-stroke vectors.
  775. *
  776. * The performance of this routine could be improved significantly if
  777. * anyone cared enough about styled lines improve it.
  778. *
  779. \**************************************************************************/
  780. VOID vPXRXStyledVerticalLine(
  781. PDEV *ppdev,
  782. STRIP *pstrip,
  783. LINESTATE *pls )
  784. {
  785. LONG x;
  786. LONG y;
  787. LONG dy;
  788. LONG* plStrip;
  789. LONG cStrips;
  790. LONG cStyle;
  791. LONG cStrip;
  792. LONG cThis;
  793. ULONG bIsGap;
  794. GLINT_DECL;
  795. //@@BEGIN_DDKSPLIT
  796. // This routine does some quite complex things with patterns. For ease of
  797. // implemantation on GLINT, I have just changed the relevant parts. This,
  798. // therefore, is definitly not an optimal solution. However, styled lines
  799. // are really not that important. If anyone feels inclined to do more work
  800. // here, then fine! XXXX
  801. //@@END_DDKSPLIT
  802. if( pstrip->flFlips & FL_FLIP_V )
  803. {
  804. dy = -1;
  805. }
  806. else
  807. {
  808. dy = 1;
  809. }
  810. cStrips = pstrip->cStrips; // Total number of strips we'll do
  811. plStrip = pstrip->alStrips; // Points to current strip
  812. x = pstrip->ptlStart.x; // x position of start of first strip
  813. y = pstrip->ptlStart.y; // y position of start of first strip
  814. // Set up the deltas for vertical line drawing.
  815. WAIT_PXRX_DMA_TAGS( 2 );
  816. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, 0 );
  817. QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(dy) );
  818. // dxDom and dXSub are initialised to 0, 0, so
  819. // we don't need to re-load them here.
  820. cStrip = *plStrip; // Number of pels in first strip
  821. cStyle = pls->spRemaining; // Number of pels in first 'gap' or 'dash'
  822. bIsGap = pls->ulStyleMask; // Tells whether in a 'gap' or a 'dash'
  823. // ulStyleMask is non-zero if we're in the middle of a 'gap',
  824. // and zero if we're in the middle of a 'dash':
  825. if (bIsGap)
  826. {
  827. goto SkipAGap;
  828. }
  829. else
  830. {
  831. goto OutputADash;
  832. }
  833. PrepareToSkipAGap:
  834. // Advance in the style-state array, so that we can find the next
  835. // 'dot' that we'll have to display:
  836. bIsGap = ~bIsGap;
  837. pls->psp++;
  838. if (pls->psp > pls->pspEnd)
  839. {
  840. pls->psp = pls->pspStart;
  841. }
  842. cStyle = *pls->psp;
  843. // If 'cStrip' is zero, we also need a new strip:
  844. if (cStrip != 0)
  845. {
  846. goto SkipAGap;
  847. }
  848. // Here, we're in the middle of a 'gap' where we don't have to
  849. // display anything. We simply cycle through all the strips
  850. // we can, keeping track of the current position, until we run
  851. // out of 'gap':
  852. while (TRUE)
  853. {
  854. // Each time we loop, we move to a new column and need a new strip:
  855. x++;
  856. plStrip++;
  857. cStrips--;
  858. if (cStrips == 0)
  859. {
  860. goto AllDone;
  861. }
  862. cStrip = *plStrip;
  863. SkipAGap:
  864. cThis = min(cStrip, cStyle);
  865. cStyle -= cThis;
  866. cStrip -= cThis;
  867. y += (dy > 0) ? cThis : -cThis;
  868. if (cStyle == 0)
  869. {
  870. goto PrepareToOutputADash;
  871. }
  872. }
  873. PrepareToOutputADash:
  874. // Advance in the style-state array, so that we can find the next
  875. // 'dot' that we'll have to display:
  876. bIsGap = ~bIsGap;
  877. pls->psp++;
  878. if (pls->psp > pls->pspEnd)
  879. {
  880. pls->psp = pls->pspStart;
  881. }
  882. cStyle = *pls->psp;
  883. // If 'cStrip' is zero, we also need a new strip.
  884. if (cStrip != 0)
  885. {
  886. goto OutputADash;
  887. }
  888. while (TRUE)
  889. {
  890. // Each time we loop, we move to a new column and need a new strip:
  891. x++;
  892. plStrip++;
  893. cStrips--;
  894. if (cStrips == 0)
  895. {
  896. goto AllDone;
  897. }
  898. cStrip = *plStrip;
  899. OutputADash:
  900. cThis = min(cStrip, cStyle);
  901. cStyle -= cThis;
  902. cStrip -= cThis;
  903. // With glint we just download the lines to draw
  904. WAIT_PXRX_DMA_TAGS( 4 );
  905. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(x) );
  906. QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(y) );
  907. QUEUE_PXRX_DMA_TAG( __GlintTagCount, cThis );
  908. QUEUE_PXRX_DMA_TAG( __GlintTagRender, __GLINT_LINE_PRIMITIVE );
  909. y += (dy > 0) ? cThis : -cThis;
  910. if( cStyle == 0 )
  911. {
  912. goto PrepareToSkipAGap;
  913. }
  914. }
  915. AllDone:
  916. SEND_PXRX_DMA_BATCH;
  917. // Update our state variables so that the next line can continue
  918. // where we left off:
  919. pls->spRemaining = cStyle;
  920. pls->ulStyleMask = bIsGap;
  921. pstrip->ptlStart.x = x;
  922. pstrip->ptlStart.y = y;
  923. }
  924. /**************************************************************************\
  925. * For a given sub-pixel coordinate (x.m, y.n) in 28.4 fixed point
  926. * format this array is indexed by (m,n) and indicates whether the
  927. * given sub-pixel is within a GIQ diamond. m coordinates run left
  928. * to right; n coordinates ru top to bottom so index the array with
  929. * ((n<<4)+m). The array as seen here really contains 4 quarter
  930. * diamonds.
  931. \**************************************************************************/
  932. static unsigned char in_diamond[] = {
  933. /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
  934. /* 0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0 */
  935. /* 1 */ 1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1, /* 1 */
  936. /* 2 */ 1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1, /* 2 */
  937. /* 3 */ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1, /* 3 */
  938. /* 4 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1, /* 4 */
  939. /* 5 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 5 */
  940. /* 6 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6 */
  941. /* 7 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7 */
  942. /* 8 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8 */
  943. /* 9 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9 */
  944. /* a */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* a */
  945. /* b */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1, /* b */
  946. /* c */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1, /* c */
  947. /* d */ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1, /* d */
  948. /* e */ 1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1, /* e */
  949. /* f */ 1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1, /* f */
  950. /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
  951. };
  952. /*
  953. * For lines with abs(slope) != 1 use IN_DIAMOND to determine if an
  954. * end point is in a diamond. For lines of slope = 1 use IN_S1DIAMOND.
  955. * For lines of slope = -1 use IN_SM1DIAMOND. The last two are a bit
  956. * strange. The documentation leaves us with a problem for slope 1
  957. * lines which run exactly betwen the diamonds. According to the docs
  958. * such a line can enter a diamond, leave it and enter again. This is
  959. * plainly rubbish so along the appropriate edge of the diamond we
  960. * consider a slope 1 line to be inside the diamond. This is the
  961. * bottom right edge for lines of slope -1 and the bottom left edge for
  962. * lines of slope 1.
  963. */
  964. #define IN_DIAMOND(m, n) (in_diamond[((m) << 4) + (n)])
  965. #define IN_S1DIAMOND(m, n) ((in_diamond[((m) << 4) + (n)]) || \
  966. ((m) - (n) == 8))
  967. #define IN_SM1DIAMOND(m, n) ((in_diamond[((m) << 4) + (n)]) || \
  968. ((m) + (n) == 8))
  969. /**************************************************************************\
  970. *
  971. * BOOL pxrxDrawLine
  972. *
  973. \**************************************************************************/
  974. BOOL pxrxDrawLine(
  975. PPDEV ppdev,
  976. LONG fx1,
  977. LONG fy1,
  978. LONG fx2,
  979. LONG fy2 )
  980. {
  981. register LONG adx, ady, tmp;
  982. FIX m1, n1, m2, n2;
  983. LONG dx, dy;
  984. LONG dX, dY;
  985. LONG count, startX, startY;
  986. GLINT_DECL;
  987. // This function is only called if we have a line with non integer end
  988. // points and the unsigned coordinates are no greater than 15.4.
  989. //
  990. // We can only guarantee to do lines whose coords need <= 12 bits
  991. // of integer. This is because to get the delta we must shift
  992. // by 16 bits. This includes 4 bits of fraction which means if
  993. // we have more than 12 bits of integer we get overrun on the
  994. // shift. We could use floating point to give us a better 16
  995. // bits of integer but this requires an extra set of multiplies
  996. // and divides in order to convert from 28.4 to fp. In any case
  997. // we have to have a test to reject coords needing > 16 bits
  998. // of integer.
  999. // Actually, we can deal with 16.4 coordinates provided dx and dy
  1000. // never require more than 12 bits of integer.
  1001. // So optimise for the common case where the line is completely
  1002. // on the screen (actually 0 to 2047.f). Since the coords have
  1003. // 4 bits of fraction we note that a 32 bit signed number
  1004. // outside the range 0 to 2047.f will have one of its top 17
  1005. // bits set. So logical or all the coords and test against
  1006. // 0xffff8000. This is about as quick a test as we can get for
  1007. // both ends of the line being on the screen. If this test fails
  1008. // then we can check everything else at a leisurely pace.
  1009. // get signed and absolute deltas
  1010. if ((adx = dx = fx2 - fx1) < 0)
  1011. {
  1012. adx = -adx;
  1013. }
  1014. if ((ady = dy = fy2 - fy1) < 0)
  1015. {
  1016. ady = -ady;
  1017. }
  1018. // Refuse to draw any lines whose delta is out of range.
  1019. // We have to shift the delta by 16, so we dont want to loose any
  1020. // precision.
  1021. if ((adx | ady) & 0xffff8000)
  1022. {
  1023. return(FALSE);
  1024. }
  1025. // fractional bits are used to check if point is in a diamond
  1026. m1 = fx1 & 0xf;
  1027. n1 = fy1 & 0xf;
  1028. m2 = fx2 & 0xf;
  1029. n2 = fy2 & 0xf;
  1030. // The rest of the code is a series of cases. Each one is "called" by a
  1031. // goto. This is simply to keep the nesting down. Main cases are: lines
  1032. // with absolute slope == 1; x-major lines; and y-major lines. We draw
  1033. // lines as they are given rather than always drawing in one direction.
  1034. // This adds extra code but saves the time required to swap the points
  1035. // and adjust for not drawing the end point.
  1036. startX = fx1 << 12;
  1037. startY = fy1 << 12;
  1038. DISPDBG((DBGLVL, "GDI Line %x, %x deltas %x, %x",
  1039. startX, startY, dx, dy));
  1040. if (adx < ady)
  1041. {
  1042. goto y_major;
  1043. }
  1044. if (adx > ady)
  1045. {
  1046. goto x_major;
  1047. }
  1048. //slope1_line:
  1049. // All slope 1 lines are sampled in X. i.e. we move the start coord to
  1050. // an integer x and let GLINT truncate in y. This is because all GIQ
  1051. // lines are rounded down in y for values exactly half way between two
  1052. // pixels. If we sampled in y then we would have to round up in x for
  1053. // lines of slope 1 and round down in x for other lines. Sampling in x
  1054. // allows us to use the same GLINT bias in all cases (0x7fff). We do
  1055. // the x round up or down when we move the start point.
  1056. if (dx != dy)
  1057. {
  1058. goto slope_minus_1;
  1059. }
  1060. if (dx < 0)
  1061. {
  1062. goto slope1_reverse;
  1063. }
  1064. dX = 1 << 16;
  1065. dY = 1 << 16;
  1066. if (IN_S1DIAMOND(m1, n1))
  1067. {
  1068. tmp = (startX + 0x8000) & ~0xffff;
  1069. }
  1070. else
  1071. {
  1072. tmp = (startX + 0xffff) & ~0xffff;
  1073. }
  1074. startY += tmp - startX;
  1075. startX = tmp;
  1076. if (IN_S1DIAMOND(m2, n2))
  1077. {
  1078. fx2 = (fx2 + 0x8) & ~0xf; // nearest integer
  1079. }
  1080. else
  1081. {
  1082. fx2 = (fx2 + 0xf) & ~0xf; // next integer
  1083. }
  1084. count = (fx2 >> 4) - (startX >> 16);
  1085. goto Draw_Line;
  1086. slope1_reverse:
  1087. dX = -1 << 16;
  1088. dY = -1 << 16;
  1089. if (IN_S1DIAMOND(m1, n1))
  1090. {
  1091. tmp = (startX + 0x8000) & ~0xffff;
  1092. }
  1093. else
  1094. {
  1095. tmp = startX & ~0xffff;
  1096. }
  1097. startY += tmp - startX;
  1098. startX = tmp;
  1099. if (IN_S1DIAMOND(m2, n2))
  1100. {
  1101. fx2 = (fx2 + 0x8) & ~0xf; // nearest integer
  1102. }
  1103. else
  1104. {
  1105. fx2 &= ~0xf; // previous integer
  1106. }
  1107. count = (startX >> 16) - (fx2 >> 4);
  1108. goto Draw_Line;
  1109. slope_minus_1:
  1110. if (dx < 0)
  1111. {
  1112. goto slope_minus_dx;
  1113. }
  1114. // dx > 0, dy < 0
  1115. dX = 1 << 16;
  1116. dY = -1 << 16;
  1117. if (IN_SM1DIAMOND(m1, n1))
  1118. {
  1119. tmp = (startX + 0x7fff) & ~0xffff;
  1120. }
  1121. else
  1122. {
  1123. tmp = (startX + 0xffff) & ~0xffff;
  1124. }
  1125. startY += startX - tmp;
  1126. startX = tmp;
  1127. if (IN_SM1DIAMOND(m2, n2))
  1128. {
  1129. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1130. }
  1131. else
  1132. {
  1133. fx2 = (fx2 + 0xf) & ~0xf; // next integer
  1134. }
  1135. count = (fx2 >> 4) - (startX >> 16);
  1136. goto Draw_Line;
  1137. slope_minus_dx:
  1138. dX = -1 << 16;
  1139. dY = 1 << 16;
  1140. if (IN_SM1DIAMOND(m1, n1))
  1141. {
  1142. tmp = (startX + 0x7fff) & ~0xffff;
  1143. }
  1144. else
  1145. {
  1146. tmp = startX & ~0xffff;
  1147. }
  1148. startY += startX - tmp;
  1149. startX = tmp;
  1150. if (IN_SM1DIAMOND(m2, n2))
  1151. {
  1152. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1153. }
  1154. else
  1155. {
  1156. fx2 &= ~0xf; // previous integer
  1157. }
  1158. count = (startX >> 16) - (fx2 >> 4);
  1159. goto Draw_Line;
  1160. x_major:
  1161. // Dont necessarily render through glint if we are worried
  1162. // about conformance.
  1163. if ((adx > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4)) &&
  1164. (glintInfo->flags & GLICAP_NT_CONFORMANT_LINES) &&
  1165. (ady != 0))
  1166. {
  1167. return(FALSE);
  1168. }
  1169. if (dx < 0)
  1170. {
  1171. goto right_to_left_x;
  1172. }
  1173. // left_to_right_x:
  1174. // line goes left to right. Round up the start x to an integer
  1175. // coordinate. This is the coord of the first diamond that the
  1176. // line crosses. Adjust start y to match this point on the line.
  1177. dX = 1 << 16;
  1178. if (IN_DIAMOND(m1, n1))
  1179. {
  1180. tmp = (startX + 0x7fff) & ~0xffff; // nearest integer
  1181. }
  1182. else
  1183. {
  1184. tmp = (startX + 0xffff) & ~0xffff; // next integer
  1185. }
  1186. // we can optimise for horizontal lines
  1187. if (dy != 0)
  1188. {
  1189. dY = dy << 16;
  1190. // Need to explicitly round delta down for -ve deltas.
  1191. if (dy < 0)
  1192. {
  1193. dY -= adx - 1;
  1194. }
  1195. dY /= adx;
  1196. startY += (((tmp - startX) >> 12) * dY) >> 4;
  1197. }
  1198. else
  1199. {
  1200. dY = 0;
  1201. }
  1202. startX = tmp;
  1203. if (IN_DIAMOND(m2, n2))
  1204. {
  1205. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1206. }
  1207. else
  1208. {
  1209. fx2 = (fx2 + 0xf) & ~0xf; // next integer
  1210. }
  1211. count = (fx2 >> 4) - (startX >> 16);
  1212. goto Draw_Line;
  1213. right_to_left_x:
  1214. dX = -1 << 16;
  1215. if (IN_DIAMOND(m1, n1))
  1216. {
  1217. tmp = (startX + 0x7fff) & ~0xffff; // nearest integer
  1218. }
  1219. else
  1220. {
  1221. tmp = startX & ~0xffff; // previous integer
  1222. }
  1223. // we can optimise for horizontal lines
  1224. if (dy != 0)
  1225. {
  1226. dY = dy << 16;
  1227. // Need to explicitly round delta down for -ve deltas.
  1228. if (dy < 0)
  1229. {
  1230. dY -= adx - 1;
  1231. }
  1232. dY /= adx;
  1233. startY += (((startX - tmp) >> 12) * dY) >> 4;
  1234. }
  1235. else
  1236. {
  1237. dY = 0;
  1238. }
  1239. startX = tmp;
  1240. if (IN_DIAMOND(m2, n2))
  1241. {
  1242. fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
  1243. }
  1244. else
  1245. {
  1246. fx2 &= ~0xf; // previous integer
  1247. }
  1248. count = (startX >> 16) - (fx2 >> 4);
  1249. goto Draw_Line;
  1250. y_major:
  1251. // Dont necessarily render through glint if we are worried
  1252. // about conformance.
  1253. if ((ady > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4)) &&
  1254. (glintInfo->flags & GLICAP_NT_CONFORMANT_LINES) &&
  1255. (adx != 0))
  1256. {
  1257. return(FALSE);
  1258. }
  1259. if (dy < 0)
  1260. {
  1261. goto high_to_low_y;
  1262. }
  1263. // low_to_high_y:
  1264. dY = 1 << 16;
  1265. if (IN_DIAMOND(m1, n1))
  1266. {
  1267. tmp = (startY + 0x7fff) & ~0xffff; // nearest integer
  1268. }
  1269. else
  1270. {
  1271. tmp = (startY + 0xffff) & ~0xffff; // next integer
  1272. }
  1273. // we can optimise for vertical lines
  1274. if (dx != 0)
  1275. {
  1276. dX = dx << 16;
  1277. // Need to explicitly round delta down for -ve deltas.
  1278. if (dx < 0)
  1279. {
  1280. dX -= ady - 1;
  1281. }
  1282. dX /= ady;
  1283. startX += (((tmp - startY) >> 12) * dX) >> 4;
  1284. }
  1285. else
  1286. {
  1287. dX = 0;
  1288. }
  1289. startY = tmp;
  1290. if (IN_DIAMOND(m2, n2))
  1291. {
  1292. fy2 = (fy2 + 0x7) & ~0xf; // nearest integer
  1293. }
  1294. else
  1295. {
  1296. fy2 = (fy2 + 0xf) & ~0xf; // next integer
  1297. }
  1298. count = (fy2 >> 4) - (startY >> 16);
  1299. goto Draw_Line;
  1300. high_to_low_y:
  1301. dY = -1 << 16;
  1302. if (IN_DIAMOND(m1, n1))
  1303. {
  1304. tmp = (startY + 0x7fff) & ~0xffff; // nearest integer
  1305. }
  1306. else
  1307. {
  1308. tmp = startY & ~0xffff; // previous integer
  1309. }
  1310. // we can optimise for horizontal lines
  1311. if (dx != 0)
  1312. {
  1313. dX = dx << 16;
  1314. // Need to explicitly round delta down for -ve deltas.
  1315. if (dx < 0)
  1316. {
  1317. dX -= ady - 1;
  1318. }
  1319. dX /= ady;
  1320. startX += (((startY - tmp) >> 12) * dX) >> 4;
  1321. }
  1322. else
  1323. {
  1324. dX = 0;
  1325. }
  1326. startY = tmp;
  1327. if (IN_DIAMOND(m2, n2))
  1328. {
  1329. fy2 = (fy2 + 0x7) & ~0xf; // nearest integer
  1330. }
  1331. else
  1332. {
  1333. fy2 &= ~0xf; // previous integer
  1334. }
  1335. count = (startY >> 16) - (fy2 >> 4);
  1336. Draw_Line:
  1337. WAIT_PXRX_DMA_TAGS( 6 );
  1338. QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, startX + 0x7fff );
  1339. QUEUE_PXRX_DMA_TAG( __GlintTagStartY, startY + 0x7fff );
  1340. QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, dX );
  1341. QUEUE_PXRX_DMA_TAG( __GlintTagdY, dY );
  1342. QUEUE_PXRX_DMA_TAG( __GlintTagCount, count );
  1343. QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_LINE_PRIMITIVE );
  1344. SEND_PXRX_DMA_BATCH;
  1345. return TRUE;
  1346. }