private Quadrant GetNextQuadrant(Quadrant current) { QuadrantOrder order = (current.Order == QuadrantOrder.DownLeft) ? QuadrantOrder.DownRight : current.Order + 1; return(SpriteControlBlock.Quadrants[(int)order]); }
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); }