예제 #1
0
        public MobdImage(SegmentStream stream, uint flags, Version version)
        {
            bool flipped;

            Width  = stream.ReadUInt32();
            Height = stream.ReadUInt32();
            Pixels = new byte[Width * Height];

            if (version == Version.KKND1)
            {
                flipped = (flags & 0x1) == 1;

                var isCompressed = stream.ReadUInt8() == 2;

                if (isCompressed)
                {
                    DecompressKknd1(stream);
                }
                else
                {
                    stream.ReadBytes(Pixels, 0, Pixels.Length);
                }
            }
            else
            {
                flipped = ((flags >> 31) & 0x1) == 1;
                var isCompressed = ((flags >> 27) & 0x1) == 1;
                var has256Colors = ((flags >> 26) & 0x1) == 1;

                if (isCompressed)
                {
                    DecompressKknd2(stream, has256Colors);
                }
                else
                {
                    stream.ReadBytes(Pixels, 0, Pixels.Length);
                }
            }

            if (!flipped)
            {
                return;
            }

            for (var i = 0; i < Height; i++)
            {
                var row = new byte[Width];
                Array.Copy(Pixels, i * Width, row, 0, Width);
                Array.Reverse(row);
                Array.Copy(row, 0, Pixels, i * Width, Width);
            }
        }
예제 #2
0
파일: MobdFrame.cs 프로젝트: pchote/KKnD
        public MobdFrame(SegmentStream stream, Version version)
        {
            OriginX = stream.ReadUInt32();
            OriginY = stream.ReadUInt32();
            /*Unk1 =*/ stream.ReadUInt32();
            var renderFlagsOffset = stream.ReadUInt32();

            /*var boxListOffset =*/ stream.ReadUInt32();             // we do not read boxes (2 points)
            /*Unk2 =*/ stream.ReadUInt32();
            var pointListOffset = stream.ReadUInt32();

            if (pointListOffset > 0)
            {
                var points = new List <MobdPoint>();
                stream.Position = pointListOffset - stream.BaseOffset;

                while (true)
                {
                    var boxId = stream.ReadUInt32();

                    if (boxId == 0xffffffff)
                    {
                        break;
                    }

                    stream.Position -= 4;
                    points.Add(new MobdPoint(stream));
                }

                Points = points.ToArray();
            }

            stream.Position = renderFlagsOffset - stream.BaseOffset;
            RenderFlags     = new MobdRenderFlags(stream, version);
        }
예제 #3
0
파일: Mobd.cs 프로젝트: jkalmar/OpenKrush
        public Mobd(SegmentStream stream)
        {
            // This is damn ugly, but it seems MOBD uses offsets from lvl start.
            var fileOffset      = (uint)stream.BaseOffset;
            var firstFrameStart = stream.Length;

            var animationOffsets     = new List <uint>();
            var rotationalAnimations = new List <MobdAnimation>();
            var simpleAnimations     = new List <MobdAnimation>();

            while (stream.Position < firstFrameStart)
            {
                var value = stream.ReadInt32();

                if (value == 0 || (value - fileOffset < stream.Position && value >= fileOffset))
                {
                    stream.Position -= 4;
                    break;
                }

                animationOffsets.Add((uint)(stream.Position - 4));

                while (true)
                {
                    value = stream.ReadInt32();

                    if (value == -1 || value == 0)
                    {
                        break;
                    }

                    firstFrameStart = Math.Min(firstFrameStart, value - fileOffset);
                }
            }

            while (stream.Position < firstFrameStart)
            {
                var value = stream.ReadUInt32();

                if (value == 0)
                {
                    continue;
                }

                animationOffsets.Remove(value - fileOffset);
                var returnPosition = stream.Position;
                stream.Position = value - fileOffset;
                rotationalAnimations.Add(new MobdAnimation(stream));
                stream.Position = returnPosition;
            }

            foreach (var animationOffset in animationOffsets)
            {
                stream.Position = animationOffset;
                simpleAnimations.Add(new MobdAnimation(stream));
            }

            RotationalAnimations = rotationalAnimations.ToArray();
            SimpleAnimations     = simpleAnimations.ToArray();
        }
