Exemplo n.º 1
0
        private Quadrant GetNextQuadrant(Quadrant current)
        {
            QuadrantOrder order = (current.Order == QuadrantOrder.DownLeft) ? QuadrantOrder.DownRight : current.Order + 1;

            return(SpriteControlBlock.Quadrants[(int)order]);
        }
Exemplo n.º 2
0
        public bool RenderSingleSprite()
        {
            // "The processing of an actual sprite can be 'skipped' on a sprite by sprite basis."
            if (scb.SPRCTL1.SkipSprite)
            {
                return(false);
            }

            bool isEverOnScreen = false;

            PROCADR.Value = scb.SPRDLINE.Value;             // Set current PROC address

            // Prepare for unpacking data
            Quadrant quadrant = scb.StartQuadrant;

            unpacker.Initialize(PROCADR.Value, scb.SPRCTL0.BitsPerPixel, scb.SPRCTL1.TotallyLiteral);

            // Loop through all quadrants
            do
            {
                // Quadrant initialization
                // Determine direction for vertical and horizontal drawing
                int horizontalIncrease = quadrant.HorizontalIncrease;
                int verticalIncrease   = quadrant.VerticalIncrease;

                if (scb.SPRCTL0.VFlip)
                {
                    verticalIncrease = -verticalIncrease;
                }
                if (scb.SPRCTL0.HFlip)
                {
                    horizontalIncrease = -horizontalIncrease;
                }

                TILTACUM.Value = 0;
                VSIZACUM.Value = (ushort)((verticalIncrease == 1) ? context.VSIZOFF.Value : 0);

                // Calculate current vertical position
                //SPRVPOS.Value = (ushort)((short)scb.VPOSSTRT.Value - context.VOFF.Value);
                int sprvpos = (short)scb.VPOSSTRT.Value - (short)context.VOFF.Value;

                // Initialize current line data value
                scb.SPRDLINE.Value = PROCADR.Value;

                // Fix squashed look by offsetting vertical offset by one
                if (quadrant.VerticalIncrease != scb.StartQuadrant.VerticalIncrease)
                {
                    sprvpos += verticalIncrease;
                }

                // Loop through all lines
                byte pixelHeight = 0;
                while ((SPRDOFF.Value = unpacker.ReadOffsetToNextLine()) >= 2)
                {
                    // Vertical scaling
                    VSIZACUM.Value   += scb.SPRVSIZ.Value;
                    pixelHeight       = VSIZACUM.HighByte;
                    VSIZACUM.HighByte = 0;

                    VIDADR.Value  = (ushort)(context.VIDBAS.Value + (SPRVPOS.Value * (Suzy.SCREEN_WIDTH / 2)));
                    COLLADR.Value = (ushort)(context.COLLBAS.Value + (SPRVPOS.Value * (Suzy.SCREEN_WIDTH / 2)));

                    // TODO: Check visibility

                    for (int v = 0; v < pixelHeight; v++)
                    {
                        // Stop vertical loop if outside of screen bounds
                        if (verticalIncrease == 1 && sprvpos >= Suzy.SCREEN_HEIGHT)
                        {
                            break;
                        }
                        if (verticalIncrease == -1 && sprvpos < 0)
                        {
                            break;
                        }

                        if (sprvpos >= 0 && sprvpos < Suzy.SCREEN_HEIGHT)
                        {
                            scb.HPOSSTRT.Value += (ushort)((short)TILTACUM.Value >> 8);
                            TILTACUM.HighByte   = 0;
                            HSIZACUM.Value      = (ushort)((horizontalIncrease == 1) ? context.HSIZOFF.Value : 0);
                            int sprhpos = (short)scb.HPOSSTRT.Value - (short)context.HOFF.Value;

                            // Fix squashed look by offsetting 1 pixel on other directions
                            if (quadrant.HorizontalIncrease != scb.StartQuadrant.HorizontalIncrease)
                            {
                                sprhpos += horizontalIncrease;
                            }

                            // Draw row of pixels
                            foreach (byte pixelIndex in unpacker.PixelsInLine((byte)(SPRDOFF.Value - 1)))
                            {
                                HSIZACUM.Value += scb.SPRHSIZ.Value;
                                byte pixelWidth = HSIZACUM.HighByte;
                                HSIZACUM.HighByte = 0;

                                // Draw pixel
                                byte pixelValue = PenIndexPalette[pixelIndex];

                                for (int h = 0; h < pixelWidth; h++)
                                {
                                    // Stop horizontal loop if outside of screen bounds
                                    if (sprhpos >= 0 && sprhpos < Suzy.SCREEN_WIDTH)
                                    {
                                        // Process pixel based on sprite type
                                        bool   left   = sprhpos % 2 == 0;
                                        ushort offset = (ushort)((sprhpos + sprvpos * Suzy.SCREEN_WIDTH) / 2);
                                        ProcessPixel((ushort)(VIDADR.Value + offset), pixelValue, left);
                                        ProcessCollision((ushort)(COLLADR.Value + offset), pixelValue, left);

                                        isEverOnScreen = true;
                                    }
                                    sprhpos += horizontalIncrease;
                                }
                            }
                        }
                        sprvpos += verticalIncrease;

                        // "The horizontal size of a sprite can be modified every time a scan line is processed.
                        // This allows for 'stretching' a sprite and in conjunction with 'tilt' can be useful in creating
                        // arbitrary polygons."
                        if (StretchingEnabled)
                        {
                            scb.SPRHSIZ.Value += STRETCH.Value;
                        }

                        // "The horizontal position of a sprite can be modified every time a scan line is processed.
                        // This allows for 'tilting' a sprite and in conjunction with 'stretch' can be useful in
                        // creating arbitrary polygons."
                        if (TiltingEnabled)
                        {
                            TILTACUM.Value += TILT.Value;
                        }
                    }

                    unpacker.MoveToNextLine((byte)(SPRDOFF.Value - 1));
                    scb.SPRDLINE.Value += SPRDOFF.Value;

                    // "The vertical size of a sprite can be modified every time a scan line is processed.
                    // This allows for 'stretching' a sprite vertically. The vertical stretch factor is the same
                    // as the horizontal stretch factor.
                    // "Vertical stretching can be enabled on a sprite by sprite basis."
                    if (context.VStretch)
                    {
                        scb.SPRVSIZ.Value += (ushort)(STRETCH.Value * pixelHeight);
                    }
                }

                // Check if all quadrant rendering is done
                if (SPRDOFF.Value == 0)
                {
                    break;
                }

                // "An offset of +1 instructs the hardware to change to the next drawing direction."
                // Switch to next quadrant
                quadrant = GetNextQuadrant(quadrant);
            }while (quadrant != scb.StartQuadrant);            // Never more than 4 quadrants

            return(isEverOnScreen);
        }