optimalizing engine for OAM, remove needles pointer dereferences in every update

master
wgroeneveld 3 years ago
parent a4fb01b87a
commit 573f1623e2
  1. 21
      demos/demo3-foodthrowing/src/food_scene.cpp
  2. 5
      engine/include/libgba-sprite-engine/sprites/sprite.h
  3. 4
      engine/src/sprites/affine_sprite.cpp
  4. 59
      engine/src/sprites/sprite.cpp
  5. 3
      engine/src/sprites/sprite_manager.cpp

@ -36,6 +36,7 @@ std::vector<Sprite *> FoodScene::sprites() {
}
void FoodScene::removeBulletsOffScreen() {
// TODO this is VERY ineffective, but it's a nice example of how C++11 remove_if works.
bullets.erase(
std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Bullet> &s) { return s->isOffScreen(); }),
bullets.end());
@ -55,6 +56,7 @@ void FoodScene::tick(u16 keys) {
TextStream::instance().setText(std::to_string(counter) + std::string(" frames/5sec"), 5, 1);
TextStream::instance().setText(std::string(engine->getTimer()->to_string()), 6, 1);
avatar->animateToFrame(0);
bool allowedToShoot = false;
int oldBulletSize = bullets.size();
@ -66,11 +68,6 @@ void FoodScene::tick(u16 keys) {
}
removeBulletsOffScreen();
TextStream::instance().setText(std::string("bullets: ") + std::to_string(bullets.size()), 1, 1);
TextStream::instance().setText(std::string("cooldown: ") + std::to_string(bulletCooldown), 2, 1);
TextStream::instance().setText(std::string("angle pa/pb: ") + std::to_string(avatar->getMatrix()->pa) + std::string("/") + std::to_string(avatar->getMatrix()->pb), 3, 1);
TextStream::instance().setText(std::string("angle pc/pd: ") + std::to_string(avatar->getMatrix()->pc) + std::string("/") + std::to_string(avatar->getMatrix()->pd), 4, 1);
if(keys & KEY_LEFT) {
avatarRotation -= AVATAR_ROTATION_DIFF;
@ -92,6 +89,7 @@ void FoodScene::tick(u16 keys) {
}
avatar->rotate(avatarRotation);
if(oldBulletSize != bullets.size()) {
engine.get()->updateSpritesInScene();
}
@ -132,18 +130,5 @@ void FoodScene::load() {
// rotation of a point on a circle within the resolution means our radius should be big enough
defaultBulletTarget = { GBA_SCREEN_WIDTH / 2, GBA_SCREEN_HEIGHT + (GBA_SCREEN_WIDTH / 2) - avatar->getCenter().y + 40};
/*
for(int i = 0; i < 10; i++) {
for(int j = 0; j < 4; j++) {
bullets.push_back(createBullet());
auto &b = bullets.at(bullets.size() - 1);
b->getSprite()->moveTo(10 + (i * 20), 10 + (j * 20));
if(j >= 1) {
b->getSprite()->moveTo(10 + (i * 20), 100 + (j * 20));
}
}
}*/
engine->getTimer()->start();
}

@ -58,10 +58,9 @@ protected:
bool stayWithinBounds;
u32 imageSize, tileIndex;
SpriteSize spriteSize;
u32 animationDelay, numberOfFrames, beginFrame, currentFrame, animationCounter;
u8 animationDelay, numberOfFrames, beginFrame, currentFrame, previousFrame, animationCounter;
bool animating;
std::unique_ptr<OBJ_ATTR> oam;
OBJ_ATTR oam;
void syncAnimation();
virtual void syncOam();

@ -38,7 +38,7 @@ void AffineSprite::setTransformationMatrix(OBJ_AFFINE *matrix) {
}
void AffineSprite::rebuildOamAttr1ForAffineIndex() {
this->oam->attr1 = this->x |
oam.attr1 = this->x |
ATTR1_AFF_ID(affIndex) |
(HORIZONTAL_FLIP_FLAG << 12) |
(VERTICAL_FLIP_FLAG << 13) |
@ -47,7 +47,7 @@ void AffineSprite::rebuildOamAttr1ForAffineIndex() {
void AffineSprite::buildOam(int tileIndex) {
Sprite::buildOam(tileIndex);
this->oam->attr0 = ATTR0_Y(this->y) |
oam.attr0 = ATTR0_Y(this->y) |
ATTR0_MODE(1) |
(GFX_MODE << 10) |
(MOSAIC_MODE << 12) |

@ -29,9 +29,7 @@ void Sprite::moveTo(VECTOR location) {
void Sprite::moveTo(int x, int y) {
this->x = x;
this->y = y;
if(oam) {
syncOam();
}
syncOam();
}
bool Sprite::isOffScreen() {
@ -40,25 +38,20 @@ bool Sprite::isOffScreen() {
void Sprite::flipHorizontally(bool flip) {
if(flip) {
oam->attr1 |= ATTR1_HFLIP;
oam.attr1 |= ATTR1_HFLIP;
} else {
oam->attr1 &= FLIP_HORIZONTAL_CLEAR;
oam.attr1 &= FLIP_HORIZONTAL_CLEAR;
}
}
void Sprite::flipVertically(bool flip) {
if(flip) {
oam->attr1 |= ATTR1_VFLIP;
oam.attr1 |= ATTR1_VFLIP;
} else {
oam->attr1 &= FLIP_VERTICAL_CLEAR;
oam.attr1 &= FLIP_VERTICAL_CLEAR;
}
}
void Sprite::syncVelocity() {
oam->attr0 = (oam->attr0 & ~ATTR0_Y_MASK) | (y & ATTR0_Y_MASK);
oam->attr1 = (oam->attr1 & ~ATTR1_X_MASK) | (x & ATTR1_X_MASK);
}
void Sprite::makeAnimated(int beginFrame, int numberOfFrames, int animationDelay) {
setBeginFrame(beginFrame);
animateToFrame(beginFrame);
@ -67,10 +60,17 @@ void Sprite::makeAnimated(int beginFrame, int numberOfFrames, int animationDelay
animate();
}
void Sprite::syncVelocity() {
oam.attr0 = (oam.attr0 & ~ATTR0_Y_MASK) | (y & ATTR0_Y_MASK);
oam.attr1 = (oam.attr1 & ~ATTR1_X_MASK) | (x & ATTR1_X_MASK);
}
void Sprite::syncAnimation() {
if(previousFrame == currentFrame) return;
int newTileIndex = this->tileIndex + (currentFrame * (this->animation_offset * 2));
oam->attr2 &= OAM_TILE_OFFSET_CLEAR;
oam->attr2 |= (newTileIndex & OAM_TILE_OFFSET_NEW);
oam.attr2 &= OAM_TILE_OFFSET_CLEAR;
oam.attr2 |= (newTileIndex & OAM_TILE_OFFSET_NEW);
}
void Sprite::syncOam() {
@ -96,6 +96,7 @@ void Sprite::updateAnimation() {
if(!animating) return;
animationCounter++;
previousFrame = currentFrame;
if(animationCounter > animationDelay) {
currentFrame++;
if(currentFrame > (numberOfFrames - 1) + beginFrame) {
@ -148,23 +149,19 @@ bool Sprite::collidesWith(Sprite &s2) {
void Sprite::buildOam(int tileIndex) {
this->tileIndex = tileIndex;
if(!oam) {
this->oam = std::unique_ptr<OBJ_ATTR>(new OBJ_ATTR());
this->oam->attr0 = ATTR0_Y(this->y & 0x00FF) |
ATTR0_MODE(0) |
(GFX_MODE << 10) |
(MOSAIC_MODE << 12) |
(COLOR_MODE_256 << 13) |
(this->shape_bits << 14);
this->oam->attr1 = (this->x & 0x01FF) |
(AFFINE_FLAG_NONE_SET_YET << 9) |
(HORIZONTAL_FLIP_FLAG << 12) |
(VERTICAL_FLIP_FLAG << 13) |
(this->size_bits << 14);
}
this->oam->attr2 = ATTR2_ID(tileIndex) |
oam.attr0 = ATTR0_Y(this->y & 0x00FF) |
ATTR0_MODE(0) |
(GFX_MODE << 10) |
(MOSAIC_MODE << 12) |
(COLOR_MODE_256 << 13) |
(this->shape_bits << 14);
oam.attr1 = (this->x & 0x01FF) |
(AFFINE_FLAG_NONE_SET_YET << 9) |
(HORIZONTAL_FLIP_FLAG << 12) |
(VERTICAL_FLIP_FLAG << 13) |
(this->size_bits << 14);
oam.attr2 = ATTR2_ID(tileIndex) |
ATTR2_PRIO(priority) |
ATTR2_PALBANK(0);
}

@ -45,8 +45,7 @@ void SpriteManager::copyOverSpriteOAMToVRAM() {
for(auto sprite : this->sprites) {
sprite->update();
auto oam = sprite->oam.get();
oam_mem[i] = *oam;
oam_mem[i] = sprite->oam;
auto affine = dynamic_cast<AffineSprite*>(sprite);
if(affine) {

Loading…
Cancel
Save