⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 path.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Permedia3 Sample Display Driver
// path.c
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//
// This file contains the GDI entry points for drawing paths, or filled shapes
// given as a set of edges.

#include "pch.h"  // Precompiled header support.
#include "debug.h"
#include "struct.h"
#include "proto.h"

// This is a dumb little helper macro.

#define Swap(a,b)  \
{                  \
  (a) = (a) ^ (b); \
  (b) = (a) ^ (b); \
  (a) = (a) ^ (b); \
}

// This is the amount we grow the edge arrays when we run out of space.

#define EDGE_ARRAY_GROW 20

// These structures are private to this module, and used for filled path
// rasterization.

typedef struct t_PERM3_EDGE {

  // This is the smaller of the y values of the edge end points. 

  LONG TopY;

  // Pointer to the next edge, as sorted by TopY values.

  struct t_PERM3_EDGE * NextTop;

  // This is the larger of the y values of the edge end points.

  LONG BottomY;

  // Pointer to the next edge, as sorted by BottomY values.

  struct t_PERM3_EDGE * NextBottom;

  // X coordinate of the edges intersection with the current scanline.

  LONG X;

  // Pointer to the next edge, sorted by x, which intersect the current line.

  struct t_PERM3_EDGE * NextActive;

  // 1 if yEnd > yStart, -1 otherwise.

  LONG Direction;

  // X coordinate coresponding to TopY.

  LONG TopX;

  // For each increment in y, how many whole pixels do we move in x?

  LONG XIntegralAdvance;

  // For each increment in y, how many fractional (1 / Height) pixels do we
  // move in x?

  LONG XFractionalAdvance;

  // The sum of all the frqctional advances we have done so far which have 
  // not yet added up to one integral advance.  Or think of it as the 
  // fraction you need to add to X to get the current real (non-integral) 
  // x-coordinate.

  LONG FractionalTotal;
  LONG FractionalTotalStart;

  // The height of the edge (BottomY - TopY)

  LONG Height;

} PERM3_EDGE;

typedef struct t_PERM3_EDGE_LIST {

  PERM3_EDGE * Array;
  PERM3_EDGE * FirstTop;
  PERM3_EDGE * FirstBottom;
  PERM3_EDGE * FirstActive;
  LONG         Size;
  LONG         Count;
  LONG         MinY;
  LONG         MaxY;

} PERM3_EDGE_LIST;

// Internal prototypes. These functions are not exposed outside this module.

static ULONG
MixToRop(
  MIX Mix
  );

static void
InitializeEdgeList(
  PERM3_EDGE_LIST * EdgeList,
  ULONG             NumEdges
  );

static BOOL
AddEdge(
  PERM3_EDGE_LIST * EdgeList,
  FIX               x1,
  FIX               y1,
  FIX               x2,
  FIX               y2
  );

static BOOL
FillEdge(
  PERM3_EDGE_LIST * EdgeList,
  PERM3_BLT_PARAM * Parameters
  );

static void
DestroyEdgeList(
  PERM3_EDGE_LIST * EdgeList
  );

