| 1 | using System; | 
 
 
 
 
 | 2 | using System.Collections.Generic; | 
 
 
 
 
 | 3 | using System.IO; | 
 
 
 
 
 | 4 | using System.Globalization; | 
 
 
 
 
 | 5 | using System.Xml; | 
 
 
 
 
 | 6 | using Oni.Xml; | 
 
 
 
 
 | 7 |  | 
 
 
 
 
 | 8 | namespace Oni.Dae.IO | 
 
 
 
 
 | 9 | { | 
 
 
 
 
 | 10 | internal class DaeReader | 
 
 
 
 
 | 11 | { | 
 
 
 
 
 | 12 | public static string[] CommandLineArgs; | 
 
 
 
 
 | 13 |  | 
 
 
 
 
 | 14 | #region Private data | 
 
 
 
 
 | 15 | private static readonly string[] emptyStrings = new string[0]; | 
 
 
 
 
 | 16 | private static readonly char[] whiteSpaceChars = new char[] { ' ', '\t' }; | 
 
 
 
 
 | 17 | private static readonly Func<string, int> intConverter = XmlConvert.ToInt32; | 
 
 
 
 
 | 18 | private static readonly Func<string, float> floatConverter = XmlConvert.ToSingle; | 
 
 
 
 
 | 19 | private TextWriter error; | 
 
 
 
 
 | 20 | private TextWriter info; | 
 
 
 
 
 | 21 | private Scene mainScene; | 
 
 
 
 
 | 22 | private Dictionary<string, Entity> entities; | 
 
 
 
 
 | 23 | private XmlReader xml; | 
 
 
 
 
 | 24 | private Axis upAxis = Axis.Y; | 
 
 
 
 
 | 25 | private float unit = 1.0f; | 
 
 
 
 
 | 26 | private List<Action> delayedBindActions; | 
 
 
 
 
 | 27 | private Uri baseUrl; | 
 
 
 
 
 | 28 | private string fileName; | 
 
 
 
 
 | 29 | private List<Scene> scenes = new List<Scene>(); | 
 
 
 
 
 | 30 | private List<Light> lights = new List<Light>(); | 
 
 
 
 
 | 31 | private List<Animation> animations = new List<Animation>(); | 
 
 
 
 
 | 32 | private List<Geometry> geometries = new List<Geometry>(); | 
 
 
 
 
 | 33 | private List<Effect> effects = new List<Effect>(); | 
 
 
 
 
 | 34 | private List<Material> materials = new List<Material>(); | 
 
 
 
 
 | 35 | private List<Image> images = new List<Image>(); | 
 
 
 
 
 | 36 | private List<Camera> cameras = new List<Camera>(); | 
 
 
 
 
 | 37 | #endregion | 
 
 
 
 
 | 38 |  | 
 
 
 
 
 | 39 | #region private class Animation | 
 
 
 
 
 | 40 |  | 
 
 
 
 
 | 41 | private class Animation : Entity | 
 
 
 
 
 | 42 | { | 
 
 
 
 
 | 43 | private List<Animation> animations; | 
 
 
 
 
 | 44 | private readonly List<Sampler> samplers = new List<Sampler>(); | 
 
 
 
 
 | 45 |  | 
 
 
 
 
 | 46 | public List<Animation> Animations | 
 
 
 
 
 | 47 | { | 
 
 
 
 
 | 48 | get | 
 
 
 
 
 | 49 | { | 
 
 
 
 
 | 50 | if (animations == null) | 
 
 
 
 
 | 51 | animations = new List<Animation>(); | 
 
 
 
 
 | 52 |  | 
 
 
 
 
 | 53 | return animations; | 
 
 
 
 
 | 54 | } | 
 
 
 
 
 | 55 | } | 
 
 
 
 
 | 56 |  | 
 
 
 
 
 | 57 | public List<Sampler> Samplers => samplers; | 
 
 
 
 
 | 58 | } | 
 
 
 
 
 | 59 |  | 
 
 
 
 
 | 60 | #endregion | 
 
 
 
 
 | 61 |  | 
 
 
 
 
 | 62 | public static Scene ReadFile(string filePath) | 
 
 
 
 
 | 63 | { | 
 
 
 
 
 | 64 | var reader = new DaeReader { | 
 
 
 
 
 | 65 | baseUrl = new Uri("file://" + Path.GetDirectoryName(filePath).Replace('\\', '/').TrimEnd('/') + "/"), | 
 
 
 
 
 | 66 | fileName = Path.GetFileName(filePath), | 
 
 
 
 
 | 67 | delayedBindActions = new List<Action>(), | 
 
 
 
 
 | 68 | error = Console.Error, | 
 
 
 
 
 | 69 | info = Console.Out | 
 
 
 
 
 | 70 | }; | 
 
 
 
 
 | 71 |  | 
 
 
 
 
 | 72 | var settings = new XmlReaderSettings { | 
 
 
 
 
 | 73 | IgnoreWhitespace = true, | 
 
 
 
 
 | 74 | IgnoreProcessingInstructions = true, | 
 
 
 
 
 | 75 | IgnoreComments = true | 
 
 
 
 
 | 76 | }; | 
 
 
 
 
 | 77 |  | 
 
 
 
 
 | 78 | using (reader.xml = XmlReader.Create(filePath, settings)) | 
 
 
 
 
 | 79 | reader.ReadRoot(); | 
 
 
 
 
 | 80 |  | 
 
 
 
 
 | 81 | return reader.mainScene; | 
 
 
 
 
 | 82 | } | 
 
 
 
 
 | 83 |  | 
 
 
 
 
 | 84 | private void ReadRoot() | 
 
 
 
 
 | 85 | { | 
 
 
 
 
 | 86 | while (xml.NodeType != XmlNodeType.Element) | 
 
 
 
 
 | 87 | xml.Read(); | 
 
 
 
 
 | 88 |  | 
 
 
 
 
 | 89 | if (xml.LocalName != "COLLADA") | 
 
 
 
 
 | 90 | throw new InvalidDataException(string.Format("Unknown root element {0} found", xml.LocalName)); | 
 
 
 
 
 | 91 |  | 
 
 
 
 
 | 92 | string version = xml.GetAttribute("version"); | 
 
 
 
 
 | 93 |  | 
 
 
 
 
 | 94 | if (version != "1.4.0" && version != "1.4.1") | 
 
 
 
 
 | 95 | throw new NotSupportedException(string.Format("Unsupported Collada file version {0}", version)); | 
 
 
 
 
 | 96 |  | 
 
 
 
 
 | 97 | if (!xml.IsEmptyElement) | 
 
 
 
 
 | 98 | { | 
 
 
 
 
 | 99 | xml.ReadStartElement(); | 
 
 
 
 
 | 100 |  | 
 
 
 
 
 | 101 | ReadAsset(); | 
 
 
 
 
 | 102 | ReadContent(); | 
 
 
 
 
 | 103 | ReadExtra(); | 
 
 
 
 
 | 104 | } | 
 
 
 
 
 | 105 |  | 
 
 
 
 
 | 106 | foreach (var action in delayedBindActions) | 
 
 
 
 
 | 107 | action(); | 
 
 
 
 
 | 108 |  | 
 
 
 
 
 | 109 | if (mainScene == null && scenes.Count > 0) | 
 
 
 
 
 | 110 | mainScene = scenes[0]; | 
 
 
 
 
 | 111 |  | 
 
 
 
 
 | 112 | BindNodes(mainScene); | 
 
 
 
 
 | 113 |  | 
 
 
 
 
 | 114 | if (upAxis != Axis.Y) | 
 
 
 
 
 | 115 | AxisConverter.Convert(mainScene, upAxis, Axis.Y); | 
 
 
 
 
 | 116 |  | 
 
 
 
 
 | 117 | float scale = 1.0f; | 
 
 
 
 
 | 118 |  | 
 
 
 
 
 | 119 | if (CommandLineArgs != null) | 
 
 
 
 
 | 120 | { | 
 
 
 
 
 | 121 | string scaleArg = Array.Find(CommandLineArgs, x => x.StartsWith("-dae-scale:", StringComparison.Ordinal)); | 
 
 
 
 
 | 122 |  | 
 
 
 
 
 | 123 | if (scaleArg != null) | 
 
 
 
 
 | 124 | scale = float.Parse(scaleArg.Substring(11), CultureInfo.InvariantCulture); | 
 
 
 
 
 | 125 | } | 
 
 
 
 
 | 126 |  | 
 
 
 
 
 | 127 | if (unit != 0.1f || scale != 1.0f) | 
 
 
 
 
 | 128 | UnitConverter.Convert(mainScene, 10.0f * unit * scale); | 
 
 
 
 
 | 129 | } | 
 
 
 
 
 | 130 |  | 
 
 
 
 
 | 131 | private void ReadContent() | 
 
 
 
 
 | 132 | { | 
 
 
 
 
 | 133 | while (xml.IsStartElement()) | 
 
 
 
 
 | 134 | { | 
 
 
 
 
 | 135 | switch (xml.LocalName) | 
 
 
 
 
 | 136 | { | 
 
 
 
 
 | 137 | case "library_cameras": | 
 
 
 
 
 | 138 | ReadLibrary(cameras, "camera", ReadCamera); | 
 
 
 
 
 | 139 | break; | 
 
 
 
 
 | 140 |  | 
 
 
 
 
 | 141 | case "library_images": | 
 
 
 
 
 | 142 | ReadLibrary(images, "image", ReadImage); | 
 
 
 
 
 | 143 | break; | 
 
 
 
 
 | 144 |  | 
 
 
 
 
 | 145 | case "library_effects": | 
 
 
 
 
 | 146 | ReadLibrary(effects, "effect", ReadEffect); | 
 
 
 
 
 | 147 | break; | 
 
 
 
 
 | 148 |  | 
 
 
 
 
 | 149 | case "library_materials": | 
 
 
 
 
 | 150 | ReadLibrary(materials, "material", ReadMaterial); | 
 
 
 
 
 | 151 | break; | 
 
 
 
 
 | 152 |  | 
 
 
 
 
 | 153 | case "library_geometries": | 
 
 
 
 
 | 154 | ReadLibrary(geometries, "geometry", ReadGeometry); | 
 
 
 
 
 | 155 | break; | 
 
 
 
 
 | 156 |  | 
 
 
 
 
 | 157 | case "library_nodes": | 
 
 
 
 
 | 158 | ReadLibrary(scenes, "node", ReadNode); | 
 
 
 
 
 | 159 | break; | 
 
 
 
 
 | 160 |  | 
 
 
 
 
 | 161 | case "library_visual_scenes": | 
 
 
 
 
 | 162 | ReadLibrary(scenes, "visual_scene", ReadScene); | 
 
 
 
 
 | 163 | break; | 
 
 
 
 
 | 164 |  | 
 
 
 
 
 | 165 | case "library_animations": | 
 
 
 
 
 | 166 | ReadLibrary(animations, "animation", ReadAnimation); | 
 
 
 
 
 | 167 | break; | 
 
 
 
 
 | 168 |  | 
 
 
 
 
 | 169 | case "library_lights": | 
 
 
 
 
 | 170 | ReadLibrary(lights, "light", ReadLight); | 
 
 
 
 
 | 171 | break; | 
 
 
 
 
 | 172 |  | 
 
 
 
 
 | 173 | case "scene": | 
 
 
 
 
 | 174 | ReadScene(); | 
 
 
 
 
 | 175 | break; | 
 
 
 
 
 | 176 |  | 
 
 
 
 
 | 177 | default: | 
 
 
 
 
 | 178 | xml.Skip(); | 
 
 
 
 
 | 179 | break; | 
 
 
 
 
 | 180 | } | 
 
 
 
 
 | 181 | } | 
 
 
 
 
 | 182 | } | 
 
 
 
 
 | 183 |  | 
 
 
 
 
 | 184 | // | 
 
 
 
 
 | 185 | // Libraries | 
 
 
 
 
 | 186 | // | 
 
 
 
 
 | 187 |  | 
 
 
 
 
 | 188 | private void ReadLibrary<T>(ICollection<T> library, string elementName, Action<T> entityReader) | 
 
 
 
 
 | 189 | where T : Entity, new() | 
 
 
 
 
 | 190 | { | 
 
 
 
 
 | 191 | if (xml.SkipEmpty()) | 
 
 
 
 
 | 192 | return; | 
 
 
 
 
 | 193 |  | 
 
 
 
 
 | 194 | xml.ReadStartElement(); | 
 
 
 
 
 | 195 | ReadAsset(); | 
 
 
 
 
 | 196 |  | 
 
 
 
 
 | 197 | while (xml.IsStartElement(elementName)) | 
 
 
 
 
 | 198 | ReadEntity<T>(library, entityReader); | 
 
 
 
 
 | 199 |  | 
 
 
 
 
 | 200 | ReadExtra(); | 
 
 
 
 
 | 201 | xml.ReadEndElement(); | 
 
 
 
 
 | 202 | } | 
 
 
 
 
 | 203 |  | 
 
 
 
 
 | 204 | private void ReadEntity<T>(ICollection<T> entityCollection, Action<T> entityReader) | 
 
 
 
 
 | 205 | where T : Entity, new() | 
 
 
 
 
 | 206 | { | 
 
 
 
 
 | 207 | T entity = ReadEntity<T>(entityReader); | 
 
 
 
 
 | 208 | entityCollection.Add(entity); | 
 
 
 
 
 | 209 | } | 
 
 
 
 
 | 210 |  | 
 
 
 
 
 | 211 | private T ReadEntity<T>(Action<T> entityReader) | 
 
 
 
 
 | 212 | where T : Entity, new() | 
 
 
 
 
 | 213 | { | 
 
 
 
 
 | 214 | string id = xml.GetAttribute("id"); | 
 
 
 
 
 | 215 |  | 
 
 
 
 
 | 216 | var entity = new T { | 
 
 
 
 
 | 217 | Name = xml.GetAttribute("name"), | 
 
 
 
 
 | 218 | FileName = fileName | 
 
 
 
 
 | 219 | }; | 
 
 
 
 
 | 220 |  | 
 
 
 
 
 | 221 | AddEntity(id, entity); | 
 
 
 
 
 | 222 |  | 
 
 
 
 
 | 223 | if (string.IsNullOrEmpty(entity.Name)) | 
 
 
 
 
 | 224 | entity.Name = id; | 
 
 
 
 
 | 225 |  | 
 
 
 
 
 | 226 | if (xml.IsEmptyElement) | 
 
 
 
 
 | 227 | { | 
 
 
 
 
 | 228 | xml.ReadStartElement(); | 
 
 
 
 
 | 229 | return entity; | 
 
 
 
 
 | 230 | } | 
 
 
 
 
 | 231 |  | 
 
 
 
 
 | 232 | xml.ReadStartElement(); | 
 
 
 
 
 | 233 | ReadAsset(); | 
 
 
 
 
 | 234 |  | 
 
 
 
 
 | 235 | entityReader(entity); | 
 
 
 
 
 | 236 |  | 
 
 
 
 
 | 237 | ReadExtra(); | 
 
 
 
 
 | 238 | xml.ReadEndElement(); | 
 
 
 
 
 | 239 |  | 
 
 
 
 
 | 240 | return entity; | 
 
 
 
 
 | 241 | } | 
 
 
 
 
 | 242 |  | 
 
 
 
 
 | 243 | // | 
 
 
 
 
 | 244 | // Cameras | 
 
 
 
 
 | 245 | // | 
 
 
 
 
 | 246 |  | 
 
 
 
 
 | 247 | private void ReadCamera(Camera camera) | 
 
 
 
 
 | 248 | { | 
 
 
 
 
 | 249 | ReadAsset(); | 
 
 
 
 
 | 250 |  | 
 
 
 
 
 | 251 | xml.ReadStartElement("optics"); | 
 
 
 
 
 | 252 | xml.ReadStartElement("technique_common"); | 
 
 
 
 
 | 253 |  | 
 
 
 
 
 | 254 | if (xml.IsStartElement("perspective")) | 
 
 
 
 
 | 255 | ReadCameraParameters(camera, CameraType.Perspective); | 
 
 
 
 
 | 256 | else if (xml.IsStartElement("orthographic")) | 
 
 
 
 
 | 257 | ReadCameraParameters(camera, CameraType.Orthographic); | 
 
 
 
 
 | 258 | else if (xml.IsStartElement()) | 
 
 
 
 
 | 259 | xml.Skip(); | 
 
 
 
 
 | 260 |  | 
 
 
 
 
 | 261 | xml.ReadEndElement(); | 
 
 
 
 
 | 262 |  | 
 
 
 
 
 | 263 | while (xml.IsStartElement()) | 
 
 
 
 
 | 264 | xml.Skip(); | 
 
 
 
 
 | 265 |  | 
 
 
 
 
 | 266 | xml.ReadEndElement(); | 
 
 
 
 
 | 267 |  | 
 
 
 
 
 | 268 | if (xml.IsStartElement("imager")) | 
 
 
 
 
 | 269 | xml.Skip(); | 
 
 
 
 
 | 270 |  | 
 
 
 
 
 | 271 | ReadExtra(); | 
 
 
 
 
 | 272 | } | 
 
 
 
 
 | 273 |  | 
 
 
 
 
 | 274 | private void ReadCameraParameters(Camera camera, CameraType type) | 
 
 
 
 
 | 275 | { | 
 
 
 
 
 | 276 | xml.ReadStartElement(); | 
 
 
 
 
 | 277 |  | 
 
 
 
 
 | 278 | camera.Type = type; | 
 
 
 
 
 | 279 |  | 
 
 
 
 
 | 280 | while (xml.IsStartElement()) | 
 
 
 
 
 | 281 | { | 
 
 
 
 
 | 282 | switch (xml.LocalName) | 
 
 
 
 
 | 283 | { | 
 
 
 
 
 | 284 | case "xfov": | 
 
 
 
 
 | 285 | camera.XFov = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 286 | break; | 
 
 
 
 
 | 287 | case "yfov": | 
 
 
 
 
 | 288 | camera.YFov = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 289 | break; | 
 
 
 
 
 | 290 | case "xmag": | 
 
 
 
 
 | 291 | camera.XMag = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 292 | break; | 
 
 
 
 
 | 293 | case "ymag": | 
 
 
 
 
 | 294 | camera.YMag = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 295 | break; | 
 
 
 
 
 | 296 | case "aspect_ratio": | 
 
 
 
 
 | 297 | camera.AspectRatio = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 298 | break; | 
 
 
 
 
 | 299 | case "znear": | 
 
 
 
 
 | 300 | camera.ZNear = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 301 | break; | 
 
 
 
 
 | 302 | case "zfar": | 
 
 
 
 
 | 303 | camera.ZFar = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 304 | break; | 
 
 
 
 
 | 305 |  | 
 
 
 
 
 | 306 | default: | 
 
 
 
 
 | 307 | xml.Skip(); | 
 
 
 
 
 | 308 | break; | 
 
 
 
 
 | 309 | } | 
 
 
 
 
 | 310 | } | 
 
 
 
 
 | 311 |  | 
 
 
 
 
 | 312 | xml.ReadEndElement(); | 
 
 
 
 
 | 313 | } | 
 
 
 
 
 | 314 |  | 
 
 
 
 
 | 315 | // | 
 
 
 
 
 | 316 | // Materials | 
 
 
 
 
 | 317 | // | 
 
 
 
 
 | 318 |  | 
 
 
 
 
 | 319 | private void ReadImage(Image image) | 
 
 
 
 
 | 320 | { | 
 
 
 
 
 | 321 | //image.Width = ReadNullableIntAttribute("width"); | 
 
 
 
 
 | 322 | //image.Height = ReadNullableIntAttribute("height"); | 
 
 
 
 
 | 323 | //image.Depth = ReadNullableIntAttribute("depth"); | 
 
 
 
 
 | 324 |  | 
 
 
 
 
 | 325 | ReadAsset(); | 
 
 
 
 
 | 326 |  | 
 
 
 
 
 | 327 | if (xml.IsStartElement("init_from")) | 
 
 
 
 
 | 328 | { | 
 
 
 
 
 | 329 | string filePath = xml.ReadElementContentAsString(); | 
 
 
 
 
 | 330 |  | 
 
 
 
 
 | 331 | if (!string.IsNullOrEmpty(filePath)) | 
 
 
 
 
 | 332 | { | 
 
 
 
 
 | 333 | var imageUri = new Uri(baseUrl, filePath); | 
 
 
 
 
 | 334 | image.FilePath = imageUri.LocalPath; | 
 
 
 
 
 | 335 | } | 
 
 
 
 
 | 336 | } | 
 
 
 
 
 | 337 | else if (xml.IsStartElement("data")) | 
 
 
 
 
 | 338 | { | 
 
 
 
 
 | 339 | throw new NotSupportedException("Embedded image data is not supported"); | 
 
 
 
 
 | 340 | } | 
 
 
 
 
 | 341 | else | 
 
 
 
 
 | 342 | { | 
 
 
 
 
 | 343 | throw new InvalidDataException(); | 
 
 
 
 
 | 344 | } | 
 
 
 
 
 | 345 |  | 
 
 
 
 
 | 346 | ReadExtra(); | 
 
 
 
 
 | 347 | } | 
 
 
 
 
 | 348 |  | 
 
 
 
 
 | 349 | private void ReadEffect(Effect effect) | 
 
 
 
 
 | 350 | { | 
 
 
 
 
 | 351 | while (xml.IsStartElement()) | 
 
 
 
 
 | 352 | { | 
 
 
 
 
 | 353 | switch (xml.LocalName) | 
 
 
 
 
 | 354 | { | 
 
 
 
 
 | 355 | case "image": | 
 
 
 
 
 | 356 | ReadEntity(images, ReadImage); | 
 
 
 
 
 | 357 | break; | 
 
 
 
 
 | 358 | case "newparam": | 
 
 
 
 
 | 359 | ReadEffectParameterDecl(effect); | 
 
 
 
 
 | 360 | break; | 
 
 
 
 
 | 361 | case "profile_COMMON": | 
 
 
 
 
 | 362 | ReadEffectProfileCommon(effect); | 
 
 
 
 
 | 363 | break; | 
 
 
 
 
 | 364 | default: | 
 
 
 
 
 | 365 | xml.Skip(); | 
 
 
 
 
 | 366 | break; | 
 
 
 
 
 | 367 | } | 
 
 
 
 
 | 368 | } | 
 
 
 
 
 | 369 |  | 
 
 
 
 
 | 370 | ReadExtra(); | 
 
 
 
 
 | 371 | } | 
 
 
 
 
 | 372 |  | 
 
 
 
 
 | 373 | private void ReadEffectProfileCommon(Effect effect) | 
 
 
 
 
 | 374 | { | 
 
 
 
 
 | 375 | xml.ReadStartElement(); | 
 
 
 
 
 | 376 | ReadAsset(); | 
 
 
 
 
 | 377 |  | 
 
 
 
 
 | 378 | while (xml.IsStartElement()) | 
 
 
 
 
 | 379 | { | 
 
 
 
 
 | 380 | switch (xml.LocalName) | 
 
 
 
 
 | 381 | { | 
 
 
 
 
 | 382 | case "image": | 
 
 
 
 
 | 383 | ReadEntity(images, ReadImage); | 
 
 
 
 
 | 384 | break; | 
 
 
 
 
 | 385 | case "newparam": | 
 
 
 
 
 | 386 | ReadEffectParameterDecl(effect); | 
 
 
 
 
 | 387 | break; | 
 
 
 
 
 | 388 | case "technique": | 
 
 
 
 
 | 389 | ReadEffectTechniqueCommon(effect); | 
 
 
 
 
 | 390 | break; | 
 
 
 
 
 | 391 | default: | 
 
 
 
 
 | 392 | xml.Skip(); | 
 
 
 
 
 | 393 | break; | 
 
 
 
 
 | 394 | } | 
 
 
 
 
 | 395 | } | 
 
 
 
 
 | 396 |  | 
 
 
 
 
 | 397 | ReadExtra(); | 
 
 
 
 
 | 398 | xml.ReadEndElement(); | 
 
 
 
 
 | 399 | } | 
 
 
 
 
 | 400 |  | 
 
 
 
 
 | 401 | private void ReadEffectTechniqueCommon(Effect effect) | 
 
 
 
 
 | 402 | { | 
 
 
 
 
 | 403 | xml.ReadStartElement(); | 
 
 
 
 
 | 404 | ReadAsset(); | 
 
 
 
 
 | 405 |  | 
 
 
 
 
 | 406 | while (xml.IsStartElement()) | 
 
 
 
 
 | 407 | { | 
 
 
 
 
 | 408 | switch (xml.LocalName) | 
 
 
 
 
 | 409 | { | 
 
 
 
 
 | 410 | case "image": | 
 
 
 
 
 | 411 | ReadEntity(images, ReadImage); | 
 
 
 
 
 | 412 | break; | 
 
 
 
 
 | 413 |  | 
 
 
 
 
 | 414 | case "constant": | 
 
 
 
 
 | 415 | case "lambert": | 
 
 
 
 
 | 416 | case "phong": | 
 
 
 
 
 | 417 | case "blinn": | 
 
 
 
 
 | 418 | xml.ReadStartElement(); | 
 
 
 
 
 | 419 | ReadEffectTechniqueParameters(effect); | 
 
 
 
 
 | 420 | xml.ReadEndElement(); | 
 
 
 
 
 | 421 | break; | 
 
 
 
 
 | 422 |  | 
 
 
 
 
 | 423 | default: | 
 
 
 
 
 | 424 | xml.Skip(); | 
 
 
 
 
 | 425 | break; | 
 
 
 
 
 | 426 | } | 
 
 
 
 
 | 427 | } | 
 
 
 
 
 | 428 |  | 
 
 
 
 
 | 429 | ReadExtra(); | 
 
 
 
 
 | 430 | xml.ReadEndElement(); | 
 
 
 
 
 | 431 | } | 
 
 
 
 
 | 432 |  | 
 
 
 
 
 | 433 | private void ReadEffectParameterDecl(Effect effect) | 
 
 
 
 
 | 434 | { | 
 
 
 
 
 | 435 | var parameter = new EffectParameter(); | 
 
 
 
 
 | 436 | parameter.Sid = xml.GetAttribute("sid"); | 
 
 
 
 
 | 437 |  | 
 
 
 
 
 | 438 | xml.ReadStartElement(); | 
 
 
 
 
 | 439 |  | 
 
 
 
 
 | 440 | while (xml.IsStartElement()) | 
 
 
 
 
 | 441 | { | 
 
 
 
 
 | 442 | switch (xml.LocalName) | 
 
 
 
 
 | 443 | { | 
 
 
 
 
 | 444 | case "semantic": | 
 
 
 
 
 | 445 | parameter.Semantic = xml.ReadElementContentAsString(); | 
 
 
 
 
 | 446 | break; | 
 
 
 
 
 | 447 | case "float": | 
 
 
 
 
 | 448 | parameter.Value = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 449 | break; | 
 
 
 
 
 | 450 | case "float2": | 
 
 
 
 
 | 451 | parameter.Value = xml.ReadElementContentAsVector2(); | 
 
 
 
 
 | 452 | break; | 
 
 
 
 
 | 453 | case "float3": | 
 
 
 
 
 | 454 | parameter.Value = xml.ReadElementContentAsVector3(); | 
 
 
 
 
 | 455 | break; | 
 
 
 
 
 | 456 | case "surface": | 
 
 
 
 
 | 457 | parameter.Value = ReadEffectSurface(effect); | 
 
 
 
 
 | 458 | break; | 
 
 
 
 
 | 459 | case "sampler2D": | 
 
 
 
 
 | 460 | parameter.Value = ReadEffectSampler2D(effect); | 
 
 
 
 
 | 461 | break; | 
 
 
 
 
 | 462 | default: | 
 
 
 
 
 | 463 | xml.Skip(); | 
 
 
 
 
 | 464 | break; | 
 
 
 
 
 | 465 | } | 
 
 
 
 
 | 466 | } | 
 
 
 
 
 | 467 |  | 
 
 
 
 
 | 468 | xml.ReadEndElement(); | 
 
 
 
 
 | 469 |  | 
 
 
 
 
 | 470 | effect.Parameters.Add(parameter); | 
 
 
 
 
 | 471 | } | 
 
 
 
 
 | 472 |  | 
 
 
 
 
 | 473 | private EffectSurface ReadEffectSurface(Effect effect) | 
 
 
 
 
 | 474 | { | 
 
 
 
 
 | 475 | var surface = new EffectSurface(); | 
 
 
 
 
 | 476 |  | 
 
 
 
 
 | 477 | xml.ReadStartElement(); | 
 
 
 
 
 | 478 |  | 
 
 
 
 
 | 479 | while (xml.IsStartElement()) | 
 
 
 
 
 | 480 | { | 
 
 
 
 
 | 481 | switch (xml.LocalName) | 
 
 
 
 
 | 482 | { | 
 
 
 
 
 | 483 | case "init_from": | 
 
 
 
 
 | 484 | BindId<Image>(xml.ReadElementContentAsString(), image => { | 
 
 
 
 
 | 485 | surface.InitFrom = image; | 
 
 
 
 
 | 486 | }); | 
 
 
 
 
 | 487 | break; | 
 
 
 
 
 | 488 |  | 
 
 
 
 
 | 489 | default: | 
 
 
 
 
 | 490 | xml.Skip(); | 
 
 
 
 
 | 491 | break; | 
 
 
 
 
 | 492 | } | 
 
 
 
 
 | 493 | } | 
 
 
 
 
 | 494 |  | 
 
 
 
 
 | 495 | xml.ReadEndElement(); | 
 
 
 
 
 | 496 | return surface; | 
 
 
 
 
 | 497 | } | 
 
 
 
 
 | 498 |  | 
 
 
 
 
 | 499 | private EffectSampler ReadEffectSampler2D(Effect effect) | 
 
 
 
 
 | 500 | { | 
 
 
 
 
 | 501 | var sampler = new EffectSampler(); | 
 
 
 
 
 | 502 |  | 
 
 
 
 
 | 503 | xml.ReadStartElement(); | 
 
 
 
 
 | 504 |  | 
 
 
 
 
 | 505 | while (xml.IsStartElement()) | 
 
 
 
 
 | 506 | { | 
 
 
 
 
 | 507 | switch (xml.LocalName) | 
 
 
 
 
 | 508 | { | 
 
 
 
 
 | 509 | case "source": | 
 
 
 
 
 | 510 | string surfaceSid = xml.ReadElementContentAsString(); | 
 
 
 
 
 | 511 | foreach (var parameter in effect.Parameters) | 
 
 
 
 
 | 512 | { | 
 
 
 
 
 | 513 | if (parameter.Sid == surfaceSid) | 
 
 
 
 
 | 514 | sampler.Surface = parameter.Value as EffectSurface; | 
 
 
 
 
 | 515 | } | 
 
 
 
 
 | 516 | break; | 
 
 
 
 
 | 517 | case "wrap_s": | 
 
 
 
 
 | 518 | sampler.WrapS = (EffectSamplerWrap)Enum.Parse(typeof(EffectSamplerWrap), xml.ReadElementContentAsString(), true); | 
 
 
 
 
 | 519 | break; | 
 
 
 
 
 | 520 | case "wrap_t": | 
 
 
 
 
 | 521 | sampler.WrapT = (EffectSamplerWrap)Enum.Parse(typeof(EffectSamplerWrap), xml.ReadElementContentAsString(), true); | 
 
 
 
 
 | 522 | break; | 
 
 
 
 
 | 523 | default: | 
 
 
 
 
 | 524 | xml.Skip(); | 
 
 
 
 
 | 525 | break; | 
 
 
 
 
 | 526 | } | 
 
 
 
 
 | 527 | } | 
 
 
 
 
 | 528 |  | 
 
 
 
 
 | 529 | xml.ReadEndElement(); | 
 
 
 
 
 | 530 | return sampler; | 
 
 
 
 
 | 531 | } | 
 
 
 
 
 | 532 |  | 
 
 
 
 
 | 533 | private void ReadEffectTechniqueParameters(Effect effect) | 
 
 
 
 
 | 534 | { | 
 
 
 
 
 | 535 | while (xml.IsStartElement()) | 
 
 
 
 
 | 536 | { | 
 
 
 
 
 | 537 | switch (xml.LocalName) | 
 
 
 
 
 | 538 | { | 
 
 
 
 
 | 539 | case "emission": | 
 
 
 
 
 | 540 | ReadColorEffectParameter(effect, effect.Emission, EffectTextureChannel.Emission); | 
 
 
 
 
 | 541 | break; | 
 
 
 
 
 | 542 | case "ambient": | 
 
 
 
 
 | 543 | ReadColorEffectParameter(effect, effect.Ambient, EffectTextureChannel.Ambient); | 
 
 
 
 
 | 544 | break; | 
 
 
 
 
 | 545 | case "diffuse": | 
 
 
 
 
 | 546 | ReadColorEffectParameter(effect, effect.Diffuse, EffectTextureChannel.Diffuse); | 
 
 
 
 
 | 547 | break; | 
 
 
 
 
 | 548 | case "specular": | 
 
 
 
 
 | 549 | ReadColorEffectParameter(effect, effect.Specular, EffectTextureChannel.Specular); | 
 
 
 
 
 | 550 | break; | 
 
 
 
 
 | 551 | case "shininess": | 
 
 
 
 
 | 552 | ReadFloatEffectParameter(effect.Shininess); | 
 
 
 
 
 | 553 | break; | 
 
 
 
 
 | 554 | case "reflective": | 
 
 
 
 
 | 555 | ReadColorEffectParameter(effect, effect.Reflective, EffectTextureChannel.Reflective); | 
 
 
 
 
 | 556 | break; | 
 
 
 
 
 | 557 | case "reflectivity": | 
 
 
 
 
 | 558 | ReadFloatEffectParameter(effect.Reflectivity); | 
 
 
 
 
 | 559 | break; | 
 
 
 
 
 | 560 | case "transparent": | 
 
 
 
 
 | 561 | ReadColorEffectParameter(effect, effect.Transparent, EffectTextureChannel.Transparent); | 
 
 
 
 
 | 562 | break; | 
 
 
 
 
 | 563 | case "transparency": | 
 
 
 
 
 | 564 | ReadFloatEffectParameter(effect.Transparency); | 
 
 
 
 
 | 565 | break; | 
 
 
 
 
 | 566 | case "index_of_refraction": | 
 
 
 
 
 | 567 | ReadFloatEffectParameter(effect.IndexOfRefraction); | 
 
 
 
 
 | 568 | break; | 
 
 
 
 
 | 569 | default: | 
 
 
 
 
 | 570 | xml.Skip(); | 
 
 
 
 
 | 571 | break; | 
 
 
 
 
 | 572 | } | 
 
 
 
 
 | 573 | } | 
 
 
 
 
 | 574 | } | 
 
 
 
 
 | 575 |  | 
 
 
 
 
 | 576 | private void ReadFloatEffectParameter(EffectParameter parameter) | 
 
 
 
 
 | 577 | { | 
 
 
 
 
 | 578 | xml.ReadStartElement(); | 
 
 
 
 
 | 579 |  | 
 
 
 
 
 | 580 | if (xml.IsStartElement("float")) | 
 
 
 
 
 | 581 | { | 
 
 
 
 
 | 582 | parameter.Sid = xml.GetAttribute("sid"); | 
 
 
 
 
 | 583 | parameter.Value = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 584 | } | 
 
 
 
 
 | 585 | else if (xml.IsStartElement("param")) | 
 
 
 
 
 | 586 | { | 
 
 
 
 
 | 587 | parameter.Reference = xml.GetAttribute("ref"); | 
 
 
 
 
 | 588 | xml.Skip(); | 
 
 
 
 
 | 589 | } | 
 
 
 
 
 | 590 |  | 
 
 
 
 
 | 591 | xml.ReadEndElement(); | 
 
 
 
 
 | 592 | } | 
 
 
 
 
 | 593 |  | 
 
 
 
 
 | 594 | private void ReadColorEffectParameter(Effect effect, EffectParameter parameter, EffectTextureChannel channel) | 
 
 
 
 
 | 595 | { | 
 
 
 
 
 | 596 | xml.ReadStartElement(); | 
 
 
 
 
 | 597 |  | 
 
 
 
 
 | 598 | if (xml.IsStartElement("color")) | 
 
 
 
 
 | 599 | { | 
 
 
 
 
 | 600 | parameter.Sid = xml.GetAttribute("sid"); | 
 
 
 
 
 | 601 | parameter.Value = xml.ReadElementContentAsVector4(); | 
 
 
 
 
 | 602 | } | 
 
 
 
 
 | 603 | else if (xml.IsStartElement("param")) | 
 
 
 
 
 | 604 | { | 
 
 
 
 
 | 605 | parameter.Sid = null; | 
 
 
 
 
 | 606 | parameter.Reference = xml.GetAttribute("ref"); | 
 
 
 
 
 | 607 | } | 
 
 
 
 
 | 608 | else if (xml.IsStartElement("texture")) | 
 
 
 
 
 | 609 | { | 
 
 
 
 
 | 610 | parameter.Sid = null; | 
 
 
 
 
 | 611 |  | 
 
 
 
 
 | 612 | string texCoordSymbol = xml.GetAttribute("texcoord"); | 
 
 
 
 
 | 613 | string samplerId = xml.GetAttribute("texture"); | 
 
 
 
 
 | 614 | xml.Skip(); | 
 
 
 
 
 | 615 |  | 
 
 
 
 
 | 616 | // | 
 
 
 
 
 | 617 | // HACK: Maya produces duplicate texture elements, skip them... | 
 
 
 
 
 | 618 | // | 
 
 
 
 
 | 619 |  | 
 
 
 
 
 | 620 | while (xml.IsStartElement("texture")) | 
 
 
 
 
 | 621 | xml.Skip(); | 
 
 
 
 
 | 622 |  | 
 
 
 
 
 | 623 | EffectSampler sampler = null; | 
 
 
 
 
 | 624 |  | 
 
 
 
 
 | 625 | foreach (var parameterDecl in effect.Parameters) | 
 
 
 
 
 | 626 | { | 
 
 
 
 
 | 627 | if (parameterDecl.Sid == samplerId) | 
 
 
 
 
 | 628 | { | 
 
 
 
 
 | 629 | sampler = parameterDecl.Value as EffectSampler; | 
 
 
 
 
 | 630 | break; | 
 
 
 
 
 | 631 | } | 
 
 
 
 
 | 632 | } | 
 
 
 
 
 | 633 |  | 
 
 
 
 
 | 634 | if (sampler == null) | 
 
 
 
 
 | 635 | { | 
 
 
 
 
 | 636 | info.WriteLine("COLLADA: cannot find sampler {0} in effect {1}, trying to use image directly", samplerId, effect.Name); | 
 
 
 
 
 | 637 |  | 
 
 
 
 
 | 638 | var surface = new EffectSurface(); | 
 
 
 
 
 | 639 | sampler = new EffectSampler(surface); | 
 
 
 
 
 | 640 |  | 
 
 
 
 
 | 641 | BindId<Image>(samplerId, image => { | 
 
 
 
 
 | 642 | surface.InitFrom = image; | 
 
 
 
 
 | 643 | }); | 
 
 
 
 
 | 644 | } | 
 
 
 
 
 | 645 |  | 
 
 
 
 
 | 646 | var texture = new EffectTexture { | 
 
 
 
 
 | 647 | Channel = channel, | 
 
 
 
 
 | 648 | TexCoordSemantic = texCoordSymbol, | 
 
 
 
 
 | 649 | Sampler = sampler | 
 
 
 
 
 | 650 | }; | 
 
 
 
 
 | 651 |  | 
 
 
 
 
 | 652 | parameter.Value = texture; | 
 
 
 
 
 | 653 | } | 
 
 
 
 
 | 654 |  | 
 
 
 
 
 | 655 | xml.ReadEndElement(); | 
 
 
 
 
 | 656 | } | 
 
 
 
 
 | 657 |  | 
 
 
 
 
 | 658 | private void ReadMaterial(Material material) | 
 
 
 
 
 | 659 | { | 
 
 
 
 
 | 660 | if (!xml.IsStartElement("instance_effect")) | 
 
 
 
 
 | 661 | return; | 
 
 
 
 
 | 662 |  | 
 
 
 
 
 | 663 | BindUrlAttribute<Effect>("url", effect => { | 
 
 
 
 
 | 664 | material.Effect = effect; | 
 
 
 
 
 | 665 | }); | 
 
 
 
 
 | 666 |  | 
 
 
 
 
 | 667 | xml.Skip(); | 
 
 
 
 
 | 668 | } | 
 
 
 
 
 | 669 |  | 
 
 
 
 
 | 670 | // | 
 
 
 
 
 | 671 | // Geometry | 
 
 
 
 
 | 672 | // | 
 
 
 
 
 | 673 |  | 
 
 
 
 
 | 674 | private void ReadGeometry(Geometry geometry) | 
 
 
 
 
 | 675 | { | 
 
 
 
 
 | 676 | if (xml.IsStartElement("mesh")) | 
 
 
 
 
 | 677 | { | 
 
 
 
 
 | 678 | ReadMesh(geometry); | 
 
 
 
 
 | 679 | } | 
 
 
 
 
 | 680 | else | 
 
 
 
 
 | 681 | { | 
 
 
 
 
 | 682 | throw new NotSupportedException(string.Format("Geometry content of type {0} is not supported", xml.LocalName)); | 
 
 
 
 
 | 683 | } | 
 
 
 
 
 | 684 | } | 
 
 
 
 
 | 685 |  | 
 
 
 
 
 | 686 | // | 
 
 
 
 
 | 687 | // Mesh | 
 
 
 
 
 | 688 | // | 
 
 
 
 
 | 689 |  | 
 
 
 
 
 | 690 | private void ReadMesh(Geometry geometry) | 
 
 
 
 
 | 691 | { | 
 
 
 
 
 | 692 | xml.ReadStartElement(); | 
 
 
 
 
 | 693 |  | 
 
 
 
 
 | 694 | while (xml.IsStartElement("source")) | 
 
 
 
 
 | 695 | ReadGeometrySource(); | 
 
 
 
 
 | 696 |  | 
 
 
 
 
 | 697 | if (xml.IsStartElement("vertices")) | 
 
 
 
 
 | 698 | ReadMeshVertices(geometry); | 
 
 
 
 
 | 699 |  | 
 
 
 
 
 | 700 | while (xml.IsStartElement()) | 
 
 
 
 
 | 701 | { | 
 
 
 
 
 | 702 | var primitives = ReadMeshPrimitives(geometry); | 
 
 
 
 
 | 703 |  | 
 
 
 
 
 | 704 | if (primitives == null) | 
 
 
 
 
 | 705 | break; | 
 
 
 
 
 | 706 |  | 
 
 
 
 
 | 707 | geometry.Primitives.Add(primitives); | 
 
 
 
 
 | 708 | } | 
 
 
 
 
 | 709 |  | 
 
 
 
 
 | 710 | ReadExtra(); | 
 
 
 
 
 | 711 | xml.ReadEndElement(); | 
 
 
 
 
 | 712 | } | 
 
 
 
 
 | 713 |  | 
 
 
 
 
 | 714 | // | 
 
 
 
 
 | 715 | // Mesh Data Source | 
 
 
 
 
 | 716 | // | 
 
 
 
 
 | 717 |  | 
 
 
 
 
 | 718 | private Source ReadGeometrySource() | 
 
 
 
 
 | 719 | { | 
 
 
 
 
 | 720 | string id = xml.GetAttribute("id"); | 
 
 
 
 
 | 721 | string name = xml.GetAttribute("name"); | 
 
 
 
 
 | 722 |  | 
 
 
 
 
 | 723 | xml.ReadStartElement(); | 
 
 
 
 
 | 724 | ReadAsset(); | 
 
 
 
 
 | 725 |  | 
 
 
 
 
 | 726 | var data = ReadFloatArray(); | 
 
 
 
 
 | 727 | var source = new Source(data, 1) { | 
 
 
 
 
 | 728 | Name = name | 
 
 
 
 
 | 729 | }; | 
 
 
 
 
 | 730 |  | 
 
 
 
 
 | 731 | if (xml.IsStartElement("technique_common")) | 
 
 
 
 
 | 732 | { | 
 
 
 
 
 | 733 | xml.ReadStartElement(); | 
 
 
 
 
 | 734 |  | 
 
 
 
 
 | 735 | if (xml.IsStartElement("accessor")) | 
 
 
 
 
 | 736 | { | 
 
 
 
 
 | 737 | source.Stride = ReadIntAttribute("stride", 1); | 
 
 
 
 
 | 738 |  | 
 
 
 
 
 | 739 | xml.ReadStartElement(); | 
 
 
 
 
 | 740 |  | 
 
 
 
 
 | 741 | while (xml.IsStartElement("param")) | 
 
 
 
 
 | 742 | ReadParam(); | 
 
 
 
 
 | 743 |  | 
 
 
 
 
 | 744 | xml.ReadEndElement(); | 
 
 
 
 
 | 745 | } | 
 
 
 
 
 | 746 |  | 
 
 
 
 
 | 747 | xml.ReadEndElement(); | 
 
 
 
 
 | 748 | } | 
 
 
 
 
 | 749 |  | 
 
 
 
 
 | 750 | xml.SkipSequence("technique"); | 
 
 
 
 
 | 751 | xml.ReadEndElement(); | 
 
 
 
 
 | 752 |  | 
 
 
 
 
 | 753 | AddEntity(id, source); | 
 
 
 
 
 | 754 |  | 
 
 
 
 
 | 755 | return source; | 
 
 
 
 
 | 756 | } | 
 
 
 
 
 | 757 |  | 
 
 
 
 
 | 758 | private string ReadParam() | 
 
 
 
 
 | 759 | { | 
 
 
 
 
 | 760 | string name = xml.GetAttribute("name"); | 
 
 
 
 
 | 761 | //string sid = xml.GetAttribute("sid"); | 
 
 
 
 
 | 762 | //string type = xml.GetAttribute("type"); | 
 
 
 
 
 | 763 | //string semantic = xml.GetAttribute("semantic"); | 
 
 
 
 
 | 764 |  | 
 
 
 
 
 | 765 | xml.Skip(); | 
 
 
 
 
 | 766 |  | 
 
 
 
 
 | 767 | return name; | 
 
 
 
 
 | 768 | } | 
 
 
 
 
 | 769 |  | 
 
 
 
 
 | 770 | // | 
 
 
 
 
 | 771 | // Mesh Vertices | 
 
 
 
 
 | 772 | // | 
 
 
 
 
 | 773 |  | 
 
 
 
 
 | 774 | private void ReadMeshVertices(Geometry mesh) | 
 
 
 
 
 | 775 | { | 
 
 
 
 
 | 776 | string id = xml.GetAttribute("id"); | 
 
 
 
 
 | 777 |  | 
 
 
 
 
 | 778 | for (xml.ReadStartElement(); xml.IsStartElement("input"); xml.Skip()) | 
 
 
 
 
 | 779 | { | 
 
 
 
 
 | 780 | var semantic = ReadSemanticAttribute(); | 
 
 
 
 
 | 781 |  | 
 
 
 
 
 | 782 | if (semantic != Semantic.None && semantic != Semantic.Vertex) | 
 
 
 
 
 | 783 | { | 
 
 
 
 
 | 784 | var input = new Input(); | 
 
 
 
 
 | 785 | input.Semantic = semantic; | 
 
 
 
 
 | 786 | BindUrlAttribute<Source>("source", s => { | 
 
 
 
 
 | 787 | input.Source = s; | 
 
 
 
 
 | 788 | }); | 
 
 
 
 
 | 789 | mesh.Vertices.Add(input); | 
 
 
 
 
 | 790 | } | 
 
 
 
 
 | 791 | } | 
 
 
 
 
 | 792 |  | 
 
 
 
 
 | 793 | ReadExtra(); | 
 
 
 
 
 | 794 | xml.ReadEndElement(); | 
 
 
 
 
 | 795 | } | 
 
 
 
 
 | 796 |  | 
 
 
 
 
 | 797 | // | 
 
 
 
 
 | 798 | // Mesh Polygons | 
 
 
 
 
 | 799 | // | 
 
 
 
 
 | 800 |  | 
 
 
 
 
 | 801 | private MeshPrimitives ReadMeshPrimitives(Geometry mesh) | 
 
 
 
 
 | 802 | { | 
 
 
 
 
 | 803 | MeshPrimitives primitives; | 
 
 
 
 
 | 804 |  | 
 
 
 
 
 | 805 | int primitiveCount = ReadIntAttribute("count", 0); | 
 
 
 
 
 | 806 | int fixedVertexCount = 0; | 
 
 
 
 
 | 807 | bool isPolygons = false; | 
 
 
 
 
 | 808 |  | 
 
 
 
 
 | 809 | switch (xml.LocalName) | 
 
 
 
 
 | 810 | { | 
 
 
 
 
 | 811 | case "lines": | 
 
 
 
 
 | 812 | primitives = new MeshPrimitives(MeshPrimitiveType.Lines); | 
 
 
 
 
 | 813 | fixedVertexCount = 2; | 
 
 
 
 
 | 814 | break; | 
 
 
 
 
 | 815 | case "triangles": | 
 
 
 
 
 | 816 | primitives = new MeshPrimitives(MeshPrimitiveType.Polygons); | 
 
 
 
 
 | 817 | fixedVertexCount = 3; | 
 
 
 
 
 | 818 | break; | 
 
 
 
 
 | 819 |  | 
 
 
 
 
 | 820 | case "linestrips": | 
 
 
 
 
 | 821 | primitives = new MeshPrimitives(MeshPrimitiveType.LineStrips); | 
 
 
 
 
 | 822 | isPolygons = true; | 
 
 
 
 
 | 823 | break; | 
 
 
 
 
 | 824 | case "trifans": | 
 
 
 
 
 | 825 | primitives = new MeshPrimitives(MeshPrimitiveType.TriangleFans); | 
 
 
 
 
 | 826 | isPolygons = true; | 
 
 
 
 
 | 827 | break; | 
 
 
 
 
 | 828 | case "tristrips": | 
 
 
 
 
 | 829 | primitives = new MeshPrimitives(MeshPrimitiveType.TriangleStrips); | 
 
 
 
 
 | 830 | isPolygons = true; | 
 
 
 
 
 | 831 | break; | 
 
 
 
 
 | 832 | case "polygons": | 
 
 
 
 
 | 833 | primitives = new MeshPrimitives(MeshPrimitiveType.Polygons); | 
 
 
 
 
 | 834 | isPolygons = true; | 
 
 
 
 
 | 835 | break; | 
 
 
 
 
 | 836 |  | 
 
 
 
 
 | 837 | case "polylist": | 
 
 
 
 
 | 838 | primitives = new MeshPrimitives(MeshPrimitiveType.Polygons); | 
 
 
 
 
 | 839 | break; | 
 
 
 
 
 | 840 |  | 
 
 
 
 
 | 841 | default: | 
 
 
 
 
 | 842 | return null; | 
 
 
 
 
 | 843 | } | 
 
 
 
 
 | 844 |  | 
 
 
 
 
 | 845 | primitives.MaterialSymbol = xml.GetAttribute("material"); | 
 
 
 
 
 | 846 |  | 
 
 
 
 
 | 847 | bool vertexFound = false; | 
 
 
 
 
 | 848 |  | 
 
 
 
 
 | 849 | // | 
 
 
 
 
 | 850 | // Read the inputs | 
 
 
 
 
 | 851 | // | 
 
 
 
 
 | 852 |  | 
 
 
 
 
 | 853 | for (xml.ReadStartElement(); xml.IsStartElement("input"); xml.Skip()) | 
 
 
 
 
 | 854 | { | 
 
 
 
 
 | 855 | var semantic = ReadSemanticAttribute(); | 
 
 
 
 
 | 856 |  | 
 
 
 
 
 | 857 | if (semantic == Semantic.None) | 
 
 
 
 
 | 858 | continue; | 
 
 
 
 
 | 859 |  | 
 
 
 
 
 | 860 | int offset = ReadIntAttribute("offset"); | 
 
 
 
 
 | 861 | string sourceId = xml.GetAttribute("source"); | 
 
 
 
 
 | 862 | int set = ReadIntAttribute("set", -1); | 
 
 
 
 
 | 863 |  | 
 
 
 
 
 | 864 | if (semantic == Semantic.Vertex) | 
 
 
 
 
 | 865 | { | 
 
 
 
 
 | 866 | if (vertexFound) | 
 
 
 
 
 | 867 | { | 
 
 
 
 
 | 868 | error.WriteLine("Duplicate vertex input found"); | 
 
 
 
 
 | 869 | continue; | 
 
 
 
 
 | 870 | } | 
 
 
 
 
 | 871 |  | 
 
 
 
 
 | 872 | vertexFound = true; | 
 
 
 
 
 | 873 |  | 
 
 
 
 
 | 874 | foreach (var vertexInput in mesh.Vertices) | 
 
 
 
 
 | 875 | { | 
 
 
 
 
 | 876 | primitives.Inputs.Add(new IndexedInput { | 
 
 
 
 
 | 877 | Source = vertexInput.Source, | 
 
 
 
 
 | 878 | Offset = offset, | 
 
 
 
 
 | 879 | Set = set, | 
 
 
 
 
 | 880 | Semantic = vertexInput.Semantic | 
 
 
 
 
 | 881 | }); | 
 
 
 
 
 | 882 | } | 
 
 
 
 
 | 883 | } | 
 
 
 
 
 | 884 | else | 
 
 
 
 
 | 885 | { | 
 
 
 
 
 | 886 | var input = new IndexedInput { | 
 
 
 
 
 | 887 | Offset = offset, | 
 
 
 
 
 | 888 | Semantic = semantic, | 
 
 
 
 
 | 889 | Set = set | 
 
 
 
 
 | 890 | }; | 
 
 
 
 
 | 891 |  | 
 
 
 
 
 | 892 | BindUrl<Source>(sourceId, s => { | 
 
 
 
 
 | 893 |  | 
 
 
 
 
 | 894 | // | 
 
 
 
 
 | 895 | // Ignore inputs with no source data | 
 
 
 
 
 | 896 | // | 
 
 
 
 
 | 897 |  | 
 
 
 
 
 | 898 | if (s.Count > 0) | 
 
 
 
 
 | 899 | { | 
 
 
 
 
 | 900 | input.Source = s; | 
 
 
 
 
 | 901 | primitives.Inputs.Add(input); | 
 
 
 
 
 | 902 | } | 
 
 
 
 
 | 903 | }); | 
 
 
 
 
 | 904 | } | 
 
 
 
 
 | 905 | } | 
 
 
 
 
 | 906 |  | 
 
 
 
 
 | 907 | if (!vertexFound) | 
 
 
 
 
 | 908 | throw new InvalidDataException("no vertex input"); | 
 
 
 
 
 | 909 |  | 
 
 
 
 
 | 910 | // | 
 
 
 
 
 | 911 | // Read vertex counts (if availabled and needed) | 
 
 
 
 
 | 912 | // | 
 
 
 
 
 | 913 |  | 
 
 
 
 
 | 914 | if (primitiveCount > 0) | 
 
 
 
 
 | 915 | primitives.VertexCounts.Capacity = primitiveCount; | 
 
 
 
 
 | 916 |  | 
 
 
 
 
 | 917 | int numIndices = 0; | 
 
 
 
 
 | 918 |  | 
 
 
 
 
 | 919 | while (xml.IsStartElement("vcount")) | 
 
 
 
 
 | 920 | { | 
 
 
 
 
 | 921 | if (fixedVertexCount != 0 || isPolygons) | 
 
 
 
 
 | 922 | { | 
 
 
 
 
 | 923 | xml.Skip(); | 
 
 
 
 
 | 924 | continue; | 
 
 
 
 
 | 925 | } | 
 
 
 
 
 | 926 |  | 
 
 
 
 
 | 927 | foreach (var token in xml.ReadElementContentAsList()) | 
 
 
 
 
 | 928 | { | 
 
 
 
 
 | 929 | int count = XmlConvert.ToInt32(token); | 
 
 
 
 
 | 930 | numIndices += count; | 
 
 
 
 
 | 931 | primitives.VertexCounts.Add(count); | 
 
 
 
 
 | 932 | } | 
 
 
 
 
 | 933 | } | 
 
 
 
 
 | 934 |  | 
 
 
 
 
 | 935 | if (fixedVertexCount != 0) | 
 
 
 
 
 | 936 | { | 
 
 
 
 
 | 937 | for (int i = 0; i < primitiveCount; i++) | 
 
 
 
 
 | 938 | primitives.VertexCounts.Add(fixedVertexCount); | 
 
 
 
 
 | 939 |  | 
 
 
 
 
 | 940 | numIndices = fixedVertexCount * primitiveCount; | 
 
 
 
 
 | 941 | } | 
 
 
 
 
 | 942 | else if (!isPolygons) | 
 
 
 
 
 | 943 | { | 
 
 
 
 
 | 944 | if (primitives.VertexCounts.Count == 0) | 
 
 
 
 
 | 945 | throw new InvalidDataException("no vcount"); | 
 
 
 
 
 | 946 | } | 
 
 
 
 
 | 947 |  | 
 
 
 
 
 | 948 | // | 
 
 
 
 
 | 949 | // Read input indices | 
 
 
 
 
 | 950 | // 1. Collect all inputs in an array indexed by input offset | 
 
 
 
 
 | 951 | // | 
 
 
 
 
 | 952 |  | 
 
 
 
 
 | 953 | var maxOffset = primitives.Inputs.Max(x => x.Offset); | 
 
 
 
 
 | 954 | var inputIndices = new List<int>[maxOffset + 1]; | 
 
 
 
 
 | 955 |  | 
 
 
 
 
 | 956 | foreach (var input in primitives.Inputs) | 
 
 
 
 
 | 957 | { | 
 
 
 
 
 | 958 | List<int> indices = inputIndices[input.Offset]; | 
 
 
 
 
 | 959 |  | 
 
 
 
 
 | 960 | if (indices == null) | 
 
 
 
 
 | 961 | { | 
 
 
 
 
 | 962 | indices = new List<int>(numIndices); | 
 
 
 
 
 | 963 | inputIndices[input.Offset] = indices; | 
 
 
 
 
 | 964 | } | 
 
 
 
 
 | 965 | } | 
 
 
 
 
 | 966 |  | 
 
 
 
 
 | 967 | // | 
 
 
 
 
 | 968 | // 2. Read polygon input indices | 
 
 
 
 
 | 969 | // | 
 
 
 
 
 | 970 |  | 
 
 
 
 
 | 971 | if (!isPolygons) | 
 
 
 
 
 | 972 | { | 
 
 
 
 
 | 973 | while (xml.IsStartElement("p")) | 
 
 
 
 
 | 974 | ReadInterleavedInputIndices(inputIndices); | 
 
 
 
 
 | 975 | } | 
 
 
 
 
 | 976 | else | 
 
 
 
 
 | 977 | { | 
 
 
 
 
 | 978 | while (xml.IsStartElement()) | 
 
 
 
 
 | 979 | { | 
 
 
 
 
 | 980 | if (xml.IsStartElement("p")) | 
 
 
 
 
 | 981 | { | 
 
 
 
 
 | 982 | primitives.VertexCounts.Add(ReadInterleavedInputIndices(inputIndices)); | 
 
 
 
 
 | 983 | } | 
 
 
 
 
 | 984 | else if (xml.IsStartElement("ph")) | 
 
 
 
 
 | 985 | { | 
 
 
 
 
 | 986 | xml.ReadStartElement(); | 
 
 
 
 
 | 987 |  | 
 
 
 
 
 | 988 | while (xml.IsStartElement()) | 
 
 
 
 
 | 989 | { | 
 
 
 
 
 | 990 | if (xml.LocalName == "p") | 
 
 
 
 
 | 991 | primitives.VertexCounts.Add(ReadInterleavedInputIndices(inputIndices)); | 
 
 
 
 
 | 992 | else | 
 
 
 
 
 | 993 | xml.Skip(); | 
 
 
 
 
 | 994 | } | 
 
 
 
 
 | 995 |  | 
 
 
 
 
 | 996 | xml.ReadEndElement(); | 
 
 
 
 
 | 997 | } | 
 
 
 
 
 | 998 | else | 
 
 
 
 
 | 999 | { | 
 
 
 
 
 | 1000 | break; | 
 
 
 
 
 | 1001 | } | 
 
 
 
 
 | 1002 | } | 
 
 
 
 
 | 1003 | } | 
 
 
 
 
 | 1004 |  | 
 
 
 
 
 | 1005 | foreach (var input in primitives.Inputs) | 
 
 
 
 
 | 1006 | input.Indices.AddRange(inputIndices[input.Offset]); | 
 
 
 
 
 | 1007 |  | 
 
 
 
 
 | 1008 | ReadExtra(); | 
 
 
 
 
 | 1009 | xml.ReadEndElement(); | 
 
 
 
 
 | 1010 |  | 
 
 
 
 
 | 1011 | return primitives; | 
 
 
 
 
 | 1012 | } | 
 
 
 
 
 | 1013 |  | 
 
 
 
 
 | 1014 | private int ReadInterleavedInputIndices(List<int>[] inputs) | 
 
 
 
 
 | 1015 | { | 
 
 
 
 
 | 1016 | int count = 0; | 
 
 
 
 
 | 1017 | int offset = 0; | 
 
 
 
 
 | 1018 |  | 
 
 
 
 
 | 1019 | foreach (string token in xml.ReadElementContentAsList()) | 
 
 
 
 
 | 1020 | { | 
 
 
 
 
 | 1021 | var input = inputs[offset++]; | 
 
 
 
 
 | 1022 |  | 
 
 
 
 
 | 1023 | if (input != null) | 
 
 
 
 
 | 1024 | input.Add(XmlConvert.ToInt32(token)); | 
 
 
 
 
 | 1025 |  | 
 
 
 
 
 | 1026 | if (offset >= inputs.Length) | 
 
 
 
 
 | 1027 | { | 
 
 
 
 
 | 1028 | offset = 0; | 
 
 
 
 
 | 1029 | count++; | 
 
 
 
 
 | 1030 | } | 
 
 
 
 
 | 1031 | } | 
 
 
 
 
 | 1032 |  | 
 
 
 
 
 | 1033 | return count; | 
 
 
 
 
 | 1034 | } | 
 
 
 
 
 | 1035 |  | 
 
 
 
 
 | 1036 | // | 
 
 
 
 
 | 1037 | // Scene | 
 
 
 
 
 | 1038 | // | 
 
 
 
 
 | 1039 |  | 
 
 
 
 
 | 1040 | private void ReadScene(Scene scene) | 
 
 
 
 
 | 1041 | { | 
 
 
 
 
 | 1042 | while (xml.IsStartElement("node")) | 
 
 
 
 
 | 1043 | ReadEntity(scene.Nodes, ReadNode); | 
 
 
 
 
 | 1044 | } | 
 
 
 
 
 | 1045 |  | 
 
 
 
 
 | 1046 | private void ReadNode(Node node) | 
 
 
 
 
 | 1047 | { | 
 
 
 
 
 | 1048 | ReadTransforms(node.Transforms); | 
 
 
 
 
 | 1049 |  | 
 
 
 
 
 | 1050 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1051 | { | 
 
 
 
 
 | 1052 | switch (xml.LocalName) | 
 
 
 
 
 | 1053 | { | 
 
 
 
 
 | 1054 | case "node": | 
 
 
 
 
 | 1055 | ReadEntity(node.Nodes, ReadNode); | 
 
 
 
 
 | 1056 | break; | 
 
 
 
 
 | 1057 |  | 
 
 
 
 
 | 1058 | case "instance_geometry": | 
 
 
 
 
 | 1059 | node.Instances.Add(ReadGeometryInstance()); | 
 
 
 
 
 | 1060 | break; | 
 
 
 
 
 | 1061 |  | 
 
 
 
 
 | 1062 | case "instance_light": | 
 
 
 
 
 | 1063 | node.Instances.Add(ReadLightInstance()); | 
 
 
 
 
 | 1064 | break; | 
 
 
 
 
 | 1065 |  | 
 
 
 
 
 | 1066 | case "instance_camera": | 
 
 
 
 
 | 1067 | node.Instances.Add(ReadCameraInstance()); | 
 
 
 
 
 | 1068 | break; | 
 
 
 
 
 | 1069 |  | 
 
 
 
 
 | 1070 | case "instance_node": | 
 
 
 
 
 | 1071 | node.Instances.Add(ReadNodeInstance()); | 
 
 
 
 
 | 1072 | break; | 
 
 
 
 
 | 1073 |  | 
 
 
 
 
 | 1074 | default: | 
 
 
 
 
 | 1075 | xml.Skip(); | 
 
 
 
 
 | 1076 | break; | 
 
 
 
 
 | 1077 | } | 
 
 
 
 
 | 1078 | } | 
 
 
 
 
 | 1079 | } | 
 
 
 
 
 | 1080 |  | 
 
 
 
 
 | 1081 | private void ReadSimpleInstance<T>(Instance<T> instance) | 
 
 
 
 
 | 1082 | where T : Entity | 
 
 
 
 
 | 1083 | { | 
 
 
 
 
 | 1084 | instance.Sid = xml.GetAttribute("sid"); | 
 
 
 
 
 | 1085 | instance.Name = xml.GetAttribute("name"); | 
 
 
 
 
 | 1086 | BindUrlAttribute<T>("url", camera => { | 
 
 
 
 
 | 1087 | instance.Target = camera; | 
 
 
 
 
 | 1088 | }); | 
 
 
 
 
 | 1089 |  | 
 
 
 
 
 | 1090 | xml.Skip(); | 
 
 
 
 
 | 1091 | } | 
 
 
 
 
 | 1092 |  | 
 
 
 
 
 | 1093 | private NodeInstance ReadNodeInstance() | 
 
 
 
 
 | 1094 | { | 
 
 
 
 
 | 1095 | var instance = new NodeInstance(); | 
 
 
 
 
 | 1096 | ReadSimpleInstance(instance); | 
 
 
 
 
 | 1097 | return instance; | 
 
 
 
 
 | 1098 | } | 
 
 
 
 
 | 1099 |  | 
 
 
 
 
 | 1100 | private CameraInstance ReadCameraInstance() | 
 
 
 
 
 | 1101 | { | 
 
 
 
 
 | 1102 | var instance = new CameraInstance(); | 
 
 
 
 
 | 1103 | ReadSimpleInstance(instance); | 
 
 
 
 
 | 1104 | return instance; | 
 
 
 
 
 | 1105 | } | 
 
 
 
 
 | 1106 |  | 
 
 
 
 
 | 1107 | private LightInstance ReadLightInstance() | 
 
 
 
 
 | 1108 | { | 
 
 
 
 
 | 1109 | var instance = new LightInstance(); | 
 
 
 
 
 | 1110 | ReadSimpleInstance(instance); | 
 
 
 
 
 | 1111 | return instance; | 
 
 
 
 
 | 1112 | } | 
 
 
 
 
 | 1113 |  | 
 
 
 
 
 | 1114 | // | 
 
 
 
 
 | 1115 | // Node Transforms | 
 
 
 
 
 | 1116 | // | 
 
 
 
 
 | 1117 |  | 
 
 
 
 
 | 1118 | private void ReadTransforms(ICollection<Transform> transforms) | 
 
 
 
 
 | 1119 | { | 
 
 
 
 
 | 1120 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1121 | { | 
 
 
 
 
 | 1122 | Transform transform = null; | 
 
 
 
 
 | 1123 |  | 
 
 
 
 
 | 1124 | switch (xml.LocalName) | 
 
 
 
 
 | 1125 | { | 
 
 
 
 
 | 1126 | case "matrix": | 
 
 
 
 
 | 1127 | transform = new TransformMatrix(); | 
 
 
 
 
 | 1128 | break; | 
 
 
 
 
 | 1129 | case "rotate": | 
 
 
 
 
 | 1130 | transform = new TransformRotate(); | 
 
 
 
 
 | 1131 | break; | 
 
 
 
 
 | 1132 | case "scale": | 
 
 
 
 
 | 1133 | transform = new TransformScale(); | 
 
 
 
 
 | 1134 | break; | 
 
 
 
 
 | 1135 | case "translate": | 
 
 
 
 
 | 1136 | transform = new TransformTranslate(); | 
 
 
 
 
 | 1137 | break; | 
 
 
 
 
 | 1138 |  | 
 
 
 
 
 | 1139 | case "skew": | 
 
 
 
 
 | 1140 | case "lookat": | 
 
 
 
 
 | 1141 | xml.Skip(); | 
 
 
 
 
 | 1142 | break; | 
 
 
 
 
 | 1143 |  | 
 
 
 
 
 | 1144 | default: | 
 
 
 
 
 | 1145 | return; | 
 
 
 
 
 | 1146 | } | 
 
 
 
 
 | 1147 |  | 
 
 
 
 
 | 1148 | if (transform != null) | 
 
 
 
 
 | 1149 | { | 
 
 
 
 
 | 1150 | transform.Sid = xml.GetAttribute("sid"); | 
 
 
 
 
 | 1151 | xml.ReadElementContentAsArray(floatConverter, transform.Values); | 
 
 
 
 
 | 1152 | transforms.Add(transform); | 
 
 
 
 
 | 1153 | } | 
 
 
 
 
 | 1154 | } | 
 
 
 
 
 | 1155 | } | 
 
 
 
 
 | 1156 |  | 
 
 
 
 
 | 1157 | // | 
 
 
 
 
 | 1158 | // Instances | 
 
 
 
 
 | 1159 | // | 
 
 
 
 
 | 1160 |  | 
 
 
 
 
 | 1161 | private void ReadInstances(ICollection<Instance> instances) | 
 
 
 
 
 | 1162 | { | 
 
 
 
 
 | 1163 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1164 | { | 
 
 
 
 
 | 1165 | switch (xml.LocalName) | 
 
 
 
 
 | 1166 | { | 
 
 
 
 
 | 1167 | case "instance_geometry": | 
 
 
 
 
 | 1168 | instances.Add(ReadGeometryInstance()); | 
 
 
 
 
 | 1169 | break; | 
 
 
 
 
 | 1170 |  | 
 
 
 
 
 | 1171 | case "instance_camera": | 
 
 
 
 
 | 1172 | case "instance_controller": | 
 
 
 
 
 | 1173 | case "instance_light": | 
 
 
 
 
 | 1174 | case "instance_node": | 
 
 
 
 
 | 1175 | xml.Skip(); | 
 
 
 
 
 | 1176 | break; | 
 
 
 
 
 | 1177 |  | 
 
 
 
 
 | 1178 | default: | 
 
 
 
 
 | 1179 | return; | 
 
 
 
 
 | 1180 | } | 
 
 
 
 
 | 1181 | } | 
 
 
 
 
 | 1182 | } | 
 
 
 
 
 | 1183 |  | 
 
 
 
 
 | 1184 | private GeometryInstance ReadGeometryInstance() | 
 
 
 
 
 | 1185 | { | 
 
 
 
 
 | 1186 | var instance = new GeometryInstance { | 
 
 
 
 
 | 1187 | Name = xml.GetAttribute("name"), | 
 
 
 
 
 | 1188 | Sid = xml.GetAttribute("sid"), | 
 
 
 
 
 | 1189 | }; | 
 
 
 
 
 | 1190 |  | 
 
 
 
 
 | 1191 | string url = xml.GetAttribute("url"); | 
 
 
 
 
 | 1192 | BindUrl<Geometry>(url, geometry => { | 
 
 
 
 
 | 1193 | instance.Target = geometry; | 
 
 
 
 
 | 1194 | }); | 
 
 
 
 
 | 1195 |  | 
 
 
 
 
 | 1196 | if (!xml.SkipEmpty()) | 
 
 
 
 
 | 1197 | { | 
 
 
 
 
 | 1198 | xml.ReadStartElement(); | 
 
 
 
 
 | 1199 |  | 
 
 
 
 
 | 1200 | if (xml.IsStartElement("bind_material")) | 
 
 
 
 
 | 1201 | ReadBindMaterial(instance, url); | 
 
 
 
 
 | 1202 |  | 
 
 
 
 
 | 1203 | ReadExtra(); | 
 
 
 
 
 | 1204 |  | 
 
 
 
 
 | 1205 | xml.ReadEndElement(); | 
 
 
 
 
 | 1206 | } | 
 
 
 
 
 | 1207 |  | 
 
 
 
 
 | 1208 | return instance; | 
 
 
 
 
 | 1209 | } | 
 
 
 
 
 | 1210 |  | 
 
 
 
 
 | 1211 | private void ReadBindMaterial(GeometryInstance geometryInstance, string geometryUrl) | 
 
 
 
 
 | 1212 | { | 
 
 
 
 
 | 1213 | xml.ReadStartElement(); | 
 
 
 
 
 | 1214 |  | 
 
 
 
 
 | 1215 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1216 | { | 
 
 
 
 
 | 1217 | if (xml.LocalName != "technique_common") | 
 
 
 
 
 | 1218 | { | 
 
 
 
 
 | 1219 | xml.Skip(); | 
 
 
 
 
 | 1220 | continue; | 
 
 
 
 
 | 1221 | } | 
 
 
 
 
 | 1222 |  | 
 
 
 
 
 | 1223 | xml.ReadStartElement(); | 
 
 
 
 
 | 1224 |  | 
 
 
 
 
 | 1225 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1226 | { | 
 
 
 
 
 | 1227 | if (xml.LocalName == "instance_material") | 
 
 
 
 
 | 1228 | ReadMaterialInstance(geometryInstance, geometryUrl); | 
 
 
 
 
 | 1229 | else | 
 
 
 
 
 | 1230 | xml.Skip(); | 
 
 
 
 
 | 1231 | } | 
 
 
 
 
 | 1232 |  | 
 
 
 
 
 | 1233 | xml.ReadEndElement(); | 
 
 
 
 
 | 1234 | } | 
 
 
 
 
 | 1235 |  | 
 
 
 
 
 | 1236 | xml.ReadEndElement(); | 
 
 
 
 
 | 1237 | } | 
 
 
 
 
 | 1238 |  | 
 
 
 
 
 | 1239 | private void ReadMaterialInstance(GeometryInstance geometryInstance, string geometryUrl) | 
 
 
 
 
 | 1240 | { | 
 
 
 
 
 | 1241 | var instance = new MaterialInstance(); | 
 
 
 
 
 | 1242 | instance.Symbol = xml.GetAttribute("symbol"); | 
 
 
 
 
 | 1243 | BindUrlAttribute<Material>("target", material => { | 
 
 
 
 
 | 1244 | instance.Target = material; | 
 
 
 
 
 | 1245 | }); | 
 
 
 
 
 | 1246 | geometryInstance.Materials.Add(instance); | 
 
 
 
 
 | 1247 |  | 
 
 
 
 
 | 1248 | if (xml.SkipEmpty()) | 
 
 
 
 
 | 1249 | return; | 
 
 
 
 
 | 1250 |  | 
 
 
 
 
 | 1251 | for (xml.ReadStartElement(); xml.IsStartElement(); xml.Skip()) | 
 
 
 
 
 | 1252 | { | 
 
 
 
 
 | 1253 | if (xml.LocalName == "bind") | 
 
 
 
 
 | 1254 | { | 
 
 
 
 
 | 1255 | var binding = new MaterialBinding(); | 
 
 
 
 
 | 1256 | binding.Semantic = xml.GetAttribute("semantic"); | 
 
 
 
 
 | 1257 | string target = xml.GetAttribute("target"); | 
 
 
 
 
 | 1258 |  | 
 
 
 
 
 | 1259 | BindId<Source>(target, s => { | 
 
 
 
 
 | 1260 | BindUrl<Geometry>(geometryUrl, g => { | 
 
 
 
 
 | 1261 | var primitives = g.Primitives.Find(p => p.MaterialSymbol == instance.Symbol); | 
 
 
 
 
 | 1262 |  | 
 
 
 
 
 | 1263 | if (primitives == null) | 
 
 
 
 
 | 1264 | return; | 
 
 
 
 
 | 1265 |  | 
 
 
 
 
 | 1266 | var input = primitives.Inputs.Find(i => i.Source == s); | 
 
 
 
 
 | 1267 |  | 
 
 
 
 
 | 1268 | if (input == null) | 
 
 
 
 
 | 1269 | return; | 
 
 
 
 
 | 1270 |  | 
 
 
 
 
 | 1271 | binding.VertexInput = input; | 
 
 
 
 
 | 1272 | instance.Bindings.Add(binding); | 
 
 
 
 
 | 1273 | }); | 
 
 
 
 
 | 1274 | }); | 
 
 
 
 
 | 1275 | } | 
 
 
 
 
 | 1276 | else if (xml.LocalName == "bind_vertex_input") | 
 
 
 
 
 | 1277 | { | 
 
 
 
 
 | 1278 | var binding = new MaterialBinding(); | 
 
 
 
 
 | 1279 | binding.Semantic = xml.GetAttribute("semantic"); | 
 
 
 
 
 | 1280 | var inputSemantic = ReadSemanticAttribute("input_semantic"); | 
 
 
 
 
 | 1281 | int inputSet = ReadIntAttribute("input_set", 0); | 
 
 
 
 
 | 1282 |  | 
 
 
 
 
 | 1283 | BindUrl<Geometry>(geometryUrl, g => { | 
 
 
 
 
 | 1284 | var primitives = g.Primitives.Find(p => p.MaterialSymbol == instance.Symbol); | 
 
 
 
 
 | 1285 |  | 
 
 
 
 
 | 1286 | if (primitives == null) | 
 
 
 
 
 | 1287 | return; | 
 
 
 
 
 | 1288 |  | 
 
 
 
 
 | 1289 | var input = primitives.Inputs.Find(i => i.Semantic == inputSemantic && i.Set == inputSet); | 
 
 
 
 
 | 1290 |  | 
 
 
 
 
 | 1291 | if (input == null) | 
 
 
 
 
 | 1292 | return; | 
 
 
 
 
 | 1293 |  | 
 
 
 
 
 | 1294 | binding.VertexInput = input; | 
 
 
 
 
 | 1295 | instance.Bindings.Add(binding); | 
 
 
 
 
 | 1296 | }); | 
 
 
 
 
 | 1297 | } | 
 
 
 
 
 | 1298 | } | 
 
 
 
 
 | 1299 |  | 
 
 
 
 
 | 1300 | xml.ReadEndElement(); | 
 
 
 
 
 | 1301 | } | 
 
 
 
 
 | 1302 |  | 
 
 
 
 
 | 1303 | // | 
 
 
 
 
 | 1304 | // Animations | 
 
 
 
 
 | 1305 | // | 
 
 
 
 
 | 1306 |  | 
 
 
 
 
 | 1307 | private void ReadAnimation(Animation animation) | 
 
 
 
 
 | 1308 | { | 
 
 
 
 
 | 1309 | while (xml.IsStartElement("animation")) | 
 
 
 
 
 | 1310 | ReadEntity(animation.Animations, ReadAnimation); | 
 
 
 
 
 | 1311 |  | 
 
 
 
 
 | 1312 | while (xml.IsStartElement("source")) | 
 
 
 
 
 | 1313 | ReadAnimationSource(); | 
 
 
 
 
 | 1314 |  | 
 
 
 
 
 | 1315 | while (xml.IsStartElement("sampler")) | 
 
 
 
 
 | 1316 | animation.Samplers.Add(ReadAnimationSampler()); | 
 
 
 
 
 | 1317 |  | 
 
 
 
 
 | 1318 | while (xml.IsStartElement("channel")) | 
 
 
 
 
 | 1319 | { | 
 
 
 
 
 | 1320 | BindAnimationSampler(xml.GetAttribute("source"), xml.GetAttribute("target")); | 
 
 
 
 
 | 1321 | xml.Skip(); | 
 
 
 
 
 | 1322 | } | 
 
 
 
 
 | 1323 | } | 
 
 
 
 
 | 1324 |  | 
 
 
 
 
 | 1325 | private Source ReadAnimationSource() | 
 
 
 
 
 | 1326 | { | 
 
 
 
 
 | 1327 | string id = xml.GetAttribute("id"); | 
 
 
 
 
 | 1328 | string name = xml.GetAttribute("name"); | 
 
 
 
 
 | 1329 |  | 
 
 
 
 
 | 1330 | if (string.IsNullOrEmpty(name)) | 
 
 
 
 
 | 1331 | name = id; | 
 
 
 
 
 | 1332 |  | 
 
 
 
 
 | 1333 | xml.ReadStartElement(); | 
 
 
 
 
 | 1334 |  | 
 
 
 
 
 | 1335 | ReadAsset(); | 
 
 
 
 
 | 1336 |  | 
 
 
 
 
 | 1337 | Source source; | 
 
 
 
 
 | 1338 |  | 
 
 
 
 
 | 1339 | if (xml.IsStartElement("float_array")) | 
 
 
 
 
 | 1340 | source = new Source(ReadFloatArray(), 1); | 
 
 
 
 
 | 1341 | else if (xml.IsStartElement("Name_array")) | 
 
 
 
 
 | 1342 | source = new Source(ReadNameArray(), 1); | 
 
 
 
 
 | 1343 | else | 
 
 
 
 
 | 1344 | throw new NotSupportedException(string.Format("Animation sources of type {0} are not supported", xml.LocalName)); | 
 
 
 
 
 | 1345 |  | 
 
 
 
 
 | 1346 | source.Name = name; | 
 
 
 
 
 | 1347 |  | 
 
 
 
 
 | 1348 | if (xml.IsStartElement("technique_common")) | 
 
 
 
 
 | 1349 | { | 
 
 
 
 
 | 1350 | xml.ReadStartElement(); | 
 
 
 
 
 | 1351 |  | 
 
 
 
 
 | 1352 | if (xml.IsStartElement("accessor")) | 
 
 
 
 
 | 1353 | { | 
 
 
 
 
 | 1354 | source.Stride = ReadIntAttribute("stride", 1); | 
 
 
 
 
 | 1355 |  | 
 
 
 
 
 | 1356 | xml.ReadStartElement(); | 
 
 
 
 
 | 1357 |  | 
 
 
 
 
 | 1358 | while (xml.IsStartElement("param")) | 
 
 
 
 
 | 1359 | ReadParam(); | 
 
 
 
 
 | 1360 |  | 
 
 
 
 
 | 1361 | xml.ReadEndElement(); | 
 
 
 
 
 | 1362 | } | 
 
 
 
 
 | 1363 |  | 
 
 
 
 
 | 1364 | xml.ReadEndElement(); | 
 
 
 
 
 | 1365 | } | 
 
 
 
 
 | 1366 |  | 
 
 
 
 
 | 1367 | xml.SkipSequence("technique"); | 
 
 
 
 
 | 1368 | xml.ReadEndElement(); | 
 
 
 
 
 | 1369 |  | 
 
 
 
 
 | 1370 | AddEntity(id, source); | 
 
 
 
 
 | 1371 |  | 
 
 
 
 
 | 1372 | return source; | 
 
 
 
 
 | 1373 | } | 
 
 
 
 
 | 1374 |  | 
 
 
 
 
 | 1375 | private Input ReadAnimationInput() | 
 
 
 
 
 | 1376 | { | 
 
 
 
 
 | 1377 | var input = new Input(); | 
 
 
 
 
 | 1378 | input.Semantic = ReadSemanticAttribute(); | 
 
 
 
 
 | 1379 | BindUrlAttribute<Source>("source", source => { | 
 
 
 
 
 | 1380 | input.Source = source; | 
 
 
 
 
 | 1381 | }); | 
 
 
 
 
 | 1382 |  | 
 
 
 
 
 | 1383 | xml.Skip(); | 
 
 
 
 
 | 1384 |  | 
 
 
 
 
 | 1385 | return input; | 
 
 
 
 
 | 1386 | } | 
 
 
 
 
 | 1387 |  | 
 
 
 
 
 | 1388 | private Sampler ReadAnimationSampler() | 
 
 
 
 
 | 1389 | { | 
 
 
 
 
 | 1390 | string id = xml.GetAttribute("id"); | 
 
 
 
 
 | 1391 |  | 
 
 
 
 
 | 1392 | xml.ReadStartElement(); | 
 
 
 
 
 | 1393 |  | 
 
 
 
 
 | 1394 | var sampler = new Sampler(); | 
 
 
 
 
 | 1395 |  | 
 
 
 
 
 | 1396 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1397 | { | 
 
 
 
 
 | 1398 | switch (xml.LocalName) | 
 
 
 
 
 | 1399 | { | 
 
 
 
 
 | 1400 | case "input": | 
 
 
 
 
 | 1401 | sampler.Inputs.Add(ReadAnimationInput()); | 
 
 
 
 
 | 1402 | break; | 
 
 
 
 
 | 1403 |  | 
 
 
 
 
 | 1404 | default: | 
 
 
 
 
 | 1405 | xml.Skip(); | 
 
 
 
 
 | 1406 | break; | 
 
 
 
 
 | 1407 | } | 
 
 
 
 
 | 1408 | } | 
 
 
 
 
 | 1409 |  | 
 
 
 
 
 | 1410 | xml.ReadEndElement(); | 
 
 
 
 
 | 1411 |  | 
 
 
 
 
 | 1412 | AddEntity(id, sampler); | 
 
 
 
 
 | 1413 |  | 
 
 
 
 
 | 1414 | return sampler; | 
 
 
 
 
 | 1415 | } | 
 
 
 
 
 | 1416 |  | 
 
 
 
 
 | 1417 | #region private class TargetPath | 
 
 
 
 
 | 1418 |  | 
 
 
 
 
 | 1419 | private class TargetPath | 
 
 
 
 
 | 1420 | { | 
 
 
 
 
 | 1421 | private string nodeId; | 
 
 
 
 
 | 1422 | private string[] path; | 
 
 
 
 
 | 1423 | private string value; | 
 
 
 
 
 | 1424 |  | 
 
 
 
 
 | 1425 | private TargetPath() | 
 
 
 
 
 | 1426 | { | 
 
 
 
 
 | 1427 | } | 
 
 
 
 
 | 1428 |  | 
 
 
 
 
 | 1429 | public static TargetPath Parse(string text) | 
 
 
 
 
 | 1430 | { | 
 
 
 
 
 | 1431 | TargetPath path = new TargetPath(); | 
 
 
 
 
 | 1432 | List<string> sids = new List<string>(); | 
 
 
 
 
 | 1433 |  | 
 
 
 
 
 | 1434 | int index = text.IndexOf('/'); | 
 
 
 
 
 | 1435 |  | 
 
 
 
 
 | 1436 | if (index == -1) | 
 
 
 
 
 | 1437 | index = text.Length; | 
 
 
 
 
 | 1438 |  | 
 
 
 
 
 | 1439 | path.nodeId = text.Substring(0, index); | 
 
 
 
 
 | 1440 |  | 
 
 
 
 
 | 1441 | for (int start = index + 1; start < text.Length; start = index + 1) | 
 
 
 
 
 | 1442 | { | 
 
 
 
 
 | 1443 | index = text.IndexOf('/', start); | 
 
 
 
 
 | 1444 |  | 
 
 
 
 
 | 1445 | if (index == -1) | 
 
 
 
 
 | 1446 | { | 
 
 
 
 
 | 1447 | index = text.IndexOf('.', start); | 
 
 
 
 
 | 1448 |  | 
 
 
 
 
 | 1449 | if (index == -1) | 
 
 
 
 
 | 1450 | { | 
 
 
 
 
 | 1451 | sids.Add(text.Substring(start)); | 
 
 
 
 
 | 1452 | } | 
 
 
 
 
 | 1453 | else | 
 
 
 
 
 | 1454 | { | 
 
 
 
 
 | 1455 | sids.Add(text.Substring(start, index - start)); | 
 
 
 
 
 | 1456 | path.value = text.Substring(index + 1); | 
 
 
 
 
 | 1457 | } | 
 
 
 
 
 | 1458 |  | 
 
 
 
 
 | 1459 | break; | 
 
 
 
 
 | 1460 | } | 
 
 
 
 
 | 1461 |  | 
 
 
 
 
 | 1462 | sids.Add(text.Substring(start, index - start)); | 
 
 
 
 
 | 1463 | } | 
 
 
 
 
 | 1464 |  | 
 
 
 
 
 | 1465 | if (sids.Count > 0) | 
 
 
 
 
 | 1466 | path.path = sids.ToArray(); | 
 
 
 
 
 | 1467 |  | 
 
 
 
 
 | 1468 | return path; | 
 
 
 
 
 | 1469 | } | 
 
 
 
 
 | 1470 |  | 
 
 
 
 
 | 1471 | public string NodeId => nodeId; | 
 
 
 
 
 | 1472 | public string[] Path => path; | 
 
 
 
 
 | 1473 | public string Value => value; | 
 
 
 
 
 | 1474 | } | 
 
 
 
 
 | 1475 |  | 
 
 
 
 
 | 1476 | #endregion | 
 
 
 
 
 | 1477 |  | 
 
 
 
 
 | 1478 | // | 
 
 
 
 
 | 1479 | // Lights | 
 
 
 
 
 | 1480 | // | 
 
 
 
 
 | 1481 |  | 
 
 
 
 
 | 1482 | private void ReadLight(Light light) | 
 
 
 
 
 | 1483 | { | 
 
 
 
 
 | 1484 | if (!xml.IsStartElement("technique_common")) | 
 
 
 
 
 | 1485 | { | 
 
 
 
 
 | 1486 | xml.Skip(); | 
 
 
 
 
 | 1487 | return; | 
 
 
 
 
 | 1488 | } | 
 
 
 
 
 | 1489 |  | 
 
 
 
 
 | 1490 | xml.ReadStartElement(); | 
 
 
 
 
 | 1491 |  | 
 
 
 
 
 | 1492 | if (xml.IsStartElement()) | 
 
 
 
 
 | 1493 | { | 
 
 
 
 
 | 1494 | switch (xml.LocalName) | 
 
 
 
 
 | 1495 | { | 
 
 
 
 
 | 1496 | case "ambient": | 
 
 
 
 
 | 1497 | light.Type = LightType.Ambient; | 
 
 
 
 
 | 1498 | break; | 
 
 
 
 
 | 1499 |  | 
 
 
 
 
 | 1500 | case "directional": | 
 
 
 
 
 | 1501 | light.Type = LightType.Directional; | 
 
 
 
 
 | 1502 | break; | 
 
 
 
 
 | 1503 |  | 
 
 
 
 
 | 1504 | case "point": | 
 
 
 
 
 | 1505 | light.Type = LightType.Point; | 
 
 
 
 
 | 1506 | break; | 
 
 
 
 
 | 1507 |  | 
 
 
 
 
 | 1508 | case "spot": | 
 
 
 
 
 | 1509 | light.Type = LightType.Spot; | 
 
 
 
 
 | 1510 | break; | 
 
 
 
 
 | 1511 | } | 
 
 
 
 
 | 1512 |  | 
 
 
 
 
 | 1513 | xml.ReadStartElement(); | 
 
 
 
 
 | 1514 |  | 
 
 
 
 
 | 1515 | light.Color = xml.ReadElementContentAsVector3("color"); | 
 
 
 
 
 | 1516 |  | 
 
 
 
 
 | 1517 | if (light.Type == LightType.Point || light.Type == LightType.Spot) | 
 
 
 
 
 | 1518 | { | 
 
 
 
 
 | 1519 | if (xml.LocalName == "constant_attenuation") | 
 
 
 
 
 | 1520 | light.ConstantAttenuation = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 1521 |  | 
 
 
 
 
 | 1522 | if (xml.LocalName == "linear_attenuation") | 
 
 
 
 
 | 1523 | light.LinearAttenuation = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 1524 |  | 
 
 
 
 
 | 1525 | if (light.Type == LightType.Point) | 
 
 
 
 
 | 1526 | { | 
 
 
 
 
 | 1527 | light.QuadraticAttenuation = xml.ReadElementContentAsFloat("quadratic_attenuation", string.Empty); | 
 
 
 
 
 | 1528 |  | 
 
 
 
 
 | 1529 | if (xml.LocalName == "zfar") | 
 
 
 
 
 | 1530 | light.ZFar = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 1531 | } | 
 
 
 
 
 | 1532 | else if (light.Type == LightType.Spot) | 
 
 
 
 
 | 1533 | { | 
 
 
 
 
 | 1534 | if (xml.LocalName == "quadratic_attenuation") | 
 
 
 
 
 | 1535 | light.QuadraticAttenuation = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 1536 |  | 
 
 
 
 
 | 1537 | if (xml.LocalName == "falloff_angle") | 
 
 
 
 
 | 1538 | light.FalloffAngle = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 1539 |  | 
 
 
 
 
 | 1540 | if (xml.LocalName == "falloff_exponent") | 
 
 
 
 
 | 1541 | light.FalloffExponent = xml.ReadElementContentAsFloat(); | 
 
 
 
 
 | 1542 | } | 
 
 
 
 
 | 1543 | } | 
 
 
 
 
 | 1544 |  | 
 
 
 
 
 | 1545 | xml.ReadEndElement(); | 
 
 
 
 
 | 1546 | } | 
 
 
 
 
 | 1547 |  | 
 
 
 
 
 | 1548 | xml.ReadEndElement(); | 
 
 
 
 
 | 1549 | } | 
 
 
 
 
 | 1550 |  | 
 
 
 
 
 | 1551 | // | 
 
 
 
 
 | 1552 | // Scene | 
 
 
 
 
 | 1553 | // | 
 
 
 
 
 | 1554 |  | 
 
 
 
 
 | 1555 | private void ReadScene() | 
 
 
 
 
 | 1556 | { | 
 
 
 
 
 | 1557 | if (!xml.IsStartElement("scene")) | 
 
 
 
 
 | 1558 | return; | 
 
 
 
 
 | 1559 |  | 
 
 
 
 
 | 1560 | xml.ReadStartElement(); | 
 
 
 
 
 | 1561 | xml.SkipSequence("instance_physics_scene"); | 
 
 
 
 
 | 1562 |  | 
 
 
 
 
 | 1563 | if (xml.IsStartElement("instance_visual_scene")) | 
 
 
 
 
 | 1564 | { | 
 
 
 
 
 | 1565 | BindUrlAttribute<Scene>("url", scene => { | 
 
 
 
 
 | 1566 | mainScene = scene; | 
 
 
 
 
 | 1567 | }); | 
 
 
 
 
 | 1568 | xml.Skip(); | 
 
 
 
 
 | 1569 | } | 
 
 
 
 
 | 1570 |  | 
 
 
 
 
 | 1571 | ReadExtra(); | 
 
 
 
 
 | 1572 | xml.ReadEndElement(); | 
 
 
 
 
 | 1573 | } | 
 
 
 
 
 | 1574 |  | 
 
 
 
 
 | 1575 | // | 
 
 
 
 
 | 1576 | // Others | 
 
 
 
 
 | 1577 | // | 
 
 
 
 
 | 1578 |  | 
 
 
 
 
 | 1579 | private void ReadAsset() | 
 
 
 
 
 | 1580 | { | 
 
 
 
 
 | 1581 | if (!xml.IsStartElement("asset")) | 
 
 
 
 
 | 1582 | return; | 
 
 
 
 
 | 1583 |  | 
 
 
 
 
 | 1584 | xml.ReadStartElement(); | 
 
 
 
 
 | 1585 |  | 
 
 
 
 
 | 1586 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1587 | { | 
 
 
 
 
 | 1588 | switch (xml.LocalName) | 
 
 
 
 
 | 1589 | { | 
 
 
 
 
 | 1590 | case "up_axis": | 
 
 
 
 
 | 1591 | upAxis = ReadUpAxis(); | 
 
 
 
 
 | 1592 | break; | 
 
 
 
 
 | 1593 | case "contributor": | 
 
 
 
 
 | 1594 | ReadAssetContributor(); | 
 
 
 
 
 | 1595 | break; | 
 
 
 
 
 | 1596 | case "unit": | 
 
 
 
 
 | 1597 | unit = XmlConvert.ToSingle(xml.GetAttribute("meter")); | 
 
 
 
 
 | 1598 | xml.Skip(); | 
 
 
 
 
 | 1599 | break; | 
 
 
 
 
 | 1600 | default: | 
 
 
 
 
 | 1601 | xml.Skip(); | 
 
 
 
 
 | 1602 | break; | 
 
 
 
 
 | 1603 | } | 
 
 
 
 
 | 1604 | } | 
 
 
 
 
 | 1605 |  | 
 
 
 
 
 | 1606 | xml.ReadEndElement(); | 
 
 
 
 
 | 1607 | } | 
 
 
 
 
 | 1608 |  | 
 
 
 
 
 | 1609 | private void ReadAssetContributor() | 
 
 
 
 
 | 1610 | { | 
 
 
 
 
 | 1611 | xml.ReadStartElement(); | 
 
 
 
 
 | 1612 |  | 
 
 
 
 
 | 1613 | while (xml.IsStartElement()) | 
 
 
 
 
 | 1614 | { | 
 
 
 
 
 | 1615 | switch (xml.LocalName) | 
 
 
 
 
 | 1616 | { | 
 
 
 
 
 | 1617 | default: | 
 
 
 
 
 | 1618 | xml.Skip(); | 
 
 
 
 
 | 1619 | break; | 
 
 
 
 
 | 1620 | } | 
 
 
 
 
 | 1621 | } | 
 
 
 
 
 | 1622 |  | 
 
 
 
 
 | 1623 | xml.ReadEndElement(); | 
 
 
 
 
 | 1624 | } | 
 
 
 
 
 | 1625 |  | 
 
 
 
 
 | 1626 | private void ReadExtra() | 
 
 
 
 
 | 1627 | { | 
 
 
 
 
 | 1628 | while (xml.IsStartElement("extra")) | 
 
 
 
 
 | 1629 | xml.Skip(); | 
 
 
 
 
 | 1630 | } | 
 
 
 
 
 | 1631 |  | 
 
 
 
 
 | 1632 | // | 
 
 
 
 
 | 1633 | // Arrays | 
 
 
 
 
 | 1634 | // | 
 
 
 
 
 | 1635 |  | 
 
 
 
 
 | 1636 | private float[] ReadFloatArray() | 
 
 
 
 
 | 1637 | { | 
 
 
 
 
 | 1638 | if (!xml.IsStartElement("float_array")) | 
 
 
 
 
 | 1639 | return null; | 
 
 
 
 
 | 1640 |  | 
 
 
 
 
 | 1641 | var id = xml.GetAttribute("id"); | 
 
 
 
 
 | 1642 | var count = ReadIntAttribute("count"); | 
 
 
 
 
 | 1643 | var data = new float[count]; | 
 
 
 
 
 | 1644 | var index = 0; | 
 
 
 
 
 | 1645 |  | 
 
 
 
 
 | 1646 | foreach (var token in xml.ReadElementContentAsList()) | 
 
 
 
 
 | 1647 | { | 
 
 
 
 
 | 1648 | if (index < data.Length) | 
 
 
 
 
 | 1649 | data[index++] = XmlConvert.ToSingle(token); | 
 
 
 
 
 | 1650 | } | 
 
 
 
 
 | 1651 |  | 
 
 
 
 
 | 1652 | return data; | 
 
 
 
 
 | 1653 | } | 
 
 
 
 
 | 1654 |  | 
 
 
 
 
 | 1655 | private string[] ReadNameArray() | 
 
 
 
 
 | 1656 | { | 
 
 
 
 
 | 1657 | if (!xml.IsStartElement("Name_array")) | 
 
 
 
 
 | 1658 | return null; | 
 
 
 
 
 | 1659 |  | 
 
 
 
 
 | 1660 | var id = xml.GetAttribute("id"); | 
 
 
 
 
 | 1661 | var count = ReadIntAttribute("count"); | 
 
 
 
 
 | 1662 | var data = new string[count]; | 
 
 
 
 
 | 1663 | var index = 0; | 
 
 
 
 
 | 1664 |  | 
 
 
 
 
 | 1665 | foreach (var token in xml.ReadElementContentAsList()) | 
 
 
 
 
 | 1666 | { | 
 
 
 
 
 | 1667 | if (index < data.Length) | 
 
 
 
 
 | 1668 | data[index++] = token; | 
 
 
 
 
 | 1669 | } | 
 
 
 
 
 | 1670 |  | 
 
 
 
 
 | 1671 | return data; | 
 
 
 
 
 | 1672 | } | 
 
 
 
 
 | 1673 |  | 
 
 
 
 
 | 1674 | // | 
 
 
 
 
 | 1675 | // Attributes | 
 
 
 
 
 | 1676 | // | 
 
 
 
 
 | 1677 |  | 
 
 
 
 
 | 1678 | private int ReadIntAttribute(string name) | 
 
 
 
 
 | 1679 | { | 
 
 
 
 
 | 1680 | string text = xml.GetAttribute(name); | 
 
 
 
 
 | 1681 |  | 
 
 
 
 
 | 1682 | if (string.IsNullOrEmpty(text)) | 
 
 
 
 
 | 1683 | throw new InvalidDataException(name + " attribute not found"); | 
 
 
 
 
 | 1684 |  | 
 
 
 
 
 | 1685 | return XmlConvert.ToInt32(text); | 
 
 
 
 
 | 1686 | } | 
 
 
 
 
 | 1687 |  | 
 
 
 
 
 | 1688 | private int ReadIntAttribute(string name, int defaultValue) | 
 
 
 
 
 | 1689 | { | 
 
 
 
 
 | 1690 | string text = xml.GetAttribute(name); | 
 
 
 
 
 | 1691 |  | 
 
 
 
 
 | 1692 | if (string.IsNullOrEmpty(text)) | 
 
 
 
 
 | 1693 | return defaultValue; | 
 
 
 
 
 | 1694 |  | 
 
 
 
 
 | 1695 | return XmlConvert.ToInt32(text); | 
 
 
 
 
 | 1696 | } | 
 
 
 
 
 | 1697 |  | 
 
 
 
 
 | 1698 | private int? ReadNullableIntAttribute(string name) | 
 
 
 
 
 | 1699 | { | 
 
 
 
 
 | 1700 | string text = xml.GetAttribute(name); | 
 
 
 
 
 | 1701 |  | 
 
 
 
 
 | 1702 | if (string.IsNullOrEmpty(text)) | 
 
 
 
 
 | 1703 | return null; | 
 
 
 
 
 | 1704 |  | 
 
 
 
 
 | 1705 | return XmlConvert.ToInt32(text); | 
 
 
 
 
 | 1706 | } | 
 
 
 
 
 | 1707 |  | 
 
 
 
 
 | 1708 | private Semantic ReadSemanticAttribute() | 
 
 
 
 
 | 1709 | { | 
 
 
 
 
 | 1710 | return ReadSemanticAttribute("semantic"); | 
 
 
 
 
 | 1711 | } | 
 
 
 
 
 | 1712 |  | 
 
 
 
 
 | 1713 | private Semantic ReadSemanticAttribute(string name) | 
 
 
 
 
 | 1714 | { | 
 
 
 
 
 | 1715 | string text = xml.GetAttribute(name); | 
 
 
 
 
 | 1716 |  | 
 
 
 
 
 | 1717 | switch (text) | 
 
 
 
 
 | 1718 | { | 
 
 
 
 
 | 1719 | case "POSITION": | 
 
 
 
 
 | 1720 | return Semantic.Position; | 
 
 
 
 
 | 1721 | case "TEXCOORD": | 
 
 
 
 
 | 1722 | return Semantic.TexCoord; | 
 
 
 
 
 | 1723 | case "NORMAL": | 
 
 
 
 
 | 1724 | return Semantic.Normal; | 
 
 
 
 
 | 1725 | case "COLOR": | 
 
 
 
 
 | 1726 | return Semantic.Color; | 
 
 
 
 
 | 1727 | case "VERTEX": | 
 
 
 
 
 | 1728 | return Semantic.Vertex; | 
 
 
 
 
 | 1729 |  | 
 
 
 
 
 | 1730 | case "INPUT": | 
 
 
 
 
 | 1731 | return Semantic.Input; | 
 
 
 
 
 | 1732 | case "IN_TANGENT": | 
 
 
 
 
 | 1733 | return Semantic.InTangent; | 
 
 
 
 
 | 1734 | case "OUT_TANGENT": | 
 
 
 
 
 | 1735 | return Semantic.OutTangent; | 
 
 
 
 
 | 1736 | case "INTERPOLATION": | 
 
 
 
 
 | 1737 | return Semantic.Interpolation; | 
 
 
 
 
 | 1738 | case "OUTPUT": | 
 
 
 
 
 | 1739 | return Semantic.Output; | 
 
 
 
 
 | 1740 |  | 
 
 
 
 
 | 1741 | default: | 
 
 
 
 
 | 1742 | return Semantic.None; | 
 
 
 
 
 | 1743 | } | 
 
 
 
 
 | 1744 | } | 
 
 
 
 
 | 1745 |  | 
 
 
 
 
 | 1746 | private string[] ReadStringListAttribute(string name) | 
 
 
 
 
 | 1747 | { | 
 
 
 
 
 | 1748 | string text = xml.GetAttribute(name); | 
 
 
 
 
 | 1749 |  | 
 
 
 
 
 | 1750 | if (string.IsNullOrEmpty(text)) | 
 
 
 
 
 | 1751 | return emptyStrings; | 
 
 
 
 
 | 1752 |  | 
 
 
 
 
 | 1753 | return text.Split(whiteSpaceChars, StringSplitOptions.RemoveEmptyEntries); | 
 
 
 
 
 | 1754 | } | 
 
 
 
 
 | 1755 |  | 
 
 
 
 
 | 1756 | private Axis ReadUpAxis() | 
 
 
 
 
 | 1757 | { | 
 
 
 
 
 | 1758 | switch (xml.ReadElementContentAsString()) | 
 
 
 
 
 | 1759 | { | 
 
 
 
 
 | 1760 | case "X_UP": | 
 
 
 
 
 | 1761 | return Axis.X; | 
 
 
 
 
 | 1762 | case "Z_UP": | 
 
 
 
 
 | 1763 | return Axis.Z; | 
 
 
 
 
 | 1764 | default: | 
 
 
 
 
 | 1765 | return Axis.Y; | 
 
 
 
 
 | 1766 | } | 
 
 
 
 
 | 1767 | } | 
 
 
 
 
 | 1768 |  | 
 
 
 
 
 | 1769 | private void AddEntity(string id, Entity entity) | 
 
 
 
 
 | 1770 | { | 
 
 
 
 
 | 1771 | if (string.IsNullOrEmpty(id)) | 
 
 
 
 
 | 1772 | return; | 
 
 
 
 
 | 1773 |  | 
 
 
 
 
 | 1774 | if (entities == null) | 
 
 
 
 
 | 1775 | entities = new Dictionary<string, Entity>(); | 
 
 
 
 
 | 1776 |  | 
 
 
 
 
 | 1777 | if (entities.ContainsKey(id)) | 
 
 
 
 
 | 1778 | error.WriteLine(string.Format("COLLADA error: duplicate id {0}", id)); | 
 
 
 
 
 | 1779 | else | 
 
 
 
 
 | 1780 | entities.Add(id, entity); | 
 
 
 
 
 | 1781 |  | 
 
 
 
 
 | 1782 | entity.Id = id; | 
 
 
 
 
 | 1783 | } | 
 
 
 
 
 | 1784 |  | 
 
 
 
 
 | 1785 | private T GetEntity<T>(string id) where T : Entity | 
 
 
 
 
 | 1786 | { | 
 
 
 
 
 | 1787 | Entity result; | 
 
 
 
 
 | 1788 |  | 
 
 
 
 
 | 1789 | if (entities == null | 
 
 
 
 
 | 1790 | || string.IsNullOrEmpty(id) | 
 
 
 
 
 | 1791 | || !entities.TryGetValue(id, out result)) | 
 
 
 
 
 | 1792 | return null; | 
 
 
 
 
 | 1793 |  | 
 
 
 
 
 | 1794 | return result as T; | 
 
 
 
 
 | 1795 | } | 
 
 
 
 
 | 1796 |  | 
 
 
 
 
 | 1797 | private void BindUrlAttribute<T>(string name, Action<T> action) | 
 
 
 
 
 | 1798 | where T : Entity | 
 
 
 
 
 | 1799 | { | 
 
 
 
 
 | 1800 | BindUrl(xml.GetAttribute(name), action); | 
 
 
 
 
 | 1801 | } | 
 
 
 
 
 | 1802 |  | 
 
 
 
 
 | 1803 | private void BindUrl<T>(string url, Action<T> action) | 
 
 
 
 
 | 1804 | where T : Entity | 
 
 
 
 
 | 1805 | { | 
 
 
 
 
 | 1806 | if (string.IsNullOrEmpty(url)) | 
 
 
 
 
 | 1807 | return; | 
 
 
 
 
 | 1808 |  | 
 
 
 
 
 | 1809 | if (url[0] != '#') | 
 
 
 
 
 | 1810 | throw new NotSupportedException(string.Format("External reference '{0}' is not supported", url)); | 
 
 
 
 
 | 1811 |  | 
 
 
 
 
 | 1812 | BindId<T>(url.Substring(1), action); | 
 
 
 
 
 | 1813 | } | 
 
 
 
 
 | 1814 |  | 
 
 
 
 
 | 1815 | private void BindId<T>(string id, Action<T> action) | 
 
 
 
 
 | 1816 | where T : Entity | 
 
 
 
 
 | 1817 | { | 
 
 
 
 
 | 1818 | if (string.IsNullOrEmpty(id)) | 
 
 
 
 
 | 1819 | return; | 
 
 
 
 
 | 1820 |  | 
 
 
 
 
 | 1821 | var entity = GetEntity<T>(id); | 
 
 
 
 
 | 1822 |  | 
 
 
 
 
 | 1823 | if (entity != null) | 
 
 
 
 
 | 1824 | { | 
 
 
 
 
 | 1825 | action(entity); | 
 
 
 
 
 | 1826 | return; | 
 
 
 
 
 | 1827 | } | 
 
 
 
 
 | 1828 |  | 
 
 
 
 
 | 1829 | delayedBindActions.Add(delegate { | 
 
 
 
 
 | 1830 | var entity2 = GetEntity<T>(id); | 
 
 
 
 
 | 1831 |  | 
 
 
 
 
 | 1832 | if (entity2 != null) | 
 
 
 
 
 | 1833 | action(entity2); | 
 
 
 
 
 | 1834 | }); | 
 
 
 
 
 | 1835 | } | 
 
 
 
 
 | 1836 |  | 
 
 
 
 
 | 1837 | private void BindAnimationSampler(string sourceId, string targetPath) | 
 
 
 
 
 | 1838 | { | 
 
 
 
 
 | 1839 | var path = TargetPath.Parse(targetPath); | 
 
 
 
 
 | 1840 |  | 
 
 
 
 
 | 1841 | BindUrlAttribute<Sampler>("source", sampler => { | 
 
 
 
 
 | 1842 | var output = sampler.Inputs.Find(i => i.Semantic == Semantic.Output); | 
 
 
 
 
 | 1843 |  | 
 
 
 
 
 | 1844 | if (output == null || output.Source == null) | 
 
 
 
 
 | 1845 | return; | 
 
 
 
 
 | 1846 |  | 
 
 
 
 
 | 1847 | int stride = output.Source.Stride; | 
 
 
 
 
 | 1848 |  | 
 
 
 
 
 | 1849 | if (stride != 1) | 
 
 
 
 
 | 1850 | { | 
 
 
 
 
 | 1851 | for (int offset = 0; offset < stride; offset++) | 
 
 
 
 
 | 1852 | { | 
 
 
 
 
 | 1853 | var newSampler = sampler.Split(offset); | 
 
 
 
 
 | 1854 |  | 
 
 
 
 
 | 1855 | BindId<Node>(path.NodeId, node => { | 
 
 
 
 
 | 1856 | Transform transform = FindTransform(node, path.Path[0]); | 
 
 
 
 
 | 1857 |  | 
 
 
 
 
 | 1858 | if (transform != null) | 
 
 
 
 
 | 1859 | transform.BindAnimation(string.Format(CultureInfo.InvariantCulture, "({0})", offset), newSampler); | 
 
 
 
 
 | 1860 | }); | 
 
 
 
 
 | 1861 | } | 
 
 
 
 
 | 1862 | } | 
 
 
 
 
 | 1863 | else | 
 
 
 
 
 | 1864 | { | 
 
 
 
 
 | 1865 | BindId<Node>(path.NodeId, node => { | 
 
 
 
 
 | 1866 | var transform = FindTransform(node, path.Path[0]); | 
 
 
 
 
 | 1867 |  | 
 
 
 
 
 | 1868 | if (transform != null) | 
 
 
 
 
 | 1869 | transform.BindAnimation(path.Value, sampler); | 
 
 
 
 
 | 1870 | }); | 
 
 
 
 
 | 1871 | } | 
 
 
 
 
 | 1872 | }); | 
 
 
 
 
 | 1873 | } | 
 
 
 
 
 | 1874 |  | 
 
 
 
 
 | 1875 | private Transform FindTransform(Node node, string sid) | 
 
 
 
 
 | 1876 | { | 
 
 
 
 
 | 1877 | return node.Transforms.Find(t => t.Sid == sid); | 
 
 
 
 
 | 1878 | } | 
 
 
 
 
 | 1879 |  | 
 
 
 
 
 | 1880 | private void BindNodes(Node node) | 
 
 
 
 
 | 1881 | { | 
 
 
 
 
 | 1882 | foreach (var instance in node.Instances.OfType<NodeInstance>().ToList()) | 
 
 
 
 
 | 1883 | { | 
 
 
 
 
 | 1884 | node.Instances.Remove(instance); | 
 
 
 
 
 | 1885 |  | 
 
 
 
 
 | 1886 | if (instance.Target != node) | 
 
 
 
 
 | 1887 | node.Nodes.Add(instance.Target); | 
 
 
 
 
 | 1888 | } | 
 
 
 
 
 | 1889 |  | 
 
 
 
 
 | 1890 | foreach (var child in node.Nodes) | 
 
 
 
 
 | 1891 | BindNodes(child); | 
 
 
 
 
 | 1892 | } | 
 
 
 
 
 | 1893 | } | 
 
 
 
 
 | 1894 | } |