예제 #1
0
        int MainRoutine(int xmoveCur, int ymoveCur)
        {
            int i, skip = 0;
            byte drawFlag = 1;
            bool use_scaling;
            byte startScaleIndexX;
            int ex1, ex2;
            var rect = new Rect();
            int step;
            var v1 = new Codec1();

            const int ScaletableSize = 128;
            bool newAmiCost = (_vm.Game.Version == 5) && (_vm.Game.Platform == Platform.Amiga);
            v1.Scaletable = smallCostumeScaleTable;

            if (_loaded.NumColors == 32)
            {
                v1.Mask = 7;
                v1.Shr = 3;
            }
            else
            {
                v1.Mask = 15;
                v1.Shr = 4;
            }
            _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin);

            switch (_loaded.Format)
            {
                case 0x60:
                case 0x61:
                    // This format is used e.g. in the Sam&Max intro
                    ex1 = _loaded.CostumeReader.ReadByte();
                    ex2 = _loaded.CostumeReader.ReadByte();
                    _srcptr += 2;
                    if (ex1 != 0xFF || ex2 != 0xFF)
                    {
                        _loaded.CostumeReader.BaseStream.Seek(_loaded.FrameOffsets + ex1 * 2, System.IO.SeekOrigin.Begin);
                        ex1 = _loaded.CostumeReader.ReadUInt16();
                        _loaded.CostumeReader.BaseStream.Seek(_loaded.BasePtr + ex1 + ex2 * 2, System.IO.SeekOrigin.Begin);
                        _srcptr = _loaded.BasePtr + _loaded.CostumeReader.ReadUInt16() + 14;
                    }
                    break;
            }

            use_scaling = (ScaleX != 0xFF) || (ScaleY != 0xFF);

            v1.X = ActorX;
            v1.Y = ActorY;

            if (use_scaling)
            {

                /* Scale direction */
                v1.ScaleXStep = -1;
                if (xmoveCur < 0)
                {
                    xmoveCur = -xmoveCur;
                    v1.ScaleXStep = 1;
                }

                // It's possible that the scale indexes will overflow and wrap
                // around to zero, so it's important that we use the same
                // method of accessing it both when calculating the size of the
                // scaled costume, and when drawing it. See bug #1519667.

                if (_mirror)
                {
                    /* Adjust X position */
                    startScaleIndexX = _scaleIndexX = (byte)(ScaletableSize - xmoveCur);
                    for (i = 0; i < xmoveCur; i++)
                    {
                        if (v1.Scaletable[_scaleIndexX++] < ScaleX)
                            v1.X -= v1.ScaleXStep;
                    }

                    rect.Left = rect.Right = v1.X;

                    _scaleIndexX = startScaleIndexX;
                    for (i = 0; i < _width; i++)
                    {
                        if (rect.Right < 0)
                        {
                            skip++;
                            startScaleIndexX = _scaleIndexX;
                        }
                        if (v1.Scaletable[_scaleIndexX++] < ScaleX)
                            rect.Right++;
                    }
                }
                else
                {
                    /* No mirror */
                    /* Adjust X position */
                    startScaleIndexX = _scaleIndexX = (byte)(xmoveCur + ScaletableSize);
                    for (i = 0; i < xmoveCur; i++)
                    {
                        if (v1.Scaletable[_scaleIndexX--] < ScaleX)
                            v1.X += v1.ScaleXStep;
                    }

                    rect.Left = rect.Right = v1.X;

                    _scaleIndexX = startScaleIndexX;
                    for (i = 0; i < _width; i++)
                    {
                        if (rect.Left >= _w)
                        {
                            startScaleIndexX = _scaleIndexX;
                            skip++;
                        }
                        if (v1.Scaletable[_scaleIndexX--] < ScaleX)
                            rect.Left--;
                    }
                }
                _scaleIndexX = startScaleIndexX;

                if (skip != 0)
                    skip--;

                step = -1;
                if (ymoveCur < 0)
                {
                    ymoveCur = -ymoveCur;
                    step = 1;
                }

                _scaleIndexY = (byte)(ScaletableSize - ymoveCur);
                for (i = 0; i < ymoveCur; i++)
                {
                    if (v1.Scaletable[_scaleIndexY++] < ScaleY)
                        v1.Y -= step;
                }

                rect.Top = rect.Bottom = v1.Y;
                _scaleIndexY = (byte)(ScaletableSize - ymoveCur);
                for (i = 0; i < _height; i++)
                {
                    if (v1.Scaletable[_scaleIndexY++] < ScaleY)
                        rect.Bottom++;
                }

                _scaleIndexY = (byte)(ScaletableSize - ymoveCur);
            }
            else
            {
                if (!_mirror)
                    xmoveCur = -xmoveCur;

                v1.X += xmoveCur;
                v1.Y += ymoveCur;

                if (_mirror)
                {
                    rect.Left = v1.X;
                    rect.Right = v1.X + _width;
                }
                else
                {
                    rect.Left = v1.X - _width;
                    rect.Right = v1.X;
                }

                rect.Top = v1.Y;
                rect.Bottom = rect.Top + _height;

            }

            v1.SkipWidth = _width;
            v1.ScaleXStep = _mirror ? 1 : -1;

            if (_vm.Game.Version == 1)
                // V1 games uses 8 x 8 pixels for actors
                _vm.MarkRectAsDirty(_vm.MainVirtScreen, rect.Left, rect.Right + 8, rect.Top, rect.Bottom, ActorID);
            else
                _vm.MarkRectAsDirty(_vm.MainVirtScreen, rect.Left, rect.Right + 1, rect.Top, rect.Bottom, ActorID);

            if (rect.Top >= _h || rect.Bottom <= 0)
                return 0;

            if (rect.Left >= _w || rect.Right <= 0)
                return 0;

            v1.RepLen = 0;

            if (_mirror)
            {
                if (!use_scaling)
                    skip = -v1.X;
                if (skip > 0)
                {
                    if (!newAmiCost && _loaded.Format != 0x57)
                    {
                        v1.SkipWidth -= skip;
                        Codec1IgnorePakCols(v1, skip);
                        v1.X = 0;
                    }
                }
                else
                {
                    skip = rect.Right - _w;
                    if (skip <= 0)
                    {
                        drawFlag = 2;
                    }
                    else
                    {
                        v1.SkipWidth -= skip;
                    }
                }
            }
            else
            {
                if (!use_scaling)
                    skip = rect.Right - _w;
                if (skip > 0)
                {
                    if (!newAmiCost && _loaded.Format != 0x57)
                    {
                        v1.SkipWidth -= skip;
                        Codec1IgnorePakCols(v1, skip);
                        v1.X = _w - 1;
                    }
                }
                else
                {
                    // V1 games uses 8 x 8 pixels for actors
                    if (_loaded.Format == 0x57)
                        skip = -8 - rect.Left;
                    else
                        skip = -1 - rect.Left;
                    if (skip <= 0)
                        drawFlag = 2;
                    else
                        v1.SkipWidth -= skip;
                }
            }

            if (v1.SkipWidth <= 0)
                return 0;

            if (rect.Left < 0)
                rect.Left = 0;

            if (rect.Top < 0)
                rect.Top = 0;

            if (rect.Top > _h)
                rect.Top = _h;

            if (rect.Bottom > _h)
                rect.Bottom = _h;

            if (DrawTop > rect.Top)
                DrawTop = rect.Top;
            if (DrawBottom < rect.Bottom)
                DrawBottom = rect.Bottom;

            if (_height + rect.Top >= 256)
            {
                return 2;
            }

            _pixelsNavigator = new PixelNavigator(startNav);
            _pixelsNavigator.Offset(v1.X, v1.Y);
            v1.DestPtr = _pixelsNavigator;

            v1.MaskPtr = _vm.GetMaskBuffer(0, v1.Y, ZBuffer);

            if (_loaded.Format == 0x57)
            {
                // The v1 costume renderer needs the actor number, which is
                // the same thing as the costume renderer's _actorID.
                ProcC64(v1, ActorID);
            }
            else if (newAmiCost)
            {
                Proc3Amiga(v1);
            }
            else
            {
                Proc3(v1);
            }

            return drawFlag;
        }
