| 1 | using System; | 
|---|
| 2 | using System.Collections.Generic; | 
|---|
| 3 | using System.IO; | 
|---|
| 4 | using Oni.Imaging; | 
|---|
| 5 |  | 
|---|
| 6 | namespace Oni.Akira | 
|---|
| 7 | { | 
|---|
| 8 | internal class AkiraDatWriter | 
|---|
| 9 | { | 
|---|
| 10 | #region Private data | 
|---|
| 11 | private Importer importer; | 
|---|
| 12 | private string name; | 
|---|
| 13 | private bool debug; | 
|---|
| 14 | private PolygonMesh source; | 
|---|
| 15 |  | 
|---|
| 16 | private List<DatPolygon> polygons = new List<DatPolygon>(); | 
|---|
| 17 | private Dictionary<Polygon, DatPolygon> polygonMap = new Dictionary<Polygon, DatPolygon>(); | 
|---|
| 18 |  | 
|---|
| 19 | private UniqueList<Vector3> points = new UniqueList<Vector3>(); | 
|---|
| 20 | private UniqueList<Vector2> texCoords = new UniqueList<Vector2>(); | 
|---|
| 21 | private UniqueList<Material> materials = new UniqueList<Material>(); | 
|---|
| 22 | private UniqueList<Plane> planes = new UniqueList<Plane>(); | 
|---|
| 23 |  | 
|---|
| 24 | private List<DatAlphaBspNode> alphaBspNodes = new List<DatAlphaBspNode>(); | 
|---|
| 25 |  | 
|---|
| 26 | private List<DatRoom> rooms = new List<DatRoom>(); | 
|---|
| 27 | private Dictionary<Room, DatRoom> roomMap = new Dictionary<Room, DatRoom>(); | 
|---|
| 28 | private List<DatRoomBspNode> roomBspNodes = new List<DatRoomBspNode>(); | 
|---|
| 29 | private List<DatRoomSide> roomSides = new List<DatRoomSide>(); | 
|---|
| 30 | private List<DatRoomAdjacency> roomAdjacencies = new List<DatRoomAdjacency>(); | 
|---|
| 31 |  | 
|---|
| 32 | private DatOctree octree; | 
|---|
| 33 | #endregion | 
|---|
| 34 |  | 
|---|
| 35 | #region private class UniqueList<T> | 
|---|
| 36 |  | 
|---|
| 37 | private class UniqueList<T> : ICollection<T> | 
|---|
| 38 | { | 
|---|
| 39 | private readonly List<T> list = new List<T>(); | 
|---|
| 40 | private readonly Dictionary<T, int> indices = new Dictionary<T, int>(); | 
|---|
| 41 |  | 
|---|
| 42 | public int Add(T t) | 
|---|
| 43 | { | 
|---|
| 44 | int index; | 
|---|
| 45 |  | 
|---|
| 46 | if (!indices.TryGetValue(t, out index)) | 
|---|
| 47 | { | 
|---|
| 48 | index = list.Count; | 
|---|
| 49 | indices.Add(t, index); | 
|---|
| 50 | list.Add(t); | 
|---|
| 51 | } | 
|---|
| 52 |  | 
|---|
| 53 | return index; | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | #region ICollection<T> Members | 
|---|
| 57 |  | 
|---|
| 58 | void ICollection<T>.Add(T item) => Add(item); | 
|---|
| 59 |  | 
|---|
| 60 | public int Count => list.Count; | 
|---|
| 61 |  | 
|---|
| 62 | void ICollection<T>.Clear() | 
|---|
| 63 | { | 
|---|
| 64 | list.Clear(); | 
|---|
| 65 | indices.Clear(); | 
|---|
| 66 | } | 
|---|
| 67 |  | 
|---|
| 68 | bool ICollection<T>.Contains(T item) => indices.ContainsKey(item); | 
|---|
| 69 |  | 
|---|
| 70 | void ICollection<T>.CopyTo(T[] array, int arrayIndex) | 
|---|
| 71 | { | 
|---|
| 72 | list.CopyTo(array, arrayIndex); | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | bool ICollection<T>.IsReadOnly => false; | 
|---|
| 76 |  | 
|---|
| 77 | bool ICollection<T>.Remove(T item) | 
|---|
| 78 | { | 
|---|
| 79 | throw new NotImplementedException(); | 
|---|
| 80 | } | 
|---|
| 81 |  | 
|---|
| 82 | IEnumerator<T> IEnumerable<T>.GetEnumerator() => list.GetEnumerator(); | 
|---|
| 83 |  | 
|---|
| 84 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => list.GetEnumerator(); | 
|---|
| 85 |  | 
|---|
| 86 | #endregion | 
|---|
| 87 | } | 
|---|
| 88 |  | 
|---|
| 89 | #endregion | 
|---|
| 90 |  | 
|---|
| 91 | #region private class DatObject<T> | 
|---|
| 92 |  | 
|---|
| 93 | private class DatObject<T> | 
|---|
| 94 | { | 
|---|
| 95 | private readonly T source; | 
|---|
| 96 |  | 
|---|
| 97 | public DatObject(T source) | 
|---|
| 98 | { | 
|---|
| 99 | this.source = source; | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | public T Source => source; | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | #endregion | 
|---|
| 106 | #region private class DatPolygon | 
|---|
| 107 |  | 
|---|
| 108 | private class DatPolygon : DatObject<Polygon> | 
|---|
| 109 | { | 
|---|
| 110 | private static readonly Color defaultColor = new Color(207, 207, 207, 255); | 
|---|
| 111 | private static readonly Color[] defaultColors = new[] { defaultColor, defaultColor, defaultColor, defaultColor }; | 
|---|
| 112 | private GunkFlags flags; | 
|---|
| 113 | private readonly int index; | 
|---|
| 114 | public readonly int[] PointIndices = new int[4]; | 
|---|
| 115 | public readonly int[] TexCoordIndices = new int[4]; | 
|---|
| 116 | public readonly Color[] Colors = new Color[4]; | 
|---|
| 117 | private readonly int objectId; | 
|---|
| 118 | private readonly int scriptId; | 
|---|
| 119 | private int materialIndex; | 
|---|
| 120 | private int planeIndex; | 
|---|
| 121 |  | 
|---|
| 122 | public DatPolygon(Polygon source, int index, UniqueList<Vector3> points, UniqueList<Vector2> texCoords) | 
|---|
| 123 | : base(source) | 
|---|
| 124 | { | 
|---|
| 125 | this.index = index; | 
|---|
| 126 | this.scriptId = source.ScriptId; | 
|---|
| 127 |  | 
|---|
| 128 | objectId = source.ObjectType << 24 | (source.ObjectId & 0xffffff); | 
|---|
| 129 | flags = source.Flags; | 
|---|
| 130 |  | 
|---|
| 131 | if (source.VertexCount == 3) | 
|---|
| 132 | { | 
|---|
| 133 | flags |= GunkFlags.Triangle; | 
|---|
| 134 |  | 
|---|
| 135 | Array.Copy(source.PointIndices, PointIndices, 3); | 
|---|
| 136 | PointIndices[3] = PointIndices[2]; | 
|---|
| 137 |  | 
|---|
| 138 | Array.Copy(source.TexCoordIndices, TexCoordIndices, 3); | 
|---|
| 139 | TexCoordIndices[3] = TexCoordIndices[2]; | 
|---|
| 140 |  | 
|---|
| 141 | if (source.Colors == null) | 
|---|
| 142 | { | 
|---|
| 143 | Colors = defaultColors; | 
|---|
| 144 | } | 
|---|
| 145 | else | 
|---|
| 146 | { | 
|---|
| 147 | Array.Copy(source.Colors, Colors, 3); | 
|---|
| 148 | Colors[3] = Colors[2]; | 
|---|
| 149 | } | 
|---|
| 150 | } | 
|---|
| 151 | else | 
|---|
| 152 | { | 
|---|
| 153 | Array.Copy(source.PointIndices, PointIndices, 4); | 
|---|
| 154 | Array.Copy(source.TexCoordIndices, TexCoordIndices, 4); | 
|---|
| 155 |  | 
|---|
| 156 | if (source.Colors != null) | 
|---|
| 157 | Colors = source.Colors; | 
|---|
| 158 | else | 
|---|
| 159 | Colors = defaultColors; | 
|---|
| 160 | } | 
|---|
| 161 |  | 
|---|
| 162 | for (int i = 0; i < 4; i++) | 
|---|
| 163 | { | 
|---|
| 164 | PointIndices[i] = points.Add(source.Mesh.Points[PointIndices[i]]); | 
|---|
| 165 | TexCoordIndices[i] = texCoords.Add(source.Mesh.TexCoords[TexCoordIndices[i]]); | 
|---|
| 166 | } | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | public int Index => index; | 
|---|
| 170 | public int ObjectId => objectId; | 
|---|
| 171 | public int ScriptId => scriptId; | 
|---|
| 172 |  | 
|---|
| 173 | public GunkFlags Flags | 
|---|
| 174 | { | 
|---|
| 175 | get { return flags; } | 
|---|
| 176 | set { flags = value; } | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | public int MaterialIndex | 
|---|
| 180 | { | 
|---|
| 181 | get { return materialIndex; } | 
|---|
| 182 | set { materialIndex = value; } | 
|---|
| 183 | } | 
|---|
| 184 |  | 
|---|
| 185 | public int PlaneIndex | 
|---|
| 186 | { | 
|---|
| 187 | get { return planeIndex; } | 
|---|
| 188 | set { planeIndex = value; } | 
|---|
| 189 | } | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | #endregion | 
|---|
| 193 | #region private class DatBspNode | 
|---|
| 194 |  | 
|---|
| 195 | private class DatBspNode<T> : DatObject<T> | 
|---|
| 196 | where T : BspNode<T> | 
|---|
| 197 | { | 
|---|
| 198 | public int PlaneIndex; | 
|---|
| 199 | public int FrontChildIndex = -1; | 
|---|
| 200 | public int BackChildIndex = -1; | 
|---|
| 201 |  | 
|---|
| 202 | public DatBspNode(T source) | 
|---|
| 203 | : base(source) | 
|---|
| 204 | { | 
|---|
| 205 | } | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 | #endregion | 
|---|
| 209 | #region private class DatAlphaBspNode | 
|---|
| 210 |  | 
|---|
| 211 | private class DatAlphaBspNode : DatBspNode<AlphaBspNode> | 
|---|
| 212 | { | 
|---|
| 213 | public readonly int PolygonIndex; | 
|---|
| 214 |  | 
|---|
| 215 | public DatAlphaBspNode(AlphaBspNode source, int polygonIndex) | 
|---|
| 216 | : base(source) | 
|---|
| 217 | { | 
|---|
| 218 | PolygonIndex = polygonIndex; | 
|---|
| 219 | } | 
|---|
| 220 | } | 
|---|
| 221 |  | 
|---|
| 222 | #endregion | 
|---|
| 223 | #region private class DatRoom | 
|---|
| 224 |  | 
|---|
| 225 | private class DatRoom : DatObject<Room> | 
|---|
| 226 | { | 
|---|
| 227 | private readonly int index; | 
|---|
| 228 | private readonly RoomFlags flags; | 
|---|
| 229 |  | 
|---|
| 230 | public int BspTreeIndex; | 
|---|
| 231 | public int SideListStart; | 
|---|
| 232 | public int SideListEnd; | 
|---|
| 233 | public int ChildIndex = -1; | 
|---|
| 234 | public int SiblingIndex = -1; | 
|---|
| 235 | public byte[] CompressedGridData; | 
|---|
| 236 | public byte[] DebugData; | 
|---|
| 237 |  | 
|---|
| 238 | public DatRoom(Room source, int index) | 
|---|
| 239 | : base(source) | 
|---|
| 240 | { | 
|---|
| 241 | this.index = index; | 
|---|
| 242 | this.flags = RoomFlags.Room; | 
|---|
| 243 |  | 
|---|
| 244 | if (source.FloorPlane.Normal.Y < 0.999f) | 
|---|
| 245 | this.flags |= RoomFlags.Stairs; | 
|---|
| 246 | } | 
|---|
| 247 |  | 
|---|
| 248 | public int Index => index; | 
|---|
| 249 | public int Flags => (int)flags; | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | #endregion | 
|---|
| 253 | #region private class DatRoomBspNode | 
|---|
| 254 |  | 
|---|
| 255 | private class DatRoomBspNode : DatBspNode<RoomBspNode> | 
|---|
| 256 | { | 
|---|
| 257 | public DatRoomBspNode(RoomBspNode source) | 
|---|
| 258 | : base(source) | 
|---|
| 259 | { | 
|---|
| 260 | } | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | #endregion | 
|---|
| 264 | #region private class DatRoomSide | 
|---|
| 265 |  | 
|---|
| 266 | private class DatRoomSide | 
|---|
| 267 | { | 
|---|
| 268 | public int AdjacencyListStart; | 
|---|
| 269 | public int AdjacencyListEnd; | 
|---|
| 270 | } | 
|---|
| 271 |  | 
|---|
| 272 | #endregion | 
|---|
| 273 | #region private class DatRoomAdjacency | 
|---|
| 274 |  | 
|---|
| 275 | private class DatRoomAdjacency : DatObject<RoomAdjacency> | 
|---|
| 276 | { | 
|---|
| 277 | public DatRoomAdjacency(RoomAdjacency source) | 
|---|
| 278 | : base(source) | 
|---|
| 279 | { | 
|---|
| 280 | } | 
|---|
| 281 |  | 
|---|
| 282 | public int AdjacentRoomIndex; | 
|---|
| 283 | public int GhostIndex; | 
|---|
| 284 | } | 
|---|
| 285 |  | 
|---|
| 286 | #endregion | 
|---|
| 287 | #region private class DatOctree | 
|---|
| 288 |  | 
|---|
| 289 | private class DatOctree | 
|---|
| 290 | { | 
|---|
| 291 | public int[] Nodes; | 
|---|
| 292 | public int[] QuadTrees; | 
|---|
| 293 | public int[] Adjacency; | 
|---|
| 294 | public DatOctreeBoundingBox[] BoundingBoxes; | 
|---|
| 295 | public DatOctreePolygonRange[] PolygonLists; | 
|---|
| 296 | public DatOctreeBnvRange[] BnvLists; | 
|---|
| 297 | public int[] PolygonIndex; | 
|---|
| 298 | public int[] BnvIndex; | 
|---|
| 299 | } | 
|---|
| 300 |  | 
|---|
| 301 | #endregion | 
|---|
| 302 | #region private struct DatOctreeBoundingBox | 
|---|
| 303 |  | 
|---|
| 304 | private struct DatOctreeBoundingBox | 
|---|
| 305 | { | 
|---|
| 306 | private readonly uint value; | 
|---|
| 307 |  | 
|---|
| 308 | public DatOctreeBoundingBox(BoundingBox bbox) | 
|---|
| 309 | { | 
|---|
| 310 | int size = (int)(Math.Log(bbox.Max.X - bbox.Min.X, 2)) - 4; | 
|---|
| 311 | int maxX = (int)(bbox.Max.X + 4080.0f); | 
|---|
| 312 | int maxY = (int)(bbox.Max.Y + 4080.0f); | 
|---|
| 313 | int maxZ = (int)(bbox.Max.Z + 4080.0f); | 
|---|
| 314 |  | 
|---|
| 315 | value = (uint)((maxX << 14) | (maxY << 5) | (maxZ >> 4) | (size << 27)); | 
|---|
| 316 | } | 
|---|
| 317 |  | 
|---|
| 318 | public uint PackedValue => value; | 
|---|
| 319 | } | 
|---|
| 320 |  | 
|---|
| 321 | #endregion | 
|---|
| 322 | #region private struct DatOctreeBnvRange | 
|---|
| 323 |  | 
|---|
| 324 | private struct DatOctreeBnvRange | 
|---|
| 325 | { | 
|---|
| 326 | private const int indexBitOffset = 8; | 
|---|
| 327 | private const int lengthBitMask = 255; | 
|---|
| 328 | private readonly uint value; | 
|---|
| 329 |  | 
|---|
| 330 | public DatOctreeBnvRange(int start, int length) | 
|---|
| 331 | { | 
|---|
| 332 | ValidateRange(start, length); | 
|---|
| 333 | value = (uint)((start << indexBitOffset) | (length & lengthBitMask)); | 
|---|
| 334 | } | 
|---|
| 335 |  | 
|---|
| 336 | private static void ValidateRange(int start, int length) | 
|---|
| 337 | { | 
|---|
| 338 | if (start > 16777215) | 
|---|
| 339 | throw new ArgumentException(string.Format("Invalid bnv list start index {0}", start), "start"); | 
|---|
| 340 |  | 
|---|
| 341 | if (length > 255) | 
|---|
| 342 | throw new ArgumentException(string.Format("Invalid bnv list length {0}", length), "length"); | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | public uint PackedValue => value; | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | #endregion | 
|---|
| 349 | #region private struct DatOctreePolygonRange | 
|---|
| 350 |  | 
|---|
| 351 | private struct DatOctreePolygonRange | 
|---|
| 352 | { | 
|---|
| 353 | private const int indexBitOffset = 12; | 
|---|
| 354 | private const int lengthBitMask = 4095; | 
|---|
| 355 | private readonly uint value; | 
|---|
| 356 |  | 
|---|
| 357 | public DatOctreePolygonRange(int start, int length) | 
|---|
| 358 | { | 
|---|
| 359 | //ValidateRange(start, length); | 
|---|
| 360 |  | 
|---|
| 361 | if (start > 1048575) | 
|---|
| 362 | { | 
|---|
| 363 | start = 1048575; | 
|---|
| 364 | length = 0; | 
|---|
| 365 | } | 
|---|
| 366 |  | 
|---|
| 367 | value = (uint)((start << indexBitOffset) | (length & lengthBitMask)); | 
|---|
| 368 | } | 
|---|
| 369 |  | 
|---|
| 370 | private static void ValidateRange(int start, int length) | 
|---|
| 371 | { | 
|---|
| 372 | if (start > 1048575) | 
|---|
| 373 | throw new ArgumentException(string.Format("Invalid quad list start index {0}", start), "start"); | 
|---|
| 374 |  | 
|---|
| 375 | if (length > 4095) | 
|---|
| 376 | throw new ArgumentException(string.Format("Invalid quad list length {0}", length), "length"); | 
|---|
| 377 | } | 
|---|
| 378 |  | 
|---|
| 379 | public uint PackedValue => value; | 
|---|
| 380 | } | 
|---|
| 381 |  | 
|---|
| 382 | #endregion | 
|---|
| 383 |  | 
|---|
| 384 | public static void Write(PolygonMesh mesh, Importer importer, string name, bool debug) | 
|---|
| 385 | { | 
|---|
| 386 | var writer = new AkiraDatWriter { | 
|---|
| 387 | name = name, | 
|---|
| 388 | importer = importer, | 
|---|
| 389 | source = mesh, | 
|---|
| 390 | debug = debug | 
|---|
| 391 | }; | 
|---|
| 392 |  | 
|---|
| 393 | writer.Write(); | 
|---|
| 394 | } | 
|---|
| 395 |  | 
|---|
| 396 | private void Write() | 
|---|
| 397 | { | 
|---|
| 398 | Console.Error.WriteLine("Environment bounding box is {0}", source.GetBoundingBox()); | 
|---|
| 399 |  | 
|---|
| 400 | RoomBuilder.BuildRooms(source); | 
|---|
| 401 |  | 
|---|
| 402 | ConvertPolygons(source.Polygons); | 
|---|
| 403 | ConvertPolygons(source.Doors); | 
|---|
| 404 | ConvertPolygons(source.Ghosts); | 
|---|
| 405 | ConvertAlphaBspTree(AlphaBspBuilder.Build(source, debug)); | 
|---|
| 406 | ConvertRooms(); | 
|---|
| 407 | ConvertOctree(); | 
|---|
| 408 |  | 
|---|
| 409 | WriteAKEV(); | 
|---|
| 410 |  | 
|---|
| 411 | //foreach (Material material in materials) | 
|---|
| 412 | //{ | 
|---|
| 413 | //    if (File.Exists(material.ImageFilePath)) | 
|---|
| 414 | //        importer.AddDependency(material.ImageFilePath, TemplateTag.TXMP); | 
|---|
| 415 | //} | 
|---|
| 416 | } | 
|---|
| 417 |  | 
|---|
| 418 | private void ConvertPolygons(List<Polygon> sourcePolygons) | 
|---|
| 419 | { | 
|---|
| 420 | foreach (var polygon in sourcePolygons) | 
|---|
| 421 | { | 
|---|
| 422 | if (polygon.VertexCount > 4) | 
|---|
| 423 | { | 
|---|
| 424 | Console.Error.WriteLine("Geometry '{0}' has a {1}-gon, ignoring.", polygon.ObjectName, polygon.VertexCount); | 
|---|
| 425 | continue; | 
|---|
| 426 | } | 
|---|
| 427 |  | 
|---|
| 428 | if (polygon.TexCoordIndices == null) | 
|---|
| 429 | { | 
|---|
| 430 | Console.Error.WriteLine("Geometry '{0}' does not contain texture coordinates, ignoring.", polygon.ObjectName); | 
|---|
| 431 | continue; | 
|---|
| 432 | } | 
|---|
| 433 |  | 
|---|
| 434 | var datPolygon = new DatPolygon(polygon, polygons.Count, points, texCoords) { | 
|---|
| 435 | PlaneIndex = planes.Add(polygon.Plane), | 
|---|
| 436 | MaterialIndex = materials.Add(polygon.Material) | 
|---|
| 437 | }; | 
|---|
| 438 |  | 
|---|
| 439 | polygons.Add(datPolygon); | 
|---|
| 440 | polygonMap.Add(polygon, datPolygon); | 
|---|
| 441 | } | 
|---|
| 442 |  | 
|---|
| 443 | //var noneMaterial = source.Materials.GetMaterial("NONE"); | 
|---|
| 444 | //int noneMaterialIndex = materials.Add(noneMaterial); | 
|---|
| 445 |  | 
|---|
| 446 | //foreach (var polygon in polygons) | 
|---|
| 447 | //{ | 
|---|
| 448 | //    var material = polygon.Source.Material; | 
|---|
| 449 |  | 
|---|
| 450 | //if (material.IsMarker) | 
|---|
| 451 | //{ | 
|---|
| 452 | //    polygon.MaterialIndex = noneMaterialIndex; | 
|---|
| 453 |  | 
|---|
| 454 | //    if (material != source.Materials.Markers.Blackness && (material.Flags & GunkFlags.Invisible) == 0) | 
|---|
| 455 | //        polygon.Flags |= GunkFlags.Transparent; | 
|---|
| 456 | //} | 
|---|
| 457 | //else | 
|---|
| 458 | //{ | 
|---|
| 459 | //    polygon.MaterialIndex = materials.Add(material); | 
|---|
| 460 | //} | 
|---|
| 461 | //} | 
|---|
| 462 | } | 
|---|
| 463 |  | 
|---|
| 464 | private int ConvertAlphaBspTree(AlphaBspNode source) | 
|---|
| 465 | { | 
|---|
| 466 | if (source == null) | 
|---|
| 467 | return -1; | 
|---|
| 468 |  | 
|---|
| 469 | int index = alphaBspNodes.Count; | 
|---|
| 470 |  | 
|---|
| 471 | var node = new DatAlphaBspNode(source, polygonMap[source.Polygon].Index) { | 
|---|
| 472 | PlaneIndex = planes.Add(source.Plane) | 
|---|
| 473 | }; | 
|---|
| 474 |  | 
|---|
| 475 | alphaBspNodes.Add(node); | 
|---|
| 476 |  | 
|---|
| 477 | if (source.FrontChild != null) | 
|---|
| 478 | node.FrontChildIndex = ConvertAlphaBspTree((AlphaBspNode)source.FrontChild); | 
|---|
| 479 |  | 
|---|
| 480 | if (source.BackChild != null) | 
|---|
| 481 | node.BackChildIndex = ConvertAlphaBspTree((AlphaBspNode)source.BackChild); | 
|---|
| 482 |  | 
|---|
| 483 | return index; | 
|---|
| 484 | } | 
|---|
| 485 |  | 
|---|
| 486 | private void ConvertRooms() | 
|---|
| 487 | { | 
|---|
| 488 | foreach (var room in source.Rooms) | 
|---|
| 489 | { | 
|---|
| 490 | var datRoom = new DatRoom(room, rooms.Count) { | 
|---|
| 491 | BspTreeIndex = ConvertRoomBspTree(room.BspTree), | 
|---|
| 492 | CompressedGridData = room.Grid.Compress(), | 
|---|
| 493 | DebugData = room.Grid.DebugData, | 
|---|
| 494 | SideListStart = roomSides.Count | 
|---|
| 495 | }; | 
|---|
| 496 |  | 
|---|
| 497 | if (room.Ajacencies.Count > 0) | 
|---|
| 498 | { | 
|---|
| 499 | var datSide = new DatRoomSide { | 
|---|
| 500 | AdjacencyListStart = roomAdjacencies.Count | 
|---|
| 501 | }; | 
|---|
| 502 |  | 
|---|
| 503 | foreach (var adjacency in room.Ajacencies) | 
|---|
| 504 | { | 
|---|
| 505 | roomAdjacencies.Add(new DatRoomAdjacency(adjacency) { | 
|---|
| 506 | AdjacentRoomIndex = source.Rooms.IndexOf(adjacency.AdjacentRoom), | 
|---|
| 507 | GhostIndex = polygonMap[adjacency.Ghost].Index | 
|---|
| 508 | }); | 
|---|
| 509 | } | 
|---|
| 510 |  | 
|---|
| 511 | datSide.AdjacencyListEnd = roomAdjacencies.Count; | 
|---|
| 512 | roomSides.Add(datSide); | 
|---|
| 513 | } | 
|---|
| 514 |  | 
|---|
| 515 | datRoom.SideListEnd = roomSides.Count; | 
|---|
| 516 |  | 
|---|
| 517 | rooms.Add(datRoom); | 
|---|
| 518 | roomMap.Add(room, datRoom); | 
|---|
| 519 | } | 
|---|
| 520 | } | 
|---|
| 521 |  | 
|---|
| 522 | private int ConvertRoomBspTree(RoomBspNode node) | 
|---|
| 523 | { | 
|---|
| 524 | int index = roomBspNodes.Count; | 
|---|
| 525 |  | 
|---|
| 526 | var datNode = new DatRoomBspNode(node) { | 
|---|
| 527 | PlaneIndex = planes.Add(node.Plane) | 
|---|
| 528 | }; | 
|---|
| 529 |  | 
|---|
| 530 | roomBspNodes.Add(datNode); | 
|---|
| 531 |  | 
|---|
| 532 | if (node.FrontChild != null) | 
|---|
| 533 | datNode.FrontChildIndex = ConvertRoomBspTree(node.FrontChild); | 
|---|
| 534 |  | 
|---|
| 535 | if (node.BackChild != null) | 
|---|
| 536 | datNode.BackChildIndex = ConvertRoomBspTree(node.BackChild); | 
|---|
| 537 |  | 
|---|
| 538 | return index; | 
|---|
| 539 | } | 
|---|
| 540 |  | 
|---|
| 541 | private void ConvertOctree() | 
|---|
| 542 | { | 
|---|
| 543 | Console.Error.WriteLine("Building octtree for {0} polygons...", source.Polygons.Count); | 
|---|
| 544 |  | 
|---|
| 545 | var root = OctreeBuilder.Build(source, debug); | 
|---|
| 546 |  | 
|---|
| 547 | var nodeList = new List<OctreeNode>(); | 
|---|
| 548 | var leafList = new List<OctreeNode>(); | 
|---|
| 549 | int quadListLength = 0; | 
|---|
| 550 | int roomListLength = 0; | 
|---|
| 551 |  | 
|---|
| 552 | // | 
|---|
| 553 | // Assign indices to nodes/leafs and compute the length of the quad and room indexes. | 
|---|
| 554 | // | 
|---|
| 555 |  | 
|---|
| 556 | root.DfsTraversal(node => { | 
|---|
| 557 | if (node.IsLeaf) | 
|---|
| 558 | { | 
|---|
| 559 | node.Index = leafList.Count; | 
|---|
| 560 | leafList.Add(node); | 
|---|
| 561 | quadListLength += node.Polygons.Count; | 
|---|
| 562 | roomListLength += node.Rooms.Count; | 
|---|
| 563 | } | 
|---|
| 564 | else | 
|---|
| 565 | { | 
|---|
| 566 | node.Index = nodeList.Count; | 
|---|
| 567 | nodeList.Add(node); | 
|---|
| 568 | } | 
|---|
| 569 | }); | 
|---|
| 570 |  | 
|---|
| 571 | // | 
|---|
| 572 | // Create the octtree data structure that will be written to the file. | 
|---|
| 573 | // | 
|---|
| 574 |  | 
|---|
| 575 | octree = new DatOctree { | 
|---|
| 576 | Nodes = new int[nodeList.Count * OctreeNode.ChildCount], | 
|---|
| 577 | Adjacency = new int[leafList.Count * OctreeNode.FaceCount], | 
|---|
| 578 | BoundingBoxes = new DatOctreeBoundingBox[leafList.Count], | 
|---|
| 579 | PolygonIndex = new int[quadListLength], | 
|---|
| 580 | PolygonLists = new DatOctreePolygonRange[leafList.Count], | 
|---|
| 581 | BnvLists = new DatOctreeBnvRange[leafList.Count], | 
|---|
| 582 | BnvIndex = new int[roomListLength] | 
|---|
| 583 | }; | 
|---|
| 584 |  | 
|---|
| 585 | Console.WriteLine("Octtree: {0} interior nodes, {1} leafs", nodeList.Count, leafList.Count); | 
|---|
| 586 |  | 
|---|
| 587 | // | 
|---|
| 588 | // Populate the node array. | 
|---|
| 589 | // The octree builder stores child nodes in a different order than Oni (by mistake) | 
|---|
| 590 | // | 
|---|
| 591 |  | 
|---|
| 592 | var interiorNodeIndexRemap = new int[] { 0, 4, 2, 6, 1, 5, 3, 7 }; | 
|---|
| 593 | var datOcttree = octree; | 
|---|
| 594 |  | 
|---|
| 595 | foreach (var node in nodeList) | 
|---|
| 596 | { | 
|---|
| 597 | int i = node.Index * OctreeNode.ChildCount; | 
|---|
| 598 |  | 
|---|
| 599 | for (int j = 0; j < OctreeNode.ChildCount; j++) | 
|---|
| 600 | { | 
|---|
| 601 | var child = node.Children[j]; | 
|---|
| 602 | int k = interiorNodeIndexRemap[j]; | 
|---|
| 603 |  | 
|---|
| 604 | if (child.IsLeaf) | 
|---|
| 605 | datOcttree.Nodes[i + k] = child.Index | int.MinValue; | 
|---|
| 606 | else | 
|---|
| 607 | datOcttree.Nodes[i + k] = child.Index; | 
|---|
| 608 | } | 
|---|
| 609 | } | 
|---|
| 610 |  | 
|---|
| 611 | // | 
|---|
| 612 | // Generate the data needed by the leafs: bounding box, quad range and room range. | 
|---|
| 613 | // | 
|---|
| 614 |  | 
|---|
| 615 | int quadListIndex = 0; | 
|---|
| 616 | int bnvListIndex = 0; | 
|---|
| 617 |  | 
|---|
| 618 | foreach (var leaf in leafList) | 
|---|
| 619 | { | 
|---|
| 620 | datOcttree.BoundingBoxes[leaf.Index] = new DatOctreeBoundingBox(leaf.BoundingBox); | 
|---|
| 621 |  | 
|---|
| 622 | if (leaf.Polygons.Count > 0) | 
|---|
| 623 | { | 
|---|
| 624 | datOcttree.PolygonLists[leaf.Index] = new DatOctreePolygonRange(quadListIndex, leaf.Polygons.Count); | 
|---|
| 625 |  | 
|---|
| 626 | foreach (var polygon in leaf.Polygons) | 
|---|
| 627 | datOcttree.PolygonIndex[quadListIndex++] = polygonMap[polygon].Index; | 
|---|
| 628 | } | 
|---|
| 629 |  | 
|---|
| 630 | if (leaf.Rooms.Count > 0) | 
|---|
| 631 | { | 
|---|
| 632 | datOcttree.BnvLists[leaf.Index] = new DatOctreeBnvRange(bnvListIndex, leaf.Rooms.Count); | 
|---|
| 633 |  | 
|---|
| 634 | foreach (var room in leaf.Rooms) | 
|---|
| 635 | datOcttree.BnvIndex[bnvListIndex++] = roomMap[room].Index; | 
|---|
| 636 | } | 
|---|
| 637 | } | 
|---|
| 638 |  | 
|---|
| 639 | // | 
|---|
| 640 | // Generate the quad trees. Note that the octtree builder doesn't build quad trees because | 
|---|
| 641 | // they're only needed when writing the octtree to the file. Currently OniSplit doesn't use | 
|---|
| 642 | // the octtree for raycasting. | 
|---|
| 643 | // | 
|---|
| 644 |  | 
|---|
| 645 | var quadTrees = new List<int>(); | 
|---|
| 646 |  | 
|---|
| 647 | foreach (var leaf in leafList) | 
|---|
| 648 | { | 
|---|
| 649 | leaf.RefineAdjacency(); | 
|---|
| 650 |  | 
|---|
| 651 | foreach (var face in OctreeNode.Face.All) | 
|---|
| 652 | { | 
|---|
| 653 | var adjacentLeaf = leaf.Adjacency[face.Index]; | 
|---|
| 654 | int index = leaf.Index * OctreeNode.FaceCount + face.Index; | 
|---|
| 655 |  | 
|---|
| 656 | if (adjacentLeaf == null) | 
|---|
| 657 | { | 
|---|
| 658 | // | 
|---|
| 659 | // There's no adjacent node or leaf, this should only happen | 
|---|
| 660 | // on the edges of the octtree. | 
|---|
| 661 | // | 
|---|
| 662 |  | 
|---|
| 663 | datOcttree.Adjacency[index] = -1; | 
|---|
| 664 | } | 
|---|
| 665 | else if (adjacentLeaf.IsLeaf) | 
|---|
| 666 | { | 
|---|
| 667 | // | 
|---|
| 668 | // The adjacent node is a leaf, there's no need for a quad tree. | 
|---|
| 669 | // | 
|---|
| 670 |  | 
|---|
| 671 | datOcttree.Adjacency[index] = adjacentLeaf.Index | int.MinValue; | 
|---|
| 672 | } | 
|---|
| 673 | else | 
|---|
| 674 | { | 
|---|
| 675 | // | 
|---|
| 676 | // The adjacent node has children, a quad tree needs to be built. | 
|---|
| 677 | // | 
|---|
| 678 |  | 
|---|
| 679 | int quadTreeBaseIndex = quadTrees.Count / 4; | 
|---|
| 680 | datOcttree.Adjacency[index] = quadTreeBaseIndex; | 
|---|
| 681 |  | 
|---|
| 682 | var quadTreeRoot = leaf.BuildFaceQuadTree(face); | 
|---|
| 683 |  | 
|---|
| 684 | foreach (var node in quadTreeRoot.GetDfsList()) | 
|---|
| 685 | { | 
|---|
| 686 | for (int i = 0; i < 4; i++) | 
|---|
| 687 | { | 
|---|
| 688 | if (node.Nodes[i] != null) | 
|---|
| 689 | quadTrees.Add(quadTreeBaseIndex + node.Nodes[i].Index); | 
|---|
| 690 | else | 
|---|
| 691 | quadTrees.Add(node.Leafs[i].Index | int.MinValue); | 
|---|
| 692 | } | 
|---|
| 693 | } | 
|---|
| 694 | } | 
|---|
| 695 | } | 
|---|
| 696 | } | 
|---|
| 697 |  | 
|---|
| 698 | datOcttree.QuadTrees = quadTrees.ToArray(); | 
|---|
| 699 | } | 
|---|
| 700 |  | 
|---|
| 701 | private void WriteAKEV() | 
|---|
| 702 | { | 
|---|
| 703 | var akev = importer.CreateInstance(TemplateTag.AKEV, name); | 
|---|
| 704 | var pnta = importer.CreateInstance(TemplateTag.PNTA); | 
|---|
| 705 | var plea = importer.CreateInstance(TemplateTag.PLEA); | 
|---|
| 706 | var txca = importer.CreateInstance(TemplateTag.TXCA); | 
|---|
| 707 | var agqg = importer.CreateInstance(TemplateTag.AGQG); | 
|---|
| 708 | var agqr = importer.CreateInstance(TemplateTag.AGQR); | 
|---|
| 709 | var agqc = importer.CreateInstance(TemplateTag.AGQC); | 
|---|
| 710 | var agdb = importer.CreateInstance(TemplateTag.AGDB); | 
|---|
| 711 | var txma = importer.CreateInstance(TemplateTag.TXMA); | 
|---|
| 712 | var akva = importer.CreateInstance(TemplateTag.AKVA); | 
|---|
| 713 | var akba = importer.CreateInstance(TemplateTag.AKBA); | 
|---|
| 714 | var idxa1 = importer.CreateInstance(TemplateTag.IDXA); | 
|---|
| 715 | var idxa2 = importer.CreateInstance(TemplateTag.IDXA); | 
|---|
| 716 | var akbp = importer.CreateInstance(TemplateTag.AKBP); | 
|---|
| 717 | var abna = importer.CreateInstance(TemplateTag.ABNA); | 
|---|
| 718 | var akot = importer.CreateInstance(TemplateTag.AKOT); | 
|---|
| 719 | var akaa = importer.CreateInstance(TemplateTag.AKAA); | 
|---|
| 720 | var akda = importer.CreateInstance(TemplateTag.AKDA); | 
|---|
| 721 |  | 
|---|
| 722 | using (var writer = akev.OpenWrite()) | 
|---|
| 723 | { | 
|---|
| 724 | writer.Write(pnta); | 
|---|
| 725 | writer.Write(plea); | 
|---|
| 726 | writer.Write(txca); | 
|---|
| 727 | writer.Write(agqg); | 
|---|
| 728 | writer.Write(agqr); | 
|---|
| 729 | writer.Write(agqc); | 
|---|
| 730 | writer.Write(agdb); | 
|---|
| 731 | writer.Write(txma); | 
|---|
| 732 | writer.Write(akva); | 
|---|
| 733 | writer.Write(akba); | 
|---|
| 734 | writer.Write(idxa1); | 
|---|
| 735 | writer.Write(idxa2); | 
|---|
| 736 | writer.Write(akbp); | 
|---|
| 737 | writer.Write(abna); | 
|---|
| 738 | writer.Write(akot); | 
|---|
| 739 | writer.Write(akaa); | 
|---|
| 740 | writer.Write(akda); | 
|---|
| 741 | writer.Write(source.GetBoundingBox()); | 
|---|
| 742 | writer.Skip(24); | 
|---|
| 743 | writer.Write(12.0f); | 
|---|
| 744 | } | 
|---|
| 745 |  | 
|---|
| 746 | pnta.WritePoints(points); | 
|---|
| 747 | plea.WritePlanes(planes); | 
|---|
| 748 | txca.WriteTexCoords(texCoords); | 
|---|
| 749 | WriteAGQG(agqg); | 
|---|
| 750 | WriteAGQR(agqr); | 
|---|
| 751 | WriteAGQC(agqc); | 
|---|
| 752 | WriteTXMA(txma); | 
|---|
| 753 | WriteAKVA(akva); | 
|---|
| 754 | WriteAKBA(akba); | 
|---|
| 755 | WriteAKBP(akbp); | 
|---|
| 756 | WriteABNA(abna); | 
|---|
| 757 | WriteAKOT(akot); | 
|---|
| 758 | WriteAKAA(akaa); | 
|---|
| 759 | WriteAKDA(akda); | 
|---|
| 760 | WriteScriptIds(idxa1, idxa2); | 
|---|
| 761 | WriteAGDB(agdb); | 
|---|
| 762 | } | 
|---|
| 763 |  | 
|---|
| 764 | private void WriteAGQG(ImporterDescriptor descriptor) | 
|---|
| 765 | { | 
|---|
| 766 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 767 | { | 
|---|
| 768 | writer.Write(polygons.Count); | 
|---|
| 769 |  | 
|---|
| 770 | foreach (var polygon in polygons) | 
|---|
| 771 | { | 
|---|
| 772 | writer.Write(polygon.PointIndices); | 
|---|
| 773 | writer.Write(polygon.TexCoordIndices); | 
|---|
| 774 | writer.Write(polygon.Colors); | 
|---|
| 775 | writer.Write((uint)polygon.Flags); | 
|---|
| 776 | writer.Write(polygon.ObjectId); | 
|---|
| 777 | } | 
|---|
| 778 | } | 
|---|
| 779 | } | 
|---|
| 780 |  | 
|---|
| 781 | private void WriteAGQC(ImporterDescriptor descriptor) | 
|---|
| 782 | { | 
|---|
| 783 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 784 | { | 
|---|
| 785 | writer.Write(polygons.Count); | 
|---|
| 786 |  | 
|---|
| 787 | foreach (var polygon in polygons) | 
|---|
| 788 | { | 
|---|
| 789 | writer.Write(polygon.PlaneIndex); | 
|---|
| 790 | writer.Write(polygon.Source.BoundingBox); | 
|---|
| 791 | } | 
|---|
| 792 | } | 
|---|
| 793 | } | 
|---|
| 794 |  | 
|---|
| 795 | private void WriteAGQR(ImporterDescriptor descriptor) | 
|---|
| 796 | { | 
|---|
| 797 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 798 | { | 
|---|
| 799 | writer.Write(polygons.Count); | 
|---|
| 800 |  | 
|---|
| 801 | foreach (var polygon in polygons) | 
|---|
| 802 | { | 
|---|
| 803 | writer.Write(polygon.MaterialIndex); | 
|---|
| 804 | } | 
|---|
| 805 | } | 
|---|
| 806 | } | 
|---|
| 807 |  | 
|---|
| 808 | private void WriteTXMA(ImporterDescriptor descriptor) | 
|---|
| 809 | { | 
|---|
| 810 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 811 | { | 
|---|
| 812 | writer.Write(materials.Count); | 
|---|
| 813 |  | 
|---|
| 814 | foreach (var material in materials) | 
|---|
| 815 | { | 
|---|
| 816 | writer.Write(importer.CreateInstance(TemplateTag.TXMP, material.Name)); | 
|---|
| 817 | } | 
|---|
| 818 | } | 
|---|
| 819 | } | 
|---|
| 820 |  | 
|---|
| 821 | private void WriteABNA(ImporterDescriptor descriptor) | 
|---|
| 822 | { | 
|---|
| 823 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 824 | { | 
|---|
| 825 | writer.Write(alphaBspNodes.Count); | 
|---|
| 826 |  | 
|---|
| 827 | foreach (var node in alphaBspNodes) | 
|---|
| 828 | { | 
|---|
| 829 | writer.Write(node.PolygonIndex); | 
|---|
| 830 | writer.Write(node.PlaneIndex); | 
|---|
| 831 | writer.Write(node.FrontChildIndex); | 
|---|
| 832 | writer.Write(node.BackChildIndex); | 
|---|
| 833 | } | 
|---|
| 834 | } | 
|---|
| 835 | } | 
|---|
| 836 |  | 
|---|
| 837 | private void WriteAKVA(ImporterDescriptor descriptor) | 
|---|
| 838 | { | 
|---|
| 839 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 840 | { | 
|---|
| 841 | writer.Write(rooms.Count); | 
|---|
| 842 |  | 
|---|
| 843 | foreach (var room in rooms) | 
|---|
| 844 | { | 
|---|
| 845 | writer.Write(room.BspTreeIndex); | 
|---|
| 846 | writer.Write(room.Index); | 
|---|
| 847 | writer.Write(room.SideListStart); | 
|---|
| 848 | writer.Write(room.SideListEnd); | 
|---|
| 849 | writer.Write(room.ChildIndex); | 
|---|
| 850 | writer.Write(room.SiblingIndex); | 
|---|
| 851 | writer.Skip(4); | 
|---|
| 852 | writer.Write(room.Source.Grid.XTiles); | 
|---|
| 853 | writer.Write(room.Source.Grid.ZTiles); | 
|---|
| 854 | writer.Write(importer.WriteRawPart(room.CompressedGridData)); | 
|---|
| 855 | writer.Write(room.CompressedGridData.Length); | 
|---|
| 856 | writer.Write(room.Source.Grid.TileSize); | 
|---|
| 857 | writer.Write(room.Source.BoundingBox); | 
|---|
| 858 | writer.WriteInt16(room.Source.Grid.XOrigin); | 
|---|
| 859 | writer.WriteInt16(room.Source.Grid.ZOrigin); | 
|---|
| 860 | writer.Write(room.Index); | 
|---|
| 861 | writer.Skip(4); | 
|---|
| 862 |  | 
|---|
| 863 | if (room.DebugData != null) | 
|---|
| 864 | { | 
|---|
| 865 | writer.Write(room.DebugData.Length); | 
|---|
| 866 | writer.Write(importer.WriteRawPart(room.DebugData)); | 
|---|
| 867 | } | 
|---|
| 868 | else | 
|---|
| 869 | { | 
|---|
| 870 | writer.Write(0); | 
|---|
| 871 | writer.Write(0); | 
|---|
| 872 | } | 
|---|
| 873 |  | 
|---|
| 874 | writer.Write(room.Flags); | 
|---|
| 875 | writer.Write(room.Source.FloorPlane); | 
|---|
| 876 | writer.Write(room.Source.Height); | 
|---|
| 877 | } | 
|---|
| 878 | } | 
|---|
| 879 | } | 
|---|
| 880 |  | 
|---|
| 881 | private void WriteAKBA(ImporterDescriptor descriptor) | 
|---|
| 882 | { | 
|---|
| 883 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 884 | { | 
|---|
| 885 | writer.Write(roomSides.Count); | 
|---|
| 886 |  | 
|---|
| 887 | foreach (var side in roomSides) | 
|---|
| 888 | { | 
|---|
| 889 | writer.Write(0); | 
|---|
| 890 | writer.Write(side.AdjacencyListStart); | 
|---|
| 891 | writer.Write(side.AdjacencyListEnd); | 
|---|
| 892 | writer.Skip(16); | 
|---|
| 893 | } | 
|---|
| 894 | } | 
|---|
| 895 | } | 
|---|
| 896 |  | 
|---|
| 897 | private void WriteAKBP(ImporterDescriptor descriptor) | 
|---|
| 898 | { | 
|---|
| 899 | using (var writer = descriptor.OpenWrite(22)) | 
|---|
| 900 | { | 
|---|
| 901 | writer.WriteUInt16(roomBspNodes.Count); | 
|---|
| 902 |  | 
|---|
| 903 | foreach (var node in roomBspNodes) | 
|---|
| 904 | { | 
|---|
| 905 | writer.Write(node.PlaneIndex); | 
|---|
| 906 | writer.Write(node.BackChildIndex); | 
|---|
| 907 | writer.Write(node.FrontChildIndex); | 
|---|
| 908 | } | 
|---|
| 909 | } | 
|---|
| 910 | } | 
|---|
| 911 |  | 
|---|
| 912 | private void WriteAKAA(ImporterDescriptor descriptor) | 
|---|
| 913 | { | 
|---|
| 914 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 915 | { | 
|---|
| 916 | writer.Write(roomAdjacencies.Count); | 
|---|
| 917 |  | 
|---|
| 918 | foreach (var adjacency in roomAdjacencies) | 
|---|
| 919 | { | 
|---|
| 920 | writer.Write(adjacency.AdjacentRoomIndex); | 
|---|
| 921 | writer.Write(adjacency.GhostIndex); | 
|---|
| 922 | writer.Write(0); | 
|---|
| 923 | } | 
|---|
| 924 | } | 
|---|
| 925 | } | 
|---|
| 926 |  | 
|---|
| 927 | private void WriteAKDA(ImporterDescriptor descriptor) | 
|---|
| 928 | { | 
|---|
| 929 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 930 | { | 
|---|
| 931 | writer.Write(0); | 
|---|
| 932 | } | 
|---|
| 933 | } | 
|---|
| 934 |  | 
|---|
| 935 | private void WriteAKOT(ImporterDescriptor akot) | 
|---|
| 936 | { | 
|---|
| 937 | var otit = importer.CreateInstance(TemplateTag.OTIT); | 
|---|
| 938 | var otlf = importer.CreateInstance(TemplateTag.OTLF); | 
|---|
| 939 | var qtna = importer.CreateInstance(TemplateTag.QTNA); | 
|---|
| 940 | var idxa1 = importer.CreateInstance(TemplateTag.IDXA); | 
|---|
| 941 | var idxa2 = importer.CreateInstance(TemplateTag.IDXA); | 
|---|
| 942 |  | 
|---|
| 943 | using (var writer = akot.OpenWrite()) | 
|---|
| 944 | { | 
|---|
| 945 | writer.Write(otit); | 
|---|
| 946 | writer.Write(otlf); | 
|---|
| 947 | writer.Write(qtna); | 
|---|
| 948 | writer.Write(idxa1); | 
|---|
| 949 | writer.Write(idxa2); | 
|---|
| 950 | } | 
|---|
| 951 |  | 
|---|
| 952 | WriteOTIT(otit); | 
|---|
| 953 | WriteOTLF(otlf); | 
|---|
| 954 | WriteQTNA(qtna); | 
|---|
| 955 |  | 
|---|
| 956 | idxa1.WriteIndices(octree.PolygonIndex); | 
|---|
| 957 | idxa2.WriteIndices(octree.BnvIndex); | 
|---|
| 958 | } | 
|---|
| 959 |  | 
|---|
| 960 | private void WriteOTIT(ImporterDescriptor descriptor) | 
|---|
| 961 | { | 
|---|
| 962 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 963 | { | 
|---|
| 964 | writer.Write(octree.Nodes.Length / OctreeNode.ChildCount); | 
|---|
| 965 | writer.Write(octree.Nodes); | 
|---|
| 966 | } | 
|---|
| 967 | } | 
|---|
| 968 |  | 
|---|
| 969 | private void WriteOTLF(ImporterDescriptor descriptor) | 
|---|
| 970 | { | 
|---|
| 971 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 972 | { | 
|---|
| 973 | writer.Write(octree.BoundingBoxes.Length); | 
|---|
| 974 |  | 
|---|
| 975 | for (int i = 0; i < octree.BoundingBoxes.Length; i++) | 
|---|
| 976 | { | 
|---|
| 977 | writer.Write(octree.PolygonLists[i].PackedValue); | 
|---|
| 978 | writer.Write(octree.Adjacency, i * OctreeNode.FaceCount, OctreeNode.FaceCount); | 
|---|
| 979 | writer.Write(octree.BoundingBoxes[i].PackedValue); | 
|---|
| 980 | writer.Write(octree.BnvLists[i].PackedValue); | 
|---|
| 981 | } | 
|---|
| 982 | } | 
|---|
| 983 | } | 
|---|
| 984 |  | 
|---|
| 985 | private void WriteQTNA(ImporterDescriptor descriptor) | 
|---|
| 986 | { | 
|---|
| 987 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 988 | { | 
|---|
| 989 | writer.Write(octree.QuadTrees.Length / 4); | 
|---|
| 990 | writer.Write(octree.QuadTrees); | 
|---|
| 991 | } | 
|---|
| 992 | } | 
|---|
| 993 |  | 
|---|
| 994 | private void WriteScriptIds(ImporterDescriptor idxa1, ImporterDescriptor idxa2) | 
|---|
| 995 | { | 
|---|
| 996 | var scriptIdMap = new List<KeyValuePair<int, int>>(256); | 
|---|
| 997 |  | 
|---|
| 998 | foreach (var polygon in polygons) | 
|---|
| 999 | { | 
|---|
| 1000 | if (polygon.ScriptId != 0) | 
|---|
| 1001 | scriptIdMap.Add(new KeyValuePair<int, int>(polygon.ScriptId, polygon.Index)); | 
|---|
| 1002 | } | 
|---|
| 1003 |  | 
|---|
| 1004 | scriptIdMap.Sort((x, y) => x.Key.CompareTo(y.Key)); | 
|---|
| 1005 |  | 
|---|
| 1006 | var scriptIds = new int[scriptIdMap.Count]; | 
|---|
| 1007 | var polygonIndices = new int[scriptIdMap.Count]; | 
|---|
| 1008 |  | 
|---|
| 1009 | for (int i = 0; i < scriptIdMap.Count; i++) | 
|---|
| 1010 | { | 
|---|
| 1011 | scriptIds[i] = scriptIdMap[i].Key; | 
|---|
| 1012 | polygonIndices[i] = scriptIdMap[i].Value; | 
|---|
| 1013 | } | 
|---|
| 1014 |  | 
|---|
| 1015 | idxa1.WriteIndices(polygonIndices); | 
|---|
| 1016 | idxa2.WriteIndices(scriptIds); | 
|---|
| 1017 | } | 
|---|
| 1018 |  | 
|---|
| 1019 | private void WriteAGDB(ImporterDescriptor descriptor) | 
|---|
| 1020 | { | 
|---|
| 1021 | if (!debug) | 
|---|
| 1022 | { | 
|---|
| 1023 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 1024 | { | 
|---|
| 1025 | writer.Write(0); | 
|---|
| 1026 | } | 
|---|
| 1027 |  | 
|---|
| 1028 | return; | 
|---|
| 1029 | } | 
|---|
| 1030 |  | 
|---|
| 1031 | var objectNames = new Dictionary<string, int>(polygons.Count, StringComparer.Ordinal); | 
|---|
| 1032 | var fileNames = new Dictionary<string, int>(polygons.Count, StringComparer.Ordinal); | 
|---|
| 1033 |  | 
|---|
| 1034 | using (var writer = descriptor.OpenWrite(20)) | 
|---|
| 1035 | { | 
|---|
| 1036 | writer.Write(polygons.Count); | 
|---|
| 1037 |  | 
|---|
| 1038 | foreach (var polygon in polygons) | 
|---|
| 1039 | { | 
|---|
| 1040 | var objectName = polygon.Source.ObjectName; | 
|---|
| 1041 | var fileName = polygon.Source.FileName; | 
|---|
| 1042 |  | 
|---|
| 1043 | if (string.IsNullOrEmpty(objectName)) | 
|---|
| 1044 | objectName = "(none)"; | 
|---|
| 1045 |  | 
|---|
| 1046 | if (string.IsNullOrEmpty(fileName)) | 
|---|
| 1047 | fileName = "(none)"; | 
|---|
| 1048 |  | 
|---|
| 1049 | int objectOffset; | 
|---|
| 1050 | int fileOffset; | 
|---|
| 1051 |  | 
|---|
| 1052 | if (!objectNames.TryGetValue(objectName, out objectOffset)) | 
|---|
| 1053 | { | 
|---|
| 1054 | objectOffset = importer.WriteRawPart(objectName); | 
|---|
| 1055 | objectNames.Add(objectName, objectOffset); | 
|---|
| 1056 | } | 
|---|
| 1057 |  | 
|---|
| 1058 | if (!fileNames.TryGetValue(fileName, out fileOffset)) | 
|---|
| 1059 | { | 
|---|
| 1060 | fileOffset = importer.WriteRawPart(fileName); | 
|---|
| 1061 | fileNames.Add(fileName, fileOffset); | 
|---|
| 1062 | } | 
|---|
| 1063 |  | 
|---|
| 1064 | writer.Write(objectOffset); | 
|---|
| 1065 | writer.Write(fileOffset); | 
|---|
| 1066 | } | 
|---|
| 1067 | } | 
|---|
| 1068 | } | 
|---|
| 1069 | } | 
|---|
| 1070 | } | 
|---|