draw method

  1. @override
void draw(
  1. Canvas canvas,
  2. SpoilerContext context
)
override

Implementation

@override
void draw(
  Canvas canvas,
  SpoilerContext context,
) {
  final isFading = context.isFading;
  final fadeRadius = context.fadeRadius;
  final fadeCenter = context.fadeCenter;
  final fadeEdgeThickness = context.config.fadeConfig?.edgeThickness ?? 1;
  _maxParticleSize = context.config.particleConfig.maxParticleSize;
  _particleColor = context.config.particleConfig.color;
  _particleSpeed = context.config.particleConfig.speed;

  final count = _particles.length;
  if (count == 0) return;

  _reallocBuffers(count);

  final transforms = _valTransforms!;
  final rects = _valRects!;
  final colors = _valColors!;
  final spriteRadius = _circleImage.dimension * 0.5;
  final bounds = context.spoilerBounds;
  final boundaryFadePx = max(spriteRadius * 3.0, 6.0);

  double smoothstep(double edge0, double edge1, double x) {
    final t = ((x - edge0) / (edge1 - edge0)).clamp(0.0, 1.0);
    return t * t * (3.0 - 2.0 * t);
  }

  int index = 0;
  for (final p in _particles) {
    final transformIndex = index * 4;
    final lifeScale = _lifeSizeMin + (1.0 - _lifeSizeMin) * p.life;
    final edgeDist = min(
      min(p.dx - bounds.left, bounds.right - p.dx),
      min(p.dy - bounds.top, bounds.bottom - p.dy),
    );
    final edgeFade =
        edgeDist <= 0.0 ? 0.0 : smoothstep(0.0, boundaryFadePx, edgeDist);
    final particleRadius = max(spriteRadius * lifeScale, 0.0001);
    final edgeClamp = (edgeDist / particleRadius).clamp(0.0, 1.0);
    final edgeScale = edgeFade * edgeClamp;

    if (isFading) {
      final distSq = (fadeCenter - p).distanceSquared;
      final radiusSq = fadeRadius * fadeRadius;

      if (distSq < radiusSq) {
        final dist = sqrt(distSq);
        final scale = (dist > fadeRadius - fadeEdgeThickness) ? 1.5 : 1.0;
        final color =
            (dist > fadeRadius - fadeEdgeThickness) ? Colors.white : p.color;
        final scaled = scale * lifeScale * edgeScale;
        final edgeColor = color.withValues(alpha: color.a * edgeScale);

        transforms[transformIndex + 0] = scaled;
        transforms[transformIndex + 1] = 0.0;
        transforms[transformIndex + 2] = p.dx - spriteRadius * scaled;
        transforms[transformIndex + 3] = p.dy - spriteRadius * scaled;

        rects[transformIndex + 0] = 0.0;
        rects[transformIndex + 1] = 0.0;
        rects[transformIndex + 2] = _circleImage.dimension.toDouble();
        rects[transformIndex + 3] = _circleImage.dimension.toDouble();

        colors[index] = edgeScale > 0.0
            ? _colorToArgb(edgeColor)
            : _colorToArgb(Colors.transparent);
        if (edgeScale <= 0.0) {
          transforms[transformIndex + 0] = 0.0;
        }
        index++;
      } else {
        // outside fade circle
        colors[index] = _colorToArgb(Colors.transparent);
        transforms[transformIndex + 0] = 0;
        index++;
      }
    } else {
      // normal
      final scaled = lifeScale * edgeScale;
      transforms[transformIndex + 0] = scaled;
      transforms[transformIndex + 1] = 0.0;
      transforms[transformIndex + 2] = p.dx - spriteRadius * scaled;
      transforms[transformIndex + 3] = p.dy - spriteRadius * scaled;

      rects[transformIndex + 0] = 0.0;
      rects[transformIndex + 1] = 0.0;
      rects[transformIndex + 2] = _circleImage.dimension.toDouble();
      rects[transformIndex + 3] = _circleImage.dimension.toDouble();

      final edgeColor = p.color.withValues(alpha: p.color.a * edgeScale);
      colors[index] = edgeScale > 0.0
          ? _colorToArgb(edgeColor)
          : _colorToArgb(Colors.transparent);
      if (edgeScale <= 0.0) {
        transforms[transformIndex + 0] = 0.0;
      }
      index++;
    }
  }

  if (index > 0) {
    canvas.drawRawAtlas(
      _circleImage.image,
      transforms,
      rects,
      colors,
      BlendMode.modulate,
      null,
      _particlePaint,
    );
  }
}