예제 #4
0
        public MobdAnimation(SegmentStream stream)
        {
            // OpenRA needs the same amount of frames per facing, filling up missing frames:
            var missingFrameWorkaround = 0;

            // Beetle => 10,10,10,8,10,10,10,10,10,10,10,10,10,10,10,10
            missingFrameWorkaround += stream.BaseStream.Position == 174278 ? 2 : 0;

            // Flame => 9,9,9,9,8,8,9,9,9,9,9,9,9,9,9,9
            missingFrameWorkaround += stream.BaseStream.Position == 2010426 || stream.BaseStream.Position == 2010466 ? 1 : 0;

            // Gort => 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11
            missingFrameWorkaround += stream.BaseStream.Position == 2094122 ? 1 : 0;

            // TODO add gen2 ones here! (Worm projectile, ...)

            // TODO this is likely the animation speed.
            //      Pattern is 0x00aabbcc
            //      0x00000010
            //      0x00aaaa2a
            //      flipping the bytes to 0xccbbaa00 makes more sence:
            //      0x10000000
            //      0x2aaaaa00
            //      Notes:
            //      0x10000000 is the most common value
            //      cc is never 00
            //      aa and bb often consist of the same value: 0000 1111 8888 aaaa ...
            /*Unk1 =*/ stream.ReadUInt32();

            var frames = new List <MobdFrame>();

            while (true)
            {
                var value = stream.ReadInt32();

                if (value == 0 || value == -1)
                {
                    break;                     // TODO 0 might mean "repeat", -1 might mean "do not repeat"
                }
                var returnPosition = stream.Position;
                stream.Position = value - stream.BaseOffset;
                var frame = new MobdFrame(stream);
                frames.Add(frame);

                if (missingFrameWorkaround-- > 0)
                {
                    frames.Add(frame);
                }

                stream.Position = returnPosition;
            }

            Frames = frames.ToArray();
        }
예제 #5
0
        public MobdRenderFlags(SegmentStream stream, Version version)
        {
            /*Type = */ stream.ReadASCII(4);
            var flags = stream.ReadUInt32();

            if (version == Version.KKND2)
            {
                var paletteOffset = stream.ReadUInt32() - stream.BaseOffset;

                var returnPos = stream.Position;
                stream.Position = paletteOffset;
                stream.ReadUInt32();                 // 00 00 00 80
                stream.ReadUInt32();                 // 00 00 00 80
                stream.ReadUInt32();                 // 00 00 00 80
                var numColors = stream.ReadUInt16();
                Palette = new uint[256];

                for (var i = 0; i < numColors; i++)
                {
                    var color16 = stream.ReadUInt16();                     // aRRRRRGGGGGBBBBB
                    var r       = ((color16 & 0x7c00) >> 7) & 0xff;
                    var g       = ((color16 & 0x03e0) >> 2) & 0xff;
                    var b       = ((color16 & 0x001f) << 3) & 0xff;
                    Palette[i] = (uint)((0xff << 24) | (r << 16) | (g << 8) | b);
                }

                stream.Position = returnPos;
            }

            var imageOffset = stream.ReadUInt32() - stream.BaseOffset;

            stream.Position = imageOffset;
            Image           = new MobdImage(stream, flags, version);
        }
예제 #6
0
        public MobdFrame(SegmentStream stream)
        {
            OffsetX = stream.ReadUInt32();
            OffsetY = stream.ReadUInt32();
            /*Unk1 =*/ stream.ReadUInt32();
            var renderFlagsOffset = stream.ReadUInt32();

            /*var boxListOffset =*/ stream.ReadUInt32();             // we do not read boxes (2 points, min and max)
            /*Unk2 =*/ stream.ReadUInt32();
            var pointListOffset = stream.ReadUInt32();

            // Theoretically we could also read the boxes here.
            // However they contain info about hitshaped etc. We define them in yaml to be able to tweak them.
            // But the points are required for turrets, muzzles and projectile launch offsets.
            if (pointListOffset > 0)
            {
                var points = new List <MobdPoint>();
                stream.Position = pointListOffset - stream.BaseOffset;

                while (true)
                {
                    var boxId = stream.ReadUInt32();

                    if (boxId == 0xffffffff)
                    {
                        break;
                    }

                    stream.Position -= 4;
                    points.Add(new MobdPoint(stream));
                }

                Points = points.ToArray();
            }

            stream.Position = renderFlagsOffset - stream.BaseOffset;
            RenderFlags     = new MobdRenderFlags(stream);
        }
예제 #7
0
        public MobdRenderFlags(SegmentStream stream)
        {
            var type  = new string(stream.ReadASCII(4).Reverse().ToArray());
            var flags = stream.ReadUInt32();

            var generation = Generation.Unknown;

            if (type == "SPRT")
            {
                generation = Generation.Gen1;
            }
            else if (type == "SPNS" || type == "SPRC")
            {
                generation = Generation.Gen2;
            }

            if (generation == Generation.Gen2)
            {
                var paletteOffset = stream.ReadUInt32() - stream.BaseOffset;

                var returnPos = stream.Position;
                stream.Position = paletteOffset;
                stream.ReadUInt32();                 // 00 00 00 80
                stream.ReadUInt32();                 // 00 00 00 80
                stream.ReadUInt32();                 // 00 00 00 80
                var numColors = stream.ReadUInt16();
                Palette = new uint[256];

                for (var i = 0; i < numColors; i++)
                {
                    var color16 = stream.ReadUInt16();                     // aRRRRRGGGGGBBBBB
                    var r       = ((color16 & 0x7c00) >> 7) & 0xff;
                    var g       = ((color16 & 0x03e0) >> 2) & 0xff;
                    var b       = ((color16 & 0x001f) << 3) & 0xff;
                    Palette[i] = (uint)((0xff << 24) | (r << 16) | (g << 8) | b);
                }

                stream.Position = returnPos;
            }

            var imageOffset = stream.ReadUInt32() - stream.BaseOffset;

            stream.Position = imageOffset;
            Image           = new MobdImage(stream, flags, generation);
        }
