Ejemplo n.º 1
0
        private void DecodeZPlaneStrip(ZPlaneStripData strip)
        {
            _bitStreamManager = new BitStreamManager(strip.ImageData);
            bool finishDecode = false;

            while (!finishDecode)
            {
                byte count = _bitStreamManager.ReadByte();
                if (count > 0)
                {
                    if (BinaryHelper.CheckBitState(count, 7))
                    {                                                   // write the same byte count times
                        count = BinaryHelper.GetBitsFromByte(count, 7); // &= 0x7F;
                        byte b = _bitStreamManager.ReadByte();

                        for (int i = 0; i < count; i++)
                        {
                            if (!CheckEndOfGraphics())
                            {
                                DrawLine(b);
                            }
                        }
                    }
                    else
                    {  // write count bytes as is from the input
                        for (int i = 0; i < count; i++)
                        {
                            if (!CheckEndOfGraphics())
                            {
                                DrawLine(_bitStreamManager.ReadByte());
                            }
                        }
                    }
                }
                //else
                //{
                //    Debugger.Break();
                //}

                if (CheckEndOfGraphics() || _bitStreamManager.EndOfStream)
                {
                    finishDecode = true;
                }
            }
        }
Ejemplo n.º 2
0
        private void DrawLine(byte b)
        {
            Color msk = Color.Empty;

            for (int i = 0; i < 8; i++)
            {
                if (BinaryHelper.CheckBitState(b, 7 - i))
                {
                    msk = Color.Black;
                }
                else
                {
                    msk = Color.White;
                }
                _resultBitmap.SetPixel(_currentOffset + i, _currentLine, msk);
            }
            _currentLine++;
        }
