static SkRect map_rect_affine(const SkRect& src, constfloat mat[16]) { // When multiplied against vectors of the form <x,y,x,y>, 'flip' allows a single min() // to compute both the min and "negated" max between the xy coordinates. Once finished, another // multiplication produces the original max. const skvx::float4 flip{1.f, 1.f, -1.f, -1.f};
// Since z = 0 and it's assumed ther's no perspective, only load the upper 2x2 and (tx,ty) in c3 auto c0 = skvx::shuffle<0,1,0,1>(skvx::float2::Load(mat + 0)) * flip; auto c1 = skvx::shuffle<0,1,0,1>(skvx::float2::Load(mat + 4)) * flip; auto c3 = skvx::shuffle<0,1,0,1>(skvx::float2::Load(mat + 12));
// Compute the min and max of the four transformed corners pre-translation; then translate once // at the end. auto minMax = c3 + flip * min(min(c0 * src.fLeft + c1 * src.fTop,
c0 * src.fRight + c1 * src.fTop),
min(c0 * src.fLeft + c1 * src.fBottom,
c0 * src.fRight + c1 * src.fBottom));
// minMax holds (min x, min y, max x, max y) so can be copied into an SkRect expecting l,t,r,b
SkRect r;
minMax.store(&r); return r;
}
static SkRect map_rect_perspective(const SkRect& src, constfloat mat[16]) { // Like map_rect_affine, z = 0 so we can skip the 3rd column, but we do need to compute w's // for each corner of the src rect. auto c0 = skvx::float4::Load(mat + 0); auto c1 = skvx::float4::Load(mat + 4); auto c3 = skvx::float4::Load(mat + 12);
// Unlike map_rect_affine, we do not defer the 4th column since we may need to homogeneous // coordinates to clip against the w=0 plane auto tl = c0 * src.fLeft + c1 * src.fTop + c3; auto tr = c0 * src.fRight + c1 * src.fTop + c3; auto bl = c0 * src.fLeft + c1 * src.fBottom + c3; auto br = c0 * src.fRight + c1 * src.fBottom + c3;
// After clipping to w>0 and projecting to 2d, 'project' employs the same negation trick to // compute min and max at the same time. const skvx::float4 flip{1.f, 1.f, -1.f, -1.f}; auto project = [&flip](const skvx::float4& p0, const skvx::float4& p1, const skvx::float4& p2) { float w0 = p0[3]; if (w0 >= SkPathPriv::kW0PlaneDistance) { // Unclipped, just divide by w return flip * skvx::shuffle<0,1,0,1>(p0) / w0;
} else { auto clip = [&](const skvx::float4& p) { float w = p[3]; if (w >= SkPathPriv::kW0PlaneDistance) { float t = (SkPathPriv::kW0PlaneDistance - w0) / (w - w0); auto c = (t * skvx::shuffle<0,1>(p) + (1.f - t) * skvx::shuffle<0,1>(p0)) /
SkPathPriv::kW0PlaneDistance;
return flip * skvx::shuffle<0,1,0,1>(c);
} else { return skvx::float4(SK_ScalarInfinity);
}
}; // Clip both edges leaving p0, and return the min/max of the two clipped points // (since clip returns infinity when both p0 and 2nd vertex have w<0, it'll // automatically be ignored). return min(clip(p1), clip(p2));
}
};
// Project all 4 corners, and pass in their adjacent vertices for clipping if it has w < 0, // then accumulate the min and max xy's. auto minMax = flip * min(min(project(tl, tr, bl), project(tr, br, tl)),
min(project(br, bl, tr), project(bl, tl, br)));
void SkM44::normalizePerspective() { // If the bottom row of the matrix is [0, 0, 0, not_one], we will treat the matrix as if it // is in perspective, even though it stills behaves like its affine. If we divide everything // by the not_one value, then it will behave the same, but will be treated as affine, // and therefore faster (e.g. clients can forward-difference calculations). if (fMat[15] != 1 && fMat[15] != 0 && fMat[3] == 0 && fMat[7] == 0 && fMat[11] == 0) { double inv = 1.0 / fMat[15];
(skvx::float4::Load(fMat + 0) * inv).store(fMat + 0);
(skvx::float4::Load(fMat + 4) * inv).store(fMat + 4);
(skvx::float4::Load(fMat + 8) * inv).store(fMat + 8);
(skvx::float4::Load(fMat + 12) * inv).store(fMat + 12);
fMat[15] = 1.0f;
}
}
/** We always perform the calculation in doubles, to avoid prematurely losing precision along the way. This relies on the compiler automatically promoting our SkScalar values to double (if needed).
*/ bool SkM44::invert(SkM44* inverse) const {
SkScalar tmp[16]; if (SkInvert4x4Matrix(fMat, tmp) == 0.0f) { returnfalse;
}
memcpy(inverse->fMat, tmp, sizeof(tmp)); returntrue;
}
SkM44& SkM44::setRotateUnitSinCos(SkV3 axis, SkScalar sinAngle, SkScalar cosAngle) { // Taken from "Essential Mathematics for Games and Interactive Applications" // James M. Van Verth and Lars M. Bishop -- third edition
SkScalar x = axis.x;
SkScalar y = axis.y;
SkScalar z = axis.z;
SkScalar c = cosAngle;
SkScalar s = sinAngle;
SkScalar t = 1 - c;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.