예제 #2
0
        protected void RestoreBackground(Rect rect, byte backColor = 0)
        {
            VirtScreen vs;

            if (rect.Top < 0)
                rect.Top = 0;
            if (rect.Left >= rect.Right || rect.Top >= rect.Bottom)
                return;

            if ((vs = FindVirtScreen(rect.Top)) == null)
                return;

            if (rect.Left > vs.Width)
                return;

            // Convert 'rect' to local (virtual screen) coordinates
            rect.Top -= vs.TopLine;
            rect.Bottom -= vs.TopLine;

            rect.Clip(vs.Width, vs.Height);

            int height = rect.Height;
            int width = rect.Width;

            if (_game.Platform == Platform.FMTowns && Game.GameId == GameId.Monkey1 && vs == VerbVirtScreen && rect.Bottom <= 154)
                rect.Right = 319;

            MarkRectAsDirty(vs, rect.Left, rect.Right, rect.Top, rect.Bottom, Gdi.UsageBitRestored);

            var screenBuf = new PixelNavigator(vs.Surfaces[0]);
            screenBuf.GoTo(vs.XStart + rect.Left, rect.Top);

            if (height == 0)
                return;

            if (vs.HasTwoBuffers && _currentRoom != 0 && IsLightOn())
            {
                var back = new PixelNavigator(vs.Surfaces[1]);
                back.GoTo(vs.XStart + rect.Left, rect.Top);
                Gdi.Blit(screenBuf, back, width, height);
                if (vs == MainVirtScreen && _charset.HasMask)
                {
                    if (_game.Platform == Platform.FMTowns)
                    {
                        var mask = new PixelNavigator(_textSurface);
                        mask.GoTo(rect.Left * _textSurfaceMultiplier, (rect.Top + vs.TopLine) * _textSurfaceMultiplier);
                        Gdi.Fill(mask, 0, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);
                    }
                    else
                    {
                        var mask = new PixelNavigator(_textSurface);
                        mask.GoTo(rect.Left, rect.Top - ScreenTop);
                        Gdi.Fill(mask, CharsetMaskTransparency, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);
                    }
                }
            }
            else
            {
                if (Game.Platform == Platform.FMTowns)
                {
                    backColor |= (byte)(backColor << 4);
                    var mask = new PixelNavigator(_textSurface);
                    mask.GoTo(rect.Left * _textSurfaceMultiplier, (rect.Top + vs.TopLine) * _textSurfaceMultiplier);
                    Gdi.Fill(mask, backColor, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);
                }

                if (Game.Features.HasFlag(GameFeatures.Is16BitColor))
                    Gdi.Fill(screenBuf, _16BitPalette[backColor], width, height);
                else
                    Gdi.Fill(screenBuf, backColor, width, height);
            }
        }