Ejemplo n.º 3
0
        public override void LoadFromBinaryReader(Stream binaryReader)
        {
            base.LoadFromBinaryReader(binaryReader);

            if (_gameInfo.ScummVersion == 6)
            {
                Size   = binaryReader.ReadUint32();     //size: 32le can be 0 (see num anim) or the size (sometimes with an offset of one ??)
                Header = binaryReader.ReadUTF8Sring(2); //header: 2*8 always contain "CO"
                if (Header != "CO")
                {
                    throw new InvalidFileFormatException(string.Format("Unknown costume Header. Expected 'CO' but was '{0}'", Header));
                }
            }

            NumAnim = binaryReader.ReadByte1(); //num anim: 8  if(size) num_anim++

            //lets assign to a new variable to keep the read value intact
            byte totalAnimations = NumAnim;

            if (Size > 0 || _gameInfo.ScummVersion == 5)
            {
                totalAnimations++;
            }

            Format = binaryReader.ReadByte1(); //format: 8  bit 7 set means that west anims must NOT be mirrored, bit 0 is the palette size (0: 16 colors, 1: 32 colors)

            //discover the palette size to continue reading
            PaletteSize = 16;
            if (BinaryHelper.CheckBitState(Format, 0))
            {
                PaletteSize = 32;
            }

            //palette            : 8*num colors coded in format
            Palette = new List <byte>();
            for (int i = 0; i < PaletteSize; i++)
            {
                byte paletteEntry = binaryReader.ReadByte1();
                Palette.Add(paletteEntry);
            }

            AnimCommandsOffset = binaryReader.ReadUint16(); //anim cmds offset   : 16le access the anim cmds array

            LimbsOffsets = new List <ushort>();
            for (int i = 0; i < 16; i++)
            {
                ushort limbOffSet = binaryReader.ReadUint16();
                LimbsOffsets.Add(limbOffSet);//limbs offset       : 16*16le access limb picture table
            }

            //anim offsets       : 16le*num anim  access anim definitions
            AnimOffsets = new List <ushort>();
            for (int i = 0; i < totalAnimations; i++)
            {
                ushort currentOffset = binaryReader.ReadUint16();
                AnimOffsets.Add(currentOffset);
            }

            /*
             *  anim
             *      limb mask        : 16le
             *      anim definitions : variable length, one definition for each bit set to 1 in the limb mask.
             *          0xFFFF       : 16le disabled limb code
             *          OR
             *          start        : 16le
             *          noloop       : 1
             *          end offset   : 7 offset of the last frame, or len-1  (Pelo que entendi, esse não é a posição final, e sim o comprimento do offset.
             */
            Animations = new List <Animation>();
            for (int i = 0; i < AnimOffsets.Count; i++)
            {
                //Por alguma razão, o NumAnimations não é o numero real de animações. Parece que tem um array "reservando" posições para animações
                //não utilizadas.
                //O que eu quero dizer é que tem o indice de animações, mas esse indice as vezes aponta para um offset de animação 0, ou seja,
                //o indice existe e diz que não aponta para nenhuma animação, pelo que entendi. Então só vou continuar lendo do binary stream
                //quando for o indice apontara para a próxima animação.
                if (AnimOffsets[i] > 0)
                {
                    Animation existingAnimation = Animations.SingleOrDefault(x => x.Offset == AnimOffsets[i]);
                    if (existingAnimation == null)
                    {
                        //Pra isso aqui funciona, a posição do binaryReader deve ser a mesma informada no offset.
                        //Se não for, então para no debug, porque tem alguma coisa errada com o meu código e
                        //preciso verificar o que é.
                        if (AnimOffsets[i] != DebugGetCurrentRelativePosition(binaryReader))
                        {
                            Debugger.Break();
                        }

                        var currentAnimation = new Animation();
                        currentAnimation.Offset   = AnimOffsets[i];
                        currentAnimation.LimbMask = binaryReader.ReadUint16();

                        for (int j = 0; j < currentAnimation.NumLimbs; j++)
                        {
                            var currentDefinition = new AnimationDefinition();
                            currentDefinition.Start = binaryReader.ReadUint16();
                            if (!currentDefinition.Disabled)
                            {
                                currentDefinition.NoLoopAndEndOffset = binaryReader.ReadByte1();
                            }
                            currentAnimation.AnimDefinitions.Add(currentDefinition);
                        }
                        Animations.Add(currentAnimation);
                    }
                }
            }


            //Segundo o site do SCUMMC, achar o tamanho do CMDArray e outro itens é somente olhando os indices, pois uma coisa começa onde a
            //outra termina. Segue o texto original abaixo:
            //
            //It seems the data is always properly ordered. That is, the first picture of the first limb comes right after the last limb table.
            //The first limb table start right after the cmd array, and so on. Currently this seems to be the only way to determine how long the
            //cmd array is, or how long the last limb table is. Clumsy but it works, however a simple decoder doesn’t need to compute these lengths :)

            //      anim cmds
            //        cmd: 8

            //Essa conta ta ficando 1 byte atrasado. Não sei se a sessão anterior termina com 00 e eu não estou pulando
            //ou se tem algum erro mesmo. Verificar se nos próximos costumes é sempre 00 ou 00 00...
            //por hora, vou comentar o código de start+length e calcular igual o site fala.

            //Tamanhos do CMD Array
            if (AnimCommandsOffset != (DebugGetCurrentRelativePosition(binaryReader)))
            {
                Debugger.Break();
            }

            int cmdArraySize = (int)(LimbsOffsets.First() - (DebugGetCurrentRelativePosition(binaryReader)));

            //cmdArraySize = 0;
            //foreach (Animation animation in Animations)
            //{
            //    foreach (AnimationDefinition animationDefinition in animation.AnimDefinitions)
            //    {
            //        if (!animationDefinition.Disabled)
            //        {
            //            int cmdArrayFinalPosition = animationDefinition.Start + animationDefinition.Length;
            //            if (cmdArrayFinalPosition > cmdArraySize)
            //            {
            //                cmdArraySize = cmdArrayFinalPosition;
            //            }
            //        }
            //    }
            //}

            Commands = new List <byte>();
            for (int i = 0; i < cmdArraySize; i++)
            {
                Commands.Add(binaryReader.ReadByte1());
            }


            Limbs = new List <Limb>();

            //Pega uma lista apenas com os limbs distintos, sem as repetições:
            //, e ignora o ultimo valor, sei lá porque, mas o ultimo valor parece apontar para o final da lista!
            List <ushort> differentLimbsOnly = LimbsOffsets.Distinct().ToList();

            for (int i = 0; i < differentLimbsOnly.Count - 1; i++)
            {
                Limb currentLimb = new Limb();
                currentLimb.OffSet = differentLimbsOnly[i];
                currentLimb.Size   = (ushort)(differentLimbsOnly[i + 1] - differentLimbsOnly[i]);

                Limbs.Add(currentLimb);
            }
            //Para determinar o tamanho do ultimo limb, é preciso saber onde começa a primeira imagem do primeiro limb,
            //pois ela vem, segundo o texto do scummc, logo apos a ultima tabela de limb. Então eu pego o offset da
            //primeira imagem do primeiro limb (dando peek no ushort, que será o primeiro valor lido)
            //e subtraio o offset de inicio do ultimo limb, com isso eu descubro o tamanho.
            Limb lastLimb = new Limb();

            lastLimb.OffSet = differentLimbsOnly[differentLimbsOnly.Count - 1];

            //TESTE para tentar descobrir que porra ta acontecendo aqui
            ushort nextValue = binaryReader.PeekUint16();

            if (nextValue == 0)
            {
                //Debugger.Break();
            }
            else
            {
                lastLimb.Size = (ushort)(nextValue - lastLimb.OffSet);
            }

            //Eu to achando que se o size for 0, então na verdade esse limb não existe.
            //O negócio é que eu acho que pra determinar o tamanho do limb, o engine do scumm
            //desconta o offset do limb seguinte do limb atual, então o ultimo limb, se não
            //tiver tamanho, era porque seu offset só serviria para determinar o tamanho do limb
            //anterior.
            //ACHO que talvez por isso, em algumas vezes o nextValue logo acima é 0,
            //porque por alguma razão o valor não era o do inicio da próxima imagem e dai foi nulado. Mas isso tudo pode ser besteira tb.
            if (lastLimb.Size > 0)
            {
                Limbs.Add(lastLimb);
            }


            foreach (Limb limb in Limbs)
            {
                if ((limb.Size % 2) != 0)
                {
                    Debugger.Break();
                }
                if (limb.OffSet != (DebugGetCurrentRelativePosition(binaryReader)))
                {
                    Debugger.Break();
                }

                //Como cada indice tem 2 bytes (ushort), então o total de entradas é o tamanho do limb dividido por 2
                for (int i = 0; i < (limb.Size / 2); i++)
                {
                    ushort currentImageOffset = binaryReader.ReadUint16();
                    limb.ImageOffsets.Add(currentImageOffset);
                }
            }

            Pictures = new List <CostumeImageData>();
            int picturesHeaderSize = 12;

            if ((Format & 0x7E) == 0x60)
            {
                //soh vai ter redir_limb e redir_pic se os bits 6 e 7 do format estiver ligados.
                picturesHeaderSize = 14;
            }

            //Primeiro vamos calcular o tamanho que tera os dados de cada imagem.
            //Para isso, precisamos pegar a imagem atual + 1, e descontar do offset dela
            //o offset da imagem atual. Com isso teremos o tamanho total da imagem.
            //Desse total, descontamos 14 (ou 12), que é o número de bytes do cabeçalho da imagem.
            CostumeImageData lastImageData = null;

            foreach (Limb limb in Limbs)
            {
                if (limb.ImageOffsets.Count > 0)
                {
                    if (lastImageData != null)
                    {
                        ushort firstWithImageOffSet = limb.ImageOffsets.Where(x => x > 0).First();
                        lastImageData.ImageDataSize = (ushort)((firstWithImageOffSet - lastImageData.ImageStartOffSet) - picturesHeaderSize);
                        Pictures.Add(lastImageData);
                    }

                    for (int i = 0; i < limb.ImageOffsets.Count - 1; i++)
                    {
                        if (limb.ImageOffsets[i] > 0)
                        {
                            //if (limb.ImageOffsets[i] != (DebugGetCurrentRelativePosition(binaryReader))) Debugger.Break();

                            ushort nextWithImageOffset = limb.ImageOffsets.Skip(i + 1).Where(x => x > 0).First();


                            CostumeImageData currentCostumeImageData = new CostumeImageData();
                            currentCostumeImageData.ImageStartOffSet = limb.ImageOffsets[i];
                            currentCostumeImageData.ImageDataSize    = (ushort)((nextWithImageOffset - currentCostumeImageData.ImageStartOffSet) - picturesHeaderSize);

                            Pictures.Add(currentCostumeImageData);
                        }
                    }
                    lastImageData = new CostumeImageData();
                    ushort lastWithImageOffset = limb.ImageOffsets.Where(x => x > 0).Last();
                    lastImageData.ImageStartOffSet = lastWithImageOffset; //limb.ImageOffsets[limb.ImageOffsets.Count - 1];
                }
            }
            if (lastImageData != null)
            {
                uint sizeVerify = 0;

                switch (_gameInfo.ScummVersion)
                {
                case 5:
                    sizeVerify = BlockSize - 2;
                    break;

                case 6:
                    //pra determinar o tamanho da ultima imagem, vamos usar o parametro size(??) que foi o primeiro valor lido pelo costume.
                    //Talvez eu deva utilizar o blocksize, não sei... é que esse size não faz muito sentido, visto que o blocksize
                    //é justamente pra isso. Sei lá, tem alguma pegadinha aqui. Mas em alguns casos o SIZE é 0, dai tem que usar o blocksize mesmo (?)
                    sizeVerify = Size == 0 ? BlockSize - 8 : Size;
                    break;

                default:
                    Debugger.Break();     //Não era pra cair aqui.
                    break;
                }
                lastImageData.ImageDataSize = (ushort)((sizeVerify - lastImageData.ImageStartOffSet) - picturesHeaderSize);
                Pictures.Add(lastImageData);
            }

            //Agora sim, finalmente, depois dessa volta MEDONHA, parece que conseguimos chegar de fato aos dados dos frames das
            //animações... espero que sim pelo menos.
            foreach (CostumeImageData picture in Pictures)
            {
                /*
                 * width            : 16le
                 * height           : 16le
                 * rel_x            : s16le
                 * rel_y            : s16le
                 * move_x           : s16le
                 * move_y           : s16le
                 * redir_limb       : 8 only present if((format & 0x7E) == 0x60)
                 * redir_pict       : 8 only present if((format & 0x7E) == 0x60)
                 * rle data
                 */
                picture.Width  = binaryReader.ReadUint16();
                picture.Height = binaryReader.ReadUint16();
                picture.RelX   = binaryReader.ReadInt16();
                picture.RelY   = binaryReader.ReadInt16();
                picture.MoveX  = binaryReader.ReadInt16();
                picture.MoveY  = binaryReader.ReadInt16();
                if (picturesHeaderSize == 14)
                {
                    //Mexendo, a impressão que parece é que só tem informações de REDIR_LIMB e REDIR_PICT quando
                    //o size == 0. Não sei porque, mas é isso que ta parecendo.
                    //Vou fazer mais uns testes.
                    picture.HasRedirInfo = true;
                    picture.RedirLimb    = binaryReader.ReadByte1();
                    picture.RedirPict    = binaryReader.ReadByte1();
                }
                picture.ImageData = binaryReader.ReadBytes(picture.ImageDataSize);
            }

            if (_gameInfo.ScummVersion == 6)
            {
                uint blockSizeWithoutHeader = (BlockSize - 8);
                if (blockSizeWithoutHeader == Size)
                {
                    //não faz nada
                }
                else if (blockSizeWithoutHeader == Size + 1)
                {
                    HasCloseByte = true;
                    CloseByte    = binaryReader.ReadByte1();
                }
            }

            //TEM GATO NA TUBA!?!?
            if (binaryReader.Position - BlockOffSet != BlockSize)
            {
                Debugger.Break();
            }
        }