of static method

Pixels of(
  1. Pixels picture, {
  2. NormalMapOptions options = const NormalMapOptions(),
})

The normal map of picture.

Implementation

static Pixels of(
  Pixels picture, {
  NormalMapOptions options = const NormalMapOptions(),
}) {
  final w = picture.width, h = picture.height;
  final height = Float32List(w * h);
  final src = picture.rgba;
  for (var i = 0; i < w * h; i++) {
    final r = src[i * 4], g = src[i * 4 + 1], b = src[i * 4 + 2];
    final a = src[i * 4 + 3] / 255;
    var lum = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
    if (options.invert) lum = 1 - lum;
    height[i] = options.tiles ? lum : lum * a;
  }
  if (options.bevel > 0 && !options.tiles) {
    final rounded = _bevel(picture, options.bevel);
    for (var i = 0; i < w * h; i++) {
      // Half the picture's own bumps, half the rounded edge.
      height[i] = height[i] * 0.5 + rounded[i] * 0.5;
    }
  }
  double at(int x, int y) {
    if (options.tiles) {
      x %= w;
      y %= h;
      if (x < 0) x += w;
      if (y < 0) y += h;
    } else {
      x = x.clamp(0, w - 1);
      y = y.clamp(0, h - 1);
    }
    return height[y * w + x];
  }

  final out = Pixels(w, h);
  final dst = out.rgba;
  final s = options.strength;
  for (var y = 0; y < h; y++) {
    for (var x = 0; x < w; x++) {
      // Sobel: the slope across and down, smoothed.
      final dx =
          (at(x + 1, y - 1) + 2 * at(x + 1, y) + at(x + 1, y + 1)) -
          (at(x - 1, y - 1) + 2 * at(x - 1, y) + at(x - 1, y + 1));
      final dy =
          (at(x - 1, y + 1) + 2 * at(x, y + 1) + at(x + 1, y + 1)) -
          (at(x - 1, y - 1) + 2 * at(x, y - 1) + at(x + 1, y - 1));
      // Up is against the picture's rows: higher below, the normal
      // leans up.
      var nx = -dx * s, ny = dy * s;
      const nz = 1.0;
      final len = math.sqrt(nx * nx + ny * ny + nz * nz);
      nx /= len;
      ny /= len;
      final i = (y * w + x) * 4;
      dst[i] = ((nx * 0.5 + 0.5) * 255).round();
      dst[i + 1] = ((ny * 0.5 + 0.5) * 255).round();
      dst[i + 2] = ((nz / len * 0.5 + 0.5) * 255).round();
      dst[i + 3] = options.tiles ? 255 : src[i + 3];
    }
  }
  return out;
}