185 {
188 args.fVaryingHandler->emitAttributes(shader);
189
190 args.fVertBuilder->defineConstant(
"float",
"PI",
"3.141592653589793238");
192
193
194
195
196 float maxEdges =
args.fShaderCaps->fVertexIDSupport ? FixedCountStrokes::kMaxEdges
197 : FixedCountStrokes::kMaxEdgesNoVertexIDs;
198 args.fVertBuilder->defineConstant(
"NUM_TOTAL_EDGES", maxEdges);
199
200
201 if (shader.hasDynamicStroke()) {
202 args.fVertBuilder->insertFunction(kNumRadialSegmentsPerRadianFn);
203 }
204 args.fVertBuilder->insertFunction(kRobustNormalizeDiffFn);
205 args.fVertBuilder->insertFunction(kCosineBetweenUnitVectorsFn);
206 args.fVertBuilder->insertFunction(kMiterExtentFn);
207 args.fVertBuilder->insertFunction(kUncheckedMixFn);
209
210
211 if (!shader.hasDynamicStroke()) {
212
213 const char* tessArgsName;
214 fTessControlArgsUniform =
args.fUniformHandler->addUniform(
216 &tessArgsName);
217 args.fVertBuilder->codeAppendf(
218 "float NUM_RADIAL_SEGMENTS_PER_RADIAN = %s.x;"
219 "float JOIN_TYPE = %s.y;"
220 "float STROKE_RADIUS = %s.z;", tessArgsName, tessArgsName, tessArgsName);
221 } else {
222
223
224
225 SkASSERT(!shader.stroke().isHairlineStyle());
226 const char* maxScaleName;
227 fTessControlArgsUniform =
args.fUniformHandler->addUniform(
229 &maxScaleName);
230 args.fVertBuilder->codeAppendf(
231 "float STROKE_RADIUS = dynamicStrokeAttr.x;"
232 "float JOIN_TYPE = dynamicStrokeAttr.y;"
233 "float NUM_RADIAL_SEGMENTS_PER_RADIAN = num_radial_segments_per_radian("
234 "%s * STROKE_RADIUS);", maxScaleName);
235
236 }
237
238 if (shader.hasDynamicColor()) {
239
241 args.fVaryingHandler->addVarying(
"dynamicColor", &dynamicColor);
242 args.fVertBuilder->codeAppendf(
"%s = dynamicColorAttr;", dynamicColor.vsOut());
243 fDynamicColorName = dynamicColor.fsIn();
244 }
245
246
247 const char* translateName, *affineMatrixName;
250 &affineMatrixName);
253 &translateName);
254 args.fVertBuilder->codeAppendf(
"float2x2 AFFINE_MATRIX = float2x2(%s.xy, %s.zw);\n",
255 affineMatrixName, affineMatrixName);
256 args.fVertBuilder->codeAppendf(
"float2 TRANSLATE = %s;\n", translateName);
257
258 if (shader.hasExplicitCurveType()) {
260 "bool is_conic_curve() { return curveTypeAttr != %g; }",
262 } else {
263 args.fVertBuilder->insertFunction(
264 "bool is_conic_curve() { return isinf(pts23Attr.w); }");
265 }
266
267
268 args.fVertBuilder->codeAppend(
269 "float2 p0=pts01Attr.xy, p1=pts01Attr.zw, p2=pts23Attr.xy, p3=pts23Attr.zw;"
270 "float2 lastControlPoint = argsAttr.xy;"
271 "float w = -1;"
272 "if (is_conic_curve()) {"
273
274 "w = p3.x;"
275 "p3 = p2;"
276 "}"
277 );
278
279
280
281
282 args.fVertBuilder->codeAppend(
283
284 "float numParametricSegments;"
285 "if (w < 0) {"
286 "if (p0 == p1 && p2 == p3) {"
287 "numParametricSegments = 1;"
288 "} else {"
289 "numParametricSegments = wangs_formula_cubic(PRECISION, p0, p1, p2, p3, AFFINE_MATRIX);"
290 "}"
291 "} else {"
292 "numParametricSegments = wangs_formula_conic(PRECISION,"
293 "AFFINE_MATRIX * p0,"
294 "AFFINE_MATRIX * p1,"
295 "AFFINE_MATRIX * p2, w);"
296 "}"
297 );
298
299 if (shader.stroke().isHairlineStyle()) {
300
301
302 args.fVertBuilder->codeAppend(
303 "p0 = AFFINE_MATRIX * p0;"
304 "p1 = AFFINE_MATRIX * p1;"
305 "p2 = AFFINE_MATRIX * p2;"
306 "p3 = AFFINE_MATRIX * p3;"
307 "lastControlPoint = AFFINE_MATRIX * lastControlPoint;"
308 );
309 }
310
311 args.fVertBuilder->codeAppend(
312
313 "float2 tan0 = robust_normalize_diff((p0 == p1) ? ((p1 == p2) ? p3 : p2) : p1, p0);"
314 "float2 tan1 = robust_normalize_diff(p3, (p3 == p2) ? ((p2 == p1) ? p0 : p1) : p2);"
315 "if (tan0 == float2(0)) {"
316
317
318 "tan0 = float2(1,0);"
319 "tan1 = float2(-1,0);"
320 "}"
321 );
322
323 if (
args.fShaderCaps->fVertexIDSupport) {
324
325 args.fVertBuilder->codeAppend(
326 "float edgeID = float(sk_VertexID >> 1);"
327 "if ((sk_VertexID & 1) != 0) {"
328 "edgeID = -edgeID;"
329 "}"
330 );
331 }
332
333
335 args.fVertBuilder->codeAppend(
336
337
338
339
340 "float2 prevTan = robust_normalize_diff(p0, lastControlPoint);"
341 "float joinRads = acos(cosine_between_unit_vectors(prevTan, tan0));"
342 "float numRadialSegmentsInJoin = max(ceil(joinRads * NUM_RADIAL_SEGMENTS_PER_RADIAN), 1);"
343
344 "float numEdgesInJoin = numRadialSegmentsInJoin + 2;"
345
346
347
348 "numEdgesInJoin = min(numEdgesInJoin, NUM_TOTAL_EDGES - 2);");
349 if (shader.hasDynamicStroke()) {
350 args.fVertBuilder->codeAppend(
351 "if (JOIN_TYPE >= 0) {"
352
353
354 "numEdgesInJoin = sign(JOIN_TYPE) + 1 + 2;"
355 "}");
356 }
357 } else {
358 args.fVertBuilder->codeAppendf(
"float numEdgesInJoin = %i;",
360 }
361
362 args.fVertBuilder->codeAppend(
363
364
365
366 "float turn = cross_length_2d(p2 - p0, p3 - p1);"
367 "float combinedEdgeID = abs(edgeID) - numEdgesInJoin;"
368 "if (combinedEdgeID < 0) {"
369 "tan1 = tan0;"
370
371
372
373 "if (lastControlPoint != p0) {"
374 "tan0 = robust_normalize_diff(p0, lastControlPoint);"
375 "}"
376 "turn = cross_length_2d(tan0, tan1);"
377 "}"
378
379
380 "float cosTheta = cosine_between_unit_vectors(tan0, tan1);"
381 "float rotation = acos(cosTheta);"
382 "if (turn < 0) {"
383
384 "rotation = -rotation;"
385 "}"
386
387 "float numRadialSegments;"
388 "float strokeOutset = sign(edgeID);"
389 "if (combinedEdgeID < 0) {"
390
391
392 "numRadialSegments = numEdgesInJoin - 2;"
393 "numParametricSegments = 1;"
394 "p3 = p2 = p1 = p0;"
395
396
397
398 "combinedEdgeID += numRadialSegments + 1;"
399
400
401
402
403 " float sinEpsilon = 1e-2;"
404 "bool tangentsNearlyParallel ="
405 "(abs(turn) * inversesqrt(dot(tan0, tan0) * dot(tan1, tan1))) < sinEpsilon;"
406 "if (!tangentsNearlyParallel || dot(tan0, tan1) < 0) {"
407
408
409
410 "if (combinedEdgeID >= 0) {"
411 "strokeOutset = (turn < 0) ? min(strokeOutset, 0) : max(strokeOutset, 0);"
412 "}"
413 "}"
414 "combinedEdgeID = max(combinedEdgeID, 0);"
415 "} else {"
416
417
418
419 "float maxCombinedSegments = NUM_TOTAL_EDGES - numEdgesInJoin - 1;"
420 "numRadialSegments = max(ceil(abs(rotation) * NUM_RADIAL_SEGMENTS_PER_RADIAN), 1);"
421 "numRadialSegments = min(numRadialSegments, maxCombinedSegments);"
422 "numParametricSegments = min(numParametricSegments,"
423 "maxCombinedSegments - numRadialSegments + 1);"
424 "}"
425
426
427 "float radsPerSegment = rotation / numRadialSegments;"
428 "float numCombinedSegments = numParametricSegments + numRadialSegments - 1;"
429 "bool isFinalEdge = (combinedEdgeID >= numCombinedSegments);"
430 "if (combinedEdgeID > numCombinedSegments) {"
431 "strokeOutset = 0;"
432 "}");
433
435 args.fVertBuilder->codeAppendf(
436
437 "if (abs(edgeID) == 2 && %s) {"
438 "strokeOutset *= miter_extent(cosTheta, JOIN_TYPE);"
439 "}", shader.hasDynamicStroke() ? "JOIN_TYPE > 0" : "true");
440 }
441
442 this->emitTessellationCode(shader, &
args.fVertBuilder->code(), gpArgs, *
args.fShaderCaps);
443
444 this->emitFragmentCode(shader,
args);
445}
SK_API SkString static SkString SkStringPrintf()
const SkStrokeRec & stroke() const
static const char * WangsFormulaSkSL()
@ kMiter_Join
extends to miter limit
SkPaint::Join getJoin() const
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static constexpr float kPrecision
static constexpr float kCubicCurveType
constexpr int NumFixedEdgesInJoin(SkPaint::Join joinType)