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.

954 lines
27 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * drawimage.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Software Rasterizer DrawImage routine and supporting functionality.
  12. *
  13. * Revision History:
  14. *
  15. * 10/20/1999 asecchia
  16. * Created it.
  17. *
  18. \**************************************************************************/
  19. #include "precomp.hpp"
  20. // Include the template class definitions for the stretch
  21. // filter modes.
  22. #include "stretch.inc"
  23. namespace DpDriverActiveEdge {
  24. // We make an array of these for use in the dda computation.
  25. struct PointFIX4
  26. {
  27. FIX4 X;
  28. FIX4 Y;
  29. };
  30. // Vertex iterator.
  31. // Has two Proxy methods for accessing the dda
  32. class DdaIterator
  33. {
  34. private:
  35. GpYDda dda;
  36. PointFIX4 *vertices;
  37. INT numVertices;
  38. INT direction;
  39. INT idx; // keep this so we don't infinite loop on
  40. // degenerate case
  41. INT idx1, idx2;
  42. BOOL valid;
  43. public:
  44. // GpYDda Proxy-like semantics
  45. INT GetX()
  46. {
  47. return dda.GetX();
  48. }
  49. // Initialize the dda and traversal direction
  50. DdaIterator(PointFIX4 *v, INT n, INT d, INT idx)
  51. {
  52. vertices=v;
  53. numVertices=n;
  54. ASSERT( (d==-1)||(d==1) );
  55. direction = d;
  56. ASSERT( (idx>=0)&&(idx<n) );
  57. this->idx=idx;
  58. idx1=idx;
  59. idx2=idx;
  60. valid = AdvanceEdge();
  61. }
  62. BOOL IsValid() { return valid; }
  63. // Advance to the next edge and initialize the dda.
  64. // Return FALSE if we're done.
  65. BOOL Next(INT y)
  66. {
  67. if(dda.DoneWithVector(y))
  68. {
  69. return AdvanceEdge();
  70. }
  71. // TRUE indicates more to do.
  72. return TRUE;
  73. }
  74. private:
  75. // Advance the internal state to the next edge.
  76. // Ignore horizontal edges.
  77. // Return FALSE if we're done.
  78. BOOL AdvanceEdge()
  79. {
  80. do {
  81. idx2 = idx1;
  82. if(direction==1)
  83. {
  84. idx1++;
  85. if(idx1>=numVertices) { idx1 = 0; }
  86. }
  87. else
  88. {
  89. idx1--;
  90. if(idx1<0) { idx1 = numVertices-1; }
  91. }
  92. // Loop till we get a non-horizontal edge.
  93. // Make sure we don't have an infinite loop on all horizontal edges.
  94. // The Ceiling is used to make almost horizontal lines appear to be
  95. // horizontal - this allows the algorithm to correctly compute the
  96. // end terminating case.
  97. } while(( GpFix4Ceiling(vertices[idx1].Y) ==
  98. GpFix4Ceiling(vertices[idx2].Y) ) &&
  99. (idx1!=idx));
  100. if(GpFix4Ceiling(vertices[idx1].Y) >
  101. GpFix4Ceiling(vertices[idx2].Y) )
  102. {
  103. // Initialize the dda
  104. dda.Init(
  105. vertices[idx2].X,
  106. vertices[idx2].Y,
  107. vertices[idx1].X,
  108. vertices[idx1].Y
  109. );
  110. return TRUE;
  111. }
  112. // terminate if we've wrapped around and started to come back up.
  113. // I.e return FALSE if we should stop.
  114. return FALSE;
  115. }
  116. };
  117. } // End namespace DpDriverActiveEdge
  118. /**************************************************************************\
  119. *
  120. * Function Description:
  121. *
  122. * This handles axis aligned drawing. The cases include identity,
  123. * integer translation, general translation and scaling.
  124. *
  125. * Arguments:
  126. *
  127. * output - span class to output the scanlines to.
  128. * dstTL - top left destination point.
  129. * dstBR - bottom right destination point.
  130. *
  131. * History:
  132. * 10/19/1999 asecchia created it.
  133. *
  134. \**************************************************************************/
  135. VOID StretchBitsMainLoop(
  136. DpOutputSpan *output,
  137. GpPoint *dstTL,
  138. GpPoint *dstBR
  139. )
  140. {
  141. // Input coordinates must be correctly ordered. This assumtion is required
  142. // by the output span routines which must have the spans come in strictly
  143. // increasing y order.
  144. ASSERT(dstTL->X < dstBR->X);
  145. ASSERT(dstTL->Y < dstBR->Y);
  146. // Main loop - output each scanline.
  147. const INT left = dstTL->X;
  148. const INT right = dstBR->X;
  149. for(INT y=dstTL->Y; y<(dstBR->Y); y++)
  150. {
  151. output->OutputSpan(y, left, right);
  152. }
  153. }
  154. /**************************************************************************\
  155. *
  156. * Function Description:
  157. *
  158. * CreateBilinearOutputSpan
  159. * Creates a bilinear or identity outputspan based on our hierarchy
  160. * of span classes.
  161. *
  162. * Arguments:
  163. *
  164. * bitmap - driver surface
  165. * scan - scan class
  166. * xForm - source rect to destination parallelogram transform
  167. * imageAttributes - encapsulates the wrap mode settings.
  168. *
  169. * Return Value:
  170. *
  171. * DpOutputSpan - returns the created output span (NULL for failure)
  172. *
  173. * History:
  174. *
  175. * 09/03/2000 asecchia
  176. * borrowed this from the brush code.
  177. *
  178. \**************************************************************************/
  179. DpOutputSpan*
  180. CreateBilinearOutputSpan(
  181. IN DpBitmap *bitmap,
  182. IN DpScanBuffer *scan,
  183. IN GpMatrix *xForm, // source rectangle to destination coordinates in
  184. // device space.
  185. IN DpContext *context,
  186. IN DpImageAttributes *imageAttributes,
  187. IN bool fLargeImage // need to handle really large stretches.
  188. // usually used for stretch algorithms that punted
  189. // due to overflow in internal computation.
  190. )
  191. {
  192. // Validate input parameters.
  193. ASSERT(bitmap);
  194. ASSERT(scan);
  195. ASSERT(xForm);
  196. ASSERT(context);
  197. ASSERT(imageAttributes);
  198. DpOutputBilinearSpan *textureSpan;
  199. GpMatrix brushTransform;
  200. GpMatrix worldToDevice;
  201. // Go through our heirarchy of scan drawers:
  202. if ((!fLargeImage) &&
  203. xForm->IsIntegerTranslate() &&
  204. ((imageAttributes->wrapMode == WrapModeTile) ||
  205. (imageAttributes->wrapMode == WrapModeClamp)))
  206. {
  207. textureSpan = new DpOutputBilinearSpan_Identity(
  208. bitmap,
  209. scan,
  210. xForm,
  211. context,
  212. imageAttributes
  213. );
  214. }
  215. else if ((!fLargeImage) &&
  216. OSInfo::HasMMX &&
  217. GpValidFixed16(bitmap->Width) &&
  218. GpValidFixed16(bitmap->Height))
  219. {
  220. textureSpan = new DpOutputBilinearSpan_MMX(
  221. bitmap,
  222. scan,
  223. xForm,
  224. context,
  225. imageAttributes
  226. );
  227. }
  228. else
  229. {
  230. textureSpan = new DpOutputBilinearSpan(
  231. bitmap,
  232. scan,
  233. xForm,
  234. context,
  235. imageAttributes
  236. );
  237. }
  238. if ((textureSpan) && !textureSpan->IsValid())
  239. {
  240. delete textureSpan;
  241. textureSpan = NULL;
  242. }
  243. return textureSpan;
  244. }
  245. /**************************************************************************\
  246. *
  247. * Function Description:
  248. *
  249. * CreateOutputSpan
  250. * Creates an outputspan based on our hierarchy of span classes.
  251. *
  252. * Arguments:
  253. *
  254. * bitmap - driver surface
  255. * scan - scan class
  256. * xForm - source rect to destination parallelogram transform
  257. * imageAttributes - encapsulates the wrap mode settings.
  258. * filterMode - which InterpolationMode setting to use
  259. *
  260. * Notes:
  261. *
  262. * The long term plan is to make this and the similar routines in the
  263. * texture brush code converge. We'd like one routine doing this for
  264. * all the texture output spans and have both the texture brush and the
  265. * drawimage reuse the same code and support all the same filter/wrap
  266. * modes.
  267. *
  268. * Return Value:
  269. *
  270. * DpOutputSpan - returns the created output span (NULL for failure)
  271. *
  272. * History:
  273. *
  274. * 09/03/2000 asecchia created it
  275. *
  276. \**************************************************************************/
  277. DpOutputSpan *CreateOutputSpan(
  278. IN DpBitmap *bitmap,
  279. IN DpScanBuffer *scan,
  280. IN GpMatrix *xForm, // source rectangle to destination coordinates in
  281. // device space.
  282. IN DpImageAttributes *imageAttributes,
  283. IN InterpolationMode filterMode,
  284. // !!! [asecchia] shouldn't need any of this following stuff - the above
  285. // bitmap and xForm should be sufficient.
  286. // The possible exception is the srcRect which may be required if we
  287. // ever implement the clamp-to-srcRect feature.
  288. IN DpContext *context,
  289. IN const GpRectF *srcRect,
  290. IN const GpRectF *dstRect,
  291. IN const GpPointF *dstPoints,
  292. IN const INT numPoints
  293. )
  294. {
  295. // Validate input parameters.
  296. ASSERT(bitmap);
  297. ASSERT(scan);
  298. ASSERT(xForm);
  299. ASSERT(imageAttributes);
  300. // Validate the stuff we had to pass through for the
  301. // OutputSpan routines that can't handle the xForm.
  302. ASSERT(context);
  303. ASSERT(srcRect);
  304. ASSERT(dstRect);
  305. ASSERT(dstPoints);
  306. ASSERT(numPoints == 3);
  307. bool fPunted = false;
  308. // Initialize up front so that all the error-out paths are covered.
  309. DpOutputSpan *output = NULL;
  310. // Copy to local so that we can modify it without breaking the
  311. // input parameter consistency.
  312. InterpolationMode theFilterMode = filterMode;
  313. // The so-called 'identity' transform which counter-intuitively includes
  314. // integer only translation.
  315. if(xForm->IsIntegerTranslate())
  316. {
  317. // Use a much simplified output span class for
  318. // special case CopyBits.
  319. // The big win is due to the fact that integer
  320. // translation only cases do not require filtering.
  321. // Note, we set InterpolationModeBilinear because we
  322. // will detect the identity in the bilinear span creation.
  323. theFilterMode = InterpolationModeBilinear;
  324. }
  325. switch(theFilterMode)
  326. {
  327. // Nearest neighbor filtering. Used mainly for printing scenarios.
  328. // Aliases badly - only really looks good on high-dpi output devices,
  329. // however it's the fastest reconstruction filter.
  330. case InterpolationModeNearestNeighbor:
  331. output = new DpOutputNearestNeighborSpan(
  332. bitmap,
  333. scan,
  334. context,
  335. *imageAttributes,
  336. numPoints,
  337. dstPoints,
  338. srcRect
  339. );
  340. break;
  341. // High quality bicubic filter convolution.
  342. case InterpolationModeHighQuality:
  343. case InterpolationModeHighQualityBicubic:
  344. // !!! [asecchia] the high quality bicubic filter code doesn't
  345. // know how to do rotation yet.
  346. if(xForm->IsTranslateScale())
  347. {
  348. output = new DpOutputSpanStretch<HighQualityBicubic>(
  349. bitmap,
  350. scan,
  351. context,
  352. *imageAttributes,
  353. dstRect,
  354. srcRect
  355. );
  356. if(output && !output->IsValid())
  357. {
  358. // Failed to create the output span, try fall through to the
  359. // regular bilinear output code.
  360. delete output;
  361. output = NULL;
  362. fPunted = true;
  363. goto FallbackCreation;
  364. }
  365. break;
  366. }
  367. // else fall through to the regular bicubic code.
  368. // Bicubic filter kernel.
  369. case InterpolationModeBicubic:
  370. output = new DpOutputBicubicImageSpan(
  371. bitmap,
  372. scan,
  373. context,
  374. *imageAttributes,
  375. numPoints,
  376. dstPoints,
  377. srcRect
  378. );
  379. break;
  380. // High quality bilinear (tent) convolution filter
  381. case InterpolationModeHighQualityBilinear:
  382. // !!! [asecchia] the high quality bilinear filter code doesn't
  383. // know how to do rotation yet.
  384. if(xForm->IsTranslateScale())
  385. {
  386. output = new DpOutputSpanStretch<HighQualityBilinear>(
  387. bitmap,
  388. scan,
  389. context,
  390. *imageAttributes,
  391. dstRect,
  392. srcRect
  393. );
  394. if(output && !output->IsValid())
  395. {
  396. // Failed to create the output span, try fall through to the
  397. // regular bilinear output code.
  398. delete output;
  399. output = NULL;
  400. fPunted = true;
  401. goto FallbackCreation;
  402. }
  403. break;
  404. }
  405. // else fall through to the regular bilinear code.
  406. // Bilinear filter kernel - default case.
  407. case InterpolationModeDefault:
  408. case InterpolationModeLowQuality:
  409. case InterpolationModeBilinear:
  410. default:
  411. FallbackCreation:
  412. // Create a bilinear span or an identity span.
  413. output = CreateBilinearOutputSpan(
  414. bitmap,
  415. scan,
  416. xForm,
  417. context,
  418. imageAttributes,
  419. fPunted // somebody failed and this is the fallback.
  420. );
  421. }
  422. // Check to see that the constructor for the output span class succeeded.
  423. if(output && !output->IsValid())
  424. {
  425. delete output;
  426. output = NULL;
  427. }
  428. // This will be NULL on an error path.
  429. return output;
  430. }
  431. /**************************************************************************\
  432. *
  433. * Function Description:
  434. *
  435. * Draws an image.
  436. *
  437. * Arguments:
  438. *
  439. * [IN] context - the context (matrix and clipping)
  440. * [IN] srcSurface - the source surface
  441. * [IN] dstSurface - the image to fill
  442. * [IN] drawBounds - the surface bounds
  443. * [IN] mapMode - the mapping mode of the image
  444. * [IN] numPoints - the number of points in dstPoints array (<= 4)
  445. * [IN] dstPoints - the array of points for affine or quad transform.
  446. * [IN] srcRect - the bounds of the src image. If this is NULL,
  447. * the whole image is used.
  448. *
  449. * Return Value:
  450. *
  451. * GpStatus - Ok or failure status
  452. *
  453. * History:
  454. *
  455. * 01/09/1999 ikkof Created it.
  456. * 10/19/1999 asecchia rewrite to support rotation.
  457. *
  458. \**************************************************************************/
  459. GpStatus
  460. DpDriver::DrawImage(
  461. DpContext * context,
  462. DpBitmap * srcSurface,
  463. DpBitmap * dstSurface,
  464. const GpRect * drawBounds,
  465. const DpImageAttributes * imgAttributes,
  466. INT numPoints,
  467. const GpPointF * dstPoints,
  468. const GpRectF * srcRect,
  469. DriverDrawImageFlags flags
  470. )
  471. {
  472. // Get the infrastructure to do active edge table stuff.
  473. using namespace DpDriverActiveEdge;
  474. // !!! [asecchia] Why do we have this if we don't use it?
  475. GpStatus status = Ok;
  476. // The caller is responsible for padding out the dstPoints structure so
  477. // that it has at least 3 valid points.
  478. ASSERT((numPoints==3)||(numPoints==4));
  479. // We need to do some reordering of points for warping (numPoints==4)
  480. // to work. For now we require numPoints == 3.
  481. ASSERT(numPoints==3);
  482. // Make a local copy so we don't end up modifying our callers' data.
  483. GpPointF fDst[4];
  484. GpMemcpy(fDst, dstPoints, sizeof(GpPointF)*numPoints);
  485. // Need to infer the transform for banding code.
  486. // !!! PERF: [asecchia] This transform actually gets computed by the Engine
  487. // before calling the Driver. We should have a way of passing it down
  488. // so that we don't have to recompute it.
  489. GpMatrix xForm;
  490. xForm.InferAffineMatrix(fDst, *srcRect);
  491. xForm.Append(context->WorldToDevice);
  492. // This is the source rectangle band.
  493. GpPointF fDst2[4];
  494. // If we are in HalfPixelMode Offset, we want to be able to read half
  495. // a pixel to the left of the image, to be able to center the drawing
  496. fDst2[0].X = srcRect->X;
  497. fDst2[0].Y = srcRect->Y;
  498. fDst2[1].X = srcRect->X+srcRect->Width;
  499. fDst2[1].Y = srcRect->Y;
  500. fDst2[2].X = srcRect->X;
  501. fDst2[2].Y = srcRect->Y+srcRect->Height;
  502. // Transform the points to the destination.
  503. xForm.Transform(fDst2, 3);
  504. if(numPoints==3)
  505. {
  506. // Force the four point destination format
  507. fDst[0].X = fDst2[0].X;
  508. fDst[0].Y = fDst2[0].Y;
  509. fDst[1].X = fDst2[2].X;
  510. fDst[1].Y = fDst2[2].Y;
  511. fDst[2].X = fDst2[1].X+fDst2[2].X-fDst2[0].X;
  512. fDst[2].Y = fDst2[1].Y+fDst2[2].Y-fDst2[0].Y;
  513. fDst[3].X = fDst2[1].X;
  514. fDst[3].Y = fDst2[1].Y;
  515. } else if (numPoints==4) {
  516. // !!! [asecchia] This code branch doesn't work yet.
  517. // The transforms required for correct banding need to be worked out
  518. // for the warp transform case.
  519. // This is a V2 feature.
  520. ASSERT(FALSE);
  521. }
  522. // Convert the transformed rectangle to fix point notation.
  523. PointFIX4 fix4Dst[4];
  524. fix4Dst[0].X = GpRealToFix4(fDst[0].X);
  525. fix4Dst[0].Y = GpRealToFix4(fDst[0].Y);
  526. fix4Dst[1].X = GpRealToFix4(fDst[1].X);
  527. fix4Dst[1].Y = GpRealToFix4(fDst[1].Y);
  528. fix4Dst[2].X = GpRealToFix4(fDst[2].X);
  529. fix4Dst[2].Y = GpRealToFix4(fDst[2].Y);
  530. fix4Dst[3].X = GpRealToFix4(fDst[3].X);
  531. fix4Dst[3].Y = GpRealToFix4(fDst[3].Y);
  532. // !!! [agodfrey] Perf: May want to add the noTransparentPixels parameter.
  533. // I guess we'd have to check that the coordinates are integer (after
  534. // translation and scaling), that there's no rotation, and that
  535. // the image contains no transparent pixels.
  536. DpScanBuffer scan(
  537. dstSurface->Scan,
  538. this,
  539. context,
  540. dstSurface
  541. );
  542. if(!scan.IsValid())
  543. {
  544. return(GenericError);
  545. }
  546. // Only valid if xForm->IsTranslateScale()
  547. GpRectF dstRect(
  548. fDst[0].X,
  549. fDst[0].Y,
  550. fDst[2].X-fDst[0].X,
  551. fDst[2].Y-fDst[0].Y
  552. );
  553. DpOutputSpan* output = CreateOutputSpan(
  554. srcSurface,
  555. &scan,
  556. &xForm,
  557. const_cast<DpImageAttributes*>(imgAttributes),
  558. context->FilterType,
  559. context,
  560. srcRect,
  561. &dstRect,
  562. dstPoints,
  563. numPoints
  564. );
  565. // if output is NULL, we failed to allocate the memory for the
  566. // output span class.
  567. if(output == NULL)
  568. {
  569. return(OutOfMemory);
  570. }
  571. // Set up the clipping.
  572. DpRegion::Visibility visibility = DpRegion::TotallyVisible;
  573. DpClipRegion *clipRegion = NULL;
  574. if (context->VisibleClip.GetRectVisibility(
  575. drawBounds->X,
  576. drawBounds->Y,
  577. drawBounds->GetRight(),
  578. drawBounds->GetBottom()
  579. ) != DpRegion::TotallyVisible
  580. )
  581. {
  582. clipRegion = &(context->VisibleClip);
  583. clipRegion->InitClipping(output, drawBounds->Y);
  584. }
  585. GpRect clippedRect;
  586. if(clipRegion)
  587. {
  588. visibility = clipRegion->GetRectVisibility(
  589. drawBounds->X,
  590. drawBounds->Y,
  591. drawBounds->GetRight(),
  592. drawBounds->GetBottom(),
  593. &clippedRect
  594. );
  595. }
  596. // Decide on our clipping strategy.
  597. DpOutputSpan *outspan;
  598. switch (visibility)
  599. {
  600. case DpRegion::TotallyVisible: // no clipping is needed
  601. outspan = output;
  602. break;
  603. case DpRegion::ClippedVisible: //
  604. case DpRegion::PartiallyVisible: // some clipping is needed
  605. outspan = clipRegion;
  606. break;
  607. case DpRegion::Invisible: // nothing on screen - quit
  608. goto DrawImage_Done;
  609. }
  610. if(xForm.IsTranslateScale() || // stretch
  611. xForm.IsIntegerTranslate()) // copybits
  612. {
  613. // Do the stretch/translate case
  614. GpPoint dstTL, dstBR;
  615. // Round to fixed point to eliminate the very close to integer
  616. // numbers that can result from transformation.
  617. // E.g. 300.0000000001 should become 300 after the ceiling operation
  618. // and not 301 (not the classical definition of ceiling).
  619. // Top Left corner.
  620. dstTL.X = GpFix4Ceiling(fix4Dst[0].X);
  621. dstTL.Y = GpFix4Ceiling(fix4Dst[0].Y);
  622. // Bottom Right corner
  623. dstBR.X = GpFix4Ceiling(fix4Dst[2].X);
  624. dstBR.Y = GpFix4Ceiling(fix4Dst[2].Y);
  625. // Swap coordinates if necessary. StretchBitsMainLoop
  626. // assumes that TL corner is less than BR corner.
  627. if (dstTL.X > dstBR.X)
  628. {
  629. INT xTmp = dstTL.X;
  630. dstTL.X = dstBR.X;
  631. dstBR.X = xTmp;
  632. }
  633. if (dstTL.Y > dstBR.Y)
  634. {
  635. INT yTmp = dstTL.Y;
  636. dstTL.Y = dstBR.Y;
  637. dstBR.Y = yTmp;
  638. }
  639. // Due to the fixed point calculations used for image stretching,
  640. // we are limited to how large an image can be stretched.
  641. // If it is out of bounds, return an error.
  642. if (srcRect->Width > 32767.0f || srcRect->Height > 32767.0f)
  643. {
  644. WARNING(("Image width or height > 32767"));
  645. status = InvalidParameter;
  646. goto DrawImage_Done;
  647. }
  648. // This handles both the stretch and the copy case
  649. // Don't draw anything if there are no scanlines to draw or if
  650. // there are no pixels in the scanlines.
  651. if( (dstBR.X != dstTL.X) &&
  652. (dstBR.Y != dstTL.Y) )
  653. {
  654. StretchBitsMainLoop(outspan, &dstTL, &dstBR);
  655. }
  656. }
  657. else
  658. {
  659. // Default case - handles generic drawing including
  660. // rotation, shear, etc.
  661. INT yMinIdx = 0; // index of the smallest y coordinate.
  662. INT y; // current scanline.
  663. // Number of points - used for wrap computation.
  664. const INT points = 4;
  665. // search for the minimum y coordinate index.
  666. for(y=1;y<points;y++)
  667. {
  668. if(fix4Dst[y].Y < fix4Dst[yMinIdx].Y)
  669. {
  670. yMinIdx = y;
  671. }
  672. }
  673. y = GpFix4Ceiling(fix4Dst[yMinIdx].Y);
  674. // DDA for left and right edges.
  675. // ASSUMPTION: Convex polygon => two edges only.
  676. // Work out which edge is left and which is right.
  677. INT index1, index2;
  678. REAL det;
  679. index1 = yMinIdx-1;
  680. if(index1<0)
  681. {
  682. index1=points-1;
  683. }
  684. index2 = yMinIdx+1;
  685. if(index2>=points)
  686. {
  687. index2=0;
  688. }
  689. // Compute the determinant.
  690. // The sign of the determinant formed by the first two edges
  691. // will tell us if the polygon is specified clockwise
  692. // or anticlockwise.
  693. if( (fix4Dst[index1].Y==fix4Dst[yMinIdx].Y) &&
  694. (fix4Dst[index2].Y==fix4Dst[yMinIdx].Y) )
  695. {
  696. // Both initial edges are horizontal - compare x coordinates.
  697. // You get this formula by "cancelling out" the zero y terms
  698. // in the determinant formula below.
  699. // This part of the formula only works because we know that
  700. // yMinIdx is the index of the minimum y coordinate in the
  701. // polygon.
  702. det = (REAL)(fix4Dst[index1].X-fix4Dst[index2].X);
  703. }
  704. else
  705. {
  706. // Full determinant computation
  707. det = (REAL)
  708. (fix4Dst[index2].Y-fix4Dst[yMinIdx].Y)*
  709. (fix4Dst[index1].X-fix4Dst[yMinIdx].X)-
  710. (REAL)
  711. (fix4Dst[index1].Y-fix4Dst[yMinIdx].Y)*
  712. (fix4Dst[index2].X-fix4Dst[yMinIdx].X);
  713. }
  714. // Even though we've discarded all the empty rectangle cases, it's
  715. // still possible for really small non-zero matrix coefficients to
  716. // be multiplied together giving zero - due to rounding error at
  717. // the precision limit of the real number representation.
  718. // If the det is zero (or really close) the quad has no area and
  719. // we succeed the call immediately.
  720. if(REALABS(det) < REAL_EPSILON)
  721. {
  722. goto DrawImage_Done;
  723. }
  724. {
  725. // Initialize the iterators with the direction dependent on the
  726. // sign of the determinant.
  727. // These are scoped because of the exit branches above (goto)
  728. DdaIterator left(fix4Dst, points, (det>0.0f)?1:-1, yMinIdx);
  729. DdaIterator right(fix4Dst, points, (det>0.0f)?-1:1, yMinIdx);
  730. // If both iterators are valid, start the loop.
  731. INT xLeft, xRight;
  732. if(left.IsValid() && right.IsValid())
  733. {
  734. do {
  735. // Output the data. We know we only have one span because
  736. // we're drawing a convex quad.
  737. xLeft = left.GetX();
  738. xRight = right.GetX();
  739. // If this ever happens, we've broken a fundumental
  740. // assumption of the OutputSpan code. Our x coordinates
  741. // must be ordered.
  742. ASSERT(xLeft <= xRight);
  743. // Trivially reject any scanlines that don't have any
  744. // pixels.
  745. if(xRight>xLeft)
  746. {
  747. outspan->OutputSpan(y, xLeft, xRight);
  748. }
  749. // Update the y value to the new scanline
  750. y++;
  751. // Incrementaly update DDAs for this new scanline.
  752. // End the loop if we're done with the last edge.
  753. } while(left.Next(y-1) && right.Next(y-1));
  754. } // end if valid iterators
  755. } // end scope
  756. } // end else (rotation block)
  757. // We're done - clean up and return status.
  758. DrawImage_Done:
  759. output->End();
  760. if (clipRegion != NULL)
  761. {
  762. clipRegion->EndClipping();
  763. }
  764. delete output;
  765. return status;
  766. }