package de.gurkenlabs.litiengine.graphics;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;

import de.gurkenlabs.litiengine.entities.Creature;
import de.gurkenlabs.litiengine.util.Imaging;

public class CreatureShadowImageEffect extends ImageEffect {
  private static final Color DEFAULT_SHADOW_COLOR = new Color(124, 164, 174, 120);

  private final Creature creature;
  private final Color shadowColor;

  /**
   * Initializes a new instance of the <code>CreatureShadowImageEffect</code>.
   *
   * @param creature
   *          The creature to which this affect will be applied to.
   */
  public CreatureShadowImageEffect(final Creature creature) {
    this(creature, DEFAULT_SHADOW_COLOR);
  }

  /**
   * Initializes a new instance of the <code>CreatureShadowImageEffect</code>.
   *
   * @param creature
   *          The creature to which this affect will be applied to.
   * @param shadowColor
   *          The color of the shadow.
   */
  public CreatureShadowImageEffect(final Creature creature, final Color shadowColor) {
    super(0, "shadow");
    this.creature = creature;
    this.shadowColor = shadowColor;
  }

  public Creature getCreature() {
    return this.creature;
  }

  @Override
  public BufferedImage apply(BufferedImage image) {
    if (this.getCreature().isDead()) {
      return image;
    }

    final BufferedImage buffer = Imaging.getCompatibleImage(image.getWidth() * 2 + 2, image.getHeight() * 2);
    final Graphics2D graphics = buffer.createGraphics();
    float offsetX = image.getWidth() / 2.0f;
    float offsetY = image.getHeight() / 2.0f;

    this.drawShadow(graphics, image.getWidth(), image.getHeight(), offsetX, offsetY);

    ImageRenderer.render(graphics, image, offsetX, offsetY);
    graphics.dispose();
    return buffer;
  }

  protected Ellipse2D getShadowEllipse(final float spriteWidth, final float spriteHeight, float offsetX, float offsetY) {
    final double ellipseWidth = 0.60 * spriteWidth;
    final double ellipseHeight = 0.20 * spriteWidth;
    final double startX = (spriteWidth - ellipseWidth) / 2.0;
    final double startY = spriteHeight - ellipseHeight;
    return new Ellipse2D.Double(startX + offsetX, startY + offsetY, ellipseWidth, ellipseHeight);
  }

  protected void drawShadow(final Graphics2D graphics, final float spriteWidth, final float spriteHeight, float offsetX, float offsetY) {
    graphics.setColor(this.shadowColor);
    final RenderingHints hints = graphics.getRenderingHints();
    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    graphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

    graphics.fill(getShadowEllipse(spriteWidth, spriteHeight, offsetX, offsetY));
    graphics.setRenderingHints(hints);
  }
}

@@ -504,16 +504,75 @@
 Color;%0A%0A
+  private float offsetX = 0;%0A  private float offsetY = 0;%0A%0A
   /**%0A  
@@ -1352,16 +1352,362 @@
 e;%0A  %7D%0A%0A
+  public float getOffsetX() %7B%0A    return this.offsetX;%0A  %7D%0A%0A  public CreatureShadowImageEffect setOffsetX(float offsetX) %7B%0A    this.offsetX = offsetX;%0A    return this;%0A  %7D%0A%0A  public float getOffsetY() %7B%0A    return this.offsetY;%0A  %7D%0A%0A  public CreatureShadowImageEffect setOffsetY(float offsetY) %7B%0A    this.offsetY = offsetY;%0A    return this;%0A  %7D%0A%0A
   @Overr
@@ -2005,23 +2005,17 @@
   float 
-offsetX
+x
  = image
@@ -2044,23 +2044,17 @@
   float 
-offsetY
+y
  = image
@@ -2142,25 +2142,43 @@
 ight(), 
-offsetX, 
+x + this.offsetX, y + this.
 offsetY)
@@ -2222,32 +2222,20 @@
  image, 
-offsetX, offsetY
+x, y
 );%0A    g

Add shadow offset fields to the shadow image effect.