private static string GetString(DataReader reader, int offset) { int tempOffset = reader.Offset; reader.SetOffset(offset); var value = reader.ReadZString(); reader.SetOffset(tempOffset); return value; }
private static string GetString(DataReader reader, int offset) { int tempOffset = reader.Offset; reader.SetOffset(offset); var value = reader.ReadZString(); reader.SetOffset(tempOffset); return(value); }
public void ReadDirectory() { var reader = new DataReader(FileData, _startOffset, _dataLen); var numEntries = reader.ReadInt32(); for (var entry = 0; entry < numEntries; ++entry) { if (EngineVersion.ReturnToArms == _engineVersion || EngineVersion.JusticeLeagueHeroes == _engineVersion) { var stringOffset = reader.ReadInt32(); var dataOffset = reader.ReadInt32(); var dataLength = reader.ReadInt32(); var tempOffset = reader.Offset; reader.SetOffset(stringOffset); var name = reader.ReadZString(); reader.SetOffset(tempOffset); var info = new EntryInfo() { Name = name, StartOffset = dataOffset + _startOffset, Length = dataLength }; Directory[name] = info; } else { var headerOffset = _startOffset + 4 + entry * 64; var subfileName = DataUtil.GetString(FileData, headerOffset); var subOffset = BitConverter.ToInt32(FileData, headerOffset + 56); var subLen = BitConverter.ToInt32(FileData, headerOffset + 60); var info = new EntryInfo() { Name = subfileName, StartOffset = subOffset + _startOffset, Length = subLen }; Directory[subfileName] = info; } } }
public static List <DialogData> Decode(EngineVersion engineVersion, byte[] data, int startOffset, int length) { var entrySize = 0x44; if (engineVersion == EngineVersion.ReturnToArms || engineVersion == EngineVersion.JusticeLeagueHeroes) { entrySize = 0x50; } var reader = new DataReader(data, startOffset, length); var numEntries = length / entrySize; var objects = new List <DialogData>(numEntries); for (var entry = 0; entry < numEntries; ++entry) { var dataObj = new DialogData(); var entryOffset = entry * entrySize; dataObj.Name = GetString(reader, entryOffset); reader.SetOffset(entryOffset + 0x40); dataObj.StartOffsetInVAFile = reader.ReadInt32(); // Check if this entry is the last one in the file if (entry != numEntries - 1) { reader.SetOffset(entryOffset + 0x84); var nextStart = reader.ReadInt32(); dataObj.Length = nextStart - dataObj.StartOffsetInVAFile; } else { // Means to the end of the VA file dataObj.Length = 0; } objects.Add(dataObj); } return(objects); }
public void ReadDirectory() { var reader = new DataReader(FileData, _startOffset, _dataLen); int numEntries = reader.ReadInt32(); for (int entry = 0; entry < numEntries; ++entry) { if (EngineVersion.ReturnToArms == _engineVersion) { int stringOffset = reader.ReadInt32(); int dataOffset = reader.ReadInt32(); int dataLength = reader.ReadInt32(); var tempOffset = reader.Offset; reader.SetOffset(stringOffset); var name = reader.ReadZString(); reader.SetOffset(tempOffset); var info = new EntryInfo() { Name = name, StartOffset = dataOffset + _startOffset, Length = dataLength }; Directory[name] = info; } else { int headerOffset = _startOffset + 4 + entry * 64; String subfileName = DataUtil.GetString(FileData, headerOffset); int subOffset = BitConverter.ToInt32(FileData, headerOffset + 56); int subLen = BitConverter.ToInt32(FileData, headerOffset + 60); var info = new EntryInfo() {Name = subfileName, StartOffset = subOffset + _startOffset, Length = subLen}; Directory[subfileName] = info; } } }
public WorldData Decode(EngineVersion engineVersion, WorldTexFile texFile, ILogger log, byte[] data, int startOffset, int length) { WorldData worldData = new WorldData(); var reader = new DataReader(data, startOffset, length); int numElements = reader.ReadInt32(); // 0 reader.Skip(12); // Skipping 3 ints int numCols = reader.ReadInt32(); // x10 int numRows = reader.ReadInt32(); // x14 reader.Skip(12); // Skipping 3 ints // x18 x1c x20 int elementArrayStart = reader.ReadInt32(); // x24 reader.Skip(8); // Skipping 2 ints int off38Cols = reader.ReadInt32(); int off38Rows = reader.ReadInt32(); int off38 = reader.ReadInt32(); reader.Skip(28); int texll = reader.ReadInt32(); int texur = reader.ReadInt32(); int texX0 = texll % 100; int texY0 = texll / 100; int texX1 = texur % 100; int texY1 = texur / 100; reader.Skip(4); int worldTexOffsetsOffset = reader.ReadInt32(); worldData.textureChunkOffsets = readTextureChunkOffsets(engineVersion, data, startOffset + worldTexOffsetsOffset, texX0, texY0, texX1+1, texY1); worldData.worldElements = new List<WorldElement>(numElements); for (int elementIdx = 0; elementIdx < numElements; ++elementIdx) { var element = new WorldElement(); if (EngineVersion.ReturnToArms == engineVersion) { reader.SetOffset(elementArrayStart + elementIdx * 0x3C); } else // Default to Dark Allience version { reader.SetOffset(elementArrayStart + elementIdx * 0x38); } int vifDataOffset = reader.ReadInt32(); if (EngineVersion.DarkAlliance == engineVersion) { int tex2 = reader.ReadInt32(); if (tex2 != 0) { log.LogLine("Tex2=" + tex2); } } int vifLen = reader.ReadInt32(); log.LogLine("-----------"); log.LogLine("vifdata: " + vifDataOffset + ", " + vifLen); float x1 = reader.ReadFloat(); float y1 = reader.ReadFloat(); float z1 = reader.ReadFloat(); float x2 = reader.ReadFloat(); float y2 = reader.ReadFloat(); float z2 = reader.ReadFloat(); element.boundingBox = new Rect3D(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); log.LogLine("Bounding Box: " + element.boundingBox.ToString()); int textureNum = reader.ReadInt32() / 0x40; log.LogLine("Texture Num: " + textureNum); int texCellxy = reader.ReadInt16(); int y = texCellxy / 100; int x = texCellxy % 100; if (EngineVersion.ReturnToArms == engineVersion) { x += texX0; y += texY0; } if (textureNum != 0) { if (EngineVersion.ReturnToArms == engineVersion) { element.Texture = texFile.GetBitmapRTA(x, y, textureNum); } else { element.Texture = texFile.GetBitmap(worldData.textureChunkOffsets[y, x], textureNum); } } if (element.Texture != null) { log.LogLine("Found in texture chunk: " + x + ", " + y); } var vifLogger = new StringLogger(); int texWidth = 100; int texHeight = 100; if (element.Texture != null) { texWidth = element.Texture.PixelWidth; texHeight = element.Texture.PixelHeight; } byte nregs = data[startOffset + vifDataOffset + 0x10]; int vifStartOffset = (nregs + 2) * 0x10; element.VifDataOffset = startOffset + vifDataOffset + vifStartOffset; element.VifDataLength = vifLen*0x10 - vifStartOffset; element.model = decodeModel(engineVersion, vifLogger, data, startOffset + vifDataOffset + vifStartOffset, vifLen * 0x10 - vifStartOffset, texWidth, texHeight); if (EngineVersion.ReturnToArms == engineVersion) { int unk = reader.ReadInt16(); log.LogLine("Unknown: " + unk); } int posx = reader.ReadInt16(); int posy = reader.ReadInt16(); int posz = reader.ReadInt16(); log.LogLine("Position : " + posx + ", " + posy + ", " + posz); element.pos = new Vector3D(posx / 16.0, posy / 16.0, posz / 16.0); if (EngineVersion.ReturnToArms == engineVersion) { // Just a guess, maybe wrong. element.pos = new Vector3D(posx / 16.0, posz / 16.0, posy / 16.0); } // I don't think RTA uses this flags scheme. From the data it looks like there are // 2 shorts (or possibly floats) following. int flags = reader.ReadInt32(); if ((flags & 0x01) == 0) { log.LogLine("Flags : " + HexUtil.formatHexUShort(flags & 0xFFFF)); element.cosAlpha = (flags >> 16) / 32767.0; element.sinAlpha = reader.ReadInt16() / 32767.0; log.LogLine("cos alpha : " + element.cosAlpha); log.LogLine("sin alpha : " + element.sinAlpha); log.LogLine("alpha(cos, sin): " + Math.Acos(element.cosAlpha) * 180.0 / Math.PI + ", " + Math.Asin(element.sinAlpha) * 180.0 / Math.PI); element.usesRotFlags = false; } else { reader.ReadInt16(); // not necessary but makes the code more obvious. log.LogLine("Flags : " + HexUtil.formatHex(flags)); element.xyzRotFlags = (flags >> 16) & 7; element.usesRotFlags = true; log.LogLine("Rot Flags : " + element.xyzRotFlags); } element.negYaxis = (flags & 0x40) == 0x40; if (EngineVersion.ReturnToArms == engineVersion) { flags = 0; element.usesRotFlags = true; log.LogLine("Forcing flags to 0 until we know the format better"); } worldData.worldElements.Add(element); } return worldData; }
private WorldElement ReadWorldElement(EngineVersion engineVersion, WorldTexFile texFile, ILogger log, byte[] data, int startOffset, WorldData worldData, DataReader reader, int elementArrayStart, int texX0, int texY0, int elementIdx) { var element = new WorldElement(); if (EngineVersion.ReturnToArms == engineVersion || EngineVersion.JusticeLeagueHeroes == engineVersion) { reader.SetOffset(elementArrayStart + elementIdx * 0x3C); } else // Default to Dark Allience version { reader.SetOffset(elementArrayStart + elementIdx * 0x38); } var vifDataOffset = reader.ReadInt32(); if (EngineVersion.DarkAlliance == engineVersion) { var tex2 = reader.ReadInt32(); if (tex2 != 0) { log.LogLine("Tex2=" + tex2); } } var vifLen = reader.ReadInt32(); log.LogLine("-----------"); log.LogLine("vifdata: " + vifDataOffset + ", " + vifLen); var x1 = reader.ReadFloat(); var y1 = reader.ReadFloat(); var z1 = reader.ReadFloat(); var x2 = reader.ReadFloat(); var y2 = reader.ReadFloat(); var z2 = reader.ReadFloat(); element.boundingBox = new Rect3D(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); log.LogLine("Bounding Box: " + element.boundingBox.ToString()); var textureNum = reader.ReadInt32() / 0x40; log.LogLine("Texture Num: " + textureNum); int texCellxy = reader.ReadInt16(); var y = texCellxy / 100; var x = texCellxy % 100; if (EngineVersion.ReturnToArms == engineVersion || EngineVersion.JusticeLeagueHeroes == engineVersion) { x += texX0; y += texY0; } if (textureNum != 0 && texFile != null) { if (EngineVersion.ReturnToArms == engineVersion || EngineVersion.JusticeLeagueHeroes == engineVersion) { element.Texture = texFile.GetBitmapRTA(x, y, textureNum); } else { element.Texture = texFile.GetBitmap(worldData.textureChunkOffsets[y, x], textureNum); } } if (element.Texture != null) { log.LogLine("Found in texture chunk: " + x + ", " + y); } var vifLogger = new StringLogger(); var texWidth = 100; var texHeight = 100; if (element.Texture != null) { texWidth = element.Texture.PixelWidth; texHeight = element.Texture.PixelHeight; } var nregs = data[startOffset + vifDataOffset + 0x10]; var vifStartOffset = (nregs + 2) * 0x10; element.VifDataOffset = startOffset + vifDataOffset + vifStartOffset; element.VifDataLength = vifLen * 0x10 - vifStartOffset; element.model = decodeModel(engineVersion, vifLogger, data, startOffset + vifDataOffset + vifStartOffset, vifLen * 0x10 - vifStartOffset, texWidth, texHeight); if (EngineVersion.ReturnToArms == engineVersion || EngineVersion.JusticeLeagueHeroes == engineVersion) { int unk = reader.ReadInt16(); log.LogLine("Unknown: " + unk); } int posx = reader.ReadInt16(); int posy = reader.ReadInt16(); int posz = reader.ReadInt16(); log.LogLine("Position : " + posx + ", " + posy + ", " + posz); element.pos = new Vector3D(posx / 16.0, posy / 16.0, posz / 16.0); if (EngineVersion.ReturnToArms == engineVersion || EngineVersion.JusticeLeagueHeroes == engineVersion) { // Just a guess, maybe wrong. element.pos = new Vector3D(posx / 16.0, posz / 16.0, posy / 16.0); } // I don't think RTA uses this flags scheme. From the data it looks like there are // 2 shorts (or possibly floats) following. var flags = reader.ReadInt32(); if ((flags & 0x01) == 0) { log.LogLine("Flags : " + HexUtil.formatHexUShort(flags & 0xFFFF)); element.cosAlpha = (flags >> 16) / 32767.0; element.sinAlpha = reader.ReadInt16() / 32767.0; log.LogLine("cos alpha : " + element.cosAlpha); log.LogLine("sin alpha : " + element.sinAlpha); log.LogLine("alpha(cos, sin): " + Math.Acos(element.cosAlpha) * 180.0 / Math.PI + ", " + Math.Asin(element.sinAlpha) * 180.0 / Math.PI); element.usesRotFlags = false; } else { reader.ReadInt16(); // not necessary but makes the code more obvious. log.LogLine("Flags : " + HexUtil.formatHex(flags)); element.xyzRotFlags = (flags >> 16) & 7; element.usesRotFlags = true; log.LogLine("Rot Flags : " + element.xyzRotFlags); } element.negYaxis = (flags & 0x40) == 0x40; if (EngineVersion.ReturnToArms == engineVersion || EngineVersion.JusticeLeagueHeroes == engineVersion) { flags = 0; element.usesRotFlags = true; log.LogLine("Forcing flags to 0 until we know the format better"); } return(element); }
public WorldData Decode(EngineVersion engineVersion, WorldTexFile texFile, ILogger log, byte[] data, int startOffset, int length) { WorldData worldData = new WorldData(); var reader = new DataReader(data, startOffset, length); int numElements = reader.ReadInt32(); // 0 reader.Skip(12); // Skipping 3 ints int numCols = reader.ReadInt32(); // x10 int numRows = reader.ReadInt32(); // x14 reader.Skip(12); // Skipping 3 ints // x18 x1c x20 int elementArrayStart = reader.ReadInt32(); // x24 reader.Skip(8); // Skipping 2 ints int off38Cols = reader.ReadInt32(); int off38Rows = reader.ReadInt32(); int off38 = reader.ReadInt32(); reader.Skip(28); int texll = reader.ReadInt32(); int texur = reader.ReadInt32(); int texX0 = texll % 100; int texY0 = texll / 100; int texX1 = texur % 100; int texY1 = texur / 100; reader.Skip(4); int worldTexOffsetsOffset = reader.ReadInt32(); worldData.textureChunkOffsets = readTextureChunkOffsets(engineVersion, data, startOffset + worldTexOffsetsOffset, texX0, texY0, texX1 + 1, texY1); worldData.worldElements = new List <WorldElement>(numElements); for (int elementIdx = 0; elementIdx < numElements; ++elementIdx) { var element = new WorldElement(); if (EngineVersion.ReturnToArms == engineVersion) { reader.SetOffset(elementArrayStart + elementIdx * 0x3C); } else // Default to Dark Allience version { reader.SetOffset(elementArrayStart + elementIdx * 0x38); } int vifDataOffset = reader.ReadInt32(); if (EngineVersion.DarkAlliance == engineVersion) { int tex2 = reader.ReadInt32(); if (tex2 != 0) { log.LogLine("Tex2=" + tex2); } } int vifLen = reader.ReadInt32(); log.LogLine("-----------"); log.LogLine("vifdata: " + vifDataOffset + ", " + vifLen); float x1 = reader.ReadFloat(); float y1 = reader.ReadFloat(); float z1 = reader.ReadFloat(); float x2 = reader.ReadFloat(); float y2 = reader.ReadFloat(); float z2 = reader.ReadFloat(); element.boundingBox = new Rect3D(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); log.LogLine("Bounding Box: " + element.boundingBox.ToString()); int textureNum = reader.ReadInt32() / 0x40; log.LogLine("Texture Num: " + textureNum); int texCellxy = reader.ReadInt16(); int y = texCellxy / 100; int x = texCellxy % 100; if (EngineVersion.ReturnToArms == engineVersion) { x += texX0; y += texY0; } if (textureNum != 0) { if (EngineVersion.ReturnToArms == engineVersion) { element.Texture = texFile.GetBitmapRTA(x, y, textureNum); } else { element.Texture = texFile.GetBitmap(worldData.textureChunkOffsets[y, x], textureNum); } } if (element.Texture != null) { log.LogLine("Found in texture chunk: " + x + ", " + y); } var vifLogger = new StringLogger(); int texWidth = 100; int texHeight = 100; if (element.Texture != null) { texWidth = element.Texture.PixelWidth; texHeight = element.Texture.PixelHeight; } byte nregs = data[startOffset + vifDataOffset + 0x10]; int vifStartOffset = (nregs + 2) * 0x10; element.VifDataOffset = startOffset + vifDataOffset + vifStartOffset; element.VifDataLength = vifLen * 0x10 - vifStartOffset; element.model = decodeModel(engineVersion, vifLogger, data, startOffset + vifDataOffset + vifStartOffset, vifLen * 0x10 - vifStartOffset, texWidth, texHeight); if (EngineVersion.ReturnToArms == engineVersion) { int unk = reader.ReadInt16(); log.LogLine("Unknown: " + unk); } int posx = reader.ReadInt16(); int posy = reader.ReadInt16(); int posz = reader.ReadInt16(); log.LogLine("Position : " + posx + ", " + posy + ", " + posz); element.pos = new Vector3D(posx / 16.0, posy / 16.0, posz / 16.0); if (EngineVersion.ReturnToArms == engineVersion) { // Just a guess, maybe wrong. element.pos = new Vector3D(posx / 16.0, posz / 16.0, posy / 16.0); } // I don't think RTA uses this flags scheme. From the data it looks like there are // 2 shorts (or possibly floats) following. int flags = reader.ReadInt32(); if ((flags & 0x01) == 0) { log.LogLine("Flags : " + HexUtil.formatHexUShort(flags & 0xFFFF)); element.cosAlpha = (flags >> 16) / 32767.0; element.sinAlpha = reader.ReadInt16() / 32767.0; log.LogLine("cos alpha : " + element.cosAlpha); log.LogLine("sin alpha : " + element.sinAlpha); log.LogLine("alpha(cos, sin): " + Math.Acos(element.cosAlpha) * 180.0 / Math.PI + ", " + Math.Asin(element.sinAlpha) * 180.0 / Math.PI); element.usesRotFlags = false; } else { reader.ReadInt16(); // not necessary but makes the code more obvious. log.LogLine("Flags : " + HexUtil.formatHex(flags)); element.xyzRotFlags = (flags >> 16) & 7; element.usesRotFlags = true; log.LogLine("Rot Flags : " + element.xyzRotFlags); } element.negYaxis = (flags & 0x40) == 0x40; if (EngineVersion.ReturnToArms == engineVersion) { flags = 0; element.usesRotFlags = true; log.LogLine("Forcing flags to 0 until we know the format better"); } worldData.worldElements.Add(element); } return(worldData); }
public static CutScene Decode(byte[] data, int startOffset, int length) { if (length == 0) { return(new CutScene()); } var reader = new DataReader(data, startOffset, length); var scene = new CutScene { flags = reader.ReadInt32(), keyframeOffset = reader.ReadInt32(), numKeyframes = reader.ReadInt32(), characterBlockOffset = reader.ReadInt32(), numCharacters = reader.ReadInt32() }; reader.SetOffset(0x20); scene.subtitles = reader.ReadZString(); reader.SetOffset(0x48); scene.string48 = reader.ReadZString(); reader.SetOffset(0x70); scene.scale = reader.ReadInt32(); scene.string74 = reader.ReadZString(); for (var c = 0; c < scene.numCharacters; ++c) { var character = new CutScene.Character(); var charOffset = scene.characterBlockOffset + c * 0x2C; reader.SetOffset(charOffset); character.extra0 = reader.ReadInt32(); character.extra4 = reader.ReadInt32(); character.name = reader.ReadZString(); reader.SetOffset(charOffset + 0x1C); character.x = reader.ReadFloat(); character.y = reader.ReadFloat(); character.z = reader.ReadFloat(); character.s28 = reader.ReadInt16(); scene.cast.Add(character); } for (var kf = 0; kf < scene.numKeyframes; ++kf) { var keyframe = new CutScene.Keyframe(); var kfOffset = scene.keyframeOffset + kf * 0x14; reader.SetOffset(kfOffset); keyframe.time = reader.ReadFloat(); keyframe.actor = reader.ReadInt16(); keyframe.action = reader.ReadInt16(); keyframe.i8 = reader.ReadInt32(); keyframe.ic = reader.ReadInt32(); keyframe.i10 = reader.ReadInt32(); if (keyframe.actor == -100 && keyframe.action == 5) { reader.Rewind(12); keyframe.f8 = reader.ReadFloat(); keyframe.fc = reader.ReadFloat(); keyframe.f10 = reader.ReadFloat(); } scene.keyframes.Add(keyframe); } return(scene); }