source: OniSplit/Akira/AkiraDatReader.cs@ 1171

Last change on this file since 1171 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 17.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using Oni.Imaging;
5using Oni.Motoko;
6
7namespace Oni.Akira
8{
9 internal class AkiraDatReader
10 {
11 #region Private data
12 private InstanceDescriptor akev;
13 private InstanceDescriptor agdb;
14 private InstanceDescriptor pnta;
15 private InstanceDescriptor plea;
16 private InstanceDescriptor txca;
17 private InstanceDescriptor agqg;
18 private InstanceDescriptor agqc;
19 private InstanceDescriptor agqr;
20 private InstanceDescriptor txma;
21 private InstanceDescriptor akva;
22 private InstanceDescriptor akba;
23 private InstanceDescriptor idxa1;
24 private InstanceDescriptor idxa2;
25 private InstanceDescriptor akbp;
26 private InstanceDescriptor akaa;
27
28 private PolygonMesh mesh;
29 private Plane[] planes;
30 private Polygon[] polygons;
31 #endregion
32
33 #region private class DatRoom
34
35 private class DatRoom
36 {
37 public readonly int BspRootIndex;
38 public readonly int SideListStart;
39 public readonly int SideListEnd;
40 public readonly int ChildIndex;
41 public readonly int SiblingIndex;
42 public readonly int XTiles;
43 public readonly int ZTiles;
44 public readonly BoundingBox BoundingBox;
45 public readonly float TileSize;
46 public readonly int XOrigin;
47 public readonly int ZOrigin;
48 public readonly RoomFlags Flags;
49 public readonly Plane Floor;
50 public readonly float Height;
51 public readonly byte[] CompressedGridData;
52
53 public DatRoom(InstanceDescriptor descriptor, BinaryReader reader)
54 {
55 BspRootIndex = reader.ReadInt32();
56 reader.Skip(4);
57 SideListStart = reader.ReadInt32();
58 SideListEnd = reader.ReadInt32();
59 ChildIndex = reader.ReadInt32();
60 SiblingIndex = reader.ReadInt32();
61 reader.Skip(4);
62 XTiles = reader.ReadInt32();
63 ZTiles = reader.ReadInt32();
64 int ofsGridData = reader.ReadInt32();
65 int lenGridData = reader.ReadInt32();
66 TileSize = reader.ReadSingle();
67 BoundingBox = reader.ReadBoundingBox();
68 XOrigin = reader.ReadInt16();
69 ZOrigin = reader.ReadInt16();
70 reader.Skip(16);
71 Flags = (RoomFlags)reader.ReadInt32();
72 Floor = reader.ReadPlane();
73 Height = reader.ReadSingle();
74
75 if (ofsGridData != 0 && lenGridData != 0)
76 {
77 using (BinaryReader rawReader = descriptor.GetRawReader(ofsGridData))
78 CompressedGridData = rawReader.ReadBytes(lenGridData);
79 }
80 }
81 }
82
83 #endregion
84 #region private class DatRoomBspNode
85
86 private class DatRoomBspNode
87 {
88 public readonly int PlaneIndex;
89 public readonly int FrontChildIndex;
90 public readonly int BackChildIndex;
91
92 public DatRoomBspNode(BinaryReader reader)
93 {
94 PlaneIndex = reader.ReadInt32();
95 BackChildIndex = reader.ReadInt32();
96 FrontChildIndex = reader.ReadInt32();
97 }
98 }
99
100 #endregion
101 #region private class DatRoomSide
102
103 private class DatRoomSide
104 {
105 public readonly int SideListStart;
106 public readonly int SideListEnd;
107
108 public DatRoomSide(BinaryReader reader)
109 {
110 reader.Skip(4);
111 SideListStart = reader.ReadInt32();
112 SideListEnd = reader.ReadInt32();
113 reader.Skip(16);
114 }
115 }
116
117 #endregion
118 #region private class DatRoomAdjacency
119
120 private class DatRoomAdjacency
121 {
122 public readonly int RoomIndex;
123 public readonly int QuadIndex;
124
125 public DatRoomAdjacency(BinaryReader reader)
126 {
127 RoomIndex = reader.ReadInt32();
128 QuadIndex = reader.ReadInt32();
129 reader.Skip(4);
130 }
131 }
132
133 #endregion
134
135 public static PolygonMesh Read(InstanceDescriptor akev)
136 {
137 var reader = new AkiraDatReader
138 {
139 akev = akev,
140 mesh = new PolygonMesh(new MaterialLibrary())
141 };
142
143 reader.Read();
144 return reader.mesh;
145 }
146
147 private void Read()
148 {
149 using (var reader = akev.OpenRead())
150 {
151 pnta = reader.ReadInstance();
152 plea = reader.ReadInstance();
153 txca = reader.ReadInstance();
154 agqg = reader.ReadInstance();
155 agqr = reader.ReadInstance();
156 agqc = reader.ReadInstance();
157 agdb = reader.ReadInstance();
158 txma = reader.ReadInstance();
159 akva = reader.ReadInstance();
160 akba = reader.ReadInstance();
161 idxa1 = reader.ReadInstance();
162 idxa2 = reader.ReadInstance();
163 akbp = reader.ReadInstance();
164 reader.Skip(8);
165 akaa = reader.ReadInstance();
166 }
167
168 ReadGeometry();
169 ReadDebugInfo();
170 ReadMaterials();
171 ReadScriptIndices();
172 ReadRooms();
173 }
174
175 private void ReadGeometry()
176 {
177 int[] planeIndices;
178
179 using (var reader = pnta.OpenRead(52))
180 mesh.Points.AddRange(reader.ReadVector3VarArray());
181
182 using (var reader = txca.OpenRead(20))
183 mesh.TexCoords.AddRange(reader.ReadVector2VarArray());
184
185 using (var reader = plea.OpenRead(20))
186 planes = reader.ReadPlaneVarArray();
187
188 using (var reader = agqc.OpenRead(20))
189 {
190 planeIndices = new int[reader.ReadInt32()];
191
192 for (int i = 0; i < planeIndices.Length; i++)
193 {
194 planeIndices[i] = reader.ReadInt32();
195
196 //
197 // Ignore bounding boxes, we don't need them
198 //
199
200 reader.Skip(24);
201 }
202 }
203
204 using (var reader = agqg.OpenRead(20))
205 {
206 polygons = new Polygon[reader.ReadInt32()];
207
208 for (int i = 0; i < polygons.Length; i++)
209 {
210 var pointIndices = reader.ReadInt32Array(4);
211 var texCoordIndices = reader.ReadInt32Array(4);
212 var colors = reader.ReadColorArray(4);
213 var flags = (GunkFlags)reader.ReadInt32();
214 int objectId = reader.ReadInt32();
215
216 if ((flags & GunkFlags.Triangle) != 0)
217 {
218 Array.Resize(ref pointIndices, 3);
219 Array.Resize(ref texCoordIndices, 3);
220 Array.Resize(ref colors, 3);
221
222 flags &= ~GunkFlags.Triangle;
223 }
224
225 var polygon = new Polygon(mesh, pointIndices, PlaneFromIndex(planeIndices[i]))
226 {
227 Flags = flags & ~GunkFlags.Transparent,
228 TexCoordIndices = texCoordIndices,
229 Colors = colors
230 };
231
232 if (objectId == -1)
233 {
234 polygon.ObjectType = -1;
235 polygon.ObjectId = -1;
236 }
237 else
238 {
239 polygon.ObjectType = (objectId >> 24) & 0xff;
240 polygon.ObjectId = objectId & 0xffffff;
241 }
242
243 polygons[i] = polygon;
244 }
245 }
246
247 foreach (var polygon in polygons)
248 {
249 if ((polygon.Flags & (GunkFlags.Ghost | GunkFlags.StairsUp | GunkFlags.StairsDown)) != 0)
250 mesh.Ghosts.Add(polygon);
251 else
252 mesh.Polygons.Add(polygon);
253 }
254 }
255
256 private Plane PlaneFromIndex(int index)
257 {
258 var plane = planes[index & int.MaxValue];
259
260 if (index < 0)
261 {
262 plane.Normal = -plane.Normal;
263 plane.D = -plane.D;
264 }
265
266 return plane;
267 }
268
269 private void ReadMaterials()
270 {
271 //
272 // Read material list from TXMA
273 //
274
275 Material[] materials;
276
277 using (var reader = txma.OpenRead(20))
278 {
279 materials = new Material[reader.ReadInt32()];
280
281 for (int i = 0; i < materials.Length; i++)
282 {
283 var texture = reader.ReadInstance();
284
285 if (texture == null)
286 continue;
287
288 var material = mesh.Materials.GetMaterial(Utils.CleanupTextureName(texture.Name));
289 material.Image = TextureDatReader.Read(texture).Surfaces[0];
290
291 if (material.Image.HasAlpha)
292 material.Flags |= GunkFlags.Transparent;
293
294 materials[i] = material;
295 }
296 }
297
298 //
299 // Assign materials to polygons based on AGQR
300 //
301
302 using (var reader = agqr.OpenRead(20))
303 {
304 int count = reader.ReadInt32();
305
306 for (int i = 0; i < count; i++)
307 polygons[i].Material = materials[reader.ReadInt32() & 0xffff];
308 }
309
310 //
311 // Assign special materials: danger, stairs etc.
312 //
313
314 foreach (var polygon in polygons)
315 {
316 var marker = mesh.Materials.Markers.GetMarker(polygon);
317
318 if (marker != null)
319 polygon.Material = marker;
320 }
321 }
322
323 private void ReadScriptIndices()
324 {
325 if (idxa1 == null || idxa2 == null)
326 return;
327
328 int[] scriptQuadIndices;
329 int[] scriptIds;
330
331 using (var reader = idxa1.OpenRead(20))
332 scriptQuadIndices = reader.ReadInt32VarArray();
333
334 using (var reader = idxa2.OpenRead(20))
335 scriptIds = reader.ReadInt32VarArray();
336
337 for (int i = 0; i < scriptQuadIndices.Length; i++)
338 polygons[scriptQuadIndices[i]].ScriptId = scriptIds[i];
339 }
340
341 private void ReadDebugInfo()
342 {
343 if (agdb == null)
344 {
345 var debugFileName = "AGDB" + akev.Name + ".oni";
346 var debugFilePath = Path.Combine(Path.GetDirectoryName(akev.File.FilePath), debugFileName);
347
348 if (!File.Exists(debugFilePath))
349 return;
350
351 Console.WriteLine(debugFilePath);
352
353 var debugFile = akev.File.FileManager.OpenFile(debugFilePath);
354
355 if (debugFile == null)
356 return;
357
358 agdb = debugFile.Descriptors[0];
359 }
360
361 if (agdb == null || agdb.Template.Tag != TemplateTag.AGDB)
362 return;
363
364 using (var reader = agdb.OpenRead(20))
365 {
366 int count = reader.ReadInt32();
367
368 var fileNames = new Dictionary<int, string>();
369 var objectNames = new Dictionary<int, string>();
370
371 for (int i = 0; i < count; i++)
372 {
373 int objectNameOffset = reader.ReadInt32();
374 string objectName;
375
376 if (!objectNames.TryGetValue(objectNameOffset, out objectName))
377 {
378 using (var rawReader = agdb.GetRawReader(objectNameOffset))
379 objectName = rawReader.ReadString(256);
380
381 objectName = objectName.Replace('.', '_');
382 objectNames.Add(objectNameOffset, objectName);
383 }
384
385 int fileNameOffset = reader.ReadInt32();
386 string fileName;
387
388 if (!fileNames.TryGetValue(fileNameOffset, out fileName))
389 {
390 using (var rawReader = agdb.GetRawReader(fileNameOffset))
391 fileName = rawReader.ReadString(256);
392
393 fileName = Path.GetFileNameWithoutExtension(fileName);
394 fileNames.Add(fileNameOffset, fileName);
395 }
396
397 if (!string.IsNullOrEmpty(objectName))
398 mesh.HasDebugInfo = true;
399
400 polygons[i].ObjectName = objectName;
401 polygons[i].FileName = fileName;
402 }
403 }
404 }
405
406 private void ReadRooms()
407 {
408 DatRoomBspNode[] bspTrees;
409 DatRoomSide[] roomSides;
410 DatRoomAdjacency[] roomAdjacencies;
411 DatRoom[] roomsData;
412
413 using (var reader = akbp.OpenRead(22))
414 {
415 bspTrees = new DatRoomBspNode[reader.ReadUInt16()];
416
417 for (int i = 0; i < bspTrees.Length; i++)
418 bspTrees[i] = new DatRoomBspNode(reader);
419 }
420
421 using (var reader = akba.OpenRead(20))
422 {
423 roomSides = new DatRoomSide[reader.ReadInt32()];
424
425 for (int i = 0; i < roomSides.Length; i++)
426 roomSides[i] = new DatRoomSide(reader);
427 }
428
429 using (var reader = akaa.OpenRead(20))
430 {
431 roomAdjacencies = new DatRoomAdjacency[reader.ReadInt32()];
432
433 for (int i = 0; i < roomAdjacencies.Length; i++)
434 roomAdjacencies[i] = new DatRoomAdjacency(reader);
435 }
436
437 using (var reader = akva.OpenRead(20))
438 {
439 roomsData = new DatRoom[reader.ReadInt32()];
440
441 for (int i = 0; i < roomsData.Length; i++)
442 roomsData[i] = new DatRoom(akva, reader);
443 }
444
445 var rooms = new Room[roomsData.Length];
446
447 for (int i = 0; i < roomsData.Length; i++)
448 {
449 var data = roomsData[i];
450
451 var room = new Room
452 {
453 BspTree = BspNodeDataToBspNode(bspTrees, data.BspRootIndex),
454 BoundingBox = data.BoundingBox
455 };
456
457 if ((data.Flags & RoomFlags.Stairs) != 0)
458 {
459 room.FloorPlane = data.Floor;
460 room.Height = data.Height;
461 }
462 else
463 {
464 room.FloorPlane = new Plane(Vector3.Up, -data.BoundingBox.Min.Y);
465 room.Height = data.BoundingBox.Max.Y - data.BoundingBox.Min.Y;
466 }
467
468 room.Grid = RoomGrid.FromCompressedData(data.XTiles, data.ZTiles, data.CompressedGridData);
469 rooms[i] = room;
470 }
471
472 for (int i = 0; i < roomsData.Length; i++)
473 {
474 var data = roomsData[i];
475 var room = rooms[i];
476
477 //if (data.SiblingIndex != -1)
478 // room.Sibling = rooms[data.SiblingIndex];
479
480 //if (data.ChildIndex != -1)
481 // room.Child = rooms[data.ChildIndex];
482
483 for (int j = data.SideListStart; j < data.SideListEnd; j++)
484 {
485 var sideData = roomSides[j];
486
487 for (int k = sideData.SideListStart; k < sideData.SideListEnd; k++)
488 {
489 var adjData = roomAdjacencies[k];
490 var adjacentRoom = rooms[adjData.RoomIndex];
491 var ghost = polygons[adjData.QuadIndex];
492
493 room.Ajacencies.Add(new RoomAdjacency(adjacentRoom, ghost));
494 }
495 }
496 }
497
498 mesh.Rooms.AddRange(rooms);
499 }
500
501 private RoomBspNode BspNodeDataToBspNode(DatRoomBspNode[] data, int index)
502 {
503 var nodeData = data[index];
504 RoomBspNode front = null, back = null;
505
506 if (nodeData.BackChildIndex != -1)
507 back = BspNodeDataToBspNode(data, nodeData.BackChildIndex);
508
509 if (nodeData.FrontChildIndex != -1)
510 front = BspNodeDataToBspNode(data, nodeData.FrontChildIndex);
511
512 return new RoomBspNode(PlaneFromIndex(nodeData.PlaneIndex), back, front);
513 }
514 }
515}
Note: See TracBrowser for help on using the repository browser.