import 'dart:math' as Math;

import '../color.dart';
import '../image.dart';

/**
 * Generate a normal map from a heightfield bump image.
 *
 * The red channel of the [src] image is used as an input, 0 represents a low
 * height and 1 a high value. The optional [strength] parameter allows to set
 * the strength of the normal image.
 */
Image bumpToNormal(Image src, {double strength: 2.0}) {
  Image dest = new Image.from(src);

  for (var y = 0; y < src.height; ++y) {
    for (var x = 0; x < src.width; ++x) {
      final height = getRed(src.getPixel(x, y)) / 255.0;
      var du = (height - getRed(src.getPixel(x < src.width - 1 ? x + 1 : x, y))
          / 255.0) * strength;
      var dv = (height - getRed(src.getPixel(x, y < src.height - 1 ? y + 1 : y))
          / 255.0) * strength;
      final z = du.abs() + dv.abs();

      if (z > 1) {
        du /= z;
        dv /= z;
      }

      final dw = Math.sqrt(1.0 - du * du - dv * dv);
      final nX = du * 0.5 + 0.5;
      final nY = dv * 0.5 + 0.5;
      final nZ = dw;

      dest.setPixelRGBA(x, y, (255 * nX).floor(), (255 * nY).floor(),
          (255 * nZ).floor());
    }
  }

  return dest;
}
