зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1626113 - Use mozilla::Span in TransformAndClipRect and do some refactoring. r=kip
Differential Revision: https://phabricator.services.mozilla.com/D68929 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
6b7047492f
Коммит
d00525a3a9
|
@ -114,5 +114,66 @@ Matrix4x4 MatrixDouble::operator*(const Matrix4x4& aMatrix) const {
|
|||
return resultMatrix;
|
||||
}
|
||||
|
||||
// Intersect the polygon given by aPoints with the half space induced by
|
||||
// aPlaneNormal and return the resulting polygon. The returned points are
|
||||
// stored in aDestBuffer, and its meaningful subspan is returned.
|
||||
template <typename F>
|
||||
Span<Point4DTyped<UnknownUnits, F>> IntersectPolygon(
|
||||
Span<Point4DTyped<UnknownUnits, F>> aPoints,
|
||||
const Point4DTyped<UnknownUnits, F>& aPlaneNormal,
|
||||
Span<Point4DTyped<UnknownUnits, F>> aDestBuffer) {
|
||||
if (aPoints.Length() < 3 || aDestBuffer.Length() < 3) {
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t nextIndex = 0; // aDestBuffer[nextIndex] is the next emitted point.
|
||||
|
||||
// Iterate over the polygon edges. In each iteration the current edge
|
||||
// is the edge from *prevPoint to point. If the two end points lie on
|
||||
// different sides of the plane, we have an intersection. Otherwise,
|
||||
// the edge is either completely "inside" the half-space created by
|
||||
// the clipping plane, and we add curPoint, or it is completely
|
||||
// "outside", and we discard curPoint. This loop can create duplicated
|
||||
// points in the polygon.
|
||||
const auto* prevPoint = &aPoints[aPoints.Length() - 1];
|
||||
F prevDot = aPlaneNormal.DotProduct(*prevPoint);
|
||||
for (const auto& curPoint : aPoints) {
|
||||
F curDot = aPlaneNormal.DotProduct(curPoint);
|
||||
|
||||
if ((curDot >= 0.0) != (prevDot >= 0.0)) {
|
||||
// An intersection with the clipping plane has been detected.
|
||||
// Interpolate to find the intersecting curPoint and emit it.
|
||||
F t = -prevDot / (curDot - prevDot);
|
||||
aDestBuffer[nextIndex++] = curPoint * t + *prevPoint * (1.0 - t);
|
||||
if (nextIndex >= aDestBuffer.Length()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (curDot >= 0.0) {
|
||||
// Emit any source points that are on the positive side of the
|
||||
// clipping plane.
|
||||
aDestBuffer[nextIndex++] = curPoint;
|
||||
if (nextIndex >= aDestBuffer.Length()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
prevPoint = &curPoint;
|
||||
prevDot = curDot;
|
||||
}
|
||||
|
||||
return aDestBuffer.To(nextIndex);
|
||||
}
|
||||
|
||||
template Span<Point4DTyped<UnknownUnits, Float>> IntersectPolygon(
|
||||
Span<Point4DTyped<UnknownUnits, Float>> aPoints,
|
||||
const Point4DTyped<UnknownUnits, Float>& aPlaneNormal,
|
||||
Span<Point4DTyped<UnknownUnits, Float>> aDestBuffer);
|
||||
template Span<Point4DTyped<UnknownUnits, Double>> IntersectPolygon(
|
||||
Span<Point4DTyped<UnknownUnits, Double>> aPoints,
|
||||
const Point4DTyped<UnknownUnits, Double>& aPlaneNormal,
|
||||
Span<Point4DTyped<UnknownUnits, Double>> aDestBuffer);
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
|
112
gfx/2d/Matrix.h
112
gfx/2d/Matrix.h
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
@ -26,6 +27,12 @@ static inline bool FuzzyEqual(Float aV1, Float aV2) {
|
|||
return fabs(aV2 - aV1) < 1e-6;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
Span<Point4DTyped<UnknownUnits, F>> IntersectPolygon(
|
||||
Span<Point4DTyped<UnknownUnits, F>> aPoints,
|
||||
const Point4DTyped<UnknownUnits, F>& aPlaneNormal,
|
||||
Span<Point4DTyped<UnknownUnits, F>> aDestBuffer);
|
||||
|
||||
template <class T>
|
||||
class BaseMatrix {
|
||||
// Alias that maps to either Point or PointDouble depending on whether T is a
|
||||
|
@ -834,99 +841,54 @@ class Matrix4x4Typed {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Initialize a double-buffered array of points in homogenous space with
|
||||
// the input rectangle, aRect.
|
||||
Point4DTyped<UnknownUnits, F> points[2][kTransformAndClipRectMaxVerts];
|
||||
Point4DTyped<UnknownUnits, F>* dstPointStart = points[0];
|
||||
Point4DTyped<UnknownUnits, F>* dstPoint = dstPointStart;
|
||||
typedef Point4DTyped<UnknownUnits, F> P4D;
|
||||
|
||||
*dstPoint++ = TransformPoint(
|
||||
Point4DTyped<UnknownUnits, F>(aRect.X(), aRect.Y(), 0, 1));
|
||||
*dstPoint++ = TransformPoint(
|
||||
Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.Y(), 0, 1));
|
||||
*dstPoint++ = TransformPoint(
|
||||
Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.YMost(), 0, 1));
|
||||
*dstPoint++ = TransformPoint(
|
||||
Point4DTyped<UnknownUnits, F>(aRect.X(), aRect.YMost(), 0, 1));
|
||||
// The initial polygon is made up by the corners of aRect in homogenous
|
||||
// space, mapped into the destination space of this transform.
|
||||
P4D rectCorners[] = {
|
||||
TransformPoint(P4D(aRect.X(), aRect.Y(), 0, 1)),
|
||||
TransformPoint(P4D(aRect.XMost(), aRect.Y(), 0, 1)),
|
||||
TransformPoint(P4D(aRect.XMost(), aRect.YMost(), 0, 1)),
|
||||
TransformPoint(P4D(aRect.X(), aRect.YMost(), 0, 1)),
|
||||
};
|
||||
|
||||
// Cut off pieces of the polygon that are outside of aClip (the "view
|
||||
// frustrum"), by consecutively intersecting the polygon with the half space
|
||||
// induced by the clipping plane for each side of aClip.
|
||||
// View frustum clipping planes are described as normals originating from
|
||||
// the 0,0,0,0 origin.
|
||||
Point4DTyped<UnknownUnits, F> planeNormals[4];
|
||||
planeNormals[0] = Point4DTyped<UnknownUnits, F>(1.0, 0.0, 0.0, -aClip.X());
|
||||
planeNormals[1] =
|
||||
Point4DTyped<UnknownUnits, F>(-1.0, 0.0, 0.0, aClip.XMost());
|
||||
planeNormals[2] = Point4DTyped<UnknownUnits, F>(0.0, 1.0, 0.0, -aClip.Y());
|
||||
planeNormals[3] =
|
||||
Point4DTyped<UnknownUnits, F>(0.0, -1.0, 0.0, aClip.YMost());
|
||||
|
||||
// Iterate through each clipping plane and clip the polygon.
|
||||
// For each clipping plane, we intersect the plane with all polygon edges.
|
||||
// Each pass can increase or decrease the number of points that make up the
|
||||
// current clipped polygon. We double buffer that set of points, alternating
|
||||
// between points[0] and points[1].
|
||||
for (int plane = 0; plane < 4; plane++) {
|
||||
auto planeNormal = planeNormals[plane];
|
||||
Point4DTyped<UnknownUnits, F>* srcPoint = dstPointStart;
|
||||
Point4DTyped<UnknownUnits, F>* srcPointEnd = dstPoint;
|
||||
// current clipped polygon. We double buffer the set of points, alternating
|
||||
// between polygonBufA and polygonBufB. Duplicated points in the polygons
|
||||
// are kept around until all clipping is done. The loop at the end filters
|
||||
// out any consecutive duplicates.
|
||||
P4D polygonBufA[kTransformAndClipRectMaxVerts];
|
||||
P4D polygonBufB[kTransformAndClipRectMaxVerts];
|
||||
|
||||
dstPointStart = points[~plane & 1];
|
||||
dstPoint = dstPointStart;
|
||||
Span<P4D> polygon(rectCorners);
|
||||
polygon = IntersectPolygon<F>(polygon, P4D(1.0, 0.0, 0.0, -aClip.X()),
|
||||
polygonBufA);
|
||||
polygon = IntersectPolygon<F>(polygon, P4D(-1.0, 0.0, 0.0, aClip.XMost()),
|
||||
polygonBufB);
|
||||
polygon = IntersectPolygon<F>(polygon, P4D(0.0, 1.0, 0.0, -aClip.Y()),
|
||||
polygonBufA);
|
||||
polygon = IntersectPolygon<F>(polygon, P4D(0.0, -1.0, 0.0, aClip.YMost()),
|
||||
polygonBufB);
|
||||
|
||||
// Iterate over the polygon edges. In each iteration the current edge is
|
||||
// the edge from prevPoint to srcPoint. If the two end points lie on
|
||||
// different sides of the plane, we have an intersection. Otherwise, the
|
||||
// edge is either completely "inside" the half-space created by the
|
||||
// clipping plane, and we add srcPoint, or it is completely "outside", and
|
||||
// we discard srcPoint.
|
||||
// We may create duplicated points in the polygon. We keep those around
|
||||
// until all clipping is done and then filter out duplicates at the end.
|
||||
Point4DTyped<UnknownUnits, F>* prevPoint = srcPointEnd - 1;
|
||||
F prevDot = planeNormal.DotProduct(*prevPoint);
|
||||
while (srcPoint < srcPointEnd &&
|
||||
((dstPoint - dstPointStart) < kTransformAndClipRectMaxVerts)) {
|
||||
F nextDot = planeNormal.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.
|
||||
F 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;
|
||||
}
|
||||
|
||||
if (dstPoint == dstPointStart) {
|
||||
// No polygon points were produced, so the polygon has been
|
||||
// completely clipped away by the current clipping plane. Exit.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Point4DTyped<UnknownUnits, F>* srcPoint = dstPointStart;
|
||||
Point4DTyped<UnknownUnits, F>* srcPointEnd = dstPoint;
|
||||
size_t vertCount = 0;
|
||||
while (srcPoint < srcPointEnd) {
|
||||
for (const auto& srcPoint : polygon) {
|
||||
PointTyped<TargetUnits, F> p;
|
||||
if (srcPoint->w == 0.0) {
|
||||
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 = PointTyped<TargetUnits, F>(0.0, 0.0);
|
||||
} else {
|
||||
p = srcPoint->As2DPoint();
|
||||
p = srcPoint.As2DPoint();
|
||||
}
|
||||
// Emit only unique points
|
||||
if (vertCount == 0 || p != aVerts[vertCount - 1]) {
|
||||
aVerts[vertCount++] = p;
|
||||
}
|
||||
srcPoint++;
|
||||
}
|
||||
|
||||
return vertCount;
|
||||
|
|
Загрузка…
Ссылка в новой задаче