Esempio n. 1
0
Rect Matrix4x4::ProjectRectBounds(const Rect& aRect) const
{
  Point4D points[4];

  points[0] = ProjectPoint(aRect.TopLeft());
  points[1] = ProjectPoint(aRect.TopRight());
  points[2] = ProjectPoint(aRect.BottomRight());
  points[3] = ProjectPoint(aRect.BottomLeft());

  Float min_x = std::numeric_limits<Float>::max();
  Float min_y = std::numeric_limits<Float>::max();
  Float max_x = -std::numeric_limits<Float>::max();
  Float max_y = -std::numeric_limits<Float>::max();

  bool foundPoint = false;
  for (int i=0; i<4; i++) {
    // Only use points that exist above the w=0 plane
    if (points[i].HasPositiveWCoord()) {
      foundPoint = true;
      Point point2d = points[i].As2DPoint();
      min_x = min<Float>(point2d.x, min_x);
      max_x = max<Float>(point2d.x, max_x);
      min_y = min<Float>(point2d.y, min_y);
      max_y = max<Float>(point2d.y, max_y);
    }

    int next = (i == 3) ? 0 : i + 1;
    if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) {
      // If the line between two points crosses the w=0 plane, then interpolate a point
      // as close to the w=0 plane as possible and use that instead.
      Point4D intercept = ComputePerspectivePlaneIntercept(points[i], points[next]);

      Point point2d = intercept.As2DPoint();
      min_x = min<Float>(point2d.x, min_x);
      max_x = max<Float>(point2d.x, max_x);
      min_y = min<Float>(point2d.y, min_y);
      max_y = max<Float>(point2d.y, max_y);
    }
  }

  if (!foundPoint) {
    return Rect(0, 0, 0, 0);
  }

  return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
}
Esempio n. 2
0
size_t
Matrix4x4::TransformAndClipRect(const Rect& aRect, const Rect& aClip,
                                Point* aVerts) const
{
  // Initialize a double-buffered array of points in homogenous space with
  // the input rectangle, aRect.
  Point4D points[2][kTransformAndClipRectMaxVerts];
  Point4D* dstPoint = points[0];
  *dstPoint++ = *this * Point4D(aRect.x, aRect.y, 0, 1);
  *dstPoint++ = *this * Point4D(aRect.XMost(), aRect.y, 0, 1);
  *dstPoint++ = *this * Point4D(aRect.XMost(), aRect.YMost(), 0, 1);
  *dstPoint++ = *this * Point4D(aRect.x, aRect.YMost(), 0, 1);

  // View frustum clipping planes are described as normals originating from
  // the 0,0,0,0 origin.
  Point4D planeNormals[4];
  planeNormals[0] = Point4D(1.0, 0.0, 0.0, -aClip.x);
  planeNormals[1] = Point4D(-1.0, 0.0, 0.0, aClip.XMost());
  planeNormals[2] = Point4D(0.0, 1.0, 0.0, -aClip.y);
  planeNormals[3] = Point4D(0.0, -1.0, 0.0, aClip.YMost());

  // Iterate through each clipping plane and clip the polygon.
  // In each pass, we double buffer, alternating between points[0] and
  // points[1].
  for (int plane=0; plane < 4; plane++) {
    planeNormals[plane].Normalize();

    Point4D* srcPoint = points[plane & 1];
    Point4D* srcPointEnd = dstPoint;
    dstPoint = points[~plane & 1];

    Point4D* prevPoint = srcPointEnd - 1;
    float prevDot = planeNormals[plane].DotProduct(*prevPoint);
    while (srcPoint < srcPointEnd) {
      float nextDot = planeNormals[plane].DotProduct(*srcPoint);

      if ((nextDot >= 0.0) != (prevDot >= 0.0)) {
        // An intersection with the clipping plane has been detected.
        // Interpolate to find the intersecting point and emit it.
        float t = -prevDot / (nextDot - prevDot);
        *dstPoint++ = *srcPoint * t + *prevPoint * (1.0 - t);
      }

      if (nextDot >= 0.0) {
        // Emit any source points that are on the positive side of the
        // clipping plane.
        *dstPoint++ = *srcPoint;
      }

      prevPoint = srcPoint++;
      prevDot = nextDot;
    }
  }

  size_t dstPointCount = 0;
  size_t srcPointCount = dstPoint - points[0];
  for (Point4D* srcPoint = points[0]; srcPoint < points[0] + srcPointCount; srcPoint++) {

    Point p;
    if (srcPoint->w == 0.0) {
      // If a point lies on the intersection of the clipping planes at
      // (0,0,0,0), we must avoid a division by zero w component.
      p = Point(0.0, 0.0);
    } else {
      p = srcPoint->As2DPoint();
    }
    // Emit only unique points
    if (dstPointCount == 0 || p != aVerts[dstPointCount - 1]) {
      aVerts[dstPointCount++] = p;
    }
  }

  return dstPointCount;
}