bios sqrt etc, bullet traveller simple impl

This commit is contained in:
wgroeneveld 2018-08-09 18:11:18 +02:00
parent 1f52458057
commit b6c461ad4d
17 changed files with 951 additions and 43 deletions

View File

@ -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)

View File

@ -0,0 +1,54 @@
//
// Created by Wouter Groeneveld on 09/08/18.
//
#include <libgba-sprite-engine/background/text_stream.h>
#include <libgba-sprite-engine/gba/tonc_bios.h>
#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);
}

View File

@ -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 <libgba-sprite-engine/sprites/sprite.h>
#include <libgba-sprite-engine/gba/tonc_math.h>
class Bullet {
private:
std::unique_ptr<Sprite> sprite;
VECTOR dest;
VECTOR vel;
VECTOR direction;
public:
Bullet(std::unique_ptr<Sprite> sprite) : sprite(std::move(sprite)), dest(VECTOR()) {}
void tick();
void setDestination(VECTOR vec);
bool isOffScreen() { return sprite->isOffScreen(); }
Sprite* getSprite() { return sprite.get(); }
};

View File

@ -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

View File

@ -6,15 +6,17 @@
#include <libgba-sprite-engine/gba_engine.h>
#include <algorithm>
#include <libgba-sprite-engine/background/text_stream.h>
#include <sstream>
#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<GBAEngine> &engine) : Scene(engine), bulletCooldown(BULLET_COOLDOWN_START) {}
FoodScene::FoodScene(const std::shared_ptr<GBAEngine> &engine) : Scene(engine) {}
std::vector<Background *> FoodScene::backgrounds() {
return {};
@ -25,9 +27,9 @@ std::vector<Sprite *> 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<Sprite *> FoodScene::sprites() {
void FoodScene::removeBulletsOffScreen() {
bullets.erase(
std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Sprite> &s) { return s->isOffScreen(); }),
std::remove_if(bullets.begin(), bullets.end(), [](std::unique_ptr<Bullet> &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<Sprite> FoodScene::createBullet() {
return spriteBuilder->withVelocity(1, 1)
.withLocation(avatar->getX(), avatar->getY())
.buildWithDataOf(*someBullet.get());
std::unique_ptr<Bullet> FoodScene::createBullet() {
return std::unique_ptr<Bullet>(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;
}

View File

@ -9,17 +9,18 @@
#include <libgba-sprite-engine/scene.h>
#include <libgba-sprite-engine/sprites/sprite_builder.h>
#include <libgba-sprite-engine/sprites/affine_sprite.h>
#include "bullet.h"
class FoodScene : public Scene {
private:
std::unique_ptr<AffineSprite> avatar;
std::unique_ptr<Sprite> someBullet;
std::vector<std::unique_ptr<Sprite>> bullets;
std::unique_ptr<Sprite> someBulletSprite;
std::vector<std::unique_ptr<Bullet>> bullets;
int avatarRotation;
u32 bulletCooldown;
std::unique_ptr<SpriteBuilder<Sprite>> spriteBuilder;
std::unique_ptr<Sprite> createBullet();
std::unique_ptr<Bullet> createBullet();
void removeBulletsOffScreen();
public:

View File

@ -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

View File

@ -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);

View File

@ -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 //<! Standard data section directive.
#define DSEC_ROM .section .rodata //!< ROM data section directive.
#define DSEC_BSS .section .bss //!< Uninited data (RAM) section directive.
#define DSEC_SBSS .section .sbss //!< Uninited data (DTCM?) section directive.
#define ARM_FUNC .arm //!< Indicates an ARM function.
#define THUMB_FUNC .thumb_func //!< Indicates a Thumb function.
//# NOTE: because these use commas, I can't pass them through CPP macros.
//# Yes, this is stupid, but do you have a better idea?
#undef CSEC_EWRAM
.macro CSEC_EWRAM
.section .ewram , "ax", %progbits
.endm
#undef CSEC_IWRAM
.macro CSEC_IWRAM
.section .iwram , "ax", %progbits
.endm
//\}
//! \name Function definition macros.
//\{
//! Start an assembly function.
/*!
\param _name Name of function.
\param _section Section to place function in (like .text)
*/
#define BEGIN_FUNC(_name, _section, _iset) \
_section; \
_iset; \
.align 2; \
.global _name; \
.type _name STT_FUNC; \
_name:
//! End of a function.
#define END_FUNC(_name) DEF_SIZE(_name)
//! Begin an ARM function
/*!
\param _name Name of function.
\param _section Section to place function in (like .text)
*/
#define BEGIN_FUNC_ARM(_name, _section) BEGIN_FUNC(_name, _section, ARM_FUNC)
//! Begin a THUMB function.
/*!
\param _name Name of function.
\param _section Section to place function in (like .text)
*/
#define BEGIN_FUNC_THUMB(_name, _section) BEGIN_FUNC(_name, _section, THUMB_FUNC)
//\}
//! \name Data definition macros.
//\{
#define BEGIN_SYMBOL(_name, _section) \
_section; \
.align; \
.global _name; \
_name:
#define END_SYMBOL(_name) DEF_SIZE(_name)
//\}
// --------------------------------------------------------------------
// CONSTANTS
// --------------------------------------------------------------------
//! \name TSurface member offsets.
//\{
#define TSRF_data 0
#define TSRF_pitch 4
#define TSRF_width 8
#define TSRF_height 10
#define TSRF_bpp 12
#define TSRF_type 13
#define TSRF_palSize 14
#define TSRF_pal 16
//\}
// --------------------------------------------------------------------
// GLOBALS
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// PROTOTYPES
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// INLINES
// --------------------------------------------------------------------
#endif // /TONC_ASMINC_H
// EOF

View File

@ -0,0 +1,355 @@
//
// BIOS call functions
// MODIFIED by Wouter Groeneveld: extern "C" - no C++ name mangling, can't find assembly methods!
//
//! \file tonc_bios.h
//! \author J Vijn
//! \date 20060508 - 20070208
//
// === NOTES ===
//
// Pretty much copied verbatim from Pern and dkARM's libgba
// (which in turn is copied from CowBite Spec (which got its info from
// GBATek))
//
//
// === NOTES ===
// * Make SURE your data is aligned to 32bit boundaries. Defining data
// as u32 (and I do mean define; not merely cast) ensures this. Either
// that or use __attribute__(( aligned(4) ))
// * There is a large (70 cycle in and out) overhead for SWIs. If you
// know what they do, consider creating replacement code
// * div by 0 locks up GBA.
// * Cpu(Fast)Set's count is in chunks, not bytes. CpuFastSet REQUIRES
// n*32 byte data
// * SoftReset is funky with interrupts on.
// * VBlankIntrWait is your friend. If you have a VBlank isr that clears
// REG_IFBIOS as well. Use this instead of REG_VCOUNT polling for
// VSync.
// * I haven't tested many of these functions. The ones that are have a
// plus (+) behind their numbers.
// * I've switched to the standard BIOS names.
#ifndef TONC_BIOS
#define TONC_BIOS
#include "tonc_types.h"
/*!
\addtogroup grpBios
\brief Interfaces and constants for the GBA BIOS routines.
For details, see
<a href="http://www.coranac.com/tonc/text/keys.htm">tonc:keys</a>
and especially
<a href="http://nocash.emubase.de/gbatek.htm#biosfunctions">gbatek:bios</a>.
\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

View File

@ -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;
};

View File

@ -7,6 +7,7 @@
#include <libgba-sprite-engine/gba/tonc_types.h>
#include <memory>
#include <libgba-sprite-engine/gba/tonc_math.h>
#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; }

288
engine/src/gba/tonc_bios.s Normal file
View File

@ -0,0 +1,288 @@
//
// Main GBA BIOS functions.
//
//! \file tonc_bios.s
//! \author J Vijn
//! \date 20071130 - 20090801
#include <libgba-sprite-engine/gba/tonc_asminc.h>
@ === 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)

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -21,7 +21,7 @@ void SpriteManager::set(std::vector<Sprite*> 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();