diff --git a/demos/demo3-foodthrowing/CMakeLists.txt b/demos/demo3-foodthrowing/CMakeLists.txt index 33d244f..e2eb1e0 100644 --- a/demos/demo3-foodthrowing/CMakeLists.txt +++ b/demos/demo3-foodthrowing/CMakeLists.txt @@ -4,7 +4,7 @@ add_executable(${PROJECT_NAME}.elf src/main.cpp src/food_scene.cpp src/food_scene.h - src/avatar.h src/bullet.h) + src/avatar.h src/bullet_data.h src/bullet.cpp src/bullet.h) target_link_libraries(${PROJECT_NAME}.elf gba-sprite-engine) diff --git a/demos/demo3-foodthrowing/src/bullet.cpp b/demos/demo3-foodthrowing/src/bullet.cpp new file mode 100644 index 0000000..55d4206 --- /dev/null +++ b/demos/demo3-foodthrowing/src/bullet.cpp @@ -0,0 +1,54 @@ +// +// Created by Wouter Groeneveld on 09/08/18. +// + +#include +#include +#include "bullet.h" + +// in 1/256 pixels +#define SPEED 50 + +u32 length(VECTOR a) { + return Sqrt(a.x * a.x + a.y * a.y); +} + +u32 distance(VECTOR a, VECTOR b) { + return length({a.x - b.x, a.y - b.y}); +} + +VECTOR normalize(VECTOR a) { + u32 l = length(a); + return { a.x / l, a.y / l }; +} + +void Bullet::setDestination(VECTOR vec) { + this->dest = vec; +} + +// TODO https://gamedev.stackexchange.com/questions/23447/moving-from-ax-y-to-bx1-y1-with-constant-speed +void Bullet::tick() { + auto pos = sprite->getPos(); + int xdiff = 1, ydiff = 1; + + if(abs(pos.x - dest.x) > abs(pos.y - dest.y)) { + xdiff += 1; + } else { + ydiff += 1; + } + + if(pos.x > dest.x) { + vel.x -= 1 * xdiff; + } else if(pos.x < dest.x) { + vel.x = 1 * xdiff; + } + if(pos.y > dest.y) { + vel.y -= 1 * ydiff; + } else if(pos.y < dest.y) { + vel.y = 1 * ydiff; + } + + TextStream::instance().setText(std::string("pos/dest: (") + std::to_string(pos.x) + std::string(",") + std::to_string(pos.y) + std::string(") (") + std::to_string(dest.x) + std::string(",") + std::to_string(dest.y) + std::string(")"), 16, 1); + + sprite->setVelocity(vel.x, vel.y); +} \ No newline at end of file diff --git a/demos/demo3-foodthrowing/src/bullet.h b/demos/demo3-foodthrowing/src/bullet.h index a43f849..45a8be3 100644 --- a/demos/demo3-foodthrowing/src/bullet.h +++ b/demos/demo3-foodthrowing/src/bullet.h @@ -5,23 +5,24 @@ #ifndef GBA_SPRITE_ENGINE_PROJECT_BULLET_H #define GBA_SPRITE_ENGINE_PROJECT_BULLET_H -const unsigned char bullet_data [] = { - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, - 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A + +#include +#include + +class Bullet { +private: + std::unique_ptr sprite; + VECTOR dest; + VECTOR vel; + VECTOR direction; + +public: + Bullet(std::unique_ptr sprite) : sprite(std::move(sprite)), dest(VECTOR()) {} + + void tick(); + void setDestination(VECTOR vec); + bool isOffScreen() { return sprite->isOffScreen(); } + Sprite* getSprite() { return sprite.get(); } }; diff --git a/demos/demo3-foodthrowing/src/bullet_data.h b/demos/demo3-foodthrowing/src/bullet_data.h new file mode 100644 index 0000000..4c4cad4 --- /dev/null +++ b/demos/demo3-foodthrowing/src/bullet_data.h @@ -0,0 +1,28 @@ +// +// Created by Wouter Groeneveld on 09/08/18. +// + +#ifndef GBA_SPRITE_ENGINE_PROJECT_BULLET_DATA_H +#define GBA_SPRITE_ENGINE_PROJECT_BULLET_DATA_H + +const unsigned char bullet_data [] = { + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A +}; + + +#endif //GBA_SPRITE_ENGINE_PROJECT_BULLET_DATA_H diff --git a/demos/demo3-foodthrowing/src/food_scene.cpp b/demos/demo3-foodthrowing/src/food_scene.cpp index 7f79620..a796a95 100644 --- a/demos/demo3-foodthrowing/src/food_scene.cpp +++ b/demos/demo3-foodthrowing/src/food_scene.cpp @@ -6,15 +6,17 @@ #include #include #include +#include #include "food_scene.h" #include "avatar.h" #include "bullet.h" +#include "bullet_data.h" -#define AVATAR_ROTATION_DIFF 300 +#define AVATAR_ROTATION_DIFF (128 * 2) #define MAX_AMOUNT_OF_BULLETS 40 #define BULLET_COOLDOWN_START 20 -FoodScene::FoodScene(const std::shared_ptr &engine) : Scene(engine), bulletCooldown(BULLET_COOLDOWN_START) {} +FoodScene::FoodScene(const std::shared_ptr &engine) : Scene(engine) {} std::vector FoodScene::backgrounds() { return {}; @@ -25,9 +27,9 @@ std::vector FoodScene::sprites() { // TODO order is important for affine transformations because of affinity - those always last! // some kind of affine bug depending on the order of sprites added in OAM for(auto& b : bullets) { - sprites.push_back(b.get()); + sprites.push_back(b->getSprite()); } - sprites.push_back(someBullet.get()); + sprites.push_back(someBulletSprite.get()); sprites.push_back(avatar.get()); return sprites; @@ -35,10 +37,30 @@ std::vector FoodScene::sprites() { void FoodScene::removeBulletsOffScreen() { bullets.erase( - std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr &s) { return s->isOffScreen(); }), + std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr &s) { return s->isOffScreen(); }), bullets.end()); } +std::string hex(int val) { + std::stringstream sstream; + sstream << std::hex << val; + std::string result = sstream.str(); + return result; +} + +u32 hex_int(u32 decimalValue) { + return (((decimalValue) & 0xF) + (((decimalValue) >> 4) * 10)); +} + +VECTOR randomDestinations[6] = { + {GBA_SCREEN_WIDTH, GBA_SCREEN_HEIGHT}, + {0, 0}, + {GBA_SCREEN_WIDTH / 2, GBA_SCREEN_HEIGHT}, + {GBA_SCREEN_WIDTH, GBA_SCREEN_HEIGHT / 2}, + {GBA_SCREEN_WIDTH, 0}, + {0, GBA_SCREEN_HEIGHT} +}; + void FoodScene::tick(u16 keys) { avatar->animateToFrame(0); bool bulletAdded, allowedToShoot; @@ -50,37 +72,55 @@ void FoodScene::tick(u16 keys) { } removeBulletsOffScreen(); - TextStream::instance().setText(std::to_string(bullets.size()) + std::string(" bullets"), 1, 1); - TextStream::instance().setText(std::to_string(bulletCooldown) + std::string(" cooldown"), 2, 1); + 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: ") + hex(avatar->getMatrix()->pa) + std::string("/") + hex(avatar->getMatrix()->pb), 3, 1); + TextStream::instance().setText(std::string("angle pc/pd: ") + hex(avatar->getMatrix()->pc) + std::string("/") + hex(avatar->getMatrix()->pd), 4, 1); + /* + + int defaultx = hex_int(GBA_SCREEN_WIDTH / 2 - 20), defaulty = hex_int(GBA_SCREEN_HEIGHT - 20); + + auto newx = toDecimal((avatar->getMatrix()->pa * defaultx + avatar->getMatrix()->pb * defaulty) >> 8); + auto newy = toDecimal((avatar->getMatrix()->pc * defaultx + avatar->getMatrix()->pd * defaulty) >> 8); + + TextStream::instance().setText(std::string("translated x/y: ") + std::to_string(newx) + std::string(",") + std::to_string(newy), 16, 1); +*/ if(keys & KEY_LEFT) { avatarRotation -= AVATAR_ROTATION_DIFF; + TextStream::instance().clear(); } else if(keys & KEY_RIGHT) { avatarRotation += AVATAR_ROTATION_DIFF; + TextStream::instance().clear(); } - if((keys & KEY_A) && allowedToShoot) { + if((keys & KEY_A)) { avatar->animateToFrame(1); - if(bullets.size() < MAX_AMOUNT_OF_BULLETS) { + if(allowedToShoot && bullets.size() < MAX_AMOUNT_OF_BULLETS) { bulletCooldown = BULLET_COOLDOWN_START; bullets.push_back(createBullet()); bulletAdded = true; auto &b = bullets.at(bullets.size() - 1); + b->setDestination(randomDestinations[rand() % 6]); } } avatar->rotate(avatarRotation); + for(auto &b : bullets) { + b->tick(); + } + if(bulletAdded) { engine->updateSpritesInScene(); } } - std::unique_ptr FoodScene::createBullet() { - return spriteBuilder->withVelocity(1, 1) - .withLocation(avatar->getX(), avatar->getY()) - .buildWithDataOf(*someBullet.get()); + std::unique_ptr FoodScene::createBullet() { + return std::unique_ptr(new Bullet(spriteBuilder + ->withLocation(avatar->getX() + avatar->getWidth() / 2, avatar->getY() + avatar->getHeight() / 2) + .buildWithDataOf(*someBulletSprite.get()))); } void FoodScene::load() { @@ -99,8 +139,9 @@ void FoodScene::load() { avatar->stopAnimating(); avatarRotation = 0; - someBullet = spriteBuilder->withData(bullet_data, sizeof(bullet_data)) + someBulletSprite = spriteBuilder->withData(bullet_data, sizeof(bullet_data)) .withSize(SIZE_16_16) .withLocation(GBA_SCREEN_WIDTH + 20, GBA_SCREEN_HEIGHT + 20) .buildPtr(); + bulletCooldown = BULLET_COOLDOWN_START; } \ No newline at end of file diff --git a/demos/demo3-foodthrowing/src/food_scene.h b/demos/demo3-foodthrowing/src/food_scene.h index 77234b9..4860511 100644 --- a/demos/demo3-foodthrowing/src/food_scene.h +++ b/demos/demo3-foodthrowing/src/food_scene.h @@ -9,17 +9,18 @@ #include #include #include +#include "bullet.h" class FoodScene : public Scene { private: std::unique_ptr avatar; - std::unique_ptr someBullet; - std::vector> bullets; + std::unique_ptr someBulletSprite; + std::vector> bullets; int avatarRotation; u32 bulletCooldown; std::unique_ptr> spriteBuilder; - std::unique_ptr createBullet(); + std::unique_ptr createBullet(); void removeBulletsOffScreen(); public: diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index b1877a3..11e36a3 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -1,6 +1,9 @@ project(gba-sprite-engine) set_property(SOURCE src/gba/sin_lut.s PROPERTY LANGUAGE C) +set_property(SOURCE src/gba/tonc_bios.s PROPERTY LANGUAGE C) +set_source_files_properties(src/gba/tonc_bios.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp") + add_library(${PROJECT_NAME} src/sprites/sprite_manager.cpp src/sprites/sprite.cpp @@ -8,6 +11,7 @@ add_library(${PROJECT_NAME} src/palette/combined_palette.cpp src/allocator.cpp src/gba/sin_lut.s + src/gba/tonc_bios.s src/sprites/sprite_builder.cpp src/sprites/affine_sprite.cpp src/gba_engine.cpp diff --git a/engine/include/libgba-sprite-engine/background/text_stream.h b/engine/include/libgba-sprite-engine/background/text_stream.h index db2bd52..3a145eb 100644 --- a/engine/include/libgba-sprite-engine/background/text_stream.h +++ b/engine/include/libgba-sprite-engine/background/text_stream.h @@ -17,7 +17,7 @@ #define PALETTE_COLOR_INDEX 15 #define PALETTE_TEXT_BANK 15 -#define failure(__mess) (consoleLog_func(__FILE__, __LINE__, __PRETTY_FUNCTION__, #__mess)) +#define failure_gba(__mess) (consoleLog_func(__FILE__, __LINE__, __PRETTY_FUNCTION__, #__mess)) void log_text(const char* text); void consoleLog_func(const char* fileName, const int lineNr, const char* fnName, const char* msg); diff --git a/engine/include/libgba-sprite-engine/gba/tonc_asminc.h b/engine/include/libgba-sprite-engine/gba/tonc_asminc.h new file mode 100644 index 0000000..b1bc28a --- /dev/null +++ b/engine/include/libgba-sprite-engine/gba/tonc_asminc.h @@ -0,0 +1,132 @@ +// +// tonc_asminc.h : header file with goodies for assembly. +// +//! \file tonc_asminc.h +//! \author J Vijn +//! \date 20081019 - 20120519 +// +/* === NOTES === + * Cleaned up the macros so that they work with comma-directives as well. + * For use in assembly only! +*/ + +#ifndef TONC_ASMINC_H +#define TONC_ASMINC_H + +#if !__ASSEMBLER__ +#error This header file is for use in assembly only! +#endif // /asm only + + +// -------------------------------------------------------------------- +// MACROS +// -------------------------------------------------------------------- + +#define DEF_SIZE(_name) .size _name, .-_name + +//! \name Section definitions for assembly. +//\{ + +#define CSEC_TEXT .text //!< Standard code section directive. +#define CSEC_EWRAM .section .ewram , "ax", %progbits //!< EWRAM code section directive. +#define CSEC_IWRAM .section .iwram, "ax", %progbits //!< IWRAM code section directive. + +#define DSEC_DATA .data //tonc:keys + and especially + gbatek:bios. + + \note While the speeds of the routines are fair, there + is a large overhead in calling the functions. +*/ + +/*! \defgroup grpBiosDef BIOS informalities + \ingroup grpBios +*/ +/*! \{ */ + + +// -------------------------------------------------------------------- +// CONSTANTS +// -------------------------------------------------------------------- + +//! \name SoftReset flags +//\{ +#define ROM_RESTART 0x00 //!< Restart from ROM entry point. +#define RAM_RESTART 0x01 //!< Restart from RAM entry point. +//\} + +//! \name RegisterRamReset flags +//\{ +#define RESET_EWRAM 0x0001 //!< Clear 256K on-board WRAM +#define RESET_IWRAM 0x0002 //!< Clear 32K in-chip WRAM +#define RESET_PALETTE 0x0004 //!< Clear Palette +#define RESET_VRAM 0x0008 //!< Clear VRAM +#define RESET_OAM 0x0010 //!< Clear OAM. does NOT disable OBJs! +#define RESET_REG_SIO 0x0020 //!< Switches to general purpose mode +#define RESET_REG_SOUND 0x0040 //!< Reset Sound registers +#define RESET_REG 0x0080 //!< All other registers + +//#define RESET_REG_VIDEO 0x0100 //!< video regs, 00h-60h (non standard!) +//#define RESET_REG_DMA 0x0200 //!< DMA regs, B0h-100h (non standard!) +//#define RESET_REG_TIMER 0x0400 //!< Timer regs (100h-110h) (non standard!) + +#define RESET_MEM_MASK 0x001F +#define RESET_REG_MASK 0x00E0 + +#define RESET_GFX 0x001C //!< Clear all gfx-related memory + +//\} + +//! \name Cpu(Fast)Set flags +//\{ +#define CS_CPY 0 //!< Copy mode +#define CS_FILL (1<<24) //!< Fill mode +#define CS_CPY16 0 //!< Copy in halfwords +#define CS_CPY32 (1<<26) //!< Copy words +#define CS_FILL32 (5<<24) //!< Fill words + +#define CFS_CPY CS_CPY //!< Copy words +#define CFS_FILL CS_FILL //!< Fill words +//\} + +//! \name ObjAffineSet P-element offsets +//\{ +#define BG_AFF_OFS 2 //!< BgAffineDest offsets +#define OBJ_AFF_OFS 8 //!< ObjAffineDest offsets +//\} + +//! \name Decompression routines +#define BUP_ALL_OFS (1<<31) + +#define LZ_TYPE 0x00000010 +#define LZ_SIZE_MASK 0xFFFFFF00 +#define LZ_SIZE_SHIFT 8 + +#define HUF_BPP_MASK 0x0000000F +#define HUF_TYPE 0x00000020 +#define HUF_SIZE_MASK 0xFFFFFF00 +#define HUF_SIZE_SHIFT 8 + +#define RL_TYPE 0x00000030 +#define RL_SIZE_MASK 0xFFFFFF00 +#define RL_SIZE_SHIFT 8 + +#define DIF_8 0x00000001 +#define DIF_16 0x00000002 +#define DIF_TYPE 0x00000080 +#define DIF_SIZE_MASK 0xFFFFFF00 +#define DIF_SIZE_SHIFT 8 +//\} + +//! \name Multiboot modes +//\{ +#define MBOOT_NORMAL 0x00 +#define MBOOT_MULTI 0x01 +#define MBOOT_FAST 0x02 +//\} + +// -------------------------------------------------------------------- +// MACROS +// -------------------------------------------------------------------- + + +//! BIOS calls from C +/*! You can use this macro in a C BIOS-call wrapper. The wrapper +* should declare the flags, then this call will do the rest. +* \param x Number of swi call (THUMB number) +* \note It checks the __thumb__ \#define to see whether we're +* in ARM or THUMB mode and fixes the swi number accordingly. +* Huzzah for the C proprocessor! +* \deprecated This macro will not work properly for functions that have IO. +*/ +#if defined ( __thumb__ ) +#define swi_call(x) __asm("swi\t"#x ::: "r0", "r1", "r2", "r3") +#else +#define swi_call(x) __asm("swi\t"#x"<<16" ::: "r0", "r1", "r2", "r3") +#endif + +// -------------------------------------------------------------------- +// CLASSES +// -------------------------------------------------------------------- + + +// --- affine function 0x0E and 0x0F --- + +/* +* Notational convention: postfix underscore is 2d vector +* +* p_ = (px, py) = texture coordinates +* q_ = (qx, qy) = screen coordinates +* P = | pa pb | = affine matrix +* | pc pd | +* d_ = (dx, dy) = background displacement +* +* Then: +* +* (1) p_ = P*q_ + d_ +* +* For transformation around a different point +* (texture point p0_ and screen point q0_), do +* +* (2) p_ - p0_ = P*(q_-q0_) +* +* Subtracting eq 2 from eq1 we immediately find: +* +* (3) _d = p0_ - P*q0_ +* +* For the special case of a texture->screen scale-then-rotate +* transformation with +* s_ = (sx, sy) = inverse scales (s>1 shrinks) +* a = alpha = Counter ClockWise (CCW) angle +* +* (4) P = | sx*cos(a) -sx*sin(a) | +* | sy*sin(a) sy*cos(a) | +* +* +* ObjAffineSet takes a and s_ as input and gives P +* BgAffineSet does that and fills in d_ as well +* +*/ + +// affine types in tonc_types.h + +//! BitUpPack ( for swi 10h) +typedef struct BUP +{ + u16 src_len; //!< source length (bytes) + u8 src_bpp; //!< source bitdepth (1,2,4,8) + u8 dst_bpp; //!< destination bitdepth (1,2,4,8,16,32) + u32 dst_ofs; //!< {0-30}: added offset {31}: zero-data offset flag +} BUP; + +//! Multiboot struct +typedef struct +{ + u32 reserved1[5]; + u8 handshake_data; + u8 padding; + u16 handshake_timeout; + u8 probe_count; + u8 client_data[3]; + u8 palette_data; + u8 response_bit; + u8 client_bit; + u8 reserved2; + u8 *boot_srcp; + u8 *boot_endp; + u8 *masterp; + u8 *reserved3[3]; + u32 system_work2[4]; + u8 sendflag; + u8 probe_target_bit; + u8 check_wait; + u8 server_type; +} MultiBootParam; + + +/*! \} */ + + + +// -------------------------------------------------------------------- +// BASIC BIOS ROUTINES +// -------------------------------------------------------------------- + + + +/*! \defgroup grpBiosMain BIOS functions +* \ingroup grpBios +*/ +/*! \{ */ + +//! \name Reset functions +//\{ +extern "C" void SoftReset(void); +extern "C" void RegisterRamReset(u32 flags); +//\} + +//! \name Halt functions +//\{ +extern "C" void Halt(void); +extern "C" void Stop(void); +extern "C" void IntrWait(u32 flagClear, u32 irq); +extern "C" void VBlankIntrWait(void); +//\} + + +//! \name Math functions +//\{ +extern "C" s32 Div(s32 num, s32 den); +extern "C" s32 DivArm(s32 den, s32 num); +extern "C" u32 Sqrt(u32 num); +extern "C" s16 ArcTan(s16 dydx); +extern "C" s16 ArcTan2(s16 x, s16 y); +//\} + +//! \name Memory copiers/fillers +//\{ +// Technically, these are misnomers. The convention is that +// xxxset is used for fills (comp memset, strset). Or perhaps +// the C library functions are misnomers, since set can be applied +// to both copies and fills. +extern "C" void CpuSet(const void *src, void *dst, u32 mode); +extern "C" void CpuFastSet(const void *src, void *dst, u32 mode); +//\} + +extern "C" u32 BiosCheckSum(void); + + +//! \name Rot/scale functions +//\{ +// These functions are misnomers, because ObjAffineSet is merely +// a special case of/precursor to BgAffineSet. Results from either +// can be used for both objs and bgs. Oh well. +extern "C" void ObjAffineSet(const ObjAffineSource *src, void *dst, s32 num, s32 offset); +extern "C" void BgAffineSet(const BgAffineSource *src, BgAffineDest *dst, s32 num); +//\} + +//! \name Decompression (see GBATek for format details) +//\{ +extern "C" void BitUnPack(const void *src, void *dst, const BUP *bup); +extern "C" void LZ77UnCompWram(const void *src, void *dst); +extern "C" void LZ77UnCompVram(const void *src, void *dst); +extern "C" void HuffUnComp(const void *src, void *dst); +extern "C" void RLUnCompWram(const void *src, void *dst); +extern "C" void RLUnCompVram(const void *src, void *dst); +extern "C" void Diff8bitUnFilterWram(const void *src, void *dst); +extern "C" void Diff8bitUnFilterVram(const void *src, void *dst); +extern "C" void Diff16bitUnFilter(const void *src, void *dst); +//\} + +//! \name Sound Functions +//\{ +// (I have even less of a clue what these do than for the others --- +extern "C" void SoundBias(u32 bias); +extern "C" void SoundDriverInit(void *src); +extern "C" void SoundDriverMode(u32 mode); +extern "C" void SoundDriverMain(void); +extern "C" void SoundDriverVSync(void); +extern "C" void SoundChannelClear(void); +extern "C" u32 MidiKey2Freq(void *wa, u8 mk, u8 fp); +extern "C" void SoundDriverVSyncOff(void); +extern "C" void SoundDriverVSyncOn(void); +//\} + +//! \name Multiboot handshake +//\{ +extern "C" int MultiBoot(MultiBootParam* mb, u32 mode); +//\} + + +/*! \} */ + + +/*! \defgroup grpBiosEx More BIOS functions +* \ingroup grpBios +*/ +/*! \{ */ + +//\{ + +// You can find these in swi_ex.s +extern "C" void VBlankIntrDelay(u32 count); +extern "C" int DivSafe(int num, int den); +extern "C" int Mod(int num, int den); +extern "C" u32 DivAbs(int num, int den); +extern "C" int DivArmMod(int den, int num); +extern "C" u32 DivArmAbs(int den, int num); +extern "C" void CpuFastFill(u32 wd, void *dst, u32 count); + +#define DivMod Mod +//\} + +/*! \} */ + + +#endif // TONC_BIOS \ No newline at end of file diff --git a/engine/include/libgba-sprite-engine/sprites/affine_sprite.h b/engine/include/libgba-sprite-engine/sprites/affine_sprite.h index e4b5620..1521beb 100644 --- a/engine/include/libgba-sprite-engine/sprites/affine_sprite.h +++ b/engine/include/libgba-sprite-engine/sprites/affine_sprite.h @@ -27,6 +27,7 @@ public: void rotate(u16 alpha); explicit AffineSprite(const AffineSprite& other); explicit AffineSprite(const void* imgData, int imgSize, int xC, int yC, SpriteSize spriteSize); + OBJ_AFFINE* getMatrix() { return affine.get(); } friend class SpriteManager; }; diff --git a/engine/include/libgba-sprite-engine/sprites/sprite.h b/engine/include/libgba-sprite-engine/sprites/sprite.h index 91aa32f..59e3f73 100644 --- a/engine/include/libgba-sprite-engine/sprites/sprite.h +++ b/engine/include/libgba-sprite-engine/sprites/sprite.h @@ -7,6 +7,7 @@ #include #include +#include #define COLOR_MODE_16 0 #define COLOR_MODE_256 1 @@ -88,6 +89,8 @@ public: void flipHorizontally(bool flip); u32 getTileIndex() { return tileIndex; } + VECTOR getPos() { return VECTOR {x, y}; } + VECTOR getVelocity() { return VECTOR { dx, dy}; } u32 getDx() { return dx; } u32 getDy() { return dy; } u32 getX() { return x; } diff --git a/engine/src/gba/tonc_bios.s b/engine/src/gba/tonc_bios.s new file mode 100644 index 0000000..d572631 --- /dev/null +++ b/engine/src/gba/tonc_bios.s @@ -0,0 +1,288 @@ +// +// Main GBA BIOS functions. +// +//! \file tonc_bios.s +//! \author J Vijn +//! \date 20071130 - 20090801 + +#include + +@ === SoftReset [00h] ================================================= +@ DECL: void SoftReset(); +@ DESC: +BEGIN_FUNC_THUMB(SoftReset, CSEC_TEXT) + swi 0x00 + bx lr +END_FUNC(SoftReset) + +@ === RegisterRamReset [01h] ========================================== +@ DECL: void RegisterRamReset(u32 flags); +@ DESC: +BEGIN_FUNC_THUMB(RegisterRamReset, CSEC_TEXT) + swi 0x01 + bx lr +END_FUNC(RegisterRamReset) + +@ === Halt [02h] ====================================================== +@ DECL: void Halt(); +@ DESC: +BEGIN_FUNC_THUMB(Halt, CSEC_TEXT) + swi 0x02 + bx lr +END_FUNC(Halt) + +@ === Stop [03h] ====================================================== +@ DECL: void Stop(); +@ DESC: +BEGIN_FUNC_THUMB(Stop, CSEC_TEXT) + swi 0x03 + bx lr +END_FUNC(Stop) + +@ === IntrWait [04h] ================================================== +@ DECL: void IntrWait(u32 flagClear, u32 irq); +@ DESC: +BEGIN_FUNC_THUMB(IntrWait, CSEC_TEXT) + swi 0x04 + bx lr +END_FUNC(IntrWait) + +@ === VBlankIntrWait [05h] ============================================ +@ DECL: void VBlankIntrWait(); +@ DESC: +BEGIN_FUNC_THUMB(VBlankIntrWait, CSEC_TEXT) + swi 0x05 + bx lr +END_FUNC(VBlankIntrWait) + +@ === Div [06h] ======================================================= +@ DECL: s32 Div(s32 num, s32 den); +@ DESC: +BEGIN_FUNC_THUMB(Div, CSEC_TEXT) + swi 0x06 + bx lr +END_FUNC(Div) + +@ === DivArm [07h] ==================================================== +@ DECL: s32 DivArm(s32 den, s32 num); +@ DESC: +BEGIN_FUNC_THUMB(DivArm, CSEC_TEXT) + swi 0x07 + bx lr +END_FUNC(DivArm) + +@ === Sqrt [08h] ====================================================== +@ DECL: u32 Sqrt(u32 num); +@ DESC: +BEGIN_FUNC_THUMB(Sqrt, CSEC_TEXT) + swi 0x08 + bx lr +END_FUNC(Sqrt) + +@ === ArcTan [09h] ==================================================== +@ DECL: s16 ArcTan(s16 dydx); +@ DESC: +BEGIN_FUNC_THUMB(ArcTan, CSEC_TEXT) + swi 0x09 + bx lr +END_FUNC(ArcTan) + +@ === ArcTan2 [0Ah] =================================================== +@ DECL: s16 ArcTan2(s16 x, s16 y); +@ DESC: +BEGIN_FUNC_THUMB(ArcTan2, CSEC_TEXT) + swi 0x0A + bx lr +END_FUNC(ArcTan2) + +@ === CpuSet [0Bh] ==================================================== +@ DECL: void CpuSet(const void *src, void *dst, u32 mode); +@ DESC: +BEGIN_FUNC_THUMB(CpuSet, CSEC_TEXT) + swi 0x0B + bx lr +END_FUNC(CpuSet) + +@ === CpuFastSet [0Ch] ================================================ +@ DECL: void CpuFastSet(const void *src, void *dst, u32 mode); +@ DESC: +BEGIN_FUNC_THUMB(CpuFastSet, CSEC_TEXT) + swi 0x0C + bx lr +END_FUNC(CpuFastSet) + +@ === BiosCheckSum [0Dh] ================================================ +@ DECL: u32 BiosCheckSum(); +@ DESC: +BEGIN_FUNC_THUMB(BiosCheckSum, CSEC_TEXT) + swi 0x0D + bx lr +END_FUNC(BiosCheckSum) + +@ === BgAffineSet [0Eh] =============================================== +@ DECL: void ObjAffineSet(const ObjAffineSource *src, void *dst, s32 num, s32 offset); +@ DESC: +BEGIN_FUNC_THUMB(BgAffineSet, CSEC_TEXT) + swi 0x0E + bx lr +END_FUNC(BgAffineSet) + +@ === ObjAffineSet [0Fh] ============================================== +@ DECL: void BgAffineSet(const BGAffineSource *src, BGAffineDest *dst, s32 num); +@ DESC: +BEGIN_FUNC_THUMB(ObjAffineSet, CSEC_TEXT) + swi 0x0F + bx lr +END_FUNC(ObjAffineSet) + +@ === BitUnPack [10h] ================================================= +@ DECL: void BitUnPack(const void *src, void *dst, BUP *bup); +@ DESC: +BEGIN_FUNC_THUMB(BitUnPack, CSEC_TEXT) + swi 0x10 + bx lr +END_FUNC(BitUnPack) + +@ === LZ77UnCompWram [11h] ============================================ +@ DECL: void LZ77UnCompWram(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(LZ77UnCompWram, CSEC_TEXT) + swi 0x11 + bx lr +END_FUNC(LZ77UnCompWram) + +@ === LZ77UnCompVram [12h] ============================================ +@ DECL: void LZ77UnCompVram(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(LZ77UnCompVram, CSEC_TEXT) + swi 0x12 + bx lr +END_FUNC(LZ77UnCompVram) + +@ === HuffUnComp [13h] ================================================ +@ DECL: void HuffUnComp(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(HuffUnComp, CSEC_TEXT) + swi 0x13 + bx lr +END_FUNC(HuffUnComp) + +@ === RLUnCompWram [14h] ============================================== +@ DECL: void RLUnCompWram(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(RLUnCompWram, CSEC_TEXT) + swi 0x14 + bx lr +END_FUNC(RLUnCompWram) + +@ === RLUnCompVram [15h] ============================================== +@ DECL: void RLUnCompVram(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(RLUnCompVram, CSEC_TEXT) + swi 0x15 + bx lr +END_FUNC(RLUnCompVram) + +@ === Diff8bitUnFilterWram [16h] ====================================== +@ DECL: void Diff8bitUnFilterWram(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(Diff8bitUnFilterWram, CSEC_TEXT) + swi 0x16 + bx lr +END_FUNC(Diff8bitUnFilterWram) + +@ === Diff8bitUnFilterVram [17h] ====================================== +@ DECL: void Diff8bitUnFilterVram(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(Diff8bitUnFilterVram, CSEC_TEXT) + swi 0x17 + bx lr +END_FUNC(Diff8bitUnFilterVram) + +@ === Diff16bitUnFilter [18h] ========================================= +@ DECL: void Diff16bitUnFilter(const void *src, void *dst); +@ DESC: +BEGIN_FUNC_THUMB(Diff16bitUnFilter, CSEC_TEXT) + swi 0x18 + bx lr +END_FUNC(Diff16bitUnFilter) + +@ === SoundBias [19h] ================================================= +@ DECL: void SoundBias(u32 bias); +@ DESC: +BEGIN_FUNC_THUMB(SoundBias, CSEC_TEXT) + swi 0x19 + bx lr +END_FUNC(SoundBias) + +@ === SoundDriverInit [1Ah] =========================================== +@ DECL: void SoundDriverInit(void *src); +@ DESC: +BEGIN_FUNC_THUMB(SoundDriverInit, CSEC_TEXT) + swi 0x1A + bx lr +END_FUNC(SoundDriverInit) + +@ === SoundDriverMode [1Bh] =========================================== +@ DECL: void SoundDriverMode(u32 mode); +@ DESC: +BEGIN_FUNC_THUMB(SoundDriverMode, CSEC_TEXT) + swi 0x1B + bx lr +END_FUNC(SoundDriverMode) + +@ === SoundDriverMain [1Ch] =========================================== +@ DECL: void SoundDriverMain(); +@ DESC: +BEGIN_FUNC_THUMB(SoundDriverMain, CSEC_TEXT) + swi 0x1C + bx lr +END_FUNC(SoundDriverMain) + +@ === SoundDriverVSync [1Dh] ========================================== +@ DECL: void SoundDriverVSync(); +@ DESC: +BEGIN_FUNC_THUMB(SoundDriverVSync, CSEC_TEXT) + swi 0x1D + bx lr +END_FUNC(SoundDriverVSync) + +@ === SoundChannelClear [1Eh] ========================================= +@ DECL: void SoundChannelClear(); +@ DESC: +BEGIN_FUNC_THUMB(SoundChannelClear, CSEC_TEXT) + swi 0x1E + bx lr +END_FUNC(SoundChannelClear) + +@ === MidiKey2Freq [1Fh] ============================================== +@ DECL: u32 MidiKey2Freq(void *wa, u8 mk, u8 fp); +@ DESC: +BEGIN_FUNC_THUMB(MidiKey2Freq, CSEC_TEXT) + swi 0x1F + bx lr +END_FUNC(MidiKey2Freq) + +@ === MultiBoot [25h] ================================================= +@ DECL: int MultiBoot(MultiBootParam* mb, u32 mode); +@ DESC: +BEGIN_FUNC_THUMB(MultiBoot, CSEC_TEXT) + swi 0x25 + bx lr +END_FUNC(MultiBoot) + +@ === SoundDriverVSyncOff [28h] ======================================= +@ DECL: void SoundDriverVSyncOff(); +@ DESC: +BEGIN_FUNC_THUMB(SoundDriverVSyncOff, CSEC_TEXT) + swi 0x28 + bx lr +END_FUNC(SoundDriverVSyncOff) + +@ === SoundDriverVSyncOn [29h] ======================================== +@ DECL: void SoundDriverVSyncOn(); +@ DESC: +BEGIN_FUNC_THUMB(SoundDriverVSyncOn, CSEC_TEXT) + swi 0x29 + bx lr +END_FUNC(SoundDriverVSyncOn) diff --git a/engine/src/gba_engine.cpp b/engine/src/gba_engine.cpp index ad6755e..b703331 100644 --- a/engine/src/gba_engine.cpp +++ b/engine/src/gba_engine.cpp @@ -142,12 +142,12 @@ void GBAEngine::setScene(Scene* scene) { auto fgPalette = scene->getForegroundPalette(); if(!fgPalette) { - failure(NoFgPaletteDefined); + failure_gba(NoFgPaletteDefined); } fgPalette->persist(); auto bgPalette = scene->getBackgroundPalette(); if(!bgPalette) { - failure(NoBgPaletteDefined); + failure_gba(NoBgPaletteDefined); } bgPalette->persist(); diff --git a/engine/src/palette/combined_palette.cpp b/engine/src/palette/combined_palette.cpp index d53e36a..abe55c6 100644 --- a/engine/src/palette/combined_palette.cpp +++ b/engine/src/palette/combined_palette.cpp @@ -15,7 +15,7 @@ void CombinedPalette::increaseBrightness(PaletteManager& palette, int bank, int void CombinedPalette::increaseBrightness(u32 intensity) { if(intensity > 31) { - failure(Brightness_Intensity_Too_High); + failure_gba(Brightness_Intensity_Too_High); return; } diff --git a/engine/src/palette/palette_manager.cpp b/engine/src/palette/palette_manager.cpp index 80683fb..995efbc 100644 --- a/engine/src/palette/palette_manager.cpp +++ b/engine/src/palette/palette_manager.cpp @@ -82,7 +82,7 @@ COLOR PaletteManager::modify(COLOR color, u32 intensity) { void PaletteManager::increaseBrightness(u32 intensity) { if(intensity > 31) { - failure(Brightness_Intensity_Too_High); + failure_gba(Brightness_Intensity_Too_High); return; } diff --git a/engine/src/sprites/sprite_manager.cpp b/engine/src/sprites/sprite_manager.cpp index 3db7c01..760dce8 100644 --- a/engine/src/sprites/sprite_manager.cpp +++ b/engine/src/sprites/sprite_manager.cpp @@ -21,7 +21,7 @@ void SpriteManager::set(std::vector sprites) { void SpriteManager::add(Sprite* sprite) { if(sprites.size() == MAX_SPRITE_SIZE) { - failure(MaxSpriteSizeReached); + failure_gba(MaxSpriteSizeReached); } sprites.push_back(sprite); @@ -30,7 +30,7 @@ void SpriteManager::add(Sprite* sprite) { void SpriteManager::render() { if(!initialized) { - failure(Cant_Render_Before_Init); + failure_gba(Cant_Render_Before_Init); } copyOverSpriteOAMToVRAM(); @@ -47,7 +47,7 @@ void SpriteManager::copyOverSpriteOAMToVRAM() { for(auto sprite : this->sprites) { if(affineIndex > MAX_AFFINE_SIZE) { - failure(MaxSpritesWithAffineReached); + failure_gba(MaxSpritesWithAffineReached); } sprite->update();