// Convert the SkColors into float colors. The conversion depends on some conditions: // - If the pixmap has a dst colorspace, we have to be "color-correct". // Do we map into dst-colorspace before or after we interpolate? // - We have to decide when to apply per-color alpha (before or after we interpolate) // // For now, we will take a simple approach, but recognize this is just a start: // - convert colors into dst colorspace before interpolation (matches gradients) // - apply per-color alpha before interpolation (matches old version of vertices) // static SkPMColor4f* convert_colors(const SkColor src[], int count,
SkColorSpace* deviceCS,
SkArenaAlloc* alloc, bool skipColorXform) {
SkPMColor4f* dst = alloc->makeArray<SkPMColor4f>(count);
staticbool compute_is_opaque(const SkColor colors[], int count) {
uint32_t c = ~0; for (int i = 0; i < count; ++i) {
c &= colors[i];
} return SkColorGetA(c) == 0xFF;
}
static constexpr int kMaxClippedTrianglePointCount = 4; staticvoid fill_triangle_3(const VertState& state, SkBlitter* blitter, const SkRasterClip& rc, const SkPoint3 dev3[]) { // Compute the crossing point (across zero) for the two values, expressed as a // normalized 0...1 value. If curr is 0, returns 0. If next is 0, returns 1. auto computeT = [](float curr, float next) { // Check that 0 is between next and curr.
SkASSERT((next <= 0 && 0 < curr) || (curr <= 0 && 0 < next)); float t = curr / (curr - next);
SkASSERT(0 <= t && t <= 1); return t;
};
auto lerp = [](SkPoint3 curr, SkPoint3 next, float t) { return curr + t * (next - curr);
};
constexpr float tol = 0.05f; // tol is the nudge away from zero, to keep the numerics nice. // Think of it as our near-clipping-plane (or w-plane). auto clip = [&](SkPoint3 curr, SkPoint3 next) { // Return the point between curr and next where the fZ value crosses tol. // To be (really) perspective correct, we should be computing based on 1/Z, not Z. // For now, this is close enough (and faster). return lerp(curr, next, computeT(curr.fZ - tol, next.fZ - tol));
};
// Clip a triangle (based on its homogeneous W values), and return the projected polygon. // Since we only clip against one "edge"/plane, the max number of points in the clipped // polygon is 4. auto clipTriangle = [&](SkPoint dst[], constint idx[3], const SkPoint3 pts[]) -> int {
SkPoint3 outPoints[kMaxClippedTrianglePointCount];
SkPoint3* outP = outPoints;
for (int i = 0; i < 3; ++i) { int curr = idx[i]; int next = idx[(i + 1) % 3]; if (pts[curr].fZ > tol) {
*outP++ = pts[curr]; if (pts[next].fZ <= tol) { // curr is IN, next is OUT
*outP++ = clip(pts[curr], pts[next]);
}
} else { if (pts[next].fZ > tol) { // curr is OUT, next is IN
*outP++ = clip(pts[curr], pts[next]);
}
}
}
if (paintShader) { if (!texCoords) {
texCoords = positions;
}
} else {
texCoords = nullptr;
}
bool blenderIsDst = false; // We can simplify things for certain blend modes. This is for speed, and SkShader_Blend // itself insists we don't pass kSrc or kDst to it. if (std::optional<SkBlendMode> bm = as_BB(blender)->asBlendMode(); bm.has_value() && colors) { switch (*bm) { case SkBlendMode::kSrc:
colors = nullptr; break; case SkBlendMode::kDst:
blenderIsDst = true;
texCoords = nullptr;
paintShader = nullptr; break; default: break;
}
}
// There is a paintShader iff there is texCoords.
SkASSERT((texCoords != nullptr) == (paintShader != nullptr));
// Explicit texture coords can't contain perspective - only the CTM can. constbool usePerspective = fCTM->hasPerspective();
// Combines per-vertex colors with 'shader' using 'blender'. auto applyShaderColorBlend = [&](SkShader* shader) -> sk_sp<SkShader> { if (!colors) { return sk_ref_sp(shader);
} if (blenderIsDst) { return sk_ref_sp(triColorShader);
}
sk_sp<SkShader> shaderWithWhichToBlend; if (!shader) { // When there is no shader then the blender applies to the vertex colors and opaque // paint color.
shaderWithWhichToBlend = SkShaders::Color(paint.getColor4f().makeOpaque(), nullptr);
} else {
shaderWithWhichToBlend = sk_ref_sp(shader);
} return SkShaders::Blend(blender,
sk_ref_sp(triColorShader),
std::move(shaderWithWhichToBlend));
};
// If there are separate texture coords then we need to insert a transform shader to update // a matrix derived from each triangle's coords. In that case we will fold the CTM into // each update and use an identity matrix.
SkTransformShader* transformShader = nullptr; const SkMatrix* ctm = fCTM; if (texCoords && texCoords != positions) {
paintShader = transformShader = outerAlloc->make<SkTransformShader>(*as_SB(paintShader),
usePerspective);
ctm = &SkMatrix::I();
}
sk_sp<SkShader> blenderShader = applyShaderColorBlend(paintShader);
// abort early if there is nothing to draw if (vertexCount < 3 || (indexCount > 0 && indexCount < 3) || fRC->isEmpty()) { return;
}
SkMatrix ctmInv; if (!fCTM->invert(&ctmInv)) { return;
}
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.