-----------------------
-- Name: Sprite Box
-- Author: upsilandre
-----------------------
-- Displays a box around each sprite, as well as a sprite counter.
-- The counter displays the number of sprites on the screen (and will be shown in red if sprite overflow occurred on any scanline)
--
-- Each scanline with overflow will be marked by a small red line on the left side of the screen.
-- As the number of sprites over the limit increases, the line will progressively turn orange, yellow and then white.
--
-- Sprites with a red box as normal priority sprites, those in blue are background priority sprites.
--
-- 4 different display modes exist (change mode by right-clicking on the screen):
--   1- Edge Mode: Displays a rectangle outline around the sprites
--   2- Fill Mode: Displays a transparent overlay over the sprites
--   3- Priority Mode: Displays a transparent overlay over the sprites (the overlay's opacity is proportional to the sprite's position in OAM RAM)
--   4- Off Mode: Displays the sprite counter and nothing else
-----------------------

function Main()
  SelectMode()
  spritesOnScreen = 0
  counterColor = 0xFFFFFF
  for scanline = 0,254 do
    spritesOnLine[scanline] = 0
  end

  ppu = emu.getState().ppu
  if ppu.control.largeSprites then
    height = 16
  else
    height = 8
  end

  for oamAddr = 0, 252, 4 do
    spriteY = emu.read(oamAddr, emu.memType.oam) + 1
    if spriteY < 240 then
      spritesOnScreen = spritesOnScreen + 1
      for i = 0, (height - 1 ) do
        spritesOnLine[spriteY + i] = spritesOnLine[spriteY + i] + 1
      end
    end
    spriteX = emu.read(oamAddr + 3, emu.memType.oam)
    if emu.read(oamAddr + 2, emu.memType.oam) & 32 == 0 then
      color = 0xff0000
    else
      color = 0x0000ff
    end
    if mode == 2 then
      alpha = oamAddr / 4 * 0x03000000 + 0x20000000
    end
    emu.drawRectangle(spriteX, spriteY, 8, height, color + alpha, fill, 1)
  end

  for scanline = 0,239 do
    overflow = spritesOnLine[scanline] - 8
    if overflow > 0 then
      if overflow > 16 then
        overflowColor = 0xFFFFFF
      elseif overflow > 8 then
        overflowColor = 0xFFFF00 + (((overflow - 1) & 7) << 5)
      else
        overflowColor = 0xFF0000 + (((overflow - 1) & 7) << 13)
      end
      emu.drawLine(0, scanline, 7, scanline, overflowColor, 1)
      counterColor = 0xFF0000
    end
  end

  emu.drawRectangle(121, 3, 13, 9, 0x404040, true, 1)
  emu.drawRectangle(120, 2, 15, 11, 0x808080, false, 1)
  emu.drawString(122, 4, string.format("%02d", spritesOnScreen), counterColor, 0xFF000000, 1)
end


function SelectMode()
  if emu.getMouseState().right then
    if not holdButton then
      mode = (mode + 1) & 3
      emu.drawRectangle(94, 87, 68, 12, 0x404040, true, 50)
      emu.drawRectangle(93, 86, 70, 14, 0x808080, false, 50)
      if mode == 0 then
        fill = false
        alpha = 0x40000000
        emu.drawString(92, 89, "  Edge Mode  ", 0xFFFFFF, 0xFF000000, 50)
      elseif mode == 1 then
        fill = true
        alpha = 0x80000000
        emu.drawString(92, 89, "   Fill Mode   ", 0xFFFFFF, 0xFF000000, 50)
      elseif mode == 2 then
        emu.drawString(92, 89, " Priority Mode ", 0xFFFFFF, 0xFF000000, 50)
      else
        emu.drawString(92, 89, "  OFF Mode  ", 0xFFFFFF, 0xFF000000, 50)
        alpha =0xFF000000
      end
      holdButton = true
    end
  else
    holdButton = false
  end
end


mode = 0
alpha = 0x40000000
holdButton = false
fill = false
spritesOnLine = {}
emu.addEventCallback(Main, emu.eventType.startFrame)
emu.displayMessage("Script", "Sprite Box")
