Esempio n. 1
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. 2
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. 3
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. 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);
        }
Esempio n. 6
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);
        }