Esempio n. 1
0
        public static TexEntry[] ReadEntries(byte[] fileData)
        {
            List<TexEntry> entries = new List<TexEntry>();

            var reader = new DataReader(fileData);

            // Unknown
            reader.ReadInt32();

            while (true)
            {
                var entry = new TexEntry();

                entry.CellOffset = reader.ReadInt32();
                entry.DirectoryOffset = reader.ReadInt32();
                entry.Size = reader.ReadInt32();

                if (entry.CellOffset < 0)
                    break;

                entries.Add(entry);
            }

            return entries.ToArray();
        }
Esempio n. 2
0
 Child readChild(DataReader reader)
 {
     int t = reader.ReadInt32();
     if (t == 0)
     {
         return null;
     }
     Child child = new Child();
     child.TextureOffset = t;
     child.VifOffset = reader.ReadInt32();
     child.VifLength = reader.ReadInt32();
     return child;
 }
Esempio n. 3
0
        public static List<ObjectData> Decode(byte[] data, int startOffset, int length)
        {
            var reader = new DataReader(data, startOffset, length);

            var count = reader.ReadInt16();
            var flags = reader.ReadInt16();
            var stringOffset = reader.ReadInt32();

            var objects = new List<ObjectData>(count);

            for (int i = 0; i < count; i++)
            {
                var obj = new ObjectData();

                int nameStringOffset = reader.ReadInt32();
                obj.Name = GetString(reader, stringOffset + nameStringOffset);
                short structSize = reader.ReadInt16(); // Size would be 20 if there isn't a stringoffsetarray, but usually 24 with an empty array
                obj.I6 = reader.ReadInt16();
                obj.Floats = new float[3];
                obj.Floats[0] = reader.ReadFloat();
                obj.Floats[1] = reader.ReadFloat();
                obj.Floats[2] = reader.ReadFloat();

                if (structSize > 20)
                {
                    var props = new List<string>();
                    for (int o =0; o < (structSize-20)/4; o++)
                    {
                        int propStringOffset = reader.ReadInt32();

                        if (propStringOffset == 0 && o == (structSize - 20) / 4 - 1)
                        {
                            // There is always a null at the end of the array
                            break;
                        }

                        props.Add(GetString(reader, stringOffset + propStringOffset));
                    }
                    obj.Properties = props;
                }

                objects.Add(obj);
            }

            return objects;
        }
Esempio n. 4
0
        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;
                }
            }
        }
Esempio n. 5
0
        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);
        }
Esempio n. 7
0
        private static void DecodeInstructions(Script script, byte[] data, int startOffset, int len)
        {
            var reader = new DataReader(data, startOffset, len);

            for (var i = 0; i < len; i += 4)
            {
                var opcode = reader.ReadInt32();
                var inst   = new Instruction
                {
                    opCode = opcode,
                    addr   = i
                };
                if (script.internalsByAddr.ContainsKey(i))
                {
                    inst.label = script.internalsByAddr[i];
                }
                var type = bgdaOpCodeArgs[opcode];
                switch (type)
                {
                case ARGS_TYPE.NO_ARGS:

                    break;

                case ARGS_TYPE.ONE_ARG:
                    inst.args.Add(reader.ReadInt32());
                    i += 4;
                    break;

                case ARGS_TYPE.ONE_ARG_INSTR:
                    inst.args.Add(reader.ReadInt32());
                    i += 4;
                    break;

                case ARGS_TYPE.TWO_ARGS:
                    inst.args.Add(reader.ReadInt32());
                    inst.args.Add(reader.ReadInt32());
                    i += 8;
                    break;

                case ARGS_TYPE.VAR_ARGS:
                    var numArgs = reader.ReadInt32();
                    for (var j = 0; j < numArgs - 1; ++j)
                    {
                        inst.args.Add(reader.ReadInt32());
                    }
                    i += numArgs * 4;
                    break;

                case ARGS_TYPE.ARGS_130:
                    var num = reader.ReadInt32(); i += 4;
                    for (var j = 0; j < num; ++j)
                    {
                        inst.args.Add(reader.ReadInt32());
                        inst.args.Add(reader.ReadInt32());
                        i += 8;
                    }
                    inst.args.Add(reader.ReadInt32());
                    i += 4;
                    break;
                }
                script.instructions.Add(inst);
            }
        }
Esempio n. 8
0
        public static Script Decode(byte[] data, int startOffset, int length)
        {
            if (length == 0)
            {
                return(new Script());
            }

            var reader = new DataReader(data, startOffset + HEADER_SIZE, length);

            var script = new Script
            {
                offset0 = reader.ReadInt32(),
                hw1     = reader.ReadInt16(),
                hw2     = reader.ReadInt16(),
                hw3     = reader.ReadInt16(),
                hw4     = reader.ReadInt16(),

                instructionsOffset = reader.ReadInt32(),
                stringsOffset      = reader.ReadInt32(),

                offset3 = reader.ReadInt32(),
                offset4 = reader.ReadInt32(),
                offset5 = reader.ReadInt32(),

                numInternals    = reader.ReadInt32(),
                offsetInternals = reader.ReadInt32(),
                numExternals    = reader.ReadInt32(),
                offsetExternals = reader.ReadInt32()
            };

            var internalOffset = startOffset + script.offsetInternals + HEADER_SIZE;

            for (var i = 0; i < script.numInternals; ++i)
            {
                var internalReader = new DataReader(data, internalOffset, 0x18);
                var labelAddress   = internalReader.ReadInt32();
                var label          = internalReader.ReadZString();
                script.internalsByAddr.Add(labelAddress, label);
                internalOffset += 0x18;
            }

            var externalOffset = startOffset + script.offsetExternals + HEADER_SIZE;

            script.externals = new string[script.numExternals];
            for (var i = 0; i < script.numExternals; ++i)
            {
                var externalReader = new DataReader(data, externalOffset, 0x18);
                var labelAddress   = externalReader.ReadInt32();
                if (labelAddress != 0)
                {
                    script.parseWarnings += "found a non-zero external label address\n";
                }
                var label = externalReader.ReadZString();
                script.externals[i] = label;

                externalOffset += 0x18;
            }

            var stringTableLen  = script.offset3 - script.stringsOffset;
            var instructionLen  = script.stringsOffset - script.instructionsOffset;
            var thisStringStart = -1;
            var stringReader    = new DataReader(data, startOffset + HEADER_SIZE + script.stringsOffset, stringTableLen + 1);
            var thisString      = new StringBuilder();

            for (var i = 0; i < stringTableLen; i += 4)
            {
                if (thisStringStart < 0)
                {
                    thisString      = new StringBuilder();
                    thisStringStart = i;
                }
                var bytes = stringReader.ReadBytes(4);
                for (var b = 3; b >= 0; --b)
                {
                    if (bytes[b] != 0)
                    {
                        thisString.Append((char)bytes[b]);
                    }
                    else
                    {
                        script.stringTable.Add(thisStringStart, thisString.ToString());
                        thisStringStart = -1;
                        break;
                    }
                }
            }
            DecodeInstructions(script, data, startOffset + HEADER_SIZE + script.instructionsOffset, instructionLen);
            return(script);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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);
        }