diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp index 5466d83..7f13fef 100644 --- a/libgambatte/src/video.cpp +++ b/libgambatte/src/video.cpp @@ -94,7 +94,7 @@ LCD::LCD(const uint8_t *const oamram, const uint8_t *const vram_in) : m3EventQueue(11, VideoEventComparer()), irqEventQueue(4, VideoEventComparer()), vEventQueue(5, VideoEventComparer()), - m3ExtraCycles(spriteMapper, scxReader, weMasterChecker, wyReg, we, wxReader), + m3ExtraCycles(*this), weMasterChecker(m3EventQueue, wyReg, lyCounter), wyReg(lyCounter, weMasterChecker), wxReader(m3EventQueue, we.enableChecker(), we.disableChecker()), @@ -1259,9 +1259,10 @@ void LCD::cgb_drawSprites(T * const buffer_line, const unsigned ypos) { const unsigned wx = wxReader.wx() < 7 ? 0 : wxReader.wx() - 7; //const bool enableWindow = (memory.fastread(0xFF40) & 0x20) && (ypos >= memory.fastread(0xFF4A)) && (wx < 160); const bool enableWindow = (weMasterChecker.weMaster() || ypos == wyReg.value()) && we.value() && wyReg.value() <= ypos && wxReader.wx() < 0xA7; + const unsigned short *const spriteMapLine = spriteMapper.sprites(ypos); - for (int i = spriteMapper.spriteMap()[ypos * 12 + 10] - 1; i >= 0; --i) { - const uint8_t *const spriteInfo = spriteMapper.oamram + (spriteMapper.spriteMap()[ypos*12+i] & 0xFF); + for (int i = spriteMapper.numSprites(ypos) - 1; i >= 0; --i) { + const uint8_t *const spriteInfo = spriteMapper.oamram + (spriteMapLine[i] & 0xFF); const unsigned spx = spriteInfo[1]; if (spx < 168 && spx) { @@ -1431,9 +1432,10 @@ void LCD::drawSprites(T * const buffer_line, const unsigned ypos) { const unsigned scy = (scReader.scy() + ypos)/*&0xFF*/; const unsigned wx = wxReader.wx() < 7 ? 0 : wxReader.wx() - 7; const bool enableWindow = (weMasterChecker.weMaster() || ypos == wyReg.value()) && we.value() && wyReg.value() <= ypos && wxReader.wx() < 0xA7; + const unsigned short *const spriteMapLine = spriteMapper.sprites(ypos); - for (int i = spriteMapper.spriteMap()[ypos * 12 + 10] - 1; i >= 0; --i) { - const uint8_t *const spriteInfo = spriteMapper.oamram + (spriteMapper.spriteMap()[ypos * 12 + i] & 0xFF); + for (int i = spriteMapper.numSprites(ypos) - 1; i >= 0; --i) { + const uint8_t *const spriteInfo = spriteMapper.oamram + (spriteMapLine[i] & 0xFF); const unsigned spx = spriteInfo[1]; if (spx < 168 && spx) { diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h index 7f6d643..508a2fe 100644 --- a/libgambatte/src/video.h +++ b/libgambatte/src/video.h @@ -50,6 +50,8 @@ class Filter; #include "video/m3_extra_cycles.h" class LCD { + friend class M3ExtraCycles; + //static const uint8_t xflipt[0x100]; uint32_t dmgColorsRgb32[3 * 4]; uint32_t dmgColorsRgb16[3 * 4]; diff --git a/libgambatte/src/video/m3_extra_cycles.cpp b/libgambatte/src/video/m3_extra_cycles.cpp index 2bd7f2c..184da08 100644 --- a/libgambatte/src/video/m3_extra_cycles.cpp +++ b/libgambatte/src/video/m3_extra_cycles.cpp @@ -15,36 +15,21 @@ * version 2 along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -***************************************************************************/ + ***************************************************************************/ #include "m3_extra_cycles.h" -#include "sprite_mapper.h" -#include "scx_reader.h" -#include "we_master_checker.h" -#include "wy.h" -#include "we.h" -#include "wx_reader.h" +#include "../video.h" -M3ExtraCycles::M3ExtraCycles(const SpriteMapper &spriteMapper_in, - const ScxReader &scxReader_in, - const WeMasterChecker &weMasterChecker_in, - const Wy &wyReg_in, - const We &we_in, - const WxReader &wxReader_in) : - spriteMapper(spriteMapper_in), - scxReader(scxReader_in), - weMasterChecker(weMasterChecker_in), - wyReg(wyReg_in), - we(we_in), - wxReader(wxReader_in) +M3ExtraCycles::M3ExtraCycles(const LCD &video) : + video(video) {} unsigned M3ExtraCycles::operator()(const unsigned ly) const { - unsigned cycles = spriteMapper.spriteMap()[ly * 12 + 11]; + unsigned cycles = video.spriteMapper.spriteCycles(ly); - cycles += scxReader.scxAnd7(); + cycles += video.scxReader.scxAnd7(); - if ((weMasterChecker.weMaster() || ly == wyReg.value()) && we.value() && wyReg.value() <= ly && wxReader.wx() < 0xA7) + if (video.we.value() && video.wxReader.wx() < 0xA7 && ly >= video.wyReg.value() && (video.weMasterChecker.weMaster() || ly == video.wyReg.value())) cycles += 6; return cycles; diff --git a/libgambatte/src/video/m3_extra_cycles.h b/libgambatte/src/video/m3_extra_cycles.h index 0e9adbb..e9b5249 100644 --- a/libgambatte/src/video/m3_extra_cycles.h +++ b/libgambatte/src/video/m3_extra_cycles.h @@ -15,33 +15,17 @@ * version 2 along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -***************************************************************************/ + ***************************************************************************/ #ifndef VIDEO_M3_EXTRA_CYCLES_H #define VIDEO_M3_EXTRA_CYCLES_H -class SpriteMapper; -class ScxReader; -class WeMasterChecker; -class Wy; -class We; -class WxReader; +class LCD; class M3ExtraCycles { - const SpriteMapper &spriteMapper; - const ScxReader &scxReader; - const WeMasterChecker &weMasterChecker; - const Wy &wyReg; - const We &we; - const WxReader &wxReader; + const LCD &video; public: - M3ExtraCycles(const SpriteMapper &spriteMapper_in, - const ScxReader &scxReader_in, - const WeMasterChecker &weMasterChecker_in, - const Wy &wyReg_in, - const We &we_in, - const WxReader &wxReader_in); - + M3ExtraCycles(const LCD &video); unsigned operator()(unsigned ly) const; }; diff --git a/libgambatte/src/video/sprite_mapper.cpp b/libgambatte/src/video/sprite_mapper.cpp index d968b09..cc54232 100644 --- a/libgambatte/src/video/sprite_mapper.cpp +++ b/libgambatte/src/video/sprite_mapper.cpp @@ -21,7 +21,8 @@ #include "scx_reader.h" #include "../event_queue.h" -#include +// #include +#include SpriteMapper::SpriteMapper(const SpriteSizeReader &spriteSizeReader_in, const ScxReader &scxReader_in, @@ -37,17 +38,53 @@ SpriteMapper::SpriteMapper(const SpriteSizeReader &spriteSizeReader_in, } void SpriteMapper::clearMap() { - for (uint16_t* i = &spritemap[10]; i < &spritemap[144 * 12]; i += 12) - i[1] = i[0] = 0; + std::memset(cycles, CYCLES_INVALID, sizeof(cycles)); + std::memset(num, 0, sizeof(num)); } -static void insertionSort(uint16_t *const start, uint16_t *const end) { - uint16_t *a = start; +void SpriteMapper::mapSprites() { + clearMap(); + + const unsigned spriteHeight = 8 << spriteSizeReader.largeSprites(); + + for (unsigned i = 0x00; i < 0xA0; i += 4) { + const unsigned bottom_pos = oamram[i] - (17 - spriteHeight); + + if (bottom_pos >= 143 + spriteHeight) + continue; + + const unsigned spx = oamram[i + 1]; + const unsigned value = spx << 8 | i; + + unsigned short *map = spritemap; + unsigned char *n = num; + + if (bottom_pos >= spriteHeight) { + const unsigned startly = bottom_pos + 1 - spriteHeight; + n += startly; + map += startly * 10; + } + + unsigned char *const end = num + (bottom_pos >= 143 ? 143 : bottom_pos); + + do { + if (*n < 10) + map[(*n)++] = value; + + map += 10; + ++n; + } while (n <= end); + } +} + +// unsafe if start is at the end of allocated memory, since start+1 could be undefined/of. +static void insertionSort(unsigned short *const start, unsigned short *const end) { + unsigned short *a = start; while (++a < end) { const unsigned e = *a; - uint16_t *b = a; + unsigned short *b = a; while (b != start && *(b - 1) > e) { *b = *(b - 1); @@ -58,77 +95,54 @@ static void insertionSort(uint16_t *const start, uint16_t *const end) { } } -void SpriteMapper::mapSprites() { - clearMap(); - - const unsigned spriteHeight = 8 << spriteSizeReader.largeSprites(); - - for (unsigned i = 0x00; i < 0xA0; i += 4) { - const unsigned bottom_pos = oamram[i] - (17 - spriteHeight); - if (bottom_pos >= 143 + spriteHeight) - continue; - - const unsigned spx = oamram[i + 1]; - const unsigned value = (spx << 8) | i; - - uint16_t *tmp = &spritemap[bottom_pos < spriteHeight ? 0 : ((bottom_pos + 1 - spriteHeight) * 12)]; - uint16_t *const end = &spritemap[bottom_pos >= 143 ? 143 * 12 : (bottom_pos * 12)]; - - do { - if (tmp[10] < 10) - tmp[tmp[10]++] = value; - tmp += 12; - } while (tmp <= end); +void SpriteMapper::updateLine(const unsigned ly) const { + if (num[ly] == 0) { + cycles[ly] = 0; + return; } - uint16_t sortBuf[11]; + unsigned short sortBuf[10]; + unsigned short *tmp = spritemap + ly * 10; - for (uint16_t *mapPos = spritemap; mapPos < spritemap + 144 * 12; mapPos += 12) { - if (mapPos[10] == 0) - continue; + if (cgb) { + std::memcpy(sortBuf, tmp, sizeof(sortBuf)); + tmp = sortBuf; + } + + insertionSort(tmp, tmp + num[ly]); +// std::sort(tmp, tmp + num[ly]); + + unsigned sum = 0; + + for (unsigned i = 0; i < num[ly]; ++i) { + const unsigned spx = tmp[i] >> 8; - uint16_t *tmp = mapPos; + if (spx > 167) + break; - if (cgb) { - std::memcpy(sortBuf, tmp, sizeof(sortBuf)); - tmp = sortBuf; - } + unsigned cycles = 6; + const unsigned posAnd7 = scxReader.scxAnd7() + spx & 7; - insertionSort(tmp, tmp + tmp[10]); -// std::sort(tmp, tmp + tmp[10]); - - unsigned sum = 0; - - for (unsigned i = 0; i < tmp[10]; ++i) { - const unsigned spx = tmp[i] >> 8; + if (posAnd7 < 5) { + cycles = 11 - posAnd7; - if (spx > 167) - break; - - unsigned cycles = 6; - const unsigned posAnd7 = scxReader.scxAnd7() + spx & 7; - - if (posAnd7 < 5) { - cycles = 11 - posAnd7; + for (unsigned j = i; j--;) { + const unsigned tmpSpx = tmp[j] >> 8; - for (unsigned j = i; j--;) { - const unsigned tmpSpx = tmp[j] >> 8; - - if (spx - tmpSpx > 4U) - break; - - if ((scxReader.scxAnd7() + tmpSpx & 7) < 4 || spx == tmpSpx) { - cycles = 6; - break; - } + if (spx - tmpSpx > 4U) + break; + + if ((scxReader.scxAnd7() + tmpSpx & 7) < 4 || spx == tmpSpx) { + cycles = 6; + break; } } - - sum += cycles; } - mapPos[11] = sum; + sum += cycles; } + + cycles[ly] = sum; } void SpriteMapper::doEvent() { diff --git a/libgambatte/src/video/sprite_mapper.h b/libgambatte/src/video/sprite_mapper.h index ebe27e8..342fdba 100644 --- a/libgambatte/src/video/sprite_mapper.h +++ b/libgambatte/src/video/sprite_mapper.h @@ -29,7 +29,11 @@ class SpriteSizeReader; class ScxReader; class SpriteMapper : public VideoEvent { - uint16_t spritemap[144*12]; + enum { CYCLES_INVALID = 0xFF }; + + mutable unsigned short spritemap[144*10]; + mutable unsigned char cycles[144]; + unsigned char num[144]; const SpriteSizeReader &spriteSizeReader; const ScxReader &scxReader; @@ -38,11 +42,12 @@ public: const uint8_t *const oamram; private: - uint8_t timeDiff; + unsigned char timeDiff; bool cgb; void clearMap(); void mapSprites(); + void updateLine(unsigned ly) const; public: SpriteMapper(const SpriteSizeReader &spriteSizeReader_in, @@ -66,8 +71,22 @@ public: timeDiff = dS ? 85 * 2 - 40 : (82 - 16); } - const uint16_t * spriteMap() const { - return spritemap; + unsigned numSprites(const unsigned ly) const { + return num[ly]; + } + + unsigned spriteCycles(const unsigned ly) const { + if (cycles[ly] == CYCLES_INVALID) + updateLine(ly); + + return cycles[ly]; + } + + const unsigned short* sprites(const unsigned ly) const { + if (cycles[ly] == CYCLES_INVALID) + updateLine(ly); + + return spritemap + ly * 10; } };