예제 #3
0
 internal void MarkRectAsDirty(VirtScreen vs, Rect r, int dirtybit = 0)
 {
     MarkRectAsDirty(vs, r.Left, r.Right, r.Top, r.Bottom, dirtybit);
 }
예제 #4
0
 void TownsSetupPalCycleField(int x1, int y1, int x2, int y2)
 {
     if (_numCyclRects >= 10)
         return;
     _cyclRects[_numCyclRects] = new Rect(x1, y1, x2, y2);
     _numCyclRects++;
     TownsPaletteFlags |= 1;
 }
예제 #5
0
        public void AddDirtyRect(int x, int y, int w, int h)
        {
            if (w <= 0 || h <= 0 || _numDirtyRects > DIRTY_RECTS_MAX)
                return;

            if (_numDirtyRects == DIRTY_RECTS_MAX)
            {
                // full redraw
                _dirtyRects.Clear();
                _dirtyRects.Add(new Rect(_width - 1, _height - 1));
                _numDirtyRects++;
                return;
            }

            int x2 = x + w - 1;
            int y2 = y + h - 1;

            Debug.Assert(x >= 0 && y >= 0 && x2 <= _width && y2 <= _height);

            bool skip = false;
            for (int i = 0; i < _dirtyRects.Count; i++)
            {
                var r = _dirtyRects[i];
                // Try to merge new rect with an existing rect (only once, since trying to merge
                // more than one overlapping rect would be causing more overhead than doing any good).
                if (x > r.Left && x < r.Right && y > r.Top && y < r.Bottom)
                {
                    x = r.Left;
                    y = r.Top;
                    skip = true;
                }

                if (x2 > r.Left && x2 < r.Right && y > r.Top && y < r.Bottom)
                {
                    x2 = r.Right;
                    y = r.Top;
                    skip = true;
                }

                if (x2 > r.Left && x2 < r.Right && y2 > r.Top && y2 < r.Bottom)
                {
                    x2 = r.Right;
                    y2 = r.Bottom;
                    skip = true;
                }

                if (x > r.Left && x < r.Right && y2 > r.Top && y2 < r.Bottom)
                {
                    x = r.Left;
                    y2 = r.Bottom;
                    skip = true;
                }

                if (skip)
                {
                    _dirtyRects[i] = new Rect(x, y, x2, y2);
                    break;
                }
            }

            if (!skip)
            {
                _dirtyRects.Add(new Rect(x, y, x2, y2));
                _numDirtyRects++;
            }
        }
