// This is free and unencumbered software released into the public domain. // // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. // // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit // of the public at large and to the detriment of our heirs and // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // For more information, please refer to // ----------------------------------------------------------------- // Uses the SVG Rendering Engine (http://svg.codeplex.com/) to extract Bezier // curves from an SVG file in an XNA ContentImporter. // // See http://www.wam-games.com/2010/04/svg-in-xna/ for more information. using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content.Pipeline; using Svg; using System.Drawing.Drawing2D; // Alias our output type -- A dictionary mapping a path name to a list of // control points. using PathDict = System.Collections.Generic.Dictionary>; // The Svg library uses this matrix type not the XNA one: using Matrix = System.Drawing.Drawing2D.Matrix; namespace ContentPipeline { [ContentImporter(".svg", DisplayName = "SVG Path Importer")] public class SvgPathImporter : ContentImporter { string filename; public override PathDict Import(string filename, ContentImporterContext context) { this.filename = filename; SvgDocument doc = SvgDocument.Open(filename); var paths = new PathDict(); collectPaths(ref paths, doc); return paths; } static bool isBezier(SvgPath path) { // All but the first point must be type '3' const int bezierPointId = 3; return path.Path.PathTypes.Skip(1).All(t => t == bezierPointId); } // Calculate the overall transform that applies to a node. static Matrix getTransform(SvgElement node) { var m = new Matrix(); while (node != null) { if (node.Transforms != null && node.Transforms.Count > 0) { var temp = new Matrix(); foreach (var trans in node.Transforms) { temp.Multiply(trans.Matrix, MatrixOrder.Prepend); } m.Multiply(temp, MatrixOrder.Append); } node = node.Parent; } return m; } // Traverse the tree of SvgElement nodes recursively. If a node is of type // SvgPath, and is a Bezier curve, then we process it and add it to our // dictionary. void collectPaths(ref PathDict paths, SvgElement e) { SvgPath path = e as SvgPath; if (path != null) { if (!isBezier(path)) { // Complain about any non-Bezier curves so we can fix them // in the editor. throw new InvalidContentException( String.Format("Cubic Beziers only: {0}", path.ID), new ContentIdentity(filename)); } // Transform points in-place. var pts = path.Path.PathPoints; getTransform(e).TransformPoints(pts); // Convert to Vector2. var vpts = pts.Select(p => new Vector2(p.X, p.Y)).ToList(); paths.Add(path.ID, vpts); } foreach (var child in e.Children) { collectPaths(ref paths, child); } } } } // To load the path data in-game, use: // var paths = Content.Load>>("test");