From f6181400c4af8aa5bf33b15ee23eaaab7045d362 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Fri, 15 Sep 2017 17:25:55 +0100 Subject: [PATCH] First stab at sprites. Lots of bugs! Signed-off-by: Adrian.Conlon --- LR35902/inc/CharacterDefinition.h | 2 +- LR35902/inc/Display.h | 12 ++ LR35902/inc/ObjectAttribute.h | 42 +++++++ LR35902/src/Display.cpp | 163 ++++++++++++++++++++-------- LR35902/src/LR35902.vcxproj | 1 + LR35902/src/LR35902.vcxproj.filters | 3 + 6 files changed, 175 insertions(+), 48 deletions(-) create mode 100644 LR35902/inc/ObjectAttribute.h diff --git a/LR35902/inc/CharacterDefinition.h b/LR35902/inc/CharacterDefinition.h index 7a2632c..da227a7 100644 --- a/LR35902/inc/CharacterDefinition.h +++ b/LR35902/inc/CharacterDefinition.h @@ -3,7 +3,7 @@ #include #include -#include "Bus.h" +#include namespace EightBit { namespace GameBoy { diff --git a/LR35902/inc/Display.h b/LR35902/inc/Display.h index 920e1f8..10cc24f 100644 --- a/LR35902/inc/Display.h +++ b/LR35902/inc/Display.h @@ -30,6 +30,18 @@ namespace EightBit { std::vector m_pixels; Bus& m_bus; const AbstractColourPalette* m_colours; + + std::array createPalette(int address); + + void renderBackground(); + void renderBackground( + int bgArea, int bgCharacters, + int offsetX, int offsetY, + int scrollX, int scrollY, + const std::array& palette); + + void renderObjects(); + void renderObjects(int objBlockHeight); }; } } \ No newline at end of file diff --git a/LR35902/inc/ObjectAttribute.h b/LR35902/inc/ObjectAttribute.h new file mode 100644 index 0000000..f2be34f --- /dev/null +++ b/LR35902/inc/ObjectAttribute.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include +#include + +namespace EightBit { + namespace GameBoy { + class ObjectAttribute { + public: + ObjectAttribute() {} + ObjectAttribute(Bus& bus, uint16_t address, int height) { + m_positionY = bus.peek(address); + m_positionX = bus.peek(address + 1); + m_pattern = bus.peek(address + 2); + if (height == 16) + m_pattern >>= 1; + m_flags = bus.peek(address + 3); + } + + uint8_t positionY() const { return m_positionY; } + uint8_t positionX() const { return m_positionX; } + uint8_t pattern() const { return m_pattern; } + uint8_t flags() const { return m_flags; } + + uint8_t priority() const { return flags() & Processor::Bit7; } + + bool highPriority() const { return priority() != 0; } + bool lowPriority() const { return priority() == 0; } + bool flipY() const { return (flags() & Processor::Bit6) != 0; } + bool flipX() const { return (flags() & Processor::Bit5) != 0; } + int palette() const { return (flags() & Processor::Bit4) >> 3; } + + private: + uint8_t m_positionY; + uint8_t m_positionX; + uint8_t m_pattern; + uint8_t m_flags; + }; + } +} \ No newline at end of file diff --git a/LR35902/src/Display.cpp b/LR35902/src/Display.cpp index c50df7c..a619288 100644 --- a/LR35902/src/Display.cpp +++ b/LR35902/src/Display.cpp @@ -2,6 +2,9 @@ #include "Display.h" #include "Processor.h" #include "CharacterDefinition.h" +#include "ObjectAttribute.h" + +#include EightBit::GameBoy::Display::Display(const AbstractColourPalette* colours, Bus& bus) : m_bus(bus), @@ -22,65 +25,131 @@ void EightBit::GameBoy::Display::render() { auto on = control & Bus::LcdEnable; if (on) { - auto windowArea = (control & Bus::WindowCodeAreaSelection) ? 0x9c00 : 0x9800; - auto window = (control & Bus::WindowEnable) != 0; - auto bgCharacters = (control & Bus::BackgroundCharacterDataSelection) ? 0x8000 : 0x8800; - auto bgArea = (control & Bus::BackgroundCodeAreaSelection) ? 0x9c00 : 0x9800; - auto objBlockHeight = (control & Bus::ObjectBlockCompositionSelection) ? 16 : 8; - auto objEnable = (control & Bus::ObjectEnable) != 0; - auto bgDisplay = (control & Bus::DisplayBackground) != 0; + const auto bgDisplay = (control & Bus::DisplayBackground) != 0; + if (bgDisplay) + renderBackground(); - auto scrollX = m_bus.peekRegister(Bus::SCX); - auto scrollY = m_bus.peekRegister(Bus::SCY); + const auto objEnable = (control & Bus::ObjectEnable) != 0; + if (objEnable) + renderObjects(); + } +} - auto paletteRaw = m_bus.peekRegister(Bus::BGP); - std::array palette; - palette[0] = paletteRaw & 0b11; - palette[1] = (paletteRaw & 0b1100) >> 2; - palette[2] = (paletteRaw & 0b110000) >> 4; - palette[3] = (paletteRaw & 0b11000000) >> 6; +std::array EightBit::GameBoy::Display::createPalette(const int address) { + const auto raw = m_bus.peekRegister(address); + std::array palette; + palette[0] = raw & 0b11; + palette[1] = (raw & 0b1100) >> 2; + palette[2] = (raw & 0b110000) >> 4; + palette[3] = (raw & 0b11000000) >> 6; + return palette; +} - auto wx = m_bus.peekRegister(Bus::WX); - auto wy = m_bus.peekRegister(Bus::WY); +void EightBit::GameBoy::Display::renderObjects() { + const auto control = m_bus.peekRegister(Bus::LCDC); + const auto objBlockHeight = (control & Bus::ObjectBlockCompositionSelection) ? 16 : 8; + renderObjects(objBlockHeight); +} - auto offsetX = window ? wx - 7 : 0; - auto offsetY = window ? wy : 0; +void EightBit::GameBoy::Display::renderObjects(int objBlockHeight) { + + std::vector> palettes(2); + palettes[0] = createPalette(Bus::OBP0); + palettes[1] = createPalette(Bus::OBP1); - std::map definitions; + auto objDefinitionAddress = 0x8000; + auto oamAddress = 0xfe00; - for (int row = 0; row < BufferCharacterHeight; ++row) { - for (int column = 0; column < BufferCharacterWidth; ++column) { + for (int i = 0; i < 40; ++i) { + const auto current = ObjectAttribute(m_bus, oamAddress + 4 * i, objBlockHeight); + const auto sprite = current.pattern(); + const auto definition = CharacterDefinition(m_bus, objDefinitionAddress + 16 * sprite); + const auto spriteX = current.positionX(); + const auto spriteY = current.positionY(); + const auto& palette = palettes[current.palette()]; - auto address = bgArea + row * BufferCharacterWidth + column; - auto character = m_bus.peek(address); + for (int cy = 0; cy < 8; ++cy) { + for (int cx = 0; cx < 8; ++cx) { - auto definitionPair = definitions.find(character); + uint8_t x = spriteX + cx; + if (x >= RasterWidth) + break; - if (definitionPair == definitions.end()) { - definitions[character] = CharacterDefinition(m_bus, bgCharacters + 16 * character); - definitionPair = definitions.find(character); - } + uint8_t y = spriteX + cy; + if (y >= RasterHeight) + break; - auto definition = definitionPair->second; + auto outputPixel = y * RasterWidth + x; - for (int cy = 0; cy < 8; ++cy) { - for (int cx = 0; cx < 8; ++cx) { - - uint8_t x = column * 8 + cx + offsetX - scrollX; - if (x >= RasterWidth) - break; - - uint8_t y = row * 8 + cy + offsetY - scrollY; - if (y >= RasterHeight) - break; - - auto outputPixel = y * RasterWidth + x; - - auto colour = palette[definition.get()[cy * 8 + cx]]; - m_pixels[outputPixel] = m_colours->getColour(colour); - } - } + auto colour = palette[definition.get()[cy * 8 + cx]]; + m_pixels[outputPixel] = m_colours->getColour(colour); } } } } + +void EightBit::GameBoy::Display::renderBackground() { + + const auto control = m_bus.peekRegister(Bus::LCDC); + + auto palette = createPalette(Bus::BGP); + + const auto window = (control & Bus::WindowEnable) != 0; + const auto bgArea = (control & Bus::BackgroundCodeAreaSelection) ? 0x9c00 : 0x9800; + const auto bgCharacters = (control & Bus::BackgroundCharacterDataSelection) ? 0x8000 : 0x8800; + + const auto wx = m_bus.peekRegister(Bus::WX); + const auto wy = m_bus.peekRegister(Bus::WY); + + const auto offsetX = window ? wx - 7 : 0; + const auto offsetY = window ? wy : 0; + + const auto scrollX = m_bus.peekRegister(Bus::SCX); + const auto scrollY = m_bus.peekRegister(Bus::SCY); + + renderBackground(bgArea, bgCharacters, offsetX, offsetY, scrollX, scrollY, palette); +} + +void EightBit::GameBoy::Display::renderBackground( + int bgArea, int bgCharacters, + int offsetX, int offsetY, + int scrollX, int scrollY, + const std::array& palette) { + + std::map definitions; + + for (int row = 0; row < BufferCharacterHeight; ++row) { + for (int column = 0; column < BufferCharacterWidth; ++column) { + + auto address = bgArea + row * BufferCharacterWidth + column; + auto character = m_bus.peek(address); + + auto definitionPair = definitions.find(character); + + if (definitionPair == definitions.end()) { + definitions[character] = CharacterDefinition(m_bus, bgCharacters + 16 * character); + definitionPair = definitions.find(character); + } + + auto definition = definitionPair->second; + + for (int cy = 0; cy < 8; ++cy) { + for (int cx = 0; cx < 8; ++cx) { + + uint8_t x = column * 8 + cx + offsetX - scrollX; + if (x >= RasterWidth) + break; + + uint8_t y = row * 8 + cy + offsetY - scrollY; + if (y >= RasterHeight) + break; + + auto outputPixel = y * RasterWidth + x; + + auto colour = palette[definition.get()[cy * 8 + cx]]; + m_pixels[outputPixel] = m_colours->getColour(colour); + } + } + } + } +} \ No newline at end of file diff --git a/LR35902/src/LR35902.vcxproj b/LR35902/src/LR35902.vcxproj index 95a2911..141fb76 100644 --- a/LR35902/src/LR35902.vcxproj +++ b/LR35902/src/LR35902.vcxproj @@ -145,6 +145,7 @@ + diff --git a/LR35902/src/LR35902.vcxproj.filters b/LR35902/src/LR35902.vcxproj.filters index 7909042..ed7430e 100644 --- a/LR35902/src/LR35902.vcxproj.filters +++ b/LR35902/src/LR35902.vcxproj.filters @@ -35,6 +35,9 @@ Header Files + + Header Files +