예제 #6
0
 void MarkRectAsDirty(Rect rect)
 {
     rect.Left -= _vm.MainVirtScreen.XStart & 7;
     rect.Right -= _vm.MainVirtScreen.XStart & 7;
     _vm.MarkRectAsDirty(_vm.MainVirtScreen, rect, ActorID);
 }
예제 #7
0
파일: Screen.cs 프로젝트: scemino/nscumm
 public void SetFocusRectangle(Rect rect)
 {
     // TODO: _system.SetFocusRectangle(rect);
     //_system.SetFocusRectangle(rect);
 }
예제 #8
0
파일: Gdi.cs 프로젝트: scemino/nscumm
        public static void Fill(Surface surface, Rect r, int color)
        {
            r = new Rect(r.Left, r.Top, r.Right, r.Bottom);
            r.Clip(surface.Width, surface.Height);

            if (!r.IsValid)
                return;

            int width = r.Width;
            int lineLen = width;
            int height = r.Height;
            bool useMemset = true;

            var bpp = Surface.GetBytesPerPixel(surface.PixelFormat);
            if (bpp == 2)
            {
                lineLen *= 2;
                if ((ushort)color != ((color & 0xff) | (color & 0xff) << 8))
                    useMemset = false;
            }
            else if (bpp == 4)
            {
                useMemset = false;
            }
            else if (bpp != 1)
            {
                throw new InvalidOperationException("Surface::fillRect: bytesPerPixel must be 1, 2, or 4");
            }

            if (useMemset)
            {
                var pn = new PixelNavigator(surface);
                pn.GoTo(r.Left, r.Top);
                for (int i = 0; i < height; i++)
                {
                    pn.Set((byte)color, lineLen);
                    pn.OffsetY(1);
                }
            }
            else
            {
                if (bpp == 2)
                {
                    var pn = new PixelNavigator(surface);
                    pn.GoTo(r.Left, r.Top);
                    for (int i = 0; i < height; i++)
                    {
                        pn.Set((ushort)color, lineLen);
                        pn.OffsetX(surface.Width);
                    }
                }
                else
                {
                    var pn = new PixelNavigator(surface);
                    pn.GoTo(r.Left, r.Top);
                    for (int i = 0; i < height; i++)
                    {
                        pn.Set((uint)color, lineLen);
                        pn.OffsetX(surface.Width / 2);
                    }
                }
            }
        }