예제 #8
0
        public MobdAnimation(SegmentStream stream, Version version)
        {
            // This are actually broken / bugged files. As we can not fix the containers, we have them hardcoded here:
            var missingFrameWorkaround = 0;

            // Beetle => 10,10,10,8,10,10,10,10,10,10,10,10,10,10,10,10
            missingFrameWorkaround += stream.BaseStream.Position == 174278 ? 2 : 0;

            // Flame => 9,9,9,9,8,8,9,9,9,9,9,9,9,9,9,9
            missingFrameWorkaround += stream.BaseStream.Position == 2010426 || stream.BaseStream.Position == 2010466 ? 1 : 0;

            // Gort => 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11
            missingFrameWorkaround += stream.BaseStream.Position == 2094122 ? 1 : 0;

            // TODO add kknd2 bugged ones here! (Worm projectile, ...)

            /*Unk1 = */ stream.ReadUInt32();            // TODO this is likely the animation speed

            var frames = new List <MobdFrame>();

            while (true)
            {
                var value = stream.ReadInt32();

                if (value == 0 || value == -1)
                {
                    break;                     // TODO this is most likely repeat pattern. 1,2,3,1,2,3 or 1,2,3,2,1,2,3
                }
                var returnPosition = stream.Position;
                stream.Position = value - stream.BaseOffset;
                var frame = new MobdFrame(stream, version);
                frames.Add(frame);

                if (missingFrameWorkaround-- > 0)
                {
                    frames.Add(frame);
                }

                stream.Position = returnPosition;
            }

            Frames = frames.ToArray();

            if (version == Version.KKND2)
            {
                // KKnD 2 uses offsets only for frames they are used on instead of the whole animation.
                var points = new List <MobdPoint>();

                foreach (var frame in Frames)
                {
                    if (frame.Points == null)
                    {
                        continue;
                    }

                    foreach (var point in frame.Points)
                    {
                        if (point.Id == 0)
                        {
                            points.Add(new MobdPoint {
                                X = point.X, Y = point.Y, Z = point.Z, Id = points.Count
                            });
                        }
                    }
                }

                foreach (var frame in Frames)
                {
                    frame.Points = points.ToArray();
                }
            }
        }
예제 #9
0
        public Mobd(SegmentStream stream, Version version)
        {
            var fileOffset          = (uint)stream.BaseOffset;
            var firstFrameStart     = stream.Length;
            var justReadFrameOffset = false;

            var animationOffsets     = new List <uint>();
            var rotationalAnimations = new List <MobdAnimation>();
            var simpleAnimations     = new List <MobdAnimation>();

            while (stream.Position < firstFrameStart)
            {
                var value = stream.ReadUInt32();

                // This parsing method is trash, because animation offsets are hardcoded in .exe but it seems to work.
                if ((value == 0xffffffff || value == 0x00000000) && justReadFrameOffset)
                {
                    // terminator
                    justReadFrameOffset = false;
                }
                else if (value - fileOffset > stream.Position && value - fileOffset < stream.Length)
                {
                    // frame
                    justReadFrameOffset = true;
                    firstFrameStart     = Math.Min(firstFrameStart, value - fileOffset);
                }
                else if (value - fileOffset < stream.Position && value >= fileOffset)
                {
                    // animation pointer
                    animationOffsets.Remove(value - fileOffset);
                    var returnPosition = stream.Position;
                    stream.Position = value - fileOffset;
                    rotationalAnimations.Add(new MobdAnimation(stream, version));
                    stream.Position = returnPosition;
                }
                else if (value == 0)
                {
                    // TODO filler ? Sprite Invisible?
                }
                else
                {
                    animationOffsets.Add((uint)(stream.Position - 4));
                }
            }

            foreach (var animationOffset in animationOffsets)
            {
                try
                {
                    stream.Position = animationOffset;
                    simpleAnimations.Add(new MobdAnimation(stream, version));
                }
                catch (Exception)
                {
                    // TODO crashes on kknd2, fix me!
                }
            }

            RotationalAnimations = rotationalAnimations.ToArray();
            SimpleAnimations     = simpleAnimations.ToArray();
        }