41 lines
1.2 KiB
C++
41 lines
1.2 KiB
C++
|
/*
|
||
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||
|
*/
|
||
|
|
||
|
#include <teagba/addresses.hpp>
|
||
|
#include <teagba/bios.hpp>
|
||
|
#include <teagba/irq.hpp>
|
||
|
|
||
|
#include <teagba/gfx.hpp>
|
||
|
|
||
|
namespace teagba {
|
||
|
|
||
|
volatile uint16_t g_spriteUpdates = 0;
|
||
|
ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
|
||
|
|
||
|
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
|
||
|
// block until g_spriteUpdates is less than buffer len
|
||
|
if (g_spriteUpdates >= g_spriteBuffer.size()) [[unlikely]] {
|
||
|
teagba_vblankintrwait();
|
||
|
}
|
||
|
const auto ie = REG_IE; // disable vblank interrupt handler
|
||
|
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler
|
||
|
const auto updateCnt = g_spriteUpdates;
|
||
|
g_spriteBuffer[updateCnt] = upd;
|
||
|
g_spriteUpdates = updateCnt + 1;
|
||
|
REG_IE = ie; // enable vblank interrupt handler
|
||
|
}
|
||
|
|
||
|
void applySpriteUpdates() noexcept {
|
||
|
// copy g_spriteUpdates to allow it to use a register instead of reading
|
||
|
// from memory every iteration of the loop, needed because g_spriteUpdates
|
||
|
// is volatile
|
||
|
const unsigned updates = g_spriteUpdates;
|
||
|
for (unsigned i = 0; i < updates; ++i) {
|
||
|
const auto &oa = g_spriteBuffer[i];
|
||
|
MEM_OAM[oa.idx] = *reinterpret_cast<const uint64_t*>(&oa);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|