using System;
using System.Collections.Generic;
namespace Otter {
///
/// Graphic that can render a bunch of static images all at once. Images must use the same
/// texture as the Decals object in order to be baked together properly.
///
public class Decals : Graphic {
#region Private Fields
List images = new List();
#endregion
#region Public Properties
///
/// If the decals have been baked or not.
///
public bool Solid { get; private set; }
///
/// The number of images in the list.
///
public int Count {
get {
return images.Count;
}
}
#endregion
#region Constructors
///
/// Create a new Decals object using a source file path for a texture.
///
/// The file path to the texture.
public Decals(string source) {
SetTexture(new Texture(source));
Initialize();
}
///
/// Create a new Decals object using a Texture.
///
/// The Texture to use.
public Decals(Texture texture) {
SetTexture(texture);
Initialize();
}
///
/// Create a new Decals object using an AtlasTexture.
///
///
public Decals(AtlasTexture texture) {
SetTexture(texture);
Initialize();
}
#endregion
#region Private Methods
void Initialize() {
NeedsUpdate = false;
}
protected override void UpdateDrawable() {
base.UpdateDrawable();
SFMLVertices.Clear();
float maxX = float.MinValue;
float minX = float.MaxValue;
float maxY = float.MinValue;
float minY = float.MaxValue;
foreach (var img in images) {
img.UpdateDrawableIfNeeded();
for (uint i = 0; i < img.GetVertices().VertexCount; i++) {
var v = img.GetVertices()[i];
var transform = SFML.Graphics.Transform.Identity;
transform.Translate(img.X - img.OriginX, img.Y - img.OriginY);
transform.Rotate(img.Angle, img.OriginX, img.OriginY);
transform.Scale(img.ScaleX, img.ScaleY, img.OriginX, img.OriginY);
var p = transform.TransformPoint(v.Position.X, v.Position.Y);
maxX = Util.Max(maxX, p.X);
minX = Util.Min(minX, p.X);
maxY = Util.Max(maxY, p.Y);
minY = Util.Min(minY, p.Y);
SFMLVertices.Append(p.X, p.Y, img.Color, v.TexCoords.X, v.TexCoords.Y);
}
}
Width = Math.Abs((int)Util.Ceil(maxX - minX));
Height = Math.Abs((int)Util.Ceil(maxY - minY));
}
#endregion
#region Public Methods
///
/// Add an image to the list of decals. Only works if Solid is false.
///
/// The image to add.
public void Add(Image image) {
if (Solid) return;
if (!image.Batchable) {
throw new ArgumentException("Non batchable images cannot be baked.");
}
if (image.Texture.SFMLTexture != Texture.SFMLTexture) {
throw new ArgumentException("Images must use the same texture as the Decals object.");
}
images.Add(image);
}
///
/// Remove an image from the list of decals. Only works if Solid is false.
///
///
public void Remove(Image image) {
if (Solid) return;
images.RemoveIfContains(image);
}
///
/// Erases all images from the list. Only works if Solid is false. Will not immediately show changes
/// until Bake() is called.
///
public void Clear() {
if (Solid) return;
images.Clear();
NeedsUpdate = true;
UpdateDrawableIfNeeded();
}
///
/// Bake all the images together for rendering.
///
public void Bake() {
if (Count == 0) return; // Don't bake if 0 images.
if (!Solid) {
NeedsUpdate = true;
Solid = true;
UpdateDrawableIfNeeded();
}
}
///
/// Unbake the images back to an editable form.
///
public void Unbake() {
if (Solid) {
Solid = false;
}
}
#endregion
}
}