BOOL DrvFillPath(
  SURFOBJ  * DestSurface,
  PATHOBJ  * Path,
  CLIPOBJ  * Clipper,
  BRUSHOBJ * Brush,
  POINTL   * BrushOrigin,
  MIX        Mix,
  FLONG      Options
  )
{
  // DrvFillPath
  // This function is called by GDI when it needs it draw a filled, closed
  // path. It accomplishes this by building a list of edges from the points
  // the GDI feeds us via path enumeration. It then scanconverts that edge
  // list with blit operations.

  // It might be possible to optimize this operation by triangulating the
  // given points and feeding them to a triangle rasterizer.

  // Local variables.

  BOOL            FnRetVal = FALSE;
  PERM3_BLT_PARAM Parameters;
  PERM3_SURFACE   Dest;
  RECT            DestRect;
  PERM3_SURFACE * BrushSurface;
  RECT            BrushRect;
  POINT           LocalBrushOrigin;
  ENUMRECTS     * ClipperRects = NULL;
  ULONG           SizeofClipperRects;
  LONG            More;
  ULONG           i;
  PERM3_EDGE_LIST EdgeList;
  PATHDATA        PathData;
  POINTFIX        FirstPoint;
  POINTFIX        LastPoint;

  // Check parameters.

  // !TODO!

  Enter(L"DrvFillPath");

  memset(&Parameters, 0, sizeof(PERM3_BLT_PARAM));

  // Fill in the blt parameters that we can reuse.

  Parameters.Rop = MixToRop(Mix);

  SurfobjToPerm3Surface(&Dest,
                        DestSurface,
                        NULL,
                        FALSE);

  Parameters.Destination = (const SURFACE *)&Dest;

  // Make sure we have a destination rectangle to fill out in FillEdge.

  Parameters.DestRect = &DestRect;

  // Using a surface as a brush to fill a path on itself is pedantically
  // possible, but, we're not going to worry about it.

  Parameters.ScanXPositive = TRUE;
  Parameters.ScanYPositive = TRUE;

  if (Brush) {

    if (Brush->iSolidColor == 0xFFFFFFFF) {    

      Parameters.PatternType = BitmapPattern;

      // Get the brush surface and transfer the appropriate details into
      // the parameters structure.

      if (Brush->pvRbrush == NULL) {

        BrushSurface = (PERM3_SURFACE *)(BRUSHOBJ_pvGetRbrush(Brush));
        // !TODO! Check return code?
      }
      else {

        BrushSurface = (PERM3_SURFACE *)(Brush->pvRbrush);
      }

      Parameters.Brush = (const SURFACE *)BrushSurface;

      BrushRect.left = 0;
      BrushRect.top = 0;

      BrushRect.right  = Parameters.Brush->Size.cx;
      BrushRect.bottom = Parameters.Brush->Size.cy;

      Parameters.BrushRect = &BrushRect;

      if (BrushOrigin) {

        Parameters.BrushOrigin = (POINT *)BrushOrigin;
      }
      else {

        LocalBrushOrigin.x = 0;
        LocalBrushOrigin.y = 0;

        Parameters.BrushOrigin = &LocalBrushOrigin;
      } 
    }
    else {

      Parameters.PatternType = SolidPattern;
      Parameters.FillValue = Brush->iSolidColor;
    }
  }

  if (Clipper && Clipper->iDComplexity != DC_TRIVIAL) {

    if (Clipper->iDComplexity == DC_RECT) {

      Parameters.ClipRectCount = 1;
      Parameters.ClipRect = (const RECT *)&(Clipper->rclBounds);
    }
    else if (Clipper->iDComplexity == DC_COMPLEX) {

      // Extract all of the rectangles from GDI.

      Parameters.ClipRectCount = CLIPOBJ_cEnumStart(Clipper,
                                                    TRUE,
                                                    CT_RECTANGLES,
                                                    CD_ANY,
                                                    0);

      // The ENUMRECTS strcuture already contains space for 1 rectangle.

      SizeofClipperRects = sizeof(ENUMRECTS) +
                           sizeof(RECT) * (Parameters.ClipRectCount - 1);
      ClipperRects = SystemAlloc(SizeofClipperRects);
      if (ClipperRects) {

        CLIPOBJ_bEnum(Clipper,
                      SizeofClipperRects,
                      (ULONG *)ClipperRects);

        Assert(ClipperRects->c == Parameters.ClipRectCount);

        Parameters.ClipRect = (const RECT *)ClipperRects->arcl;
      }
      else {

        Error(L"System memory allocation failure.\n");
      }
    }
    else {
      Error(L"Unknown clipping complexity.\n");
    }
  }

  // Now, we extract the path information into a PERM3_EDGE_LIST structure
  // that we can rasterize.

  InitializeEdgeList(&EdgeList, Path->cCurves);
  PATHOBJ_vEnumStart(Path);

  do {
    More = PATHOBJ_bEnum(Path, &PathData);

    if (PathData.count == 0) break;

    // Handle the first point.

    if (PathData.flags & PD_BEGINSUBPATH) {

      // This is the start of a new sub-path. We need only save the first
      // point to close the path with.

      FirstPoint = PathData.pptfx[0];
    } 
    else {

      // Continue the current subpath.

      if (!AddEdge(&EdgeList, 
                   LastPoint.x, 
                   LastPoint.y, 
                   PathData.pptfx[0].x,
                   PathData.pptfx[0].y)) {
        More = 0;
      }
    }

    // Add all of the points remaining in this PathData.

    for (i = 0; i < PathData.count - 1; i++) {

      if (!AddEdge(&EdgeList,
                   PathData.pptfx[i].x,
                   PathData.pptfx[i].y,
                   PathData.pptfx[i + 1].x,
                   PathData.pptfx[i + 1].y)) {
        More = 0;
      }
    }

    // Handle the last point. Either close the subpath, or save the last
    // point to use with the next batch of data.

    if (PathData.flags & PD_ENDSUBPATH) {
			
      if (!AddEdge(&EdgeList, 
                   PathData.pptfx[i].x,
                   PathData.pptfx[i].y, 
                   FirstPoint.x, 
                   FirstPoint.y)){
        More = 0;
      }
    }
    else {
      LastPoint = PathData.pptfx[i];
    }

  } while (More != 0);

  // Rasterize.

  FnRetVal = FillEdge(&EdgeList, &Parameters);

  // Cleanup.

  DestroyEdgeList(&EdgeList);

  if (ClipperRects) {
    SystemFree(ClipperRects);
  }

  FreeSurfobjDerivedPerm3Surface(&Dest);

  Exit(L"DrvFillPath");

  return FnRetVal;
}

ULONG
MixToRop(
  MIX Mix
  )
{
  // MixToRop
  // This function converts a MIX value (a pair of ROP2's) into a ROP4
  // appropriate for blitting. No Enter/Exit semantics for inlined functions.

  // Local constants. 

  // This lookup is derived from the definition of the ROP2 and MIX
  // raster operation definitions.

  const BYTE MixLookup[] =
  {
    0xFF,  // R2_WHITE        - Allow rop = gaMix[mix & 0x0F]
    0x00,  // R2_BLACK
    0x05,  // R2_NOTMERGEPEN
    0x0A,  // R2_MASKNOTPEN
    0x0F,  // R2_NOTCOPYPEN
    0x50,  // R2_MASKPENNOT
    0x55,  // R2_NOT
    0x5A,  // R2_XORPEN
    0x5F,  // R2_NOTMASKPEN
    0xA0,  // R2_MASKPEN
    0xA5,  // R2_NOTXORPEN
    0xAA,  // R2_NOP
    0xAF,  // R2_MERGENOTPEN
    0xF0,  // R2_COPYPEN
    0xF5,  // R2_MERGEPENNOT
    0xFA,  // R2_MERGEPEN
    0xFF   // R2_WHITE        - Allow rop = gaMix[mix & 0xFF]
  };

  // Check parameters.

  // !TODO!

  return (((ULONG)(MixLookup[(Mix >> 8) & 0x0f]) << 8) | MixLookup[Mix & 0x0f]);
}

void
InitializeEdgeList(
  PERM3_EDGE_LIST * EdgeList,
  ULONG             NumEdges
  )
{
  // InitializeEdgeList
  // This function will, given an PERM3_EDGE_LIST structure, and a number of
  // edges, prepare that edge list for use (for AddEdge and FillEdge to be
  // called on it.)

  // Check parameters.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -