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 } }