initial commit, stripped-down version of gba-sprite-engine
This commit is contained in:
parent
62dbfddd6b
commit
27e6a9065c
|
@ -1,4 +1,83 @@
|
|||
CMakeLists.txt.user
|
||||
.DS_Store
|
||||
build/
|
||||
.idea/
|
||||
|
||||
# Created by https://www.gitignore.io/api/clion,cmake
|
||||
|
||||
### CLion ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
### CLion Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
|
||||
### CMake ###
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
|
@ -8,4 +87,42 @@ cmake_install.cmake
|
|||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/clion,cmake
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
#VisualStudio code
|
||||
.vscode
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
# use the GBA cross-compiler.
|
||||
# WARNING: CMAKE_AR and RANLIB didn't use find_program() to scan the PATH yet.
|
||||
# If using CMake < 3.12, consider using an absolute path. https://gitlab.kitware.com/cmake/cmake/merge_requests/1720
|
||||
SET(CMAKE_SYSTEM_NAME Generic)
|
||||
SET(CMAKE_GENERATOR "Unix Makefiles")
|
||||
SET(CMAKE_C_COMPILER arm-none-eabi-gcc)
|
||||
SET(CMAKE_CXX_COMPILER arm-none-eabi-g++)
|
||||
SET(CMAKE_OBJCOPY arm-none-eabi-objcopy)
|
||||
SET(CMAKE_AR arm-none-eabi-ar CACHE FILEPATH "Archiver")
|
||||
SET(CMAKE_RANLIB arm-none-eabi-ranlib)
|
||||
|
||||
SET(BASE_CMAKE_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${BASE_CMAKE_LINK_FLAGS} -mthumb-interwork -mthumb -specs=gba.specs")
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing -O3")
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
project(gba-bitmap-engine-project VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
# Must use GNUInstallDirs to install libraries into correct locations on all platforms.
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_subdirectory(engine)
|
||||
|
||||
# this should be a part of the engine CMakeLists.txt file but cross-compiling and gtest doesn't work
|
||||
add_subdirectory(test)
|
||||
|
||||
add_subdirectory(demos/demo1-wireframes)
|
|
@ -0,0 +1,5 @@
|
|||
## A high-level object-oriented Game Boy Advance bitmap 3D software engine
|
||||
|
||||
Engine layout: stripped-down version of [https://github.com/wgroeneveld/gba-sprite-engine/](https://github.com/wgroeneveld/gba-sprite-engine/)
|
||||
|
||||
**Work in progress**, using mode4 to create a software 3D engine from scratch.
|
|
@ -0,0 +1,13 @@
|
|||
project(wireframes)
|
||||
|
||||
add_executable(${PROJECT_NAME}.elf
|
||||
src/main.cpp
|
||||
src/wirescene.cpp
|
||||
src/wirescene.h
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}.elf gba-bitmap-engine)
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
|
||||
COMMAND ${CMAKE_OBJCOPY} -v -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.gba
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
#include <libgba-sprite-engine/scene.h>
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
|
||||
#include "wirescene.h"
|
||||
|
||||
int main() {
|
||||
std::shared_ptr<GBAEngine> engine(new GBAEngine());
|
||||
|
||||
WireScene* startScene = new WireScene(engine);
|
||||
engine->setScene(startScene);
|
||||
|
||||
while (true) {
|
||||
engine->update();
|
||||
engine->delay(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 02/08/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include "wirescene.h"
|
||||
|
||||
|
||||
const unsigned short pal[3] __attribute__((aligned(4))) = {
|
||||
0x0000, 0xFFFF, 0x3AE2
|
||||
};
|
||||
|
||||
void WireScene::load() {
|
||||
foregroundPalette = std::unique_ptr<ForegroundPaletteManager>(new ForegroundPaletteManager());
|
||||
backgroundPalette = std::unique_ptr<BackgroundPaletteManager>(new BackgroundPaletteManager(pal, sizeof(pal)));
|
||||
}
|
||||
|
||||
void WireScene::tick(u16 keys) {
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 02/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SAMPLE_START_SCENE_H
|
||||
#define GBA_SPRITE_ENGINE_SAMPLE_START_SCENE_H
|
||||
|
||||
#include <libgba-sprite-engine/scene.h>
|
||||
|
||||
class WireScene : public Scene {
|
||||
private:
|
||||
|
||||
public:
|
||||
|
||||
WireScene(std::shared_ptr<GBAEngine> engine) : Scene(engine) {}
|
||||
|
||||
void load() override;
|
||||
void tick(u16 keys) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_SAMPLE_START_SCENE_H
|
|
@ -0,0 +1,22 @@
|
|||
project(gba-bitmap-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/palette/palette_manager.cpp
|
||||
src/palette/combined_palette.cpp
|
||||
src/gba/sin_lut.s
|
||||
src/gba/tonc_bios.s
|
||||
src/gba_engine.cpp
|
||||
src/sound_control.cpp src/scene.cpp src/timer.cpp include/libgba-sprite-engine/gbavector.h src/gbavector.cpp)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
PRIVATE src)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT GbaSpriteEngineTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,573 @@
|
|||
//
|
||||
// Core functionality
|
||||
//
|
||||
//! \file tonc_core.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20080128
|
||||
//
|
||||
/* === NOTES ===
|
||||
* Contents: bits, random, dma, timer
|
||||
* 20080129,jv: added tonccpy/set routines.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TONC_CORE
|
||||
#define TONC_CORE
|
||||
|
||||
#include "tonc_memmap.h"
|
||||
#include "tonc_memdef.h"
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// BITS and BITFIELDS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpCoreBit Bit(field) macros
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name Simple bit macros
|
||||
//\{
|
||||
|
||||
//! Create value with bit \a n set
|
||||
#define BIT(n) ( 1<<(n) )
|
||||
|
||||
//! Shift \a a by \a n
|
||||
#define BIT_SHIFT(a, n) ( (a)<<(n) )
|
||||
|
||||
//! Create a bitmask \a len bits long
|
||||
#define BIT_MASK(len) ( BIT(len)-1 )
|
||||
|
||||
//! Set the \a flag bits in \a word
|
||||
#define BIT_SET(y, flag) ( y |= (flag) )
|
||||
|
||||
//! Clear the \a flag bits in \a word
|
||||
#define BIT_CLEAR(y, flag) ( y &= ~(flag) )
|
||||
|
||||
//! Flip the \a flag bits in \a word
|
||||
#define BIT_FLIP(y, flag) ( y ^= (flag) )
|
||||
|
||||
//! Test whether all the \a flag bits in \a word are set
|
||||
#define BIT_EQ(y, flag) ( ((y)&(flag)) == (flag) )
|
||||
|
||||
|
||||
|
||||
//! Create a bitmask of length \a len starting at bit \a shift.
|
||||
#define BF_MASK(shift, len) ( BIT_MASK(len)<<(shift) )
|
||||
|
||||
|
||||
//! Retrieve a bitfield mask of length \a starting at bit \a shift from \a y.
|
||||
#define _BF_GET(y, shift, len) ( ((y)>>(shift))&BIT_MASK(len) )
|
||||
|
||||
//! Prepare a bitmask for insertion or combining.
|
||||
#define _BF_PREP(x, shift, len) ( ((x)&BIT_MASK(len))<<(shift) )
|
||||
|
||||
//! Insert a new bitfield value \a x into \a y.
|
||||
#define _BF_SET(y, x, shift, len) \
|
||||
( y= ((y) &~ BF_MASK(shift, len)) | _BF_PREP(x, shift, len) )
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name some EVIL bit-field operations, >:)
|
||||
* These allow you to mimic bitfields with macros. Most of the
|
||||
* bitfields in the registers have <i>foo</i>_SHIFT and
|
||||
* <i>foo</i>_SHIFT macros indicating the mask and shift values
|
||||
* of the bitfield named <i>foo</i> in a variable.
|
||||
* These macros let you prepare, get and set the bitfields.
|
||||
*/
|
||||
//\{
|
||||
|
||||
//! Prepare a named bit-field for for insterion or combination.
|
||||
#define BFN_PREP(x, name) ( ((x)<<name##_SHIFT) & name##_MASK )
|
||||
|
||||
//! Get the value of a named bitfield from \a y. Equivalent to (var=) y.name
|
||||
#define BFN_GET(y, name) ( ((y) & name##_MASK)>>name##_SHIFT )
|
||||
|
||||
//! Set a named bitfield in \a y to \a x. Equivalent to y.name= x.
|
||||
#define BFN_SET(y, x, name) (y = ((y)&~name##_MASK) | BFN_PREP(x,name) )
|
||||
|
||||
//! Compare a named bitfield to named literal \a x.
|
||||
#define BFN_CMP(y, x, name) ( ((y)&name##_MASK) == (x) )
|
||||
|
||||
|
||||
//! Massage \a x for use in bitfield \a name with pre-shifted \a x
|
||||
#define BFN_PREP2(x, name) ( (x) & name##_MASK )
|
||||
|
||||
//! Get the value of bitfield \a name from \a y, but don't down-shift
|
||||
#define BFN_GET2(y, name) ( (y) & name##_MASK )
|
||||
|
||||
//! Set bitfield \a name from \a y to \a x with pre-shifted \a x
|
||||
#define BFN_SET2(y,x,name) ( y = ((y)&~name##_MASK) | BFN_PREP2(x,name) )
|
||||
|
||||
//\}
|
||||
|
||||
INLINE u32 bf_get(u32 y, uint shift, uint len);
|
||||
INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len);
|
||||
INLINE u32 bf_clamp(int x, uint len);
|
||||
|
||||
INLINE int bit_tribool(u32 x, uint plus, uint minus);
|
||||
INLINE u32 ROR(u32 x, uint ror);
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpData Data routines
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! Get the number of elements in an array
|
||||
#define countof(_array) ( sizeof(_array)/sizeof(_array[0]) )
|
||||
|
||||
//! Align \a x to the next multiple of \a width.
|
||||
INLINE uint align(uint x, uint width);
|
||||
|
||||
//! \name Copying and filling routines
|
||||
//\{
|
||||
|
||||
//! Simplified copier for GRIT-exported data.
|
||||
#define GRIT_CPY(dst, name) memcpy16(dst, name, name##Len/2)
|
||||
|
||||
|
||||
// Base memcpy/set replacements.
|
||||
void *tonccpy(void *dst, const void *src, uint size);
|
||||
|
||||
void *__toncset(void *dst, u32 fill, uint size);
|
||||
INLINE void *toncset(void *dst, u8 src, uint count);
|
||||
INLINE void *toncset16(void *dst, u16 src, uint count);
|
||||
INLINE void *toncset32(void *dst, u32 src, uint count);
|
||||
|
||||
|
||||
// Fast memcpy/set
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
IWRAM_CODE void memset32(void *dst, u32 wd, uint wcount);
|
||||
IWRAM_CODE void memcpy32(void *dst, const void* src, uint wcount);
|
||||
|
||||
|
||||
//! Fastfill for halfwords, analogous to memset()
|
||||
/*! Uses <code>memset32()</code> if \a hwcount>5
|
||||
* \param dst Destination address.
|
||||
* \param hw Source halfword (not address).
|
||||
* \param hwcount Number of halfwords to fill.
|
||||
* \note \a dst <b>must</b> be halfword aligned.
|
||||
* \note \a r0 returns as \a dst + \a hwcount*2.
|
||||
*/
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
|
||||
//! \brief Copy for halfwords.
|
||||
/*! Uses <code>memcpy32()</code> if \a hwn>6 and
|
||||
\a src and \a dst are aligned equally.
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param hwcount Number of halfwords to fill.
|
||||
\note \a dst and \a src <b>must</b> be halfword aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a hwcount*2 and \a src + \a hwcount*2.
|
||||
*/
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
|
||||
//! Fast-fill by words, analogous to memset()
|
||||
/*! Like CpuFastSet(), only without the requirement of
|
||||
32byte chunks and no awkward store-value-in-memory-first issue.
|
||||
\param dst Destination address.
|
||||
\param wd Fill word (not address).
|
||||
\param wdcount Number of words to fill.
|
||||
\note \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 returns as \a dst + \a wdcount*4.
|
||||
*/
|
||||
IWRAM_CODE void memset32(void *dst, u32 wd, uint wdcount);
|
||||
|
||||
|
||||
//! \brief Fast-copy by words.
|
||||
/*! Like CpuFastFill(), only without the requirement of 32byte chunks
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param wdcount Number of words.
|
||||
\note \a src and \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a wdcount*4 and \a src + \a wdcount*4.
|
||||
*/
|
||||
IWRAM_CODE void memcpy32(void *dst, const void* src, uint wdcount);
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name Repeated-value creators
|
||||
These function take a hex-value and duplicate it to all fields,
|
||||
like 0x88 -> 0x88888888.
|
||||
*/
|
||||
//\{
|
||||
INLINE u16 dup8(u8 x);
|
||||
INLINE u32 dup16(u16 x);
|
||||
INLINE u32 quad8(u8 x);
|
||||
INLINE u32 octup(u8 x);
|
||||
//\}
|
||||
|
||||
//! \name Packing routines.
|
||||
//\{
|
||||
INLINE u16 bytes2hword(u8 b0, u8 b1);
|
||||
INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3);
|
||||
INLINE u32 hword2word(u16 h0, u16 h1);
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DMA
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpDma */
|
||||
/*! \{ */
|
||||
|
||||
//! General purpose DMA transfer macro
|
||||
/*! \param _dst Destination address.
|
||||
\param _src Source address.
|
||||
\param count Number of transfers.
|
||||
\param ch DMA channel.
|
||||
\param mode DMA mode.
|
||||
*/
|
||||
#define DMA_TRANSFER(_dst, _src, count, ch, mode) \
|
||||
do { \
|
||||
REG_DMA[ch].cnt= 0; \
|
||||
REG_DMA[ch].src= (const void*)(_src); \
|
||||
REG_DMA[ch].dst= (void*)(_dst); \
|
||||
REG_DMA[ch].cnt= (count) | (mode); \
|
||||
} while(0)
|
||||
|
||||
|
||||
INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode);
|
||||
INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode);
|
||||
|
||||
INLINE void dma3_cpy(void *dst, const void *src, uint size);
|
||||
INLINE void dma3_fill(void *dst, volatile u32 src, uint size);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TIMER
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
INLINE void profile_start(void);
|
||||
INLINE uint profile_stop(void);
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TONE GENERATOR
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NOTE_C=0, NOTE_CIS, NOTE_D, NOTE_DIS,
|
||||
NOTE_E, NOTE_F, NOTE_FIS, NOTE_G,
|
||||
NOTE_GIS, NOTE_A, NOTE_BES, NOTE_B
|
||||
} eSndNoteId;
|
||||
|
||||
extern const uint __snd_rates[12];
|
||||
|
||||
//! Gives the period of a note for the tone-gen registers.
|
||||
/*! GBA sound range: 8 octaves: [-2, 5]; 8*12= 96 notes (kinda).
|
||||
* \param note ID (range: [0,11>). See eSndNoteId.
|
||||
* \param oct octave (range [-2,4)>).
|
||||
*/
|
||||
#define SND_RATE(note, oct) ( 2048-(__snd_rates[note]>>(4+(oct))) )
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MISC
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpCoreMisc Miscellaneous routines
|
||||
* \ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
//! Create text string from a literal
|
||||
#define XSTR(x) STR(x)
|
||||
|
||||
|
||||
//! \name Inline assembly
|
||||
//\{
|
||||
|
||||
//! Assembly comment
|
||||
#define ASM_CMT(str) asm volatile("@# " str)
|
||||
|
||||
//! No$gba breakpoint
|
||||
#define ASM_BREAK() asm volatile("\tmov\t\tr11, r11")
|
||||
|
||||
//! No-op; wait a bit.
|
||||
#define ASM_NOP() asm volatile("\tnop")
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Sector checking
|
||||
//\{
|
||||
|
||||
u32 octant(int x, int y);
|
||||
u32 octant_rot(int x0, int y0);
|
||||
|
||||
//\}
|
||||
|
||||
//! \name Random numbers
|
||||
//\{
|
||||
|
||||
#define QRAN_SHIFT 15
|
||||
#define QRAN_MASK ((1<<QRAN_SHIFT)-1)
|
||||
#define QRAN_MAX QRAN_MASK
|
||||
|
||||
int sqran(int seed);
|
||||
INLINE int qran(void);
|
||||
INLINE int qran_range(int min, int max);
|
||||
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// GLOBALS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
extern const u8 oam_sizes[3][4][2];
|
||||
extern const BG_AFFINE bg_aff_default;
|
||||
extern COLOR *vid_page;
|
||||
|
||||
extern int __qran_seed;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// INLINES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
// --- Bit and bitfields -----------------------------------------------
|
||||
|
||||
|
||||
//! Get \a len long bitfield from \a y, starting at \a shift.
|
||||
/*! \param y Value containing bitfield.
|
||||
\param shift Bitfield Start;
|
||||
\param len Length of bitfield.
|
||||
\return Bitfield between bits \a shift and \a shift + \a length.
|
||||
*/
|
||||
INLINE u32 bf_get(u32 y, uint shift, uint len)
|
||||
{ return (y>>shift) & ( (1<<len)-1 ); }
|
||||
|
||||
//! Merge \a x into an \a len long bitfield from \a y, starting at \a shift.
|
||||
/*! \param y Value containing bitfield.
|
||||
\param x Value to merge (will be masked to fit).
|
||||
\param shift Bitfield Start;
|
||||
\param len Length of bitfield.
|
||||
\return Result of merger: (y&~M) | (x<<s & M)
|
||||
\note Does \e not write the result back into \a y (Because pure C
|
||||
does't have references, that's why)
|
||||
*/
|
||||
INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len)
|
||||
{
|
||||
u32 mask= ((u32)(1<<len)-1);
|
||||
return (y &~ (mask<<shift)) | (x & mask)<<shift;
|
||||
}
|
||||
|
||||
//! Clamp \a to within the range allowed by \a len bits
|
||||
INLINE u32 bf_clamp(int x, uint len)
|
||||
{
|
||||
u32 y=x>>len;
|
||||
if(y)
|
||||
x= (~y)>>(32-len);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
//! Gives a tribool (-1, 0, or +1) depending on the state of some bits.
|
||||
/*! Looks at the \a plus and \a minus bits of \a flags, and subtracts
|
||||
their status to give a +1, -1 or 0 result. Useful for direction flags.
|
||||
\param flags Value with bit-flags.
|
||||
\param plus Bit number for positive result.
|
||||
\param minus Bit number for negative result.
|
||||
\return <b>+1</b> if \a plus bit is set but \a minus bit isn't<br>
|
||||
<b>-1</b> if \a minus bit is set and \a plus bit isn't<br>
|
||||
<b>0</b> if neither or both are set.
|
||||
*/
|
||||
INLINE int bit_tribool(u32 flags, uint plus, uint minus)
|
||||
{ return ((flags>>plus)&1) - ((flags>>minus)&1); }
|
||||
|
||||
|
||||
//! Rotate bits right. Yes, this does lead to a ror instruction.
|
||||
INLINE u32 ROR(u32 x, uint ror)
|
||||
{ return (x<<(32-ror)) | (x>>ror); }
|
||||
|
||||
|
||||
// --- Data -----------------------------------------------------------
|
||||
|
||||
INLINE uint align(uint x, uint width)
|
||||
{ return (x+width-1)/width*width; }
|
||||
|
||||
|
||||
//! VRAM-safe memset, byte version. Size in bytes.
|
||||
INLINE void *toncset(void *dst, u8 src, uint count)
|
||||
{ return __toncset(dst, quad8(src), count); }
|
||||
|
||||
//! VRAM-safe memset, halfword version. Size in hwords.
|
||||
INLINE void *toncset16(void *dst, u16 src, uint count)
|
||||
{ return __toncset(dst, src|src<<16, count*2); }
|
||||
|
||||
//! VRAM-safe memset, word version. Size in words.
|
||||
INLINE void *toncset32(void *dst, u32 src, uint count)
|
||||
{ return __toncset(dst, src, count*4); }
|
||||
|
||||
|
||||
|
||||
//! Duplicate a byte to form a halfword: 0x12 -> 0x1212.
|
||||
INLINE u16 dup8(u8 x) { return x|(x<<8); }
|
||||
|
||||
//! Duplicate a halfword to form a word: 0x1234 -> 0x12341234.
|
||||
INLINE u32 dup16(u16 x) { return x|(x<<16); }
|
||||
|
||||
//! Quadruple a byte to form a word: 0x12 -> 0x12121212.
|
||||
INLINE u32 quad8(u8 x) { return x*0x01010101; }
|
||||
|
||||
//! Octuple a nybble to form a word: 0x1 -> 0x11111111
|
||||
INLINE u32 octup(u8 x) { return x*0x11111111; }
|
||||
|
||||
|
||||
//! Pack 2 bytes into a word. Little-endian order.
|
||||
INLINE u16 bytes2hword(u8 b0, u8 b1)
|
||||
{ return b0 | b1<<8; }
|
||||
|
||||
//! Pack 4 bytes into a word. Little-endian order.
|
||||
INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3)
|
||||
{ return b0 | b1<<8 | b2<<16 | b3<<24; }
|
||||
|
||||
INLINE u32 hword2word(u16 h0, u16 h1)
|
||||
{ return h0 | h1<<16; }
|
||||
|
||||
|
||||
// --- DMA ------------------------------------------------------------
|
||||
|
||||
/*! \addtogroup grpDma */
|
||||
/*! \{ */
|
||||
|
||||
//! Generic DMA copy routine.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source address.
|
||||
* \param count Number of copies to perform.
|
||||
* \param ch DMA channel.
|
||||
* \param mode DMA transfer mode.
|
||||
* \note \a count is the number of copies, not the size in bytes.
|
||||
*/
|
||||
INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode)
|
||||
{
|
||||
REG_DMA[ch].cnt= 0;
|
||||
REG_DMA[ch].src= src;
|
||||
REG_DMA[ch].dst= dst;
|
||||
REG_DMA[ch].cnt= mode | count;
|
||||
}
|
||||
|
||||
//! Generic DMA fill routine.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source value.
|
||||
* \param count Number of copies to perform.
|
||||
* \param ch DMA channel.
|
||||
* \param mode DMA transfer mode.
|
||||
* \note \a count is the number of copies, not the size in bytes.
|
||||
*/
|
||||
INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode)
|
||||
{
|
||||
REG_DMA[ch].cnt= 0;
|
||||
REG_DMA[ch].src= (const void*)&src;
|
||||
REG_DMA[ch].dst= dst;
|
||||
REG_DMA[ch].cnt= count | mode | DMA_SRC_FIXED;
|
||||
}
|
||||
|
||||
//! Specific DMA copier, using channel 3, word transfers.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source address.
|
||||
* \param size Number of bytes to copy
|
||||
* \note \a size is the number of bytes
|
||||
*/
|
||||
INLINE void dma3_cpy(void *dst, const void *src, uint size)
|
||||
{ dma_cpy(dst, src, size/4, 3, DMA_CPY32); }
|
||||
|
||||
//! Specific DMA filler, using channel 3, word transfers.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source value.
|
||||
* \param size Number of bytes to copy
|
||||
* \note \a size is the number of bytes
|
||||
*/
|
||||
INLINE void dma3_fill(void *dst, volatile u32 src, uint size)
|
||||
{ dma_fill(dst, src, size/4, 3, DMA_FILL32); }
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --- Random ---------------------------------------------------------
|
||||
|
||||
//! Quick (and very dirty) pseudo-random number generator
|
||||
/*! \return random in range [0,8000h>
|
||||
*/
|
||||
INLINE int qran(void)
|
||||
{
|
||||
__qran_seed= 1664525*__qran_seed+1013904223;
|
||||
return (__qran_seed>>16) & QRAN_MAX;
|
||||
}
|
||||
|
||||
|
||||
//! Ranged random number
|
||||
/*! \return random in range [\a min, \a max>
|
||||
* \note (max-min) must be lower than 8000h
|
||||
*/
|
||||
INLINE int qran_range(int min, int max)
|
||||
{ return (qran()*(max-min)>>QRAN_SHIFT)+min; }
|
||||
|
||||
|
||||
// --- Timer ----------------------------------------------------------
|
||||
|
||||
/*! \addtogroup grpTimer */
|
||||
/*! \{ */
|
||||
|
||||
//! Start a profiling run
|
||||
/*! \note Routine uses timers 3 and 3; if you're already using these
|
||||
* somewhere, chaos is going to ensue.
|
||||
*/
|
||||
INLINE void profile_start(void)
|
||||
{
|
||||
REG_TM2D= 0; REG_TM3D= 0;
|
||||
REG_TM2CNT= 0; REG_TM3CNT= 0;
|
||||
REG_TM3CNT= TM_ENABLE | TM_CASCADE;
|
||||
REG_TM2CNT= TM_ENABLE;
|
||||
}
|
||||
|
||||
//! Stop a profiling run and return the time since its start.
|
||||
/*! \return 32bit cycle count
|
||||
*/
|
||||
INLINE uint profile_stop(void)
|
||||
{
|
||||
REG_TM2CNT= 0;
|
||||
return (REG_TM3D<<16)|REG_TM2D;
|
||||
}
|
||||
|
||||
/*! \} /addtogroup */
|
||||
|
||||
|
||||
#endif // TONC_CORE
|
||||
|
|
@ -0,0 +1,573 @@
|
|||
//
|
||||
// Core functionality
|
||||
//
|
||||
//! \file tonc_core.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20080128
|
||||
//
|
||||
/* === NOTES ===
|
||||
* Contents: bits, random, dma, timer
|
||||
* 20080129,jv: added tonccpy/set routines.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TONC_CORE_STUB
|
||||
#define TONC_CORE_STUB
|
||||
|
||||
#include "tonc_memmap.h"
|
||||
#include "tonc_memdef.h"
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// BITS and BITFIELDS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpCoreBit Bit(field) macros
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name Simple bit macros
|
||||
//\{
|
||||
|
||||
//! Create value with bit \a n set
|
||||
#define BIT(n) ( 1<<(n) )
|
||||
|
||||
//! Shift \a a by \a n
|
||||
#define BIT_SHIFT(a, n) ( (a)<<(n) )
|
||||
|
||||
//! Create a bitmask \a len bits long
|
||||
#define BIT_MASK(len) ( BIT(len)-1 )
|
||||
|
||||
//! Set the \a flag bits in \a word
|
||||
#define BIT_SET(y, flag) ( y |= (flag) )
|
||||
|
||||
//! Clear the \a flag bits in \a word
|
||||
#define BIT_CLEAR(y, flag) ( y &= ~(flag) )
|
||||
|
||||
//! Flip the \a flag bits in \a word
|
||||
#define BIT_FLIP(y, flag) ( y ^= (flag) )
|
||||
|
||||
//! Test whether all the \a flag bits in \a word are set
|
||||
#define BIT_EQ(y, flag) ( ((y)&(flag)) == (flag) )
|
||||
|
||||
|
||||
|
||||
//! Create a bitmask of length \a len starting at bit \a shift.
|
||||
#define BF_MASK(shift, len) ( BIT_MASK(len)<<(shift) )
|
||||
|
||||
|
||||
//! Retrieve a bitfield mask of length \a starting at bit \a shift from \a y.
|
||||
#define _BF_GET(y, shift, len) ( ((y)>>(shift))&BIT_MASK(len) )
|
||||
|
||||
//! Prepare a bitmask for insertion or combining.
|
||||
#define _BF_PREP(x, shift, len) ( ((x)&BIT_MASK(len))<<(shift) )
|
||||
|
||||
//! Insert a new bitfield value \a x into \a y.
|
||||
#define _BF_SET(y, x, shift, len) \
|
||||
( y= ((y) &~ BF_MASK(shift, len)) | _BF_PREP(x, shift, len) )
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name some EVIL bit-field operations, >:)
|
||||
* These allow you to mimic bitfields with macros. Most of the
|
||||
* bitfields in the registers have <i>foo</i>_SHIFT and
|
||||
* <i>foo</i>_SHIFT macros indicating the mask and shift values
|
||||
* of the bitfield named <i>foo</i> in a variable.
|
||||
* These macros let you prepare, get and set the bitfields.
|
||||
*/
|
||||
//\{
|
||||
|
||||
//! Prepare a named bit-field for for insterion or combination.
|
||||
#define BFN_PREP(x, name) ( ((x)<<name##_SHIFT) & name##_MASK )
|
||||
|
||||
//! Get the value of a named bitfield from \a y. Equivalent to (var=) y.name
|
||||
#define BFN_GET(y, name) ( ((y) & name##_MASK)>>name##_SHIFT )
|
||||
|
||||
//! Set a named bitfield in \a y to \a x. Equivalent to y.name= x.
|
||||
#define BFN_SET(y, x, name) (y = ((y)&~name##_MASK) | BFN_PREP(x,name) )
|
||||
|
||||
//! Compare a named bitfield to named literal \a x.
|
||||
#define BFN_CMP(y, x, name) ( ((y)&name##_MASK) == (x) )
|
||||
|
||||
|
||||
//! Massage \a x for use in bitfield \a name with pre-shifted \a x
|
||||
#define BFN_PREP2(x, name) ( (x) & name##_MASK )
|
||||
|
||||
//! Get the value of bitfield \a name from \a y, but don't down-shift
|
||||
#define BFN_GET2(y, name) ( (y) & name##_MASK )
|
||||
|
||||
//! Set bitfield \a name from \a y to \a x with pre-shifted \a x
|
||||
#define BFN_SET2(y,x,name) ( y = ((y)&~name##_MASK) | BFN_PREP2(x,name) )
|
||||
|
||||
//\}
|
||||
|
||||
INLINE u32 bf_get(u32 y, uint shift, uint len);
|
||||
INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len);
|
||||
INLINE u32 bf_clamp(int x, uint len);
|
||||
|
||||
INLINE int bit_tribool(u32 x, uint plus, uint minus);
|
||||
INLINE u32 ROR(u32 x, uint ror);
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpData Data routines
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! Get the number of elements in an array
|
||||
#define countof(_array) ( sizeof(_array)/sizeof(_array[0]) )
|
||||
|
||||
//! Align \a x to the next multiple of \a width.
|
||||
INLINE uint align(uint x, uint width);
|
||||
|
||||
//! \name Copying and filling routines
|
||||
//\{
|
||||
|
||||
//! Simplified copier for GRIT-exported data.
|
||||
#define GRIT_CPY(dst, name) memcpy16(dst, name, name##Len/2)
|
||||
|
||||
|
||||
// Base memcpy/set replacements.
|
||||
void *tonccpy(void *dst, const void *src, uint size);
|
||||
|
||||
void *__toncset(void *dst, u32 fill, uint size);
|
||||
INLINE void *toncset(void *dst, u8 src, uint count);
|
||||
INLINE void *toncset16(void *dst, u16 src, uint count);
|
||||
INLINE void *toncset32(void *dst, u32 src, uint count);
|
||||
|
||||
|
||||
// Fast memcpy/set
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
void memset32(void *dst, u32 wd, uint wcount);
|
||||
void memcpy32(void *dst, const void* src, uint wcount);
|
||||
|
||||
|
||||
//! Fastfill for halfwords, analogous to memset()
|
||||
/*! Uses <code>memset32()</code> if \a hwcount>5
|
||||
* \param dst Destination address.
|
||||
* \param hw Source halfword (not address).
|
||||
* \param hwcount Number of halfwords to fill.
|
||||
* \note \a dst <b>must</b> be halfword aligned.
|
||||
* \note \a r0 returns as \a dst + \a hwcount*2.
|
||||
*/
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
|
||||
//! \brief Copy for halfwords.
|
||||
/*! Uses <code>memcpy32()</code> if \a hwn>6 and
|
||||
\a src and \a dst are aligned equally.
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param hwcount Number of halfwords to fill.
|
||||
\note \a dst and \a src <b>must</b> be halfword aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a hwcount*2 and \a src + \a hwcount*2.
|
||||
*/
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
|
||||
//! Fast-fill by words, analogous to memset()
|
||||
/*! Like CpuFastSet(), only without the requirement of
|
||||
32byte chunks and no awkward store-value-in-memory-first issue.
|
||||
\param dst Destination address.
|
||||
\param wd Fill word (not address).
|
||||
\param wdcount Number of words to fill.
|
||||
\note \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 returns as \a dst + \a wdcount*4.
|
||||
*/
|
||||
void memset32(void *dst, u32 wd, uint wdcount);
|
||||
|
||||
|
||||
//! \brief Fast-copy by words.
|
||||
/*! Like CpuFastFill(), only without the requirement of 32byte chunks
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param wdcount Number of words.
|
||||
\note \a src and \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a wdcount*4 and \a src + \a wdcount*4.
|
||||
*/
|
||||
void memcpy32(void *dst, const void* src, uint wdcount);
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name Repeated-value creators
|
||||
These function take a hex-value and duplicate it to all fields,
|
||||
like 0x88 -> 0x88888888.
|
||||
*/
|
||||
//\{
|
||||
INLINE u16 dup8(u8 x);
|
||||
INLINE u32 dup16(u16 x);
|
||||
INLINE u32 quad8(u8 x);
|
||||
INLINE u32 octup(u8 x);
|
||||
//\}
|
||||
|
||||
//! \name Packing routines.
|
||||
//\{
|
||||
INLINE u16 bytes2hword(u8 b0, u8 b1);
|
||||
INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3);
|
||||
INLINE u32 hword2word(u16 h0, u16 h1);
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DMA
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpDma */
|
||||
/*! \{ */
|
||||
|
||||
//! General purpose DMA transfer macro
|
||||
/*! \param _dst Destination address.
|
||||
\param _src Source address.
|
||||
\param count Number of transfers.
|
||||
\param ch DMA channel.
|
||||
\param mode DMA mode.
|
||||
*/
|
||||
#define DMA_TRANSFER(_dst, _src, count, ch, mode) \
|
||||
do { \
|
||||
REG_DMA[ch].cnt= 0; \
|
||||
REG_DMA[ch].src= (const void*)(_src); \
|
||||
REG_DMA[ch].dst= (void*)(_dst); \
|
||||
REG_DMA[ch].cnt= (count) | (mode); \
|
||||
} while(0)
|
||||
|
||||
|
||||
INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode);
|
||||
INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode);
|
||||
|
||||
INLINE void dma3_cpy(void *dst, const void *src, uint size);
|
||||
INLINE void dma3_fill(void *dst, volatile u32 src, uint size);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TIMER
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
INLINE void profile_start(void);
|
||||
INLINE uint profile_stop(void);
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TONE GENERATOR
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NOTE_C=0, NOTE_CIS, NOTE_D, NOTE_DIS,
|
||||
NOTE_E, NOTE_F, NOTE_FIS, NOTE_G,
|
||||
NOTE_GIS, NOTE_A, NOTE_BES, NOTE_B
|
||||
} eSndNoteId;
|
||||
|
||||
extern const uint __snd_rates[12];
|
||||
|
||||
//! Gives the period of a note for the tone-gen registers.
|
||||
/*! GBA sound range: 8 octaves: [-2, 5]; 8*12= 96 notes (kinda).
|
||||
* \param note ID (range: [0,11>). See eSndNoteId.
|
||||
* \param oct octave (range [-2,4)>).
|
||||
*/
|
||||
#define SND_RATE(note, oct) ( 2048-(__snd_rates[note]>>(4+(oct))) )
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MISC
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpCoreMisc Miscellaneous routines
|
||||
* \ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
//! Create text string from a literal
|
||||
#define XSTR(x) STR(x)
|
||||
|
||||
|
||||
//! \name Inline assembly
|
||||
//\{
|
||||
|
||||
//! Assembly comment
|
||||
#define ASM_CMT(str) asm volatile("@# " str)
|
||||
|
||||
//! No$gba breakpoint
|
||||
#define ASM_BREAK() asm volatile("\tmov\t\tr11, r11")
|
||||
|
||||
//! No-op; wait a bit.
|
||||
#define ASM_NOP() asm volatile("\tnop")
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Sector checking
|
||||
//\{
|
||||
|
||||
u32 octant(int x, int y);
|
||||
u32 octant_rot(int x0, int y0);
|
||||
|
||||
//\}
|
||||
|
||||
//! \name Random numbers
|
||||
//\{
|
||||
|
||||
#define QRAN_SHIFT 15
|
||||
#define QRAN_MASK ((1<<QRAN_SHIFT)-1)
|
||||
#define QRAN_MAX QRAN_MASK
|
||||
|
||||
int sqran(int seed);
|
||||
INLINE int qran(void);
|
||||
INLINE int qran_range(int min, int max);
|
||||
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// GLOBALS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
extern const u8 oam_sizes[3][4][2];
|
||||
extern const BG_AFFINE bg_aff_default;
|
||||
extern COLOR *vid_page;
|
||||
|
||||
extern int __qran_seed;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// INLINES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
// --- Bit and bitfields -----------------------------------------------
|
||||
|
||||
|
||||
//! Get \a len long bitfield from \a y, starting at \a shift.
|
||||
/*! \param y Value containing bitfield.
|
||||
\param shift Bitfield Start;
|
||||
\param len Length of bitfield.
|
||||
\return Bitfield between bits \a shift and \a shift + \a length.
|
||||
*/
|
||||
INLINE u32 bf_get(u32 y, uint shift, uint len)
|
||||
{ return (y>>shift) & ( (1<<len)-1 ); }
|
||||
|
||||
//! Merge \a x into an \a len long bitfield from \a y, starting at \a shift.
|
||||
/*! \param y Value containing bitfield.
|
||||
\param x Value to merge (will be masked to fit).
|
||||
\param shift Bitfield Start;
|
||||
\param len Length of bitfield.
|
||||
\return Result of merger: (y&~M) | (x<<s & M)
|
||||
\note Does \e not write the result back into \a y (Because pure C
|
||||
does't have references, that's why)
|
||||
*/
|
||||
INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len)
|
||||
{
|
||||
u32 mask= ((u32)(1<<len)-1);
|
||||
return (y &~ (mask<<shift)) | (x & mask)<<shift;
|
||||
}
|
||||
|
||||
//! Clamp \a to within the range allowed by \a len bits
|
||||
INLINE u32 bf_clamp(int x, uint len)
|
||||
{
|
||||
u32 y=x>>len;
|
||||
if(y)
|
||||
x= (~y)>>(32-len);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
//! Gives a tribool (-1, 0, or +1) depending on the state of some bits.
|
||||
/*! Looks at the \a plus and \a minus bits of \a flags, and subtracts
|
||||
their status to give a +1, -1 or 0 result. Useful for direction flags.
|
||||
\param flags Value with bit-flags.
|
||||
\param plus Bit number for positive result.
|
||||
\param minus Bit number for negative result.
|
||||
\return <b>+1</b> if \a plus bit is set but \a minus bit isn't<br>
|
||||
<b>-1</b> if \a minus bit is set and \a plus bit isn't<br>
|
||||
<b>0</b> if neither or both are set.
|
||||
*/
|
||||
INLINE int bit_tribool(u32 flags, uint plus, uint minus)
|
||||
{ return ((flags>>plus)&1) - ((flags>>minus)&1); }
|
||||
|
||||
|
||||
//! Rotate bits right. Yes, this does lead to a ror instruction.
|
||||
INLINE u32 ROR(u32 x, uint ror)
|
||||
{ return (x<<(32-ror)) | (x>>ror); }
|
||||
|
||||
|
||||
// --- Data -----------------------------------------------------------
|
||||
|
||||
INLINE uint align(uint x, uint width)
|
||||
{ return (x+width-1)/width*width; }
|
||||
|
||||
|
||||
//! VRAM-safe memset, byte version. Size in bytes.
|
||||
INLINE void *toncset(void *dst, u8 src, uint count)
|
||||
{ return __toncset(dst, quad8(src), count); }
|
||||
|
||||
//! VRAM-safe memset, halfword version. Size in hwords.
|
||||
INLINE void *toncset16(void *dst, u16 src, uint count)
|
||||
{ return __toncset(dst, src|src<<16, count*2); }
|
||||
|
||||
//! VRAM-safe memset, word version. Size in words.
|
||||
INLINE void *toncset32(void *dst, u32 src, uint count)
|
||||
{ return __toncset(dst, src, count*4); }
|
||||
|
||||
|
||||
|
||||
//! Duplicate a byte to form a halfword: 0x12 -> 0x1212.
|
||||
INLINE u16 dup8(u8 x) { return x|(x<<8); }
|
||||
|
||||
//! Duplicate a halfword to form a word: 0x1234 -> 0x12341234.
|
||||
INLINE u32 dup16(u16 x) { return x|(x<<16); }
|
||||
|
||||
//! Quadruple a byte to form a word: 0x12 -> 0x12121212.
|
||||
INLINE u32 quad8(u8 x) { return x*0x01010101; }
|
||||
|
||||
//! Octuple a nybble to form a word: 0x1 -> 0x11111111
|
||||
INLINE u32 octup(u8 x) { return x*0x11111111; }
|
||||
|
||||
|
||||
//! Pack 2 bytes into a word. Little-endian order.
|
||||
INLINE u16 bytes2hword(u8 b0, u8 b1)
|
||||
{ return b0 | b1<<8; }
|
||||
|
||||
//! Pack 4 bytes into a word. Little-endian order.
|
||||
INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3)
|
||||
{ return b0 | b1<<8 | b2<<16 | b3<<24; }
|
||||
|
||||
INLINE u32 hword2word(u16 h0, u16 h1)
|
||||
{ return h0 | h1<<16; }
|
||||
|
||||
|
||||
// --- DMA ------------------------------------------------------------
|
||||
|
||||
/*! \addtogroup grpDma */
|
||||
/*! \{ */
|
||||
|
||||
//! Generic DMA copy routine.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source address.
|
||||
* \param count Number of copies to perform.
|
||||
* \param ch DMA channel.
|
||||
* \param mode DMA transfer mode.
|
||||
* \note \a count is the number of copies, not the size in bytes.
|
||||
*/
|
||||
INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode)
|
||||
{
|
||||
REG_DMA[ch].cnt= 0;
|
||||
REG_DMA[ch].src= src;
|
||||
REG_DMA[ch].dst= dst;
|
||||
REG_DMA[ch].cnt= mode | count;
|
||||
}
|
||||
|
||||
//! Generic DMA fill routine.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source value.
|
||||
* \param count Number of copies to perform.
|
||||
* \param ch DMA channel.
|
||||
* \param mode DMA transfer mode.
|
||||
* \note \a count is the number of copies, not the size in bytes.
|
||||
*/
|
||||
INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode)
|
||||
{
|
||||
REG_DMA[ch].cnt= 0;
|
||||
REG_DMA[ch].src= (const void*)&src;
|
||||
REG_DMA[ch].dst= dst;
|
||||
REG_DMA[ch].cnt= count | mode | DMA_SRC_FIXED;
|
||||
}
|
||||
|
||||
//! Specific DMA copier, using channel 3, word transfers.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source address.
|
||||
* \param size Number of bytes to copy
|
||||
* \note \a size is the number of bytes
|
||||
*/
|
||||
INLINE void dma3_cpy(void *dst, const void *src, uint size)
|
||||
{ dma_cpy(dst, src, size/4, 3, DMA_CPY32); }
|
||||
|
||||
//! Specific DMA filler, using channel 3, word transfers.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source value.
|
||||
* \param size Number of bytes to copy
|
||||
* \note \a size is the number of bytes
|
||||
*/
|
||||
INLINE void dma3_fill(void *dst, volatile u32 src, uint size)
|
||||
{ dma_fill(dst, src, size/4, 3, DMA_FILL32); }
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --- Random ---------------------------------------------------------
|
||||
|
||||
//! Quick (and very dirty) pseudo-random number generator
|
||||
/*! \return random in range [0,8000h>
|
||||
*/
|
||||
INLINE int qran(void)
|
||||
{
|
||||
__qran_seed= 1664525*__qran_seed+1013904223;
|
||||
return (__qran_seed>>16) & QRAN_MAX;
|
||||
}
|
||||
|
||||
|
||||
//! Ranged random number
|
||||
/*! \return random in range [\a min, \a max>
|
||||
* \note (max-min) must be lower than 8000h
|
||||
*/
|
||||
INLINE int qran_range(int min, int max)
|
||||
{ return (qran()*(max-min)>>QRAN_SHIFT)+min; }
|
||||
|
||||
|
||||
// --- Timer ----------------------------------------------------------
|
||||
|
||||
/*! \addtogroup grpTimer */
|
||||
/*! \{ */
|
||||
|
||||
//! Start a profiling run
|
||||
/*! \note Routine uses timers 3 and 3; if you're already using these
|
||||
* somewhere, chaos is going to ensue.
|
||||
*/
|
||||
INLINE void profile_start(void)
|
||||
{
|
||||
REG_TM2D= 0; REG_TM3D= 0;
|
||||
REG_TM2CNT= 0; REG_TM3CNT= 0;
|
||||
REG_TM3CNT= TM_ENABLE | TM_CASCADE;
|
||||
REG_TM2CNT= TM_ENABLE;
|
||||
}
|
||||
|
||||
//! Stop a profiling run and return the time since its start.
|
||||
/*! \return 32bit cycle count
|
||||
*/
|
||||
INLINE uint profile_stop(void)
|
||||
{
|
||||
REG_TM2CNT= 0;
|
||||
return (REG_TM3D<<16)|REG_TM2D;
|
||||
}
|
||||
|
||||
/*! \} /addtogroup */
|
||||
|
||||
|
||||
#endif // TONC_CORE
|
||||
|
|
@ -0,0 +1,691 @@
|
|||
//
|
||||
// Mathematical functions
|
||||
//
|
||||
//! \file tonc_math.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20060908
|
||||
//
|
||||
// === NOTES ===
|
||||
|
||||
|
||||
#ifndef TONC_MATH
|
||||
#define TONC_MATH
|
||||
|
||||
#include "tonc_types.h"
|
||||
|
||||
// --- Doxygen modules ---
|
||||
|
||||
/*! \defgroup grpMathBase Base math
|
||||
* \brief Basic math macros and functions like MIN, MAX
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathFixed Fixed point math
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathLut Look-up tables
|
||||
* \brief Tonc's internal look-up tables and related routines.
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathPoint Point functions
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathVector Vector functions
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathRect Rect functions
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// GENERAL
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpMathBase */
|
||||
/*! \{ */
|
||||
|
||||
// Also available as inline functions
|
||||
|
||||
//! \name core math macros
|
||||
//\{
|
||||
|
||||
#ifndef ABS
|
||||
//! Get the absolute value of \a x
|
||||
#define ABS(x) ( (x)>=0 ? (x) : -(x) )
|
||||
#endif // ABS
|
||||
|
||||
#ifndef SGN
|
||||
//! Get the sign of \a x.
|
||||
#define SGN(x) ( (x)>=0 ? 1 : -1 )
|
||||
#define SGN2 SGN
|
||||
#endif // SGN
|
||||
|
||||
#ifndef SGN3
|
||||
//! Tri-state sign: -1 for negative, 0 for 0, +1 for positive.
|
||||
#define SGN3(x) ( (x)>0 ? 1 : ( (x)<0 ? -1 : 0) )
|
||||
#endif // SGN3
|
||||
|
||||
#ifndef MAX
|
||||
|
||||
//! Get the maximum of \a a and \a b
|
||||
#define MAX(a, b) ( ((a) > (b)) ? (a) : (b) )
|
||||
|
||||
//! Get the minimum of \a a and \a b
|
||||
#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
|
||||
#endif // MAX
|
||||
|
||||
#ifndef SWAP
|
||||
//! In-place swap.
|
||||
#define SWAP2(a, b) do { a=(a)-(b); b=(a)+(b); a=(b)-(a); } while(0)
|
||||
|
||||
#define SWAP SWAP2
|
||||
|
||||
//Alternative:
|
||||
//#define SWAP2(a, b) ( (b) ^= ((a) ^= ((b) ^= (a))) )
|
||||
|
||||
//! Swaps \a a and \a b, using \a tmp as a temporary
|
||||
#define SWAP3(a, b, tmp) do { (tmp)=(a); (a)=(b); (b)=(tmp); } while(0)
|
||||
#endif // SWAP
|
||||
|
||||
|
||||
INLINE int sgn(int x);
|
||||
INLINE int sgn3(int x);
|
||||
INLINE int max(int a, int b);
|
||||
INLINE int min(int a, int b);
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Boundary response macros
|
||||
//\{
|
||||
|
||||
|
||||
//! Range check
|
||||
#define IN_RANGE(x, min, max) ( ((x)>=(min)) && ((x)<(max)) )
|
||||
|
||||
//! Truncates \a x to stay in range [\a min, \a max>
|
||||
/*! \return Truncated value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
#define CLAMP(x, min, max) \
|
||||
( (x)>=(max) ? ((max)-1) : ( ((x)<(min)) ? (min) : (x) ) )
|
||||
|
||||
//! Reflects \a x at boundaries \a min and \a max
|
||||
/*! If \a x is outside the range [\a min, \a max>,
|
||||
* it'll be placed inside again with the same distance
|
||||
* to the 'wall', but on the other side. Example for lower
|
||||
* border: y = \a min - (\a x- \a min) = 2*\a min + \a x.
|
||||
* \return Reflected value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
#define REFLECT(x, min, max) \
|
||||
( (x)>=(max) ? 2*((max)-1)-(x) : ( ((x)<(min)) ? 2*(min)-(x) : (x) ) )
|
||||
|
||||
//! Wraps \a x to stay in range [\a min, \a max>
|
||||
#define WRAP(x, min, max) \
|
||||
( (x)>=(max) ? (x)+(min)-(max) : ( ((x)<(min)) ? (x)+(max)-(min) : (x) ) )
|
||||
|
||||
|
||||
INLINE BOOL in_range(int x, int min, int max);
|
||||
INLINE int clamp(int x, int min, int max);
|
||||
INLINE int reflect(int x, int min, int max);
|
||||
INLINE int wrap(int x, int min, int max);
|
||||
|
||||
//\}
|
||||
|
||||
/* \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// FIXED POINT
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpMathFixed */
|
||||
/*! \{ */
|
||||
|
||||
#define FIX_SHIFT 8
|
||||
#define FIX_SCALE ( 1<<FIX_SHIFT )
|
||||
#define FIX_MASK ( FIX_SCALE-1 )
|
||||
#define FIX_SCALEF ( (float)FIX_SCALE )
|
||||
#define FIX_SCALEF_INV ( 1.0/FIX_SCALEF )
|
||||
|
||||
#define FIX_ONE FIX_SCALE
|
||||
|
||||
//! Get the fixed point reciprocal of \a a, in \a fp fractional bits.
|
||||
/*!
|
||||
* \param a Value to take the reciprocal of.
|
||||
* \param fp Number of fixed point bits
|
||||
* \note The routine does do a division, but the compiler will
|
||||
* optimize it to a single constant ... \e if both \a a and \a fp
|
||||
* are constants!
|
||||
* \sa #FX_RECIMUL
|
||||
*/
|
||||
#define FX_RECIPROCAL(a, fp) ( ((1<<(fp))+(a)-1)/(a) )
|
||||
|
||||
//! Perform the division \a x/ \a a by reciprocal multiplication
|
||||
/*! Division is slow, but you can approximate division by a constant
|
||||
* by multiplying with its reciprocal: x/a vs x*(1/a). This routine
|
||||
* gives the reciprocal of \a a as a fixed point number with \a fp
|
||||
* fractional bits.
|
||||
* \param a Value to take the reciprocal of.
|
||||
* \param fp Number of fixed point bits
|
||||
* \note The routine does do a division, but the compiler will
|
||||
* optimize it to a single constant ... \e if both \a a and \a fp
|
||||
* are constants!
|
||||
* \note Rules for safe reciprocal division, using
|
||||
* n = 2<sup>fp</sup> and m = (n+a-1)/a (i.e., rounding up)
|
||||
* \li Maximum safe numerator \a x: x < n/(m*a-n)
|
||||
* \li Minimum n for known \a x: n > x*(a-1)
|
||||
*/
|
||||
#define FX_RECIMUL(x, a, fp) ( ((x)*((1<<(fp))+(a)-1)/(a))>>(fp) )
|
||||
|
||||
INLINE FIXED int2fx(int d);
|
||||
INLINE FIXED float2fx(float f);
|
||||
INLINE u32 fx2uint(FIXED fx);
|
||||
INLINE u32 fx2ufrac(FIXED fx);
|
||||
INLINE int fx2int(FIXED fx);
|
||||
INLINE float fx2float(FIXED fx);
|
||||
INLINE FIXED fxadd(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxsub(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxmul(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxdiv(FIXED fa, FIXED fb);
|
||||
|
||||
INLINE FIXED fxmul64(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxdiv64(FIXED fa, FIXED fb);
|
||||
|
||||
/*! \} */
|
||||
|
||||
// === LUT ============================================================
|
||||
|
||||
|
||||
/*! \addtogroup grpMathLut */
|
||||
/*! \{ */
|
||||
|
||||
#define SIN_LUT_SIZE 514 // 512 for main lut, 2 extra for lerp
|
||||
#define DIV_LUT_SIZE 257 // 256 for main lut, 1 extra for lerp
|
||||
|
||||
extern s32 div_lut[257]; // .16f
|
||||
extern s16 sin_lut[514]; // .12f
|
||||
|
||||
INLINE s32 lu_sin(uint theta);
|
||||
INLINE s32 lu_cos(uint theta);
|
||||
INLINE uint lu_div(uint x);
|
||||
|
||||
INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift);
|
||||
INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift);
|
||||
|
||||
/*! \} */
|
||||
|
||||
// === POINT ==========================================================
|
||||
|
||||
struct RECT;
|
||||
|
||||
//! \addtogroup grpMathPoint
|
||||
//! \{
|
||||
|
||||
//! 2D Point struct
|
||||
typedef struct POINT { int x, y; } POINT, POINT32;
|
||||
|
||||
|
||||
// --- Point functions ---
|
||||
INLINE POINT *pt_set(POINT *pd, int x, int y);
|
||||
INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb);
|
||||
INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb);
|
||||
INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c);
|
||||
|
||||
INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb);
|
||||
INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb);
|
||||
INLINE POINT *pt_scale_eq(POINT *pd, int c);
|
||||
|
||||
INLINE int pt_cross(const POINT *pa, const POINT *pb);
|
||||
INLINE int pt_dot(const POINT *pa, const POINT *pb);
|
||||
|
||||
int pt_in_rect(const POINT *pt, const struct RECT *rc);
|
||||
|
||||
//! \}
|
||||
|
||||
|
||||
// === RECT ===========================================================
|
||||
|
||||
/*! \addtogroup grpMathRect */
|
||||
/*! \{ */
|
||||
|
||||
//! Rectangle struct
|
||||
typedef struct RECT
|
||||
{
|
||||
int left, top;
|
||||
int right, bottom;
|
||||
} RECT, RECT32;
|
||||
|
||||
INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b);
|
||||
INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h);
|
||||
INLINE int rc_width(const RECT *rc);
|
||||
INLINE int rc_height(const RECT *rc);
|
||||
INLINE RECT *rc_set_pos(RECT *rc, int x, int y);
|
||||
INLINE RECT *rc_set_size(RECT *rc, int w, int h);
|
||||
INLINE RECT *rc_move(RECT *rc, int dx, int dy);
|
||||
INLINE RECT *rc_inflate(RECT *rc, int dw, int dh);
|
||||
INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr);
|
||||
|
||||
RECT *rc_normalize(RECT *rc);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// === VECTOR =========================================================
|
||||
|
||||
/*! \addtogroup grpMathVector */
|
||||
/*! \{ */
|
||||
|
||||
//! Vector struct
|
||||
typedef struct VECTOR { FIXED x, y, z; } VECTOR;
|
||||
|
||||
|
||||
INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z);
|
||||
INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c);
|
||||
INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb);
|
||||
|
||||
INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c);
|
||||
|
||||
VECTOR *vec_cross(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
|
||||
// === INLINE =========================================================
|
||||
|
||||
// --- General --------------------------------------------------------
|
||||
|
||||
//! Get the sign of \a x.
|
||||
INLINE int sgn(int x)
|
||||
{ return (x>=0) ? +1 : -1; }
|
||||
|
||||
//! Tri-state sign of \a x: -1 for negative, 0 for 0, +1 for positive.
|
||||
INLINE int sgn3(int x)
|
||||
{ return (x>>31) - (-x>>31); }
|
||||
|
||||
//! Get the maximum of \a a and \a b
|
||||
INLINE int max(int a, int b)
|
||||
{ return (a > b) ? (a) : (b); }
|
||||
|
||||
//! Get the minimum of \a a and \a b
|
||||
INLINE int min(int a, int b)
|
||||
{ return (a < b) ? (a) : (b); }
|
||||
|
||||
|
||||
//! Range check
|
||||
INLINE BOOL in_range(int x, int min, int max)
|
||||
{ return (u32)(x-min) < (u32)(max-min); }
|
||||
|
||||
|
||||
//! Truncates \a x to stay in range [\a min, \a max>
|
||||
/*! \return Truncated value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
INLINE int clamp(int x, int min, int max)
|
||||
{ return (x>=max) ? (max-1) : ( (x<min) ? min : x ); }
|
||||
|
||||
//! Reflects \a x at boundaries \a min and \a max
|
||||
/*! If \a x is outside the range [\a min, \a max>,
|
||||
* it'll be placed inside again with the same distance
|
||||
* to the 'wall', but on the other side. Example for lower
|
||||
* border: y = \a min - (\a x- \a min) = 2*\a min + \a x.
|
||||
* \return Reflected value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
INLINE int reflect(int x, int min, int max)
|
||||
{ return (x>=max) ? (2*(max-1)-x) : ( (x<min) ? (2*min-x) : x ); }
|
||||
|
||||
//! Wraps \a x to stay in range [\a min, \a max>
|
||||
INLINE int wrap(int x, int min, int max)
|
||||
{ return (x>=max) ? (x+min-max) : ( (x<min) ? (x+max-min) : x ); }
|
||||
|
||||
|
||||
// --- Fixed point ----------------------------------------------------
|
||||
|
||||
|
||||
//! Convert an integer to fixed-point
|
||||
INLINE FIXED int2fx(int d)
|
||||
{ return d<<FIX_SHIFT; }
|
||||
|
||||
//! Convert a float to fixed-point
|
||||
INLINE FIXED float2fx(float f)
|
||||
{ return (FIXED)(f*FIX_SCALEF); }
|
||||
|
||||
|
||||
//! Convert a FIXED point value to an unsigned integer (orly?).
|
||||
INLINE u32 fx2uint(FIXED fx)
|
||||
{ return fx>>FIX_SHIFT; }
|
||||
|
||||
//! Get the unsigned fractional part of a fixed point value (orly?).
|
||||
INLINE u32 fx2ufrac(FIXED fx)
|
||||
{ return fx&FIX_MASK; }
|
||||
|
||||
//! Convert a FIXED point value to an signed integer.
|
||||
INLINE int fx2int(FIXED fx)
|
||||
{ return fx/FIX_SCALE; }
|
||||
|
||||
//! Convert a fixed point value to floating point.
|
||||
INLINE float fx2float(FIXED fx)
|
||||
{ return fx/FIX_SCALEF; }
|
||||
|
||||
//! Add two fixed point values
|
||||
INLINE FIXED fxadd(FIXED fa, FIXED fb)
|
||||
{ return fa + fb; }
|
||||
|
||||
//! Subtract two fixed point values
|
||||
INLINE FIXED fxsub(FIXED fa, FIXED fb)
|
||||
{ return fa - fb; }
|
||||
|
||||
|
||||
//! Multiply two fixed point values
|
||||
INLINE FIXED fxmul(FIXED fa, FIXED fb)
|
||||
{ return (fa*fb)>>FIX_SHIFT; }
|
||||
|
||||
//! Divide two fixed point values.
|
||||
INLINE FIXED fxdiv(FIXED fa, FIXED fb)
|
||||
{ return ((fa)*FIX_SCALE)/(fb); }
|
||||
|
||||
|
||||
//! Multiply two fixed point values using 64bit math.
|
||||
INLINE FIXED fxmul64(FIXED fa, FIXED fb)
|
||||
{ return (((s64)fa)*fb)>>FIX_SHIFT; }
|
||||
|
||||
|
||||
//! Divide two fixed point values using 64bit math.
|
||||
INLINE FIXED fxdiv64(FIXED fa, FIXED fb)
|
||||
{ return ( ((s64)fa)<<FIX_SHIFT)/(fb); }
|
||||
|
||||
|
||||
// --- LUT ------------------------------------------------------------
|
||||
|
||||
//! Look-up a sine value (2π = 0x10000)
|
||||
/*! \param theta Angle in [0,FFFFh] range
|
||||
* \return .12f sine value
|
||||
*/
|
||||
INLINE s32 lu_sin(uint theta)
|
||||
{ return sin_lut[(theta>>7)&0x1FF]; }
|
||||
|
||||
//! Look-up a cosine value (2π = 0x10000)
|
||||
/*! \param theta Angle in [0,FFFFh] range
|
||||
* \return .12f cosine value
|
||||
*/
|
||||
INLINE s32 lu_cos(uint theta)
|
||||
{ return sin_lut[((theta>>7)+128)&0x1FF]; }
|
||||
|
||||
//! Look-up a division value between 0 and 255
|
||||
/*! \param x reciprocal to look up.
|
||||
* \return 1/x (.16f)
|
||||
*/
|
||||
INLINE uint lu_div(uint x)
|
||||
{ return div_lut[x]; }
|
||||
|
||||
|
||||
//! Linear interpolator for 32bit LUTs.
|
||||
/*! A lut is essentially the discrete form of a function, f(<i>x</i>).
|
||||
* You can get values for non-integer \e x via (linear)
|
||||
* interpolation between f(x) and f(x+1).
|
||||
* \param lut The LUT to interpolate from.
|
||||
* \param x Fixed point number to interpolate at.
|
||||
* \param shift Number of fixed-point bits of \a x.
|
||||
*/
|
||||
INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift)
|
||||
{
|
||||
int xa, ya, yb;
|
||||
xa=x>>shift;
|
||||
ya= lut[xa]; yb= lut[xa+1];
|
||||
return ya + ( (yb-ya)*(x-(xa<<shift))>>shift );
|
||||
}
|
||||
|
||||
//! As lu_lerp32, but for 16bit LUTs.
|
||||
INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift)
|
||||
{
|
||||
int xa, ya, yb;
|
||||
xa=x>>shift;
|
||||
ya= lut[xa]; yb= lut[xa+1];
|
||||
return ya + ( (yb-ya)*(x-(xa<<shift))>>shift );
|
||||
}
|
||||
|
||||
|
||||
// --- Point ----------------------------------------------------------
|
||||
|
||||
//! Initialize \a pd to (\a x, \a y)
|
||||
INLINE POINT *pt_set(POINT *pd, int x, int y)
|
||||
{
|
||||
pd->x= x; pd->y= y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point addition: \a pd = \a pa + \a pb
|
||||
INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb)
|
||||
{
|
||||
pd->x= pa->x + pb->x;
|
||||
pd->y= pa->x + pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point subtraction: \a pd = \a pa - \a pb
|
||||
INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb)
|
||||
{
|
||||
pd->x= pa->x - pb->x;
|
||||
pd->y= pa->x - pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point scale: \a pd = \a c * \a pa
|
||||
INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c)
|
||||
{
|
||||
pd->x= pa->x*c;
|
||||
pd->y= pa->y*c;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point increment: \a pd += \a pb
|
||||
INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb)
|
||||
{
|
||||
pd->x += pb->y;
|
||||
pd->y += pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point decrement: \a pd -= \a pb
|
||||
INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb)
|
||||
{
|
||||
pd->x -= pb->y;
|
||||
pd->y -= pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point scale: \a pd *= \a c
|
||||
INLINE POINT *pt_scale_eq(POINT *pd, int c)
|
||||
{
|
||||
pd->x *= c;
|
||||
pd->y *= c;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point 'cross'-product: \a pa \htmlonly × \endhtmlonly \a pb
|
||||
/*! Actually, there's no such thing as a 2D cross-product, but you could
|
||||
* extend it to 3D and get the value of its <i>z</i>-component,
|
||||
* which can be used for a test for parallelism.
|
||||
*/
|
||||
INLINE int pt_cross(const POINT *pa, const POINT *pb)
|
||||
{ return pa->x * pb->y - pa->y * pb->x; }
|
||||
|
||||
|
||||
//! Point 'dot'-product:\a pa \htmlonly · \endhtmlonly \a pb
|
||||
INLINE int pt_dot(const POINT *pa, const POINT *pb)
|
||||
{ return pa->x * pb->x + pa->y * pb->y; }
|
||||
|
||||
|
||||
|
||||
// --- Rect -----------------------------------------------------------
|
||||
|
||||
//! Initialize a rectangle.
|
||||
/*! \param l Left side.
|
||||
* \param t Top side.
|
||||
* \param r Right side.
|
||||
* \param b Bottom side.
|
||||
*/
|
||||
INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b)
|
||||
{
|
||||
rc->left= l; rc->top= t; rc->right= r; rc->bottom= b;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Initialize a rectangle, with sizes inside of max boundaries.
|
||||
/*! \param x Left side.
|
||||
* \param y Top side.
|
||||
* \param w Width.
|
||||
* \param h Height.
|
||||
*/
|
||||
INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h)
|
||||
{
|
||||
rc->left= x; rc->top= y; rc->right= x+w; rc->bottom= y+h;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Get rectangle width.
|
||||
INLINE int rc_width(const RECT *rc)
|
||||
{ return rc->right - rc->left; }
|
||||
|
||||
//! Get rectangle height
|
||||
INLINE int rc_height(const RECT *rc)
|
||||
{ return rc->bottom - rc->top; }
|
||||
|
||||
//! Move rectangle to (\a x, \a y) position.
|
||||
INLINE RECT *rc_set_pos(RECT *rc, int x, int y)
|
||||
{
|
||||
rc->right += x-rc->left; rc->left= x;
|
||||
rc->bottom += y-rc->top; rc->top= y;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Reside rectangle.
|
||||
INLINE RECT *rc_set_size(RECT *rc, int w, int h)
|
||||
{
|
||||
rc->right= rc->left+w; rc->bottom= rc->top+h;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Move rectangle by (\a dx, \a dy).
|
||||
INLINE RECT *rc_move(RECT *rc, int dx, int dy)
|
||||
{
|
||||
rc->left += dx; rc->top += dy;
|
||||
rc->right += dx; rc->bottom += dy;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Increase size by \a dw horizontally and \a dh vertically.
|
||||
INLINE RECT *rc_inflate(RECT *rc, int dw, int dh)
|
||||
{
|
||||
rc->left -= dw; rc->top -= dh;
|
||||
rc->right += dw; rc->bottom += dh;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Increase sizes on all sides by values of rectangle \a dr.
|
||||
INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr)
|
||||
{
|
||||
rc->left += dr->left; rc->top += dr->top;
|
||||
rc->right += dr->right; rc->bottom += dr->bottom;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
// --- Vector ---------------------------------------------------------
|
||||
|
||||
//! Initialize a vector
|
||||
INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z)
|
||||
{
|
||||
vd->x= x; vd->y= y; vd->z= z;
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Add vectors: \b d = \b a + \b b;
|
||||
INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
vd->x= va->x + vb->x;
|
||||
vd->y= va->y + vb->y;
|
||||
vd->z= va->z + vb->z;
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Subtract vectors: \b d = \b a - \b b;
|
||||
INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
vd->x= va->x - vb->x;
|
||||
vd->y= va->y - vb->y;
|
||||
vd->z= va->z - vb->z;
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Multiply vectors elements: \b d = \b S(ax, ay, az) <20>\b b
|
||||
INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
vd->x= fxmul(va->x, vb->x);
|
||||
vd->y= fxmul(va->y, vb->y);
|
||||
vd->z= fxmul(va->z, vb->z);
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Scale vector: \b d = c*\b a
|
||||
INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c)
|
||||
{
|
||||
vd->x= fxmul(va->x, c);
|
||||
vd->y= fxmul(va->y, c);
|
||||
vd->z= fxmul(va->z, c);
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Dot-product: d = \b a <20>\b b
|
||||
INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
FIXED dot;
|
||||
dot = fxmul(va->x, vb->x);
|
||||
dot += fxmul(va->y, vb->y);
|
||||
dot += fxmul(va->z, vb->z);
|
||||
return dot;
|
||||
}
|
||||
|
||||
//! Increment vector: \b d += \b b;
|
||||
INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb)
|
||||
{ vd->x += vb->x; vd->y += vb->y; vd->z += vb->z; return vd; }
|
||||
|
||||
//! Decrease vector: \b d -= \b b;
|
||||
INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb)
|
||||
{ vd->x -= vb->x; vd->y -= vb->y; vd->z -= vb->z; return vd; }
|
||||
|
||||
//! Multiply vectors elements: \b d = \b S(dx, dy, dz) <20>\b b
|
||||
INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb)
|
||||
{
|
||||
vd->x= fxmul(vd->x, vb->x);
|
||||
vd->y= fxmul(vd->y, vb->y);
|
||||
vd->z= fxmul(vd->z, vb->z);
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Scale vector: \b d = c*\b d
|
||||
INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c)
|
||||
{
|
||||
vd->x= fxmul(vd->x, c);
|
||||
vd->y= fxmul(vd->y, c);
|
||||
vd->z= fxmul(vd->z, c);
|
||||
return vd;
|
||||
}
|
||||
|
||||
#endif // TONC_MATH
|
|
@ -0,0 +1,702 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 14/12/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_TONC_MATH_STUB_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_TONC_MATH_STUB_H
|
||||
|
||||
//
|
||||
// Mathematical functions
|
||||
//
|
||||
//! \file tonc_math.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20060908
|
||||
//
|
||||
// === NOTES ===
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include "tonc_types.h"
|
||||
|
||||
// --- Doxygen modules ---
|
||||
|
||||
/*! \defgroup grpMathBase Base math
|
||||
* \brief Basic math macros and functions like MIN, MAX
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathFixed Fixed point math
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathLut Look-up tables
|
||||
* \brief Tonc's internal look-up tables and related routines.
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathPoint Point functions
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathVector Vector functions
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
/*! \defgroup grpMathRect Rect functions
|
||||
* \ingroup grpMath
|
||||
*/
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// GENERAL
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpMathBase */
|
||||
/*! \{ */
|
||||
|
||||
// Also available as inline functions
|
||||
|
||||
//! \name core math macros
|
||||
//\{
|
||||
|
||||
#ifndef ABS
|
||||
//! Get the absolute value of \a x
|
||||
#define ABS(x) ( (x)>=0 ? (x) : -(x) )
|
||||
#endif // ABS
|
||||
|
||||
#ifndef SGN
|
||||
//! Get the sign of \a x.
|
||||
#define SGN(x) ( (x)>=0 ? 1 : -1 )
|
||||
#define SGN2 SGN
|
||||
#endif // SGN
|
||||
|
||||
#ifndef SGN3
|
||||
//! Tri-state sign: -1 for negative, 0 for 0, +1 for positive.
|
||||
#define SGN3(x) ( (x)>0 ? 1 : ( (x)<0 ? -1 : 0) )
|
||||
#endif // SGN3
|
||||
|
||||
#ifndef MAX
|
||||
|
||||
//! Get the maximum of \a a and \a b
|
||||
#define MAX(a, b) ( ((a) > (b)) ? (a) : (b) )
|
||||
|
||||
//! Get the minimum of \a a and \a b
|
||||
#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
|
||||
#endif // MAX
|
||||
|
||||
#ifndef SWAP
|
||||
//! In-place swap.
|
||||
#define SWAP2(a, b) do { a=(a)-(b); b=(a)+(b); a=(b)-(a); } while(0)
|
||||
|
||||
#define SWAP SWAP2
|
||||
|
||||
//Alternative:
|
||||
//#define SWAP2(a, b) ( (b) ^= ((a) ^= ((b) ^= (a))) )
|
||||
|
||||
//! Swaps \a a and \a b, using \a tmp as a temporary
|
||||
#define SWAP3(a, b, tmp) do { (tmp)=(a); (a)=(b); (b)=(tmp); } while(0)
|
||||
#endif // SWAP
|
||||
|
||||
|
||||
INLINE int sgn(int x);
|
||||
INLINE int sgn3(int x);
|
||||
INLINE int max(int a, int b);
|
||||
INLINE int min(int a, int b);
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Boundary response macros
|
||||
//\{
|
||||
|
||||
|
||||
//! Range check
|
||||
#define IN_RANGE(x, min, max) ( ((x)>=(min)) && ((x)<(max)) )
|
||||
|
||||
//! Truncates \a x to stay in range [\a min, \a max>
|
||||
/*! \return Truncated value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
#define CLAMP(x, min, max) \
|
||||
( (x)>=(max) ? ((max)-1) : ( ((x)<(min)) ? (min) : (x) ) )
|
||||
|
||||
//! Reflects \a x at boundaries \a min and \a max
|
||||
/*! If \a x is outside the range [\a min, \a max>,
|
||||
* it'll be placed inside again with the same distance
|
||||
* to the 'wall', but on the other side. Example for lower
|
||||
* border: y = \a min - (\a x- \a min) = 2*\a min + \a x.
|
||||
* \return Reflected value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
#define REFLECT(x, min, max) \
|
||||
( (x)>=(max) ? 2*((max)-1)-(x) : ( ((x)<(min)) ? 2*(min)-(x) : (x) ) )
|
||||
|
||||
//! Wraps \a x to stay in range [\a min, \a max>
|
||||
#define WRAP(x, min, max) \
|
||||
( (x)>=(max) ? (x)+(min)-(max) : ( ((x)<(min)) ? (x)+(max)-(min) : (x) ) )
|
||||
|
||||
|
||||
INLINE BOOL in_range(int x, int min, int max);
|
||||
INLINE int clamp(int x, int min, int max);
|
||||
INLINE int reflect(int x, int min, int max);
|
||||
INLINE int wrap(int x, int min, int max);
|
||||
|
||||
//\}
|
||||
|
||||
/* \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// FIXED POINT
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpMathFixed */
|
||||
/*! \{ */
|
||||
|
||||
#define FIX_SHIFT 8
|
||||
#define FIX_SCALE ( 1<<FIX_SHIFT )
|
||||
#define FIX_MASK ( FIX_SCALE-1 )
|
||||
#define FIX_SCALEF ( (float)FIX_SCALE )
|
||||
#define FIX_SCALEF_INV ( 1.0/FIX_SCALEF )
|
||||
|
||||
#define FIX_ONE FIX_SCALE
|
||||
|
||||
//! Get the fixed point reciprocal of \a a, in \a fp fractional bits.
|
||||
/*!
|
||||
* \param a Value to take the reciprocal of.
|
||||
* \param fp Number of fixed point bits
|
||||
* \note The routine does do a division, but the compiler will
|
||||
* optimize it to a single constant ... \e if both \a a and \a fp
|
||||
* are constants!
|
||||
* \sa #FX_RECIMUL
|
||||
*/
|
||||
#define FX_RECIPROCAL(a, fp) ( ((1<<(fp))+(a)-1)/(a) )
|
||||
|
||||
//! Perform the division \a x/ \a a by reciprocal multiplication
|
||||
/*! Division is slow, but you can approximate division by a constant
|
||||
* by multiplying with its reciprocal: x/a vs x*(1/a). This routine
|
||||
* gives the reciprocal of \a a as a fixed point number with \a fp
|
||||
* fractional bits.
|
||||
* \param a Value to take the reciprocal of.
|
||||
* \param fp Number of fixed point bits
|
||||
* \note The routine does do a division, but the compiler will
|
||||
* optimize it to a single constant ... \e if both \a a and \a fp
|
||||
* are constants!
|
||||
* \note Rules for safe reciprocal division, using
|
||||
* n = 2<sup>fp</sup> and m = (n+a-1)/a (i.e., rounding up)
|
||||
* \li Maximum safe numerator \a x: x < n/(m*a-n)
|
||||
* \li Minimum n for known \a x: n > x*(a-1)
|
||||
*/
|
||||
#define FX_RECIMUL(x, a, fp) ( ((x)*((1<<(fp))+(a)-1)/(a))>>(fp) )
|
||||
|
||||
INLINE FIXED int2fx(int d);
|
||||
INLINE FIXED float2fx(float f);
|
||||
INLINE u32 fx2uint(FIXED fx);
|
||||
INLINE u32 fx2ufrac(FIXED fx);
|
||||
INLINE int fx2int(FIXED fx);
|
||||
INLINE float fx2float(FIXED fx);
|
||||
INLINE FIXED fxadd(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxsub(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxmul(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxdiv(FIXED fa, FIXED fb);
|
||||
|
||||
INLINE FIXED fxmul64(FIXED fa, FIXED fb);
|
||||
INLINE FIXED fxdiv64(FIXED fa, FIXED fb);
|
||||
|
||||
/*! \} */
|
||||
|
||||
// === LUT ============================================================
|
||||
|
||||
|
||||
/*! \addtogroup grpMathLut */
|
||||
/*! \{ */
|
||||
|
||||
#define SIN_LUT_SIZE 514 // 512 for main lut, 2 extra for lerp
|
||||
#define DIV_LUT_SIZE 257 // 256 for main lut, 1 extra for lerp
|
||||
|
||||
INLINE s32 lu_sin(uint theta);
|
||||
INLINE s32 lu_cos(uint theta);
|
||||
INLINE uint lu_div(uint x);
|
||||
|
||||
INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift);
|
||||
INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift);
|
||||
|
||||
/*! \} */
|
||||
|
||||
// === POINT ==========================================================
|
||||
|
||||
struct RECT;
|
||||
|
||||
//! \addtogroup grpMathPoint
|
||||
//! \{
|
||||
|
||||
//! 2D Point struct
|
||||
typedef struct POINT { int x, y; } POINT, POINT32;
|
||||
|
||||
|
||||
// --- Point functions ---
|
||||
INLINE POINT *pt_set(POINT *pd, int x, int y);
|
||||
INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb);
|
||||
INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb);
|
||||
INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c);
|
||||
|
||||
INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb);
|
||||
INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb);
|
||||
INLINE POINT *pt_scale_eq(POINT *pd, int c);
|
||||
|
||||
INLINE int pt_cross(const POINT *pa, const POINT *pb);
|
||||
INLINE int pt_dot(const POINT *pa, const POINT *pb);
|
||||
|
||||
int pt_in_rect(const POINT *pt, const struct RECT *rc);
|
||||
|
||||
//! \}
|
||||
|
||||
|
||||
// === RECT ===========================================================
|
||||
|
||||
/*! \addtogroup grpMathRect */
|
||||
/*! \{ */
|
||||
|
||||
//! Rectangle struct
|
||||
typedef struct RECT
|
||||
{
|
||||
int left, top;
|
||||
int right, bottom;
|
||||
} RECT, RECT32;
|
||||
|
||||
INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b);
|
||||
INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h);
|
||||
INLINE int rc_width(const RECT *rc);
|
||||
INLINE int rc_height(const RECT *rc);
|
||||
INLINE RECT *rc_set_pos(RECT *rc, int x, int y);
|
||||
INLINE RECT *rc_set_size(RECT *rc, int w, int h);
|
||||
INLINE RECT *rc_move(RECT *rc, int dx, int dy);
|
||||
INLINE RECT *rc_inflate(RECT *rc, int dw, int dh);
|
||||
INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr);
|
||||
|
||||
RECT *rc_normalize(RECT *rc);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// === VECTOR =========================================================
|
||||
|
||||
/*! \addtogroup grpMathVector */
|
||||
/*! \{ */
|
||||
|
||||
//! Vector struct
|
||||
typedef struct VECTOR { FIXED x, y, z; } VECTOR;
|
||||
|
||||
|
||||
INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z);
|
||||
INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c);
|
||||
INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb);
|
||||
|
||||
INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb);
|
||||
INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c);
|
||||
|
||||
VECTOR *vec_cross(VECTOR *vd, const VECTOR *va, const VECTOR *vb);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
|
||||
// === INLINE =========================================================
|
||||
|
||||
// --- General --------------------------------------------------------
|
||||
|
||||
//! Get the sign of \a x.
|
||||
INLINE int sgn(int x)
|
||||
{ return (x>=0) ? +1 : -1; }
|
||||
|
||||
//! Tri-state sign of \a x: -1 for negative, 0 for 0, +1 for positive.
|
||||
INLINE int sgn3(int x)
|
||||
{ return (x>>31) - (-x>>31); }
|
||||
|
||||
//! Get the maximum of \a a and \a b
|
||||
INLINE int max(int a, int b)
|
||||
{ return (a > b) ? (a) : (b); }
|
||||
|
||||
//! Get the minimum of \a a and \a b
|
||||
INLINE int min(int a, int b)
|
||||
{ return (a < b) ? (a) : (b); }
|
||||
|
||||
|
||||
//! Range check
|
||||
INLINE BOOL in_range(int x, int min, int max)
|
||||
{ return (u32)(x-min) < (u32)(max-min); }
|
||||
|
||||
|
||||
//! Truncates \a x to stay in range [\a min, \a max>
|
||||
/*! \return Truncated value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
INLINE int clamp(int x, int min, int max)
|
||||
{ return (x>=max) ? (max-1) : ( (x<min) ? min : x ); }
|
||||
|
||||
//! Reflects \a x at boundaries \a min and \a max
|
||||
/*! If \a x is outside the range [\a min, \a max>,
|
||||
* it'll be placed inside again with the same distance
|
||||
* to the 'wall', but on the other side. Example for lower
|
||||
* border: y = \a min - (\a x- \a min) = 2*\a min + \a x.
|
||||
* \return Reflected value of \a x.
|
||||
* \note \a max is exclusive!
|
||||
*/
|
||||
INLINE int reflect(int x, int min, int max)
|
||||
{ return (x>=max) ? (2*(max-1)-x) : ( (x<min) ? (2*min-x) : x ); }
|
||||
|
||||
//! Wraps \a x to stay in range [\a min, \a max>
|
||||
INLINE int wrap(int x, int min, int max)
|
||||
{ return (x>=max) ? (x+min-max) : ( (x<min) ? (x+max-min) : x ); }
|
||||
|
||||
|
||||
// --- Fixed point ----------------------------------------------------
|
||||
|
||||
|
||||
//! Convert an integer to fixed-point
|
||||
INLINE FIXED int2fx(int d)
|
||||
{ return d<<FIX_SHIFT; }
|
||||
|
||||
//! Convert a float to fixed-point
|
||||
INLINE FIXED float2fx(float f)
|
||||
{ return (FIXED)(f*FIX_SCALEF); }
|
||||
|
||||
|
||||
//! Convert a FIXED point value to an unsigned integer (orly?).
|
||||
INLINE u32 fx2uint(FIXED fx)
|
||||
{ return fx>>FIX_SHIFT; }
|
||||
|
||||
//! Get the unsigned fractional part of a fixed point value (orly?).
|
||||
INLINE u32 fx2ufrac(FIXED fx)
|
||||
{ return fx&FIX_MASK; }
|
||||
|
||||
//! Convert a FIXED point value to an signed integer.
|
||||
INLINE int fx2int(FIXED fx)
|
||||
{ return fx/FIX_SCALE; }
|
||||
|
||||
//! Convert a fixed point value to floating point.
|
||||
INLINE float fx2float(FIXED fx)
|
||||
{ return fx/FIX_SCALEF; }
|
||||
|
||||
//! Add two fixed point values
|
||||
INLINE FIXED fxadd(FIXED fa, FIXED fb)
|
||||
{ return fa + fb; }
|
||||
|
||||
//! Subtract two fixed point values
|
||||
INLINE FIXED fxsub(FIXED fa, FIXED fb)
|
||||
{ return fa - fb; }
|
||||
|
||||
|
||||
//! Multiply two fixed point values
|
||||
INLINE FIXED fxmul(FIXED fa, FIXED fb)
|
||||
{ return (fa*fb)>>FIX_SHIFT; }
|
||||
|
||||
//! Divide two fixed point values.
|
||||
INLINE FIXED fxdiv(FIXED fa, FIXED fb)
|
||||
{ return ((fa)*FIX_SCALE)/(fb); }
|
||||
|
||||
|
||||
//! Multiply two fixed point values using 64bit math.
|
||||
INLINE FIXED fxmul64(FIXED fa, FIXED fb)
|
||||
{ return (((s64)fa)*fb)>>FIX_SHIFT; }
|
||||
|
||||
|
||||
//! Divide two fixed point values using 64bit math.
|
||||
INLINE FIXED fxdiv64(FIXED fa, FIXED fb)
|
||||
{ return ( ((s64)fa)<<FIX_SHIFT)/(fb); }
|
||||
|
||||
|
||||
// --- LUT ------------------------------------------------------------
|
||||
|
||||
//! Look-up a sine value (2π = 0x10000)
|
||||
/*! \param theta Angle in [0,FFFFh] range
|
||||
* \return .12f sine value
|
||||
*/
|
||||
INLINE s32 lu_sin(uint theta) {
|
||||
// Stub expects for testing the angle in degrees
|
||||
double rad = theta*M_PI/180;
|
||||
auto x = sin(rad);
|
||||
return (int)(x * 65536.0f / 16.0f);;
|
||||
}
|
||||
|
||||
//! Look-up a cosine value (2π = 0x10000)
|
||||
/*! \param theta Angle in [0,FFFFh] range
|
||||
* \return .12f cosine value
|
||||
*/
|
||||
INLINE s32 lu_cos(uint theta) {
|
||||
// Stub expects for testing the angle in degrees
|
||||
double rad = theta*M_PI/180;
|
||||
auto x = cos(rad);
|
||||
return (int)(x * 65536.0f / 16.0f);;
|
||||
}
|
||||
|
||||
//! Look-up a division value between 0 and 255
|
||||
/*! \param x reciprocal to look up.
|
||||
* \return 1/x (.16f)
|
||||
*/
|
||||
INLINE uint lu_div(uint x)
|
||||
{ return 0; }
|
||||
|
||||
|
||||
//! Linear interpolator for 32bit LUTs.
|
||||
/*! A lut is essentially the discrete form of a function, f(<i>x</i>).
|
||||
* You can get values for non-integer \e x via (linear)
|
||||
* interpolation between f(x) and f(x+1).
|
||||
* \param lut The LUT to interpolate from.
|
||||
* \param x Fixed point number to interpolate at.
|
||||
* \param shift Number of fixed-point bits of \a x.
|
||||
*/
|
||||
INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift)
|
||||
{
|
||||
int xa, ya, yb;
|
||||
xa=x>>shift;
|
||||
ya= lut[xa]; yb= lut[xa+1];
|
||||
return ya + ( (yb-ya)*(x-(xa<<shift))>>shift );
|
||||
}
|
||||
|
||||
//! As lu_lerp32, but for 16bit LUTs.
|
||||
INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift)
|
||||
{
|
||||
int xa, ya, yb;
|
||||
xa=x>>shift;
|
||||
ya= lut[xa]; yb= lut[xa+1];
|
||||
return ya + ( (yb-ya)*(x-(xa<<shift))>>shift );
|
||||
}
|
||||
|
||||
|
||||
// --- Point ----------------------------------------------------------
|
||||
|
||||
//! Initialize \a pd to (\a x, \a y)
|
||||
INLINE POINT *pt_set(POINT *pd, int x, int y)
|
||||
{
|
||||
pd->x= x; pd->y= y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point addition: \a pd = \a pa + \a pb
|
||||
INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb)
|
||||
{
|
||||
pd->x= pa->x + pb->x;
|
||||
pd->y= pa->x + pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point subtraction: \a pd = \a pa - \a pb
|
||||
INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb)
|
||||
{
|
||||
pd->x= pa->x - pb->x;
|
||||
pd->y= pa->x - pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point scale: \a pd = \a c * \a pa
|
||||
INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c)
|
||||
{
|
||||
pd->x= pa->x*c;
|
||||
pd->y= pa->y*c;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point increment: \a pd += \a pb
|
||||
INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb)
|
||||
{
|
||||
pd->x += pb->y;
|
||||
pd->y += pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point decrement: \a pd -= \a pb
|
||||
INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb)
|
||||
{
|
||||
pd->x -= pb->y;
|
||||
pd->y -= pb->y;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point scale: \a pd *= \a c
|
||||
INLINE POINT *pt_scale_eq(POINT *pd, int c)
|
||||
{
|
||||
pd->x *= c;
|
||||
pd->y *= c;
|
||||
return pd;
|
||||
}
|
||||
|
||||
//! Point 'cross'-product: \a pa \htmlonly × \endhtmlonly \a pb
|
||||
/*! Actually, there's no such thing as a 2D cross-product, but you could
|
||||
* extend it to 3D and get the value of its <i>z</i>-component,
|
||||
* which can be used for a test for parallelism.
|
||||
*/
|
||||
INLINE int pt_cross(const POINT *pa, const POINT *pb)
|
||||
{ return pa->x * pb->y - pa->y * pb->x; }
|
||||
|
||||
|
||||
//! Point 'dot'-product:\a pa \htmlonly · \endhtmlonly \a pb
|
||||
INLINE int pt_dot(const POINT *pa, const POINT *pb)
|
||||
{ return pa->x * pb->x + pa->y * pb->y; }
|
||||
|
||||
|
||||
|
||||
// --- Rect -----------------------------------------------------------
|
||||
|
||||
//! Initialize a rectangle.
|
||||
/*! \param l Left side.
|
||||
* \param t Top side.
|
||||
* \param r Right side.
|
||||
* \param b Bottom side.
|
||||
*/
|
||||
INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b)
|
||||
{
|
||||
rc->left= l; rc->top= t; rc->right= r; rc->bottom= b;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Initialize a rectangle, with sizes inside of max boundaries.
|
||||
/*! \param x Left side.
|
||||
* \param y Top side.
|
||||
* \param w Width.
|
||||
* \param h Height.
|
||||
*/
|
||||
INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h)
|
||||
{
|
||||
rc->left= x; rc->top= y; rc->right= x+w; rc->bottom= y+h;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Get rectangle width.
|
||||
INLINE int rc_width(const RECT *rc)
|
||||
{ return rc->right - rc->left; }
|
||||
|
||||
//! Get rectangle height
|
||||
INLINE int rc_height(const RECT *rc)
|
||||
{ return rc->bottom - rc->top; }
|
||||
|
||||
//! Move rectangle to (\a x, \a y) position.
|
||||
INLINE RECT *rc_set_pos(RECT *rc, int x, int y)
|
||||
{
|
||||
rc->right += x-rc->left; rc->left= x;
|
||||
rc->bottom += y-rc->top; rc->top= y;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Reside rectangle.
|
||||
INLINE RECT *rc_set_size(RECT *rc, int w, int h)
|
||||
{
|
||||
rc->right= rc->left+w; rc->bottom= rc->top+h;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Move rectangle by (\a dx, \a dy).
|
||||
INLINE RECT *rc_move(RECT *rc, int dx, int dy)
|
||||
{
|
||||
rc->left += dx; rc->top += dy;
|
||||
rc->right += dx; rc->bottom += dy;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Increase size by \a dw horizontally and \a dh vertically.
|
||||
INLINE RECT *rc_inflate(RECT *rc, int dw, int dh)
|
||||
{
|
||||
rc->left -= dw; rc->top -= dh;
|
||||
rc->right += dw; rc->bottom += dh;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//! Increase sizes on all sides by values of rectangle \a dr.
|
||||
INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr)
|
||||
{
|
||||
rc->left += dr->left; rc->top += dr->top;
|
||||
rc->right += dr->right; rc->bottom += dr->bottom;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
// --- Vector ---------------------------------------------------------
|
||||
|
||||
//! Initialize a vector
|
||||
INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z)
|
||||
{
|
||||
vd->x= x; vd->y= y; vd->z= z;
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Add vectors: \b d = \b a + \b b;
|
||||
INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
vd->x= va->x + vb->x;
|
||||
vd->y= va->y + vb->y;
|
||||
vd->z= va->z + vb->z;
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Subtract vectors: \b d = \b a - \b b;
|
||||
INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
vd->x= va->x - vb->x;
|
||||
vd->y= va->y - vb->y;
|
||||
vd->z= va->z - vb->z;
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Multiply vectors elements: \b d = \b S(ax, ay, az) <20>\b b
|
||||
INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
vd->x= fxmul(va->x, vb->x);
|
||||
vd->y= fxmul(va->y, vb->y);
|
||||
vd->z= fxmul(va->z, vb->z);
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Scale vector: \b d = c*\b a
|
||||
INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c)
|
||||
{
|
||||
vd->x= fxmul(va->x, c);
|
||||
vd->y= fxmul(va->y, c);
|
||||
vd->z= fxmul(va->z, c);
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Dot-product: d = \b a <20>\b b
|
||||
INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb)
|
||||
{
|
||||
FIXED dot;
|
||||
dot = fxmul(va->x, vb->x);
|
||||
dot += fxmul(va->y, vb->y);
|
||||
dot += fxmul(va->z, vb->z);
|
||||
return dot;
|
||||
}
|
||||
|
||||
//! Increment vector: \b d += \b b;
|
||||
INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb)
|
||||
{ vd->x += vb->x; vd->y += vb->y; vd->z += vb->z; return vd; }
|
||||
|
||||
//! Decrease vector: \b d -= \b b;
|
||||
INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb)
|
||||
{ vd->x -= vb->x; vd->y -= vb->y; vd->z -= vb->z; return vd; }
|
||||
|
||||
//! Multiply vectors elements: \b d = \b S(dx, dy, dz) <20>\b b
|
||||
INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb)
|
||||
{
|
||||
vd->x= fxmul(vd->x, vb->x);
|
||||
vd->y= fxmul(vd->y, vb->y);
|
||||
vd->z= fxmul(vd->z, vb->z);
|
||||
return vd;
|
||||
}
|
||||
|
||||
//! Scale vector: \b d = c*\b d
|
||||
INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c)
|
||||
{
|
||||
vd->x= fxmul(vd->x, c);
|
||||
vd->y= fxmul(vd->y, c);
|
||||
vd->z= fxmul(vd->z, c);
|
||||
return vd;
|
||||
}
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_PROJECT_TONC_MATH_STUB_H
|
|
@ -0,0 +1,962 @@
|
|||
//
|
||||
// Memory map defines. All of them
|
||||
//
|
||||
//! \file tonc_memdef.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20080521
|
||||
//
|
||||
/* === NOTES ===
|
||||
* 20080521 : comms items taken from libgba
|
||||
*/
|
||||
|
||||
#ifndef TONC_MEMDEF
|
||||
#define TONC_MEMDEF
|
||||
|
||||
/*! \defgroup grpMemBits Memory map bit(fields)
|
||||
\ingroup grpMemmap
|
||||
\brief List of all bit(field) definitions of memory mapped items.
|
||||
*/
|
||||
|
||||
// --- Prefixes ---
|
||||
// REG_DISPCNT : DCNT
|
||||
// REG_DISPSTAT : DSTAT
|
||||
// REG_BGxCNT : BG
|
||||
// REG_WIN_x : WIN
|
||||
// REG_MOSAIC : MOS
|
||||
// REG_BLDCNT : BLD
|
||||
// REG_SND1SWEEP : SSW
|
||||
// REG_SNDxCNT, : SSQR
|
||||
// REG_SNDxFREQ, : SFREQ
|
||||
// REG_SNDDMGCNT : SDMG
|
||||
// REG_SNDDSCNT : SDS
|
||||
// REG_SNDSTAT : SSTAT
|
||||
// REG_DMAxCNT : DMA
|
||||
// REG_TMxCNT : TM
|
||||
// REG_SIOCNT : SIO(N/M/U)
|
||||
// REG_RCNT : R / GPIO
|
||||
// REG_KEYINPUT : KEY
|
||||
// REG_KEYCNT : KCNT
|
||||
// REG_IE, REG_IF : IRQ
|
||||
// REG_WSCNT : WS
|
||||
// Regular SE : SE
|
||||
// OAM attr 0 : ATTR0
|
||||
// OAM attr 1 : ATTR1
|
||||
// OAM attr 2 : ATTR2
|
||||
|
||||
|
||||
// --- REG_DISPCNT -----------------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoDCNT Display Control Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_DISPCNT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define DCNT_MODE0 0 //!< Mode 0; bg 0-4: reg
|
||||
#define DCNT_MODE1 0x0001 //!< Mode 1; bg 0-1: reg; bg 2: affine
|
||||
#define DCNT_MODE2 0x0002 //!< Mode 2; bg 2-3: affine
|
||||
#define DCNT_MODE3 0x0003 //!< Mode 3; bg2: 240x160\@16 bitmap
|
||||
#define DCNT_MODE4 0x0004 //!< Mode 4; bg2: 240x160\@8 bitmap
|
||||
#define DCNT_MODE5 0x0005 //!< Mode 5; bg2: 160x128\@16 bitmap
|
||||
#define DCNT_GB 0x0008 //!< (R) GBC indicator
|
||||
#define DCNT_PAGE 0x0010 //!< Page indicator
|
||||
#define DCNT_OAM_HBL 0x0020 //!< Allow OAM updates in HBlank
|
||||
#define DCNT_OBJ_2D 0 //!< OBJ-VRAM as matrix
|
||||
#define DCNT_OBJ_1D 0x0040 //!< OBJ-VRAM as array
|
||||
#define DCNT_BLANK 0x0080 //!< Force screen blank
|
||||
#define DCNT_BG0 0x0100 //!< Enable bg 0
|
||||
#define DCNT_BG1 0x0200 //!< Enable bg 1
|
||||
#define DCNT_BG2 0x0400 //!< Enable bg 2
|
||||
#define DCNT_BG3 0x0800 //!< Enable bg 3
|
||||
#define DCNT_OBJ 0x1000 //!< Enable objects
|
||||
#define DCNT_WIN0 0x2000 //!< Enable window 0
|
||||
#define DCNT_WIN1 0x4000 //!< Enable window 1
|
||||
#define DCNT_WINOBJ 0x8000 //!< Enable object window
|
||||
|
||||
#define DCNT_MODE_MASK 0x0007
|
||||
#define DCNT_MODE_SHIFT 0
|
||||
#define DCNT_MODE(n) ((n)<<DCNT_MODE_SHIFT)
|
||||
|
||||
#define DCNT_LAYER_MASK 0x1F00
|
||||
#define DCNT_LAYER_SHIFT 8
|
||||
#define DCNT_LAYER(n) ((n)<<DCNT_LAYER_SHIFT)
|
||||
|
||||
#define DCNT_WIN_MASK 0xE000
|
||||
#define DCNT_WIN_SHIFT 13
|
||||
#define DCNT_WIN(n) ((n)<<DCNT_WIN_SHIFT)
|
||||
|
||||
#define DCNT_BUILD(mode, layer, win, obj1d, objhbl) \
|
||||
( \
|
||||
(((win)&7)<<13) | (((layer)&31)<<8) | (((obj1d)&1)<<6) \
|
||||
| (((objhbl)&1)<<5) | ((mode)&7) \
|
||||
)
|
||||
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
|
||||
// --- REG_DISPSTAT ----------------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoDSTAT Display Status Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_DISPSTAT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define DSTAT_IN_VBL 0x0001 //!< Now in VBlank
|
||||
#define DSTAT_IN_HBL 0x0002 //!< Now in HBlank
|
||||
#define DSTAT_IN_VCT 0x0004 //!< Now in set VCount
|
||||
#define DSTAT_VBL_IRQ 0x0008 //!< Enable VBlank irq
|
||||
#define DSTAT_HBL_IRQ 0x0010 //!< Enable HBlank irq
|
||||
#define DSTAT_VCT_IRQ 0x0020 //!< Enable VCount irq
|
||||
|
||||
#define DSTAT_VCT_MASK 0xFF00
|
||||
#define DSTAT_VCT_SHIFT 8
|
||||
#define DSTAT_VCT(n) ((n)<<DSTAT_VCT_SHIFT)
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_BGxCNT ------------------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoBGCNT Background Control Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_BGxCNT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define BG_MOSAIC 0x0040 //!< Enable Mosaic
|
||||
#define BG_4BPP 0 //!< 4bpp (16 color) bg (no effect on affine bg)
|
||||
#define BG_8BPP 0x0080 //!< 8bpp (256 color) bg (no effect on affine bg)
|
||||
#define BG_WRAP 0x2000 //!< Wrap around edges of affine bgs
|
||||
#define BG_SIZE0 0
|
||||
#define BG_SIZE1 0x4000
|
||||
#define BG_SIZE2 0x8000
|
||||
#define BG_SIZE3 0xC000
|
||||
#define BG_REG_32x32 0 //!< reg bg, 32x32 (256x256 px)
|
||||
#define BG_REG_64x32 0x4000 //!< reg bg, 64x32 (512x256 px)
|
||||
#define BG_REG_32x64 0x8000 //!< reg bg, 32x64 (256x512 px)
|
||||
#define BG_REG_64x64 0xC000 //!< reg bg, 64x64 (512x512 px)
|
||||
#define BG_AFF_16x16 0 //!< affine bg, 16x16 (128x128 px)
|
||||
#define BG_AFF_32x32 0x4000 //!< affine bg, 32x32 (256x256 px)
|
||||
#define BG_AFF_64x64 0x8000 //!< affine bg, 64x64 (512x512 px)
|
||||
#define BG_AFF_128x128 0xC000 //!< affine bg, 128x128 (1024x1024 px)
|
||||
|
||||
#define BG_PRIO_MASK 0x0003
|
||||
#define BG_PRIO_SHIFT 0
|
||||
#define BG_PRIO(n) ((n)<<BG_PRIO_SHIFT)
|
||||
|
||||
#define BG_CBB_MASK 0x000C
|
||||
#define BG_CBB_SHIFT 2
|
||||
#define BG_CBB(n) ((n)<<BG_CBB_SHIFT)
|
||||
|
||||
#define BG_SBB_MASK 0x1F00
|
||||
#define BG_SBB_SHIFT 8
|
||||
#define BG_SBB(n) ((n)<<BG_SBB_SHIFT)
|
||||
|
||||
#define BG_SIZE_MASK 0xC000
|
||||
#define BG_SIZE_SHIFT 14
|
||||
#define BG_SIZE(n) ((n)<<BG_SIZE_SHIFT)
|
||||
|
||||
|
||||
#define BG_BUILD(cbb, sbb, size, bpp, prio, mos, wrap) \
|
||||
( \
|
||||
((size)<<14) | (((wrap)&1)<<13) | (((sbb)&31)<<8 \
|
||||
| (((bpp)&8)<<4) | (((mos)&1)<<6) | (((cbb)&3)<<2) \
|
||||
| ((prio)&3) \
|
||||
)
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
/*! \defgroup grpVideoGfx Graphic effects
|
||||
\ingroup grpMemBits
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
// --- REG_WIN_x ------------------------------------------------------
|
||||
|
||||
//! \name Window macros
|
||||
//\{
|
||||
|
||||
#define WIN_BG0 0x0001 //!< Windowed bg 0
|
||||
#define WIN_BG1 0x0002 //!< Windowed bg 1
|
||||
#define WIN_BG2 0x0004 //!< Windowed bg 2
|
||||
#define WIN_BG3 0x0008 //!< Windowed bg 3
|
||||
#define WIN_OBJ 0x0010 //!< Windowed objects
|
||||
#define WIN_ALL 0x001F //!< All layers in window.
|
||||
#define WIN_BLD 0x0020 //!< Windowed blending
|
||||
|
||||
#define WIN_LAYER_MASK 0x003F
|
||||
#define WIN_LAYER_SHIFT 0
|
||||
#define WIN_LAYER(n) ((n)<<WIN_LAYER_SHIFT)
|
||||
|
||||
|
||||
#define WIN_BUILD(low, high) \
|
||||
( ((high)<<8) | (low) )
|
||||
|
||||
#define WININ_BUILD(win0, win1) WIN_BUILD(win0, win1)
|
||||
|
||||
#define WINOUT_BUILD(out, obj) WIN_BUILD(out, obj)
|
||||
|
||||
//\}
|
||||
|
||||
// --- REG_MOSAIC ------------------------------------------------------
|
||||
|
||||
//! \name Mosaic macros
|
||||
//\{
|
||||
|
||||
#define MOS_BH_MASK 0x000F
|
||||
#define MOS_BH_SHIFT 0
|
||||
#define MOS_BH(n) ((n)<<MOS_BH_SHIFT)
|
||||
|
||||
#define MOS_BV_MASK 0x00F0
|
||||
#define MOS_BV_SHIFT 4
|
||||
#define MOS_BV(n) ((n)<<MOS_BV_SHIFT)
|
||||
|
||||
#define MOS_OH_MASK 0x0F00
|
||||
#define MOS_OH_SHIFT 8
|
||||
#define MOS_OH(n) ((n)<<MOS_OH_SHIFT)
|
||||
|
||||
#define MOS_OV_MASK 0xF000
|
||||
#define MOS_OV_SHIFT 12
|
||||
#define MOS_OV(n) ((n)<<MOS_OV_SHIFT)
|
||||
|
||||
#define MOS_BUILD(bh, bv, oh, ov) \
|
||||
( (((ov)&15)<<12) | (((oh)&15)<<8) | (((bv)&15)<<4)| ((bh)&15) )
|
||||
|
||||
//\}
|
||||
|
||||
/* \} */
|
||||
|
||||
|
||||
// --- REG_BLDCNT ------------------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoBLD Blend Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Macros for REG_BLDCNT, REG_BLDY and REG_BLDALPHA
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//!\ name Blend control
|
||||
//\{
|
||||
|
||||
#define BLD_BG0 0x0001 //!< Blend bg 0
|
||||
#define BLD_BG1 0x0002 //!< Blend bg 1
|
||||
#define BLD_BG2 0x0004 //!< Blend bg 2
|
||||
#define BLD_BG3 0x0008 //!< Blend bg 3
|
||||
#define BLD_OBJ 0x0010 //!< Blend objects
|
||||
#define BLD_ALL 0x001F //!< All layers (except backdrop)
|
||||
#define BLD_BACKDROP 0x0020 //!< Blend backdrop
|
||||
#define BLD_OFF 0 //!< Blend mode is off
|
||||
#define BLD_STD 0x0040 //!< Normal alpha blend (with REG_EV)
|
||||
#define BLD_WHITE 0x0080 //!< Fade to white (with REG_Y)
|
||||
#define BLD_BLACK 0x00C0 //!< Fade to black (with REG_Y)
|
||||
|
||||
#define BLD_TOP_MASK 0x003F
|
||||
#define BLD_TOP_SHIFT 0
|
||||
#define BLD_TOP(n) ((n)<<BLD_TOP_SHIFT)
|
||||
|
||||
#define BLD_MODE_MASK 0x00C0
|
||||
#define BLD_MODE_SHIFT 6
|
||||
#define BLD_MODE(n) ((n)<<BLD_MODE_SHIFT)
|
||||
|
||||
#define BLD_BOT_MASK 0x3F00
|
||||
#define BLD_BOT_SHIFT 8
|
||||
#define BLD_BOT(n) ((n)<<BLD_BOT_SHIFT)
|
||||
|
||||
#define BLD_BUILD(top, bot, mode) \
|
||||
( (((bot)&63)<<8) | (((mode)&3)<<6) | ((top)&63) )
|
||||
|
||||
//\}
|
||||
|
||||
// --- REG_BLDALPHA ---
|
||||
|
||||
//! \name Blend weights
|
||||
|
||||
#define BLD_EVA_MASK 0x001F
|
||||
#define BLD_EVA_SHIFT 0
|
||||
#define BLD_EVA(n) ((n)<<BLD_EVA_SHIFT)
|
||||
|
||||
#define BLD_EVB_MASK 0x1F00
|
||||
#define BLD_EVB_SHIFT 8
|
||||
#define BLD_EVB(n) ((n)<<BLD_EVB_SHIFT)
|
||||
|
||||
#define BLDA_BUILD(eva, evb) \
|
||||
( ((eva)&31) | (((evb)&31)<<8) )
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
// --- REG_BLDY ---
|
||||
|
||||
//! \name Fade levels
|
||||
|
||||
#define BLDY_MASK 0x001F
|
||||
#define BLDY_SHIFT 0
|
||||
#define BLDY(n) ((n)<<BLD_EY_SHIFT)
|
||||
|
||||
#define BLDY_BUILD(ey) \
|
||||
( (ey)&31 )
|
||||
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --- REG_SND1SWEEP ---------------------------------------------------
|
||||
|
||||
/*! \defgroup grpAudioSSW Tone Generator, Sweep Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_SND1SWEEP (aka REG_SOUND1CNT_L)
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define SSW_INC 0 //!< Increasing sweep rate
|
||||
#define SSW_DEC 0x0008 //!< Decreasing sweep rate
|
||||
#define SSW_OFF 0x0008 //!< Disable sweep altogether
|
||||
|
||||
#define SSW_SHIFT_MASK 0x0007
|
||||
#define SSW_SHIFT_SHIFT 0
|
||||
#define SSW_SHIFT(n) ((n)<<SSW_SHIFT_SHIFT)
|
||||
|
||||
#define SSW_TIME_MASK 0x0070
|
||||
#define SSW_TIME_SHIFT 4
|
||||
#define SSW_TIME(n) ((n)<<SSW_TIME_SHIFT)
|
||||
|
||||
|
||||
#define SSW_BUILD(shift, dir, time) \
|
||||
( (((time)&7)<<4) | ((dir)<<3) | ((shift)&7) )
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_SND1CNT, REG_SND2CNT, REG_SND4CNT ---------------------------
|
||||
|
||||
/*! \defgroup grpAudioSSQR Tone Generator, Square Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_SND{1,2,4}CNT
|
||||
(aka REG_SOUND1CNT_H, REG_SOUND2CNT_L, REG_SOUND4CNT_L, respectively)
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define SSQR_DUTY1_8 0 //!< 12.5% duty cycle (#-------)
|
||||
#define SSQR_DUTY1_4 0x0040 //!< 25% duty cycle (##------)
|
||||
#define SSQR_DUTY1_2 0x0080 //!< 50% duty cycle (####----)
|
||||
#define SSQR_DUTY3_4 0x00C0 //!< 75% duty cycle (######--) Equivalent to 25%
|
||||
#define SSQR_INC 0 //!< Increasing volume
|
||||
#define SSQR_DEC 0x0800 //!< Decreasing volume
|
||||
|
||||
#define SSQR_LEN_MASK 0x003F
|
||||
#define SSQR_LEN_SHIFT 0
|
||||
#define SSQR_LEN(n) ((n)<<SSQR_LEN_SHIFT)
|
||||
|
||||
#define SSQR_DUTY_MASK 0x00C0
|
||||
#define SSQR_DUTY_SHIFT 6
|
||||
#define SSQR_DUTY(n) ((n)<<SSQR_DUTY_SHIFT)
|
||||
|
||||
#define SSQR_TIME_MASK 0x0700
|
||||
#define SSQR_TIME_SHIFT 8
|
||||
#define SSQR_TIME(n) ((n)<<SSQR_TIME_SHIFT)
|
||||
|
||||
#define SSQR_IVOL_MASK 0xF000
|
||||
#define SSQR_IVOL_SHIFT 12
|
||||
#define SSQR_IVOL(n) ((n)<<SSQR_IVOL_SHIFT)
|
||||
|
||||
|
||||
#define SSQR_ENV_BUILD(ivol, dir, time) \
|
||||
( ((ivol)<<12) | ((dir)<<11) | (((time)&7)<<8) )
|
||||
|
||||
#define SSQR_BUILD(_ivol, dir, step, duty, len) \
|
||||
( SSQR_ENV_BUILD(ivol,dir,step) | (((duty)&3)<<6) | ((len)&63) )
|
||||
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_SND1FREQ, REG_SND2FREQ, REG_SND3FREQ ------------------------
|
||||
|
||||
/*! \defgroup grpAudioSFREQ Tone Generator, Frequency Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_SND{1-3}FREQ
|
||||
(aka REG_SOUND1CNT_X, REG_SOUND2CNT_H, REG_SOUND3CNT_X)
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define SFREQ_HOLD 0 //!< Continuous play
|
||||
#define SFREQ_TIMED 0x4000 //!< Timed play
|
||||
#define SFREQ_RESET 0x8000 //!< Reset sound
|
||||
|
||||
#define SFREQ_RATE_MASK 0x07FF
|
||||
#define SFREQ_RATE_SHIFT 0
|
||||
#define SFREQ_RATE(n) ((n)<<SFREQ_RATE_SHIFT)
|
||||
|
||||
#define SFREQ_BUILD(rate, timed, reset) \
|
||||
( ((rate)&0x7FF) | ((timed)<<14) | ((reset)<<15) )
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_SNDDMGCNT ---------------------------------------------------
|
||||
|
||||
/*! \defgroup grpAudioSDMG Tone Generator, Control Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_SNDDMGCNT (aka REG_SOUNDCNT_L)
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
|
||||
#define SDMG_LSQR1 0x0100 //!< Enable channel 1 on left
|
||||
#define SDMG_LSQR2 0x0200 //!< Enable channel 2 on left
|
||||
#define SDMG_LWAVE 0x0400 //!< Enable channel 3 on left
|
||||
#define SDMG_LNOISE 0x0800 //!< Enable channel 4 on left
|
||||
#define SDMG_RSQR1 0x1000 //!< Enable channel 1 on right
|
||||
#define SDMG_RSQR2 0x2000 //!< Enable channel 2 on right
|
||||
#define SDMG_RWAVE 0x4000 //!< Enable channel 3 on right
|
||||
#define SDMG_RNOISE 0x8000 //!< Enable channel 4 on right
|
||||
|
||||
#define SDMG_LVOL_MASK 0x0007
|
||||
#define SDMG_LVOL_SHIFT 0
|
||||
#define SDMG_LVOL(n) ((n)<<SDMG_LVOL_SHIFT)
|
||||
|
||||
#define SDMG_RVOL_MASK 0x0070
|
||||
#define SDMG_RVOL_SHIFT 4
|
||||
#define SDMG_RVOL(n) ((n)<<SDMG_RVOL_SHIFT)
|
||||
|
||||
|
||||
// Unshifted values
|
||||
#define SDMG_SQR1 0x01
|
||||
#define SDMG_SQR2 0x02
|
||||
#define SDMG_WAVE 0x04
|
||||
#define SDMG_NOISE 0x08
|
||||
|
||||
|
||||
#define SDMG_BUILD(_lmode, _rmode, _lvol, _rvol) \
|
||||
( ((_rmode)<<12) | ((_lmode)<<8) | (((_rvol)&7)<<4) | ((_lvol)&7) )
|
||||
|
||||
#define SDMG_BUILD_LR(_mode, _vol) SDMG_BUILD(_mode, _mode, _vol, _vol)
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_SNDDSCNT ----------------------------------------------------
|
||||
|
||||
/*! \defgroup grpAudioSDS Direct Sound Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_SNDDSCNT (aka REG_SOUNDCNT_H)
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define SDS_DMG25 0 //!< Tone generators at 25% volume
|
||||
#define SDS_DMG50 0x0001 //!< Tone generators at 50% volume
|
||||
#define SDS_DMG100 0x0002 //!< Tone generators at 100% volume
|
||||
#define SDS_A50 0 //!< Direct Sound A at 50% volume
|
||||
#define SDS_A100 0x0004 //!< Direct Sound A at 100% volume
|
||||
#define SDS_B50 0 //!< Direct Sound B at 50% volume
|
||||
#define SDS_B100 0x0008 //!< Direct Sound B at 100% volume
|
||||
#define SDS_AR 0x0100 //!< Enable Direct Sound A on right
|
||||
#define SDS_AL 0x0200 //!< Enable Direct Sound A on left
|
||||
#define SDS_ATMR0 0 //!< Direct Sound A to use timer 0
|
||||
#define SDS_ATMR1 0x0400 //!< Direct Sound A to use timer 1
|
||||
#define SDS_ARESET 0x0800 //!< Reset FIFO of Direct Sound A
|
||||
#define SDS_BR 0x1000 //!< Enable Direct Sound B on right
|
||||
#define SDS_BL 0x2000 //!< Enable Direct Sound B on left
|
||||
#define SDS_BTMR0 0 //!< Direct Sound B to use timer 0
|
||||
#define SDS_BTMR1 0x4000 //!< Direct Sound B to use timer 1
|
||||
#define SDS_BRESET 0x8000 //!< Reset FIFO of Direct Sound B
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_SNDSTAT -----------------------------------------------------
|
||||
|
||||
/*! \defgroup grpAudioSSTAT Sound Status Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_SNDSTAT (and REG_SOUNDCNT_X)
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define SSTAT_SQR1 0x0001 //!< (R) Channel 1 status
|
||||
#define SSTAT_SQR2 0x0002 //!< (R) Channel 2 status
|
||||
#define SSTAT_WAVE 0x0004 //!< (R) Channel 3 status
|
||||
#define SSTAT_NOISE 0x0008 //!< (R) Channel 4 status
|
||||
#define SSTAT_DISABLE 0 //!< Disable sound
|
||||
#define SSTAT_ENABLE 0x0080 //!< Enable sound. NOTE: enable before using any other sound regs
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_DMAxCNT -----------------------------------------------------
|
||||
|
||||
/*! \defgroup grpAudioDMA DMA Control Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_DMAxCNT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define DMA_DST_INC 0 //!< Incrementing destination address
|
||||
#define DMA_DST_DEC 0x00200000 //!< Decrementing destination
|
||||
#define DMA_DST_FIXED 0x00400000 //!< Fixed destination
|
||||
#define DMA_DST_RELOAD 0x00600000 //!< Increment destination, reset after full run
|
||||
#define DMA_SRC_INC 0 //!< Incrementing source address
|
||||
#define DMA_SRC_DEC 0x00800000 //!< Decrementing source address
|
||||
#define DMA_SRC_FIXED 0x01000000 //!< Fixed source address
|
||||
#define DMA_REPEAT 0x02000000 //!< Repeat transfer at next start condition
|
||||
#define DMA_16 0 //!< Transfer by halfword
|
||||
#define DMA_32 0x04000000 //!< Transfer by word
|
||||
#define DMA_AT_NOW 0 //!< Start transfer now
|
||||
#define DMA_GAMEPAK 0x08000000 //!< Gamepak DRQ
|
||||
#define DMA_AT_VBLANK 0x10000000 //!< Start transfer at VBlank
|
||||
#define DMA_AT_HBLANK 0x20000000 //!< Start transfer at HBlank
|
||||
#define DMA_AT_SPECIAL 0x30000000 //!< Start copy at 'special' condition. Channel dependent
|
||||
#define DMA_AT_FIFO 0x30000000 //!< Start at FIFO empty (DMA0/DMA1)
|
||||
#define DMA_AT_REFRESH 0x30000000 //!< VRAM special; start at VCount=2 (DMA3)
|
||||
#define DMA_IRQ 0x40000000 //!< Enable DMA irq
|
||||
#define DMA_ENABLE 0x80000000 //!< Enable DMA
|
||||
|
||||
#define DMA_COUNT_MASK 0x0000FFFF
|
||||
#define DMA_COUNT_SHIFT 0
|
||||
#define DMA_COUNT(n) ((n)<<DMA_COUNT_SHIFT)
|
||||
|
||||
|
||||
// \name Extra
|
||||
//\{
|
||||
|
||||
#define DMA_NOW (DMA_ENABLE | DMA_AT_NOW)
|
||||
#define DMA_16NOW (DMA_NOW | DMA_16)
|
||||
#define DMA_32NOW (DMA_NOW | DMA_32)
|
||||
|
||||
// copies
|
||||
#define DMA_CPY16 (DMA_NOW | DMA_16)
|
||||
#define DMA_CPY32 (DMA_NOW | DMA_32)
|
||||
|
||||
// fills
|
||||
#define DMA_FILL16 (DMA_NOW | DMA_SRC_FIXED | DMA_16)
|
||||
#define DMA_FILL32 (DMA_NOW | DMA_SRC_FIXED | DMA_32)
|
||||
|
||||
#define DMA_HDMA (DMA_ENABLE | DMA_REPEAT | DMA_AT_HBLANK | DMA_DST_RELOAD)
|
||||
|
||||
//\}
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
|
||||
// --- REG_TMxCNT ------------------------------------------------------
|
||||
|
||||
/*! \defgroup grpTimerTM Timer Control Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_TMxCNT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define TM_FREQ_SYS 0 //!< System clock timer (16.7 Mhz)
|
||||
#define TM_FREQ_1 0 //!< 1 cycle/tick (16.7 Mhz)
|
||||
#define TM_FREQ_64 0x0001 //!< 64 cycles/tick (262 kHz)
|
||||
#define TM_FREQ_256 0x0002 //!< 256 cycles/tick (66 kHz)
|
||||
#define TM_FREQ_1024 0x0003 //!< 1024 cycles/tick (16 kHz)
|
||||
#define TM_CASCADE 0x0004 //!< Increment when preceding timer overflows
|
||||
#define TM_IRQ 0x0040 //!< Enable timer irq
|
||||
#define TM_ENABLE 0x0080 //!< Enable timer
|
||||
|
||||
#define TM_FREQ_MASK 0x0003
|
||||
#define TM_FREQ_SHIFT 0
|
||||
#define TM_FREQ(n) ((n)<<TM_FREQ_SHIFT)
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
|
||||
// --- REG_SIOCNT ----------------------------------------------------------
|
||||
|
||||
/*! \defgroup grpSioCnt Serial I/O Control
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_TMxCNT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name General SIO bits.
|
||||
//\{
|
||||
#define SIO_MODE_8BIT 0x0000 //!< Normal comm mode, 8-bit.
|
||||
#define SIO_MODE_32BIT 0x1000 //!< Normal comm mode, 32-bit.
|
||||
#define SIO_MODE_MULTI 0x2000 //!< Multi-play comm mode.
|
||||
#define SIO_MODE_UART 0x3000 //!< UART comm mode.
|
||||
|
||||
#define SIO_SI_HIGH 0x0004
|
||||
#define SIO_IRQ 0x4000 //!< Enable serial irq.
|
||||
|
||||
#define SIO_MODE_MASK 0x3000
|
||||
#define SIO_MODE_SHIFT 12
|
||||
#define SIO_MODE(n) ((n)<<SIO_MODE_SHIFT)
|
||||
//\}
|
||||
|
||||
//! \name Normal mode bits. UNTESTED.
|
||||
//\{
|
||||
#define SION_CLK_EXT 0x0000 //!< Slave unit; use external clock (default).
|
||||
#define SION_CLK_INT 0x0001 //!< Master unit; use internal clock.
|
||||
|
||||
#define SION_256KHZ 0x0000 //!< 256 kHz clockspeed (default).
|
||||
#define SION_2MHZ 0x0002 //!< 2 MHz clockspeed.
|
||||
|
||||
#define SION_RECV_HIGH 0x0004 //!< SI high; opponent ready to receive (R).
|
||||
#define SION_SEND_HIGH 0x0008 //!< SO high; ready to transfer.
|
||||
|
||||
#define SION_ENABLE 0x0080 //!< Start transfer/transfer enabled.
|
||||
//\}
|
||||
|
||||
//! \name Multiplayer mode bits. UNTESTED.
|
||||
//\{
|
||||
#define SIOM_9600 0x0000 //!< Baud rate, 9.6 kbps.
|
||||
#define SIOM_38400 0x0001 //!< Baud rate, 38.4 kbps.
|
||||
#define SIOM_57600 0x0002 //!< Baud rate, 57.6 kbps.
|
||||
#define SIOM_115200 0x0003 //!< Baud rate, 115.2 kbps.
|
||||
|
||||
#define SIOM_SI 0x0004 //!< SI port (R).
|
||||
#define SIOM_SLAVE 0x0004 //!< Not the master (R).
|
||||
#define SIOM_SD 0x0008 //!< SD port (R).
|
||||
#define SIOM_CONNECTED 0x0008 //!< All GBAs connected (R)
|
||||
|
||||
#define SIOM_ERROR 0x0040 //!< Error in transfer (R).
|
||||
#define SIOM_ENABLE 0x0080 //!< Start transfer/transfer enabled.
|
||||
|
||||
|
||||
#define SIOM_BAUD_MASK 0x0003
|
||||
#define SIOM_BAUD_SHIFT 0
|
||||
#define SIOM_BAUD(n) ((n)<<SIOM_BAUD_SHIFT)
|
||||
|
||||
#define SIOM_ID_MASK 0x0030 //!< Multi-player ID mask (R)
|
||||
#define SIOM_ID_SHIFT 4
|
||||
#define SIOM_ID(n) ((n)<<SIOM_ID_SHIFT)
|
||||
//\}
|
||||
|
||||
//! \name UART mode bits. UNTESTED.
|
||||
//!\{
|
||||
#define SIOU_9600 0x0000 //!< Baud rate, 9.6 kbps.
|
||||
#define SIOU_38400 0x0001 //!< Baud rate, 38.4 kbps.
|
||||
#define SIOU_57600 0x0002 //!< Baud rate, 57.6 kbps.
|
||||
#define SIOU_115200 0x0003 //!< Baud rate, 115.2 kbps.
|
||||
|
||||
#define SIOU_CTS 0x0004 //!< CTS enable.
|
||||
#define SIOU_PARITY_EVEN 0x0000 //!< Use even parity.
|
||||
#define SIOU_PARITY_ODD 0x0008 //!< Use odd parity.
|
||||
#define SIOU_SEND_FULL 0x0010 //!< Send data is full (R).
|
||||
#define SIOU_RECV_EMPTY 0x0020 //!< Receive data is empty (R).
|
||||
#define SIOU_ERROR 0x0040 //!< Error in transfer (R).
|
||||
#define SIOU_7BIT 0x0000 //!< Data is 7bits long.
|
||||
#define SIOU_8BIT 0x0080 //!< Data is 8bits long.
|
||||
#define SIOU_SEND 0x0100 //!< Start sending data.
|
||||
#define SIOU_RECV 0x0200 //!< Start receiving data.
|
||||
|
||||
#define SIOU_BAUD_MASK 0x0003
|
||||
#define SIOU_BAUD_SHIFT 0
|
||||
#define SIOU_BAUD(n) ((n)<<SIOU_BAUD_SHIFT)
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
/*! \defgroup grpCommR Comm control.
|
||||
\ingroup grpMemBits
|
||||
\brief Communication mode select and general purpose I/O (REG_RCNT).
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name Communication mode select.
|
||||
//\{
|
||||
#define R_MODE_NORMAL 0x0000 //!< Normal mode.
|
||||
#define R_MODE_MULTI 0x0000 //!< Multiplayer mode.
|
||||
#define R_MODE_UART 0x0000 //!< UART mode.
|
||||
#define R_MODE_GPIO 0x8000 //!< General purpose mode.
|
||||
#define R_MODE_JOYBUS 0xC000 //!< JOY mode.
|
||||
|
||||
#define R_MODE_MASK 0xC000
|
||||
#define R_MODE_SHIFT 14
|
||||
#define R_MODE(n) ((n)<<R_MODE_SHIFT)
|
||||
//\}
|
||||
|
||||
//! \name General purpose I/O data
|
||||
//\{
|
||||
#define GPIO_SC 0x0001 // Data
|
||||
#define GPIO_SD 0x0002
|
||||
#define GPIO_SI 0x0004
|
||||
#define GPIO_SO 0x0008
|
||||
#define GPIO_SC_IO 0x0010 // Select I/O
|
||||
#define GPIO_SD_IO 0x0020
|
||||
#define GPIO_SI_IO 0x0040
|
||||
#define GPIO_SO_IO 0x0080
|
||||
#define GPIO_SC_INPUT 0x0000 // Input setting
|
||||
#define GPIO_SD_INPUT 0x0000
|
||||
#define GPIO_SI_INPUT 0x0000
|
||||
#define GPIO_SO_INPUT 0x0000
|
||||
#define GPIO_SC_OUTPUT 0x0010 // Output setting
|
||||
#define GPIO_SD_OUTPUT 0x0020
|
||||
#define GPIO_SI_OUTPUT 0x0040
|
||||
#define GPIO_SO_OUTPUT 0x0080
|
||||
|
||||
#define GPIO_IRQ 0x0100 //! Interrupt on SI.
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --- REG_KEYINPUT --------------------------------------------------------
|
||||
|
||||
/*! \defgroup grpInputKEY Key Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_KEYINPUT and REG_KEYCNT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define KEY_A 0x0001 //!< Button A
|
||||
#define KEY_B 0x0002 //!< Button B
|
||||
#define KEY_SELECT 0x0004 //!< Select button
|
||||
#define KEY_START 0x0008 //!< Start button
|
||||
#define KEY_RIGHT 0x0010 //!< Right D-pad
|
||||
#define KEY_LEFT 0x0020 //!< Left D-pad
|
||||
#define KEY_UP 0x0040 //!< Up D-pad
|
||||
#define KEY_DOWN 0x0080 //!< Down D-pad
|
||||
#define KEY_R 0x0100 //!< Shoulder R
|
||||
#define KEY_L 0x0200 //!< Shoulder L
|
||||
|
||||
#define KEY_ACCEPT 0x0009 //!< Accept buttons: A or start
|
||||
#define KEY_CANCEL 0x0002 //!< Cancel button: B (well, it usually is)
|
||||
#define KEY_RESET 0x030C //!< St+Se+L+R
|
||||
|
||||
#define KEY_FIRE 0x0003 //!< Fire buttons: A or B
|
||||
#define KEY_SPECIAL 0x000C //!< Special buttons: Select or Start
|
||||
#define KEY_DIR 0x00F0 //!< Directions: left, right, up down
|
||||
#define KEY_SHOULDER 0x0300 //!< L or R
|
||||
|
||||
#define KEY_ANY 0x03FF //!< Here's the Any key :)
|
||||
|
||||
#define KEY_MASK 0x03FF
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_KEYCNT ------------------------------------------------------
|
||||
|
||||
/*! \defgroup grpInputKCNT Key Control Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_KEYCNT
|
||||
*/
|
||||
|
||||
/*! \{ */
|
||||
|
||||
#define KCNT_IRQ 0x4000 //!< Enable key irq
|
||||
#define KCNT_OR 0 //!< Interrupt on any of selected keys
|
||||
#define KCNT_AND 0x8000 //!< Interrupt on all of selected keys
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_IE, REG_IF, REG_IF_BIOS -------------------------------------
|
||||
|
||||
/*! \defgroup grpIrqIRQ Interrupt Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_IE, REG_IF and REG_IFBIOS
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define IRQ_VBLANK 0x0001 //!< Catch VBlank irq
|
||||
#define IRQ_HBLANK 0x0002 //!< Catch HBlank irq
|
||||
#define IRQ_VCOUNT 0x0004 //!< Catch VCount irq
|
||||
#define IRQ_TIMER0 0x0008 //!< Catch timer 0 irq
|
||||
#define IRQ_TIMER1 0x0010 //!< Catch timer 1 irq
|
||||
#define IRQ_TIMER2 0x0020 //!< Catch timer 2 irq
|
||||
#define IRQ_TIMER3 0x0040 //!< Catch timer 3 irq
|
||||
#define IRQ_SERIAL 0x0080 //!< Catch serial comm irq
|
||||
#define IRQ_DMA0 0x0100 //!< Catch DMA 0 irq
|
||||
#define IRQ_DMA1 0x0200 //!< Catch DMA 1 irq
|
||||
#define IRQ_DMA2 0x0400 //!< Catch DMA 2 irq
|
||||
#define IRQ_DMA3 0x0800 //!< Catch DMA 3 irq
|
||||
#define IRQ_KEYPAD 0x1000 //!< Catch key irq
|
||||
#define IRQ_GAMEPAK 0x2000 //!< Catch cart irq
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- REG_WSCNT -------------------------------------------------------
|
||||
|
||||
/*! \defgroup grpMiscWS Waitstate Control Flags
|
||||
\ingroup grpMemBits
|
||||
\brief Bits for REG_WAITCNT
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define WS_SRAM_4 0
|
||||
#define WS_SRAM_3 0x0001
|
||||
#define WS_SRAM_2 0x0002
|
||||
#define WS_SRAM_8 0x0003
|
||||
#define WS_ROM0_N4 0
|
||||
#define WS_ROM0_N3 0x0004
|
||||
#define WS_ROM0_N2 0x0008
|
||||
#define WS_ROM0_N8 0x000C
|
||||
#define WS_ROM0_S2 0
|
||||
#define WS_ROM0_S1 0x0010
|
||||
#define WS_ROM1_N4 0
|
||||
#define WS_ROM1_N3 0x0020
|
||||
#define WS_ROM1_N2 0x0040
|
||||
#define WS_ROM1_N8 0x0060
|
||||
#define WS_ROM1_S4 0
|
||||
#define WS_ROM1_S1 0x0080
|
||||
#define WS_ROM2_N4 0
|
||||
#define WS_ROM2_N3 0x0100
|
||||
#define WS_ROM2_N2 0x0200
|
||||
#define WS_ROM2_N8 0x0300
|
||||
#define WS_ROM2_S8 0
|
||||
#define WS_ROM2_S1 0x0400
|
||||
#define WS_PHI_OFF 0
|
||||
#define WS_PHI_4 0x0800
|
||||
#define WS_PHI_2 0x1000
|
||||
#define WS_PHI_1 0x1800
|
||||
#define WS_PREFETCH 0x4000
|
||||
#define WS_GBA 0
|
||||
#define WS_CGB 0x8000
|
||||
|
||||
#define WS_STANDARD 0x4317
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- Reg screen entries ----------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoSE Screen-entry Flags
|
||||
\ingroup grpMemBits
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define SE_HFLIP 0x0400 //!< Horizontal flip
|
||||
#define SE_VFLIP 0x0800 //!< Vertical flip
|
||||
|
||||
#define SE_ID_MASK 0x03FF
|
||||
#define SE_ID_SHIFT 0
|
||||
#define SE_ID(n) ((n)<<SE_ID_SHIFT)
|
||||
|
||||
#define SE_FLIP_MASK 0x0C00
|
||||
#define SE_FLIP_SHIFT 10
|
||||
#define SE_FLIP(n) ((n)<<SE_FLIP_SHIFT)
|
||||
|
||||
#define SE_PALBANK_MASK 0xF000
|
||||
#define SE_PALBANK_SHIFT 12
|
||||
#define SE_PALBANK(n) ((n)<<SE_PALBANK_SHIFT)
|
||||
|
||||
|
||||
#define SE_BUILD(id, PALBANK, hflip, vflip) \
|
||||
( ((id)&0x03FF) | (((hflip)&1)<<10) | (((vflip)&1)<<11) | ((PALBANK)<<12) )
|
||||
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- OAM attribute 0 -------------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoAttr0 Object Attribute 0 Flags
|
||||
\ingroup grpMemBits
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define ATTR0_REG 0 //!< Regular object
|
||||
#define ATTR0_AFF 0x0100 //!< Affine object
|
||||
#define ATTR0_HIDE 0x0200 //!< Inactive object
|
||||
#define ATTR0_AFF_DBL 0x0300 //!< Double-size affine object
|
||||
#define ATTR0_AFF_DBL_BIT 0x0200
|
||||
#define ATTR0_BLEND 0x0400 //!< Enable blend
|
||||
#define ATTR0_WINDOW 0x0800 //!< Use for object window
|
||||
#define ATTR0_MOSAIC 0x1000 //!< Enable mosaic
|
||||
#define ATTR0_4BPP 0 //!< Use 4bpp (16 color) tiles
|
||||
#define ATTR0_8BPP 0x2000 //!< Use 8bpp (256 color) tiles
|
||||
#define ATTR0_SQUARE 0 //!< Square shape
|
||||
#define ATTR0_WIDE 0x4000 //!< Tall shape (height > width)
|
||||
#define ATTR0_TALL 0x8000 //!< Wide shape (height < width)
|
||||
|
||||
#define ATTR0_Y_MASK 0x00FF
|
||||
#define ATTR0_Y_SHIFT 0
|
||||
#define ATTR0_Y(n) ((n)<<ATTR0_Y_SHIFT)
|
||||
|
||||
#define ATTR0_MODE_MASK 0x0300
|
||||
#define ATTR0_MODE_SHIFT 8
|
||||
#define ATTR0_MODE(n) ((n)<<ATTR0_MODE_SHIFT)
|
||||
|
||||
#define ATTR0_SHAPE_MASK 0xC000
|
||||
#define ATTR0_SHAPE_SHIFT 14
|
||||
#define ATTR0_SHAPE(n) ((n)<<ATTR0_SHAPE_SHIFT)
|
||||
|
||||
|
||||
#define ATTR0_BUILD(y, shape, bpp, mode, mos, bld, win) \
|
||||
( \
|
||||
((y)&255) | (((mode)&3)<<8) | (((bld)&1)<<10) | (((win)&1)<<11) \
|
||||
| (((mos)&1)<<12) | (((bpp)&8)<<10)| (((shape)&3)<<14) \
|
||||
)
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- OAM attribute 1 -------------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoAttr1 Object Attribute 1 Flags
|
||||
\ingroup grpMemBits
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define ATTR1_HFLIP 0x1000 //!< Horizontal flip (reg obj only)
|
||||
#define ATTR1_VFLIP 0x2000 //!< Vertical flip (reg obj only)
|
||||
// Base sizes
|
||||
#define ATTR1_SIZE_8 0
|
||||
#define ATTR1_SIZE_16 0x4000
|
||||
#define ATTR1_SIZE_32 0x8000
|
||||
#define ATTR1_SIZE_64 0xC000
|
||||
// Square sizes
|
||||
#define ATTR1_SIZE_8x8 0 //!< Size flag for 8x8 px object
|
||||
#define ATTR1_SIZE_16x16 0x4000 //!< Size flag for 16x16 px object
|
||||
#define ATTR1_SIZE_32x32 0x8000 //!< Size flag for 32x32 px object
|
||||
#define ATTR1_SIZE_64x64 0xC000 //!< Size flag for 64x64 px object
|
||||
// Tall sizes
|
||||
#define ATTR1_SIZE_8x16 0 //!< Size flag for 8x16 px object
|
||||
#define ATTR1_SIZE_8x32 0x4000 //!< Size flag for 8x32 px object
|
||||
#define ATTR1_SIZE_16x32 0x8000 //!< Size flag for 16x32 px object
|
||||
#define ATTR1_SIZE_32x64 0xC000 //!< Size flag for 32x64 px object
|
||||
// Wide sizes
|
||||
#define ATTR1_SIZE_16x8 0 //!< Size flag for 16x8 px object
|
||||
#define ATTR1_SIZE_32x8 0x4000 //!< Size flag for 32x8 px object
|
||||
#define ATTR1_SIZE_32x16 0x8000 //!< Size flag for 32x16 px object
|
||||
#define ATTR1_SIZE_64x32 0xC000 //!< Size flag for 64x64 px object
|
||||
|
||||
|
||||
#define ATTR1_X_MASK 0x01FF
|
||||
#define ATTR1_X_SHIFT 0
|
||||
#define ATTR1_X(n) ((n)<<ATTR1_X_SHIFT)
|
||||
|
||||
#define ATTR1_AFF_ID_MASK 0x3E00
|
||||
#define ATTR1_AFF_ID_SHIFT 9
|
||||
#define ATTR1_AFF_ID(n) ((n)<<ATTR1_AFF_ID_SHIFT)
|
||||
|
||||
#define ATTR1_FLIP_MASK 0x3000
|
||||
#define ATTR1_FLIP_SHIFT 12
|
||||
#define ATTR1_FLIP(n) ((n)<<ATTR1_FLIP_SHIFT)
|
||||
|
||||
#define ATTR1_SIZE_MASK 0xC000
|
||||
#define ATTR1_SIZE_SHIFT 14
|
||||
#define ATTR1_SIZE(n) ((n)<<ATTR1_SIZE_SHIFT)
|
||||
|
||||
|
||||
#define ATTR1_BUILDR(x, size, hflip, vflip) \
|
||||
( ((x)&511) | (((hflip)&1)<<12) | (((vflip)&1)<<13) | (((size)&3)<<14) )
|
||||
|
||||
#define ATTR1_BUILDA(x, size, affid) \
|
||||
( ((x)&511) | (((affid)&31)<<9) | (((size)&3)<<14) )
|
||||
|
||||
/*! \} /defgroup */
|
||||
|
||||
// --- OAM attribute 2 -------------------------------------------------
|
||||
|
||||
/*! \defgroup grpVideoAttr2 Object Attribute 2 Flags
|
||||
\ingroup grpMemBits
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define ATTR2_ID_MASK 0x03FF
|
||||
#define ATTR2_ID_SHIFT 0
|
||||
#define ATTR2_ID(n) ((n)<<ATTR2_ID_SHIFT)
|
||||
|
||||
#define ATTR2_PRIO_MASK 0x0C00
|
||||
#define ATTR2_PRIO_SHIFT 10
|
||||
#define ATTR2_PRIO(n) ((n)<<ATTR2_PRIO_SHIFT)
|
||||
|
||||
#define ATTR2_PALBANK_MASK 0xF000
|
||||
#define ATTR2_PALBANK_SHIFT 12
|
||||
#define ATTR2_PALBANK(n) ((n)<<ATTR2_PALBANK_SHIFT)
|
||||
|
||||
|
||||
#define ATTR2_BUILD(id, pb, prio) \
|
||||
( ((id)&0x3FF) | (((pb)&15)<<12) | (((prio)&3)<<10) )
|
||||
|
||||
/*! \} //defgroup */
|
||||
|
||||
|
||||
#endif // TONC_MEMDEF
|
|
@ -0,0 +1,583 @@
|
|||
//
|
||||
// GBA Memory map
|
||||
//
|
||||
//! \file tonc_memmap.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20060508
|
||||
//
|
||||
//
|
||||
// === NOTES ===
|
||||
//
|
||||
// * The REG_BGxy registers for affine backgrounds
|
||||
// should be _signed_ (vs16 / vs32), not unsigned (vu16 / vu32)
|
||||
// * I have removed several REG_x_L, REG_x_H pairs because all they
|
||||
// do is clutter up the file
|
||||
// * C++ doesn't seem to like struct copies if the type specifiers
|
||||
// don't match (e.g., volatile, non-volatile). Most registers
|
||||
// don't really need the volatile specifier anyway, so if this
|
||||
// presents a problem consider removing it.
|
||||
// * I'm using defines for the memory map here, but GCC cannot optimize
|
||||
// these properly and they will often appear inside a loop, potentially
|
||||
// slowing it down to up 50% or so, depending on how much you do
|
||||
// in the loop. Possible remedy: use a set of global pointers for the
|
||||
// memory map instead of defines. It'll only be 4 or so pointers, so
|
||||
// it should be ok. (PONDER: system with void pointers?)
|
||||
|
||||
#ifndef TONC_MEMMAP
|
||||
#define TONC_MEMMAP
|
||||
|
||||
#ifndef __ASM__
|
||||
#include "tonc_types.h"
|
||||
#endif
|
||||
|
||||
/*! \defgroup grpReg IO Registers */
|
||||
/*! \defgroup grpRegAlt IO Alternates */
|
||||
|
||||
|
||||
// === MEMORY SECTIONS ================================================
|
||||
|
||||
/*! \addtogroup grpMemmap
|
||||
\brief Basic memory map
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
|
||||
//! \name Main sections
|
||||
//\{
|
||||
#define MEM_EWRAM 0x02000000 //!< External work RAM
|
||||
#define MEM_IWRAM 0x03000000 //!< Internal work RAM
|
||||
#define MEM_IO 0x04000000 //!< I/O registers
|
||||
#define MEM_PAL 0x05000000 //!< Palette. Note: no 8bit write !!
|
||||
#define MEM_VRAM 0x06000000 //!< Video RAM. Note: no 8bit write !!
|
||||
#define MEM_OAM 0x07000000 //!< Object Attribute Memory (OAM) Note: no 8bit write !!
|
||||
#define MEM_ROM 0x08000000 //!< ROM. No write at all (duh)
|
||||
#define MEM_SRAM 0x0E000000 //!< Static RAM. 8bit write only
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Main section sizes
|
||||
//\{
|
||||
#define EWRAM_SIZE 0x40000
|
||||
#define IWRAM_SIZE 0x08000
|
||||
#define PAL_SIZE 0x00400
|
||||
#define VRAM_SIZE 0x18000
|
||||
#define OAM_SIZE 0x00400
|
||||
#define SRAM_SIZE 0x10000
|
||||
//\}
|
||||
|
||||
//! \name Sub section sizes
|
||||
//\{
|
||||
#define PAL_BG_SIZE 0x00200 //!< BG palette size
|
||||
#define PAL_OBJ_SIZE 0x00200 //!< Object palette size
|
||||
#define CBB_SIZE 0x04000 //!< Charblock size
|
||||
#define SBB_SIZE 0x00800 //!< Screenblock size
|
||||
#define VRAM_BG_SIZE 0x10000 //!< BG VRAM size
|
||||
#define VRAM_OBJ_SIZE 0x08000 //!< Object VRAM size
|
||||
#define M3_SIZE 0x12C00 //!< Mode 3 buffer size
|
||||
#define M4_SIZE 0x09600 //!< Mode 4 buffer size
|
||||
#define M5_SIZE 0x0A000 //!< Mode 5 buffer size
|
||||
#define VRAM_PAGE_SIZE 0x0A000 //!< Bitmap page size
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Sub sections
|
||||
//\{
|
||||
#define REG_BASE MEM_IO
|
||||
|
||||
#define MEM_PAL_BG (MEM_PAL) //!< Background palette address
|
||||
#define MEM_PAL_OBJ (MEM_PAL + PAL_BG_SIZE) //!< Object palette address
|
||||
#define MEM_VRAM_FRONT (MEM_VRAM) //!< Front page address
|
||||
#define MEM_VRAM_BACK (MEM_VRAM + VRAM_PAGE_SIZE) //!< Back page address
|
||||
#define MEM_VRAM_OBJ (MEM_VRAM + VRAM_BG_SIZE) //!< Object VRAM address
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// STRUCTURED MEMORY MAP
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpMemArray Memory mapped arrays
|
||||
\ingroup grpMemmap
|
||||
\brief These are some macros for easier access of various
|
||||
memory sections. They're all arrays or matrices, using the
|
||||
types that would be the most natural for that concept.
|
||||
*/
|
||||
/* \{ */
|
||||
|
||||
|
||||
//! \name Palette
|
||||
//\{
|
||||
|
||||
//! Background palette.
|
||||
/*! pal_bg_mem[i] = color i ( COLOR )
|
||||
*/
|
||||
#define pal_bg_mem ((COLOR*)MEM_PAL)
|
||||
|
||||
//! Object palette.
|
||||
/*! pal_obj_mem[i] = color i ( COLOR )
|
||||
*/
|
||||
#define pal_obj_mem ((COLOR*)MEM_PAL_OBJ)
|
||||
|
||||
|
||||
//! Background palette matrix.
|
||||
/*! pal_bg_bank[y] = bank y ( COLOR[ ] )<br>
|
||||
pal_bg_bank[y][x] = color color y*16+x ( COLOR )
|
||||
*/
|
||||
#define pal_bg_bank ((PALBANK*)MEM_PAL)
|
||||
|
||||
//! Object palette matrix.
|
||||
/*! pal_obj_bank[y] = bank y ( COLOR[ ] )<br>
|
||||
pal_obj_bank[y][x] = color y*16+x ( COLOR )
|
||||
*/
|
||||
#define pal_obj_bank ((PALBANK*)MEM_PAL_OBJ)
|
||||
|
||||
//\} // End Palette
|
||||
|
||||
|
||||
//! \name VRAM
|
||||
//\{
|
||||
|
||||
//! Charblocks, 4bpp tiles.
|
||||
/*! tile_mem[y] = charblock y ( TILE[ ] )<br>
|
||||
tile_mem[y][x] = block y, tile x ( TILE )
|
||||
*/
|
||||
#define tile_mem ( (CHARBLOCK*)MEM_VRAM)
|
||||
|
||||
//! Charblocks, 8bpp tiles.
|
||||
/*! tile_mem[y] = charblock y ( TILE[ ] )<br>
|
||||
tile_mem[y][x] = block y, tile x ( TILE )
|
||||
*/
|
||||
#define tile8_mem ((CHARBLOCK8*)MEM_VRAM)
|
||||
|
||||
//! Object charblocks, 4bpp tiles.
|
||||
/*! tile_mem[y] = charblock y ( TILE[ ] )<br>
|
||||
tile_mem[y][x] = block y, tile x ( TILE )
|
||||
*/
|
||||
#define tile_mem_obj ( (CHARBLOCK*)MEM_VRAM_OBJ)
|
||||
|
||||
//! Object charblocks, 4bpp tiles.
|
||||
/*! tile_mem[y] = charblock y ( TILE[ ] )<br>
|
||||
tile_mem[y][x] = block y, tile x ( TILE )
|
||||
*/
|
||||
#define tile8_mem_obj ((CHARBLOCK8*)MEM_VRAM_OBJ)
|
||||
|
||||
//! Screenblocks as arrays
|
||||
/*! se_mem[y] = screenblock y ( SCR_ENTRY[ ] )<br>
|
||||
* se_mem[y][x] = screenblock y, entry x ( SCR_ENTRY )
|
||||
*/
|
||||
#define se_mem ((SCREENBLOCK*)MEM_VRAM)
|
||||
|
||||
|
||||
//! Screenblock as matrices
|
||||
/*! se_mat[s] = screenblock s ( SCR_ENTRY[ ][ ] )<br>
|
||||
se_mat[s][y][x] = screenblock s, entry (x,y) ( SCR_ENTRY )
|
||||
*/
|
||||
#define se_mat ((SCREENMAT*)MEM_VRAM)
|
||||
|
||||
//! Main mode 3/5 frame as an array
|
||||
/*! vid_mem[i] = pixel i ( COLOR )
|
||||
*/
|
||||
#define vid_mem ((COLOR*)MEM_VRAM)
|
||||
|
||||
//! Mode 3 frame as a matrix
|
||||
/*! m3_mem[y][x] = pixel (x, y) ( COLOR )
|
||||
*/
|
||||
#define m3_mem ((M3LINE*)MEM_VRAM)
|
||||
|
||||
|
||||
//! Mode 4 first page as a matrix
|
||||
/*! m4_mem[y][x] = pixel (x, y) ( u8 )
|
||||
* \note This is a byte-buffer. Not to be used for writing.
|
||||
*/
|
||||
#define m4_mem ((M4LINE*)MEM_VRAM)
|
||||
|
||||
//! Mode 5 first page as a matrix
|
||||
/*! m5_mem[y][x] = pixel (x, y) ( COLOR )
|
||||
*/
|
||||
#define m5_mem ((M5LINE*)MEM_VRAM)
|
||||
|
||||
//! First page array
|
||||
#define vid_mem_front ((COLOR*)MEM_VRAM)
|
||||
|
||||
//! Second page array
|
||||
#define vid_mem_back ((COLOR*)MEM_VRAM_BACK)
|
||||
|
||||
//! Mode 4 second page as a matrix
|
||||
/*! m4_mem[y][x] = pixel (x, y) ( u8 )
|
||||
* \note This is a byte-buffer. Not to be used for writing.
|
||||
*/
|
||||
#define m4_mem_back ((M4LINE*)MEM_VRAM_BACK)
|
||||
|
||||
//! Mode 5 second page as a matrix
|
||||
/*! m5_mem[y][x] = pixel (x, y) ( COLOR )
|
||||
*/
|
||||
#define m5_mem_back ((M5LINE*)MEM_VRAM_BACK)
|
||||
|
||||
//\} // End VRAM
|
||||
|
||||
|
||||
//! \name OAM
|
||||
//\{
|
||||
|
||||
//! Object attribute memory
|
||||
/*! oam_mem[i] = object i ( OBJ_ATTR )
|
||||
*/
|
||||
#define oam_mem ((OBJ_ATTR*)MEM_OAM)
|
||||
#define obj_mem ((OBJ_ATTR*)MEM_OAM)
|
||||
|
||||
//! Object affine memory
|
||||
/*! obj_aff_mem[i] = object matrix i ( OBJ_AFFINE )
|
||||
*/
|
||||
#define obj_aff_mem ((OBJ_AFFINE*)MEM_OAM)
|
||||
|
||||
//\} // End OAM
|
||||
|
||||
//! \name ROM
|
||||
//\{
|
||||
|
||||
//! ROM pointer
|
||||
#define rom_mem ((u16*)MEM_ROM)
|
||||
|
||||
//\}
|
||||
|
||||
//! \name SRAM
|
||||
//\{
|
||||
|
||||
//! SRAM pointer
|
||||
#define sram_mem ((u8*)MEM_SRAM)
|
||||
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// REGISTER LIST
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpReg
|
||||
\ingroup grpMemmap
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name IWRAM 'registers'
|
||||
//\{
|
||||
|
||||
// 0300:7ff[y] is mirrored at 03ff:fff[y], which is why this works out:
|
||||
#define REG_IFBIOS *(vu16*)(REG_BASE-0x0008) //!< IRQ ack for IntrWait functions
|
||||
#define REG_RESET_DST *(vu16*)(REG_BASE-0x0006) //!< Destination for after SoftReset
|
||||
#define REG_ISR_MAIN *(fnptr*)(REG_BASE-0x0004) //!< IRQ handler address
|
||||
//\}
|
||||
|
||||
//! \name Display registers
|
||||
//\{
|
||||
#define REG_DISPCNT *(vu32*)(REG_BASE+0x0000) //!< Display control
|
||||
#define REG_DISPSTAT *(vu16*)(REG_BASE+0x0004) //!< Display status
|
||||
#define REG_VCOUNT *(vu16*)(REG_BASE+0x0006) //!< Scanline count
|
||||
//\}
|
||||
|
||||
//! \name Background control registers
|
||||
//\{
|
||||
#define REG_BGCNT ((vu16*)(REG_BASE+0x0008)) //!< Bg control array
|
||||
|
||||
#define REG_BG0CNT *(vu16*)(REG_BASE+0x0008) //!< Bg0 control
|
||||
#define REG_BG1CNT *(vu16*)(REG_BASE+0x000A) //!< Bg1 control
|
||||
#define REG_BG2CNT *(vu16*)(REG_BASE+0x000C) //!< Bg2 control
|
||||
#define REG_BG3CNT *(vu16*)(REG_BASE+0x000E) //!< Bg3 control
|
||||
//\}
|
||||
|
||||
//! \name Regular background scroll registers. (write only!)
|
||||
//\{
|
||||
#define REG_BG_OFS ((BG_POINT*)(REG_BASE+0x0010)) //!< Bg scroll array
|
||||
|
||||
#define REG_BG0HOFS *(vu16*)(REG_BASE+0x0010) //!< Bg0 horizontal scroll
|
||||
#define REG_BG0VOFS *(vu16*)(REG_BASE+0x0012) //!< Bg0 vertical scroll
|
||||
#define REG_BG1HOFS *(vu16*)(REG_BASE+0x0014) //!< Bg1 horizontal scroll
|
||||
#define REG_BG1VOFS *(vu16*)(REG_BASE+0x0016) //!< Bg1 vertical scroll
|
||||
#define REG_BG2HOFS *(vu16*)(REG_BASE+0x0018) //!< Bg2 horizontal scroll
|
||||
#define REG_BG2VOFS *(vu16*)(REG_BASE+0x001A) //!< Bg2 vertical scroll
|
||||
#define REG_BG3HOFS *(vu16*)(REG_BASE+0x001C) //!< Bg3 horizontal scroll
|
||||
#define REG_BG3VOFS *(vu16*)(REG_BASE+0x001E) //!< Bg3 vertical scroll
|
||||
//\}
|
||||
|
||||
//! \name Affine background parameters. (write only!)
|
||||
//\{
|
||||
#define REG_BG_AFFINE ((BG_AFFINE*)(REG_BASE+0x0000)) //!< Bg affine array
|
||||
|
||||
#define REG_BG2PA *(vs16*)(REG_BASE+0x0020) //!< Bg2 matrix.pa
|
||||
#define REG_BG2PB *(vs16*)(REG_BASE+0x0022) //!< Bg2 matrix.pb
|
||||
#define REG_BG2PC *(vs16*)(REG_BASE+0x0024) //!< Bg2 matrix.pc
|
||||
#define REG_BG2PD *(vs16*)(REG_BASE+0x0026) //!< Bg2 matrix.pd
|
||||
#define REG_BG2X *(vs32*)(REG_BASE+0x0028) //!< Bg2 x scroll
|
||||
#define REG_BG2Y *(vs32*)(REG_BASE+0x002C) //!< Bg2 y scroll
|
||||
#define REG_BG3PA *(vs16*)(REG_BASE+0x0030) //!< Bg3 matrix.pa.
|
||||
#define REG_BG3PB *(vs16*)(REG_BASE+0x0032) //!< Bg3 matrix.pb
|
||||
#define REG_BG3PC *(vs16*)(REG_BASE+0x0034) //!< Bg3 matrix.pc
|
||||
#define REG_BG3PD *(vs16*)(REG_BASE+0x0036) //!< Bg3 matrix.pd
|
||||
#define REG_BG3X *(vs32*)(REG_BASE+0x0038) //!< Bg3 x scroll
|
||||
#define REG_BG3Y *(vs32*)(REG_BASE+0x003C) //!< Bg3 y scroll
|
||||
//\}
|
||||
|
||||
//! \name Windowing registers
|
||||
//\{
|
||||
#define REG_WIN0H *(vu16*)(REG_BASE+0x0040) //!< win0 right, left (0xLLRR)
|
||||
#define REG_WIN1H *(vu16*)(REG_BASE+0x0042) //!< win1 right, left (0xLLRR)
|
||||
#define REG_WIN0V *(vu16*)(REG_BASE+0x0044) //!< win0 bottom, top (0xTTBB)
|
||||
#define REG_WIN1V *(vu16*)(REG_BASE+0x0046) //!< win1 bottom, top (0xTTBB)
|
||||
#define REG_WININ *(vu16*)(REG_BASE+0x0048) //!< win0, win1 control
|
||||
#define REG_WINOUT *(vu16*)(REG_BASE+0x004A) //!< winOut, winObj control
|
||||
//\}
|
||||
|
||||
//! \name Alternate Windowing registers
|
||||
//\{
|
||||
#define REG_WIN0R *(vu8*)(REG_BASE+0x0040) //!< Win 0 right
|
||||
#define REG_WIN0L *(vu8*)(REG_BASE+0x0041) //!< Win 0 left
|
||||
#define REG_WIN1R *(vu8*)(REG_BASE+0x0042) //!< Win 1 right
|
||||
#define REG_WIN1L *(vu8*)(REG_BASE+0x0043) //!< Win 1 left
|
||||
|
||||
#define REG_WIN0B *(vu8*)(REG_BASE+0x0044) //!< Win 0 bottom
|
||||
#define REG_WIN0T *(vu8*)(REG_BASE+0x0045) //!< Win 0 top
|
||||
#define REG_WIN1B *(vu8*)(REG_BASE+0x0046) //!< Win 1 bottom
|
||||
#define REG_WIN1T *(vu8*)(REG_BASE+0x0047) //!< Win 1 top
|
||||
|
||||
#define REG_WIN0CNT *(vu8*)(REG_BASE+0x0048) //!< window 0 control
|
||||
#define REG_WIN1CNT *(vu8*)(REG_BASE+0x0049) //!< window 1 control
|
||||
#define REG_WINOUTCNT *(vu8*)(REG_BASE+0x004A) //!< Out window control
|
||||
#define REG_WINOBJCNT *(vu8*)(REG_BASE+0x004B) //!< Obj window control
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Graphic effects
|
||||
//\{
|
||||
#define REG_MOSAIC *(vu32*)(REG_BASE+0x004C) //!< Mosaic control
|
||||
#define REG_BLDCNT *(vu16*)(REG_BASE+0x0050) //!< Alpha control
|
||||
#define REG_BLDALPHA *(vu16*)(REG_BASE+0x0052) //!< Fade level
|
||||
#define REG_BLDY *(vu16*)(REG_BASE+0x0054) //!< Blend levels
|
||||
//\}
|
||||
|
||||
|
||||
// === SOUND REGISTERS ===
|
||||
// sound regs, partially following pin8gba's nomenclature
|
||||
|
||||
//! \name Channel 1: Square wave with sweep
|
||||
//\{
|
||||
#define REG_SND1SWEEP *(vu16*)(REG_BASE+0x0060) //!< Channel 1 Sweep
|
||||
#define REG_SND1CNT *(vu16*)(REG_BASE+0x0062) //!< Channel 1 Control
|
||||
#define REG_SND1FREQ *(vu16*)(REG_BASE+0x0064) //!< Channel 1 frequency
|
||||
//\}
|
||||
|
||||
//! \name Channel 2: Simple square wave
|
||||
//\{
|
||||
#define REG_SND2CNT *(vu16*)(REG_BASE+0x0068) //!< Channel 2 control
|
||||
#define REG_SND2FREQ *(vu16*)(REG_BASE+0x006C) //!< Channel 2 frequency
|
||||
//\}
|
||||
|
||||
//! \name Channel 3: Wave player
|
||||
//\{
|
||||
#define REG_SND3SEL *(vu16*)(REG_BASE+0x0070) //!< Channel 3 wave select
|
||||
#define REG_SND3CNT *(vu16*)(REG_BASE+0x0072) //!< Channel 3 control
|
||||
#define REG_SND3FREQ *(vu16*)(REG_BASE+0x0074) //!< Channel 3 frequency
|
||||
//\}
|
||||
|
||||
//! \name Channel 4: Noise generator
|
||||
//\{
|
||||
#define REG_SND4CNT *(vu16*)(REG_BASE+0x0078) //!< Channel 4 control
|
||||
#define REG_SND4FREQ *(vu16*)(REG_BASE+0x007C) //!< Channel 4 frequency
|
||||
//\}
|
||||
|
||||
//! \name Sound control
|
||||
//\{
|
||||
#define REG_SNDCNT *(vu32*)(REG_BASE+0x0080) //!< Main sound control
|
||||
#define REG_SNDDMGCNT *(vu16*)(REG_BASE+0x0080) //!< DMG channel control
|
||||
#define REG_SNDDSCNT *(vu16*)(REG_BASE+0x0082) //!< Direct Sound control
|
||||
#define REG_SNDSTAT *(vu16*)(REG_BASE+0x0084) //!< Sound status
|
||||
#define REG_SNDBIAS *(vu16*)(REG_BASE+0x0088) //!< Sound bias
|
||||
//\}
|
||||
|
||||
//! \name Sound buffers
|
||||
//\{
|
||||
#define REG_WAVE_RAM (vu32*)(REG_BASE+0x0090) //!< Channel 3 wave buffer
|
||||
|
||||
#define REG_WAVE_RAM0 *(vu32*)(REG_BASE+0x0090)
|
||||
#define REG_WAVE_RAM1 *(vu32*)(REG_BASE+0x0094)
|
||||
#define REG_WAVE_RAM2 *(vu32*)(REG_BASE+0x0098)
|
||||
#define REG_WAVE_RAM3 *(vu32*)(REG_BASE+0x009C)
|
||||
|
||||
#define REG_FIFO_A *(vu32*)(REG_BASE+0x00A0) //!< DSound A FIFO
|
||||
#define REG_FIFO_B *(vu32*)(REG_BASE+0x00A4) //!< DSound B FIFO
|
||||
//\}
|
||||
|
||||
//! \name DMA registers
|
||||
//\{
|
||||
#define REG_DMA ((volatile DMA_REC*)(REG_BASE+0x00B0)) //!< DMA as DMA_REC array
|
||||
|
||||
#define REG_DMA0SAD *(vu32*)(REG_BASE+0x00B0) //!< DMA 0 Source address
|
||||
#define REG_DMA0DAD *(vu32*)(REG_BASE+0x00B4) //!< DMA 0 Destination address
|
||||
#define REG_DMA0CNT *(vu32*)(REG_BASE+0x00B8) //!< DMA 0 Control
|
||||
|
||||
#define REG_DMA1SAD *(vu32*)(REG_BASE+0x00BC) //!< DMA 1 Source address
|
||||
#define REG_DMA1DAD *(vu32*)(REG_BASE+0x00C0) //!< DMA 1 Destination address
|
||||
#define REG_DMA1CNT *(vu32*)(REG_BASE+0x00C4) //!< DMA 1 Control
|
||||
|
||||
#define REG_DMA2SAD *(vu32*)(REG_BASE+0x00C8) //!< DMA 2 Source address
|
||||
#define REG_DMA2DAD *(vu32*)(REG_BASE+0x00CC) //!< DMA 2 Destination address
|
||||
#define REG_DMA2CNT *(vu32*)(REG_BASE+0x00D0) //!< DMA 2 Control
|
||||
|
||||
#define REG_DMA3SAD *(vu32*)(REG_BASE+0x00D4) //!< DMA 3 Source address
|
||||
#define REG_DMA3DAD *(vu32*)(REG_BASE+0x00D8) //!< DMA 3 Destination address
|
||||
#define REG_DMA3CNT *(vu32*)(REG_BASE+0x00DC) //!< DMA 3 Control
|
||||
//\}
|
||||
|
||||
//! \name Timer registers
|
||||
//\{
|
||||
#define REG_TM ((volatile TMR_REC*)(REG_BASE+0x0100)) //!< Timers as TMR_REC array
|
||||
|
||||
#define REG_TM0D *(vu16*)(REG_BASE+0x0100) //!< Timer 0 data
|
||||
#define REG_TM0CNT *(vu16*)(REG_BASE+0x0102) //!< Timer 0 control
|
||||
#define REG_TM1D *(vu16*)(REG_BASE+0x0104) //!< Timer 1 data
|
||||
#define REG_TM1CNT *(vu16*)(REG_BASE+0x0106) //!< Timer 1 control
|
||||
#define REG_TM2D *(vu16*)(REG_BASE+0x0108) //!< Timer 2 data
|
||||
#define REG_TM2CNT *(vu16*)(REG_BASE+0x010A) //!< Timer 2 control
|
||||
#define REG_TM3D *(vu16*)(REG_BASE+0x010C) //!< Timer 3 data
|
||||
#define REG_TM3CNT *(vu16*)(REG_BASE+0x010E) //!< Timer 3 control
|
||||
//\}
|
||||
|
||||
//! \name Serial communication
|
||||
//{
|
||||
#define REG_SIOCNT *(vu16*)(REG_BASE+0x0128) //!< Serial IO control (Normal/MP/UART)
|
||||
|
||||
#define REG_SIODATA ((vu32*)(REG_BASE+0x0120))
|
||||
#define REG_SIODATA32 *(vu32*)(REG_BASE+0x0120) //!< Normal/UART 32bit data
|
||||
#define REG_SIODATA8 *(vu16*)(REG_BASE+0x012A) //!< Normal/UART 8bit data
|
||||
|
||||
#define REG_SIOMULTI ((vu16*)(REG_BASE+0x0120)) //!< Multiplayer data array
|
||||
#define REG_SIOMULTI0 *(vu16*)(REG_BASE+0x0120) //!< MP master data
|
||||
#define REG_SIOMULTI1 *(vu16*)(REG_BASE+0x0122) //!< MP Slave 1 data
|
||||
#define REG_SIOMULTI2 *(vu16*)(REG_BASE+0x0124) //!< MP Slave 2 data
|
||||
#define REG_SIOMULTI3 *(vu16*)(REG_BASE+0x0126) //!< MP Slave 3 data
|
||||
|
||||
#define REG_SIOMLT_RECV *(vu16*)(REG_BASE+0x0120) //!< MP data receiver
|
||||
#define REG_SIOMLT_SEND *(vu16*)(REG_BASE+0x012A) //!< MP data sender
|
||||
//\}
|
||||
|
||||
//! \name Keypad registers
|
||||
//\{
|
||||
#define REG_KEYINPUT *(vu16*)(REG_BASE+0x0130) //!< Key status (read only??)
|
||||
#define REG_KEYCNT *(vu16*)(REG_BASE+0x0132) //!< Key IRQ control
|
||||
//\}
|
||||
|
||||
//! \name Joybus communication
|
||||
//\{
|
||||
#define REG_RCNT *(vu16*)(REG_BASE+0x0134) //!< SIO Mode Select/General Purpose Data
|
||||
#define REG_JOYCNT *(vu16*)(REG_BASE+0x0140) //!< JOY bus control
|
||||
#define REG_JOY_RECV *(vu32*)(REG_BASE+0x0150) //!< JOY bus receiever
|
||||
#define REG_JOY_TRANS *(vu32*)(REG_BASE+0x0154) //!< JOY bus transmitter
|
||||
#define REG_JOYSTAT *(vu16*)(REG_BASE+0x0158) //!< JOY bus status
|
||||
//\}
|
||||
|
||||
//! \name Interrupt / System registers
|
||||
//\{
|
||||
#define REG_IE *(vu16*)(REG_BASE+0x0200) //!< IRQ enable
|
||||
#define REG_IF *(vu16*)(REG_BASE+0x0202) //!< IRQ status/acknowledge
|
||||
#define REG_WAITCNT *(vu16*)(REG_BASE+0x0204) //!< Waitstate control
|
||||
#define REG_IME *(vu16*)(REG_BASE+0x0208) //!< IRQ master enable
|
||||
#define REG_PAUSE *(vu16*)(REG_BASE+0x0300) //!< Pause system (?)
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ALT REGISTERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpRegAlt
|
||||
\ingroup grpMemmap
|
||||
\brief Alternate names for some of the registers
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define REG_BLDMOD *(vu16*)(REG_BASE+0x0050) // alpha control
|
||||
#define REG_COLEV *(vu16*)(REG_BASE+0x0052) // fade level
|
||||
#define REG_COLEY *(vu16*)(REG_BASE+0x0054) // blend levels
|
||||
|
||||
// sound regs as in belogic and GBATek (mostly for compatability)
|
||||
#define REG_SOUND1CNT *(vu32*)(REG_BASE+0x0060)
|
||||
#define REG_SOUND1CNT_L *(vu16*)(REG_BASE+0x0060)
|
||||
#define REG_SOUND1CNT_H *(vu16*)(REG_BASE+0x0062)
|
||||
#define REG_SOUND1CNT_X *(vu16*)(REG_BASE+0x0064)
|
||||
#define REG_SOUND2CNT_L *(vu16*)(REG_BASE+0x0068)
|
||||
#define REG_SOUND2CNT_H *(vu16*)(REG_BASE+0x006C)
|
||||
#define REG_SOUND3CNT *(vu32*)(REG_BASE+0x0070)
|
||||
#define REG_SOUND3CNT_L *(vu16*)(REG_BASE+0x0070)
|
||||
#define REG_SOUND3CNT_H *(vu16*)(REG_BASE+0x0072)
|
||||
#define REG_SOUND3CNT_X *(vu16*)(REG_BASE+0x0074)
|
||||
#define REG_SOUND4CNT_L *(vu16*)(REG_BASE+0x0078)
|
||||
#define REG_SOUND4CNT_H *(vu16*)(REG_BASE+0x007C)
|
||||
#define REG_SOUNDCNT *(vu32*)(REG_BASE+0x0080)
|
||||
#define REG_SOUNDCNT_L *(vu16*)(REG_BASE+0x0080)
|
||||
#define REG_SOUNDCNT_H *(vu16*)(REG_BASE+0x0082)
|
||||
#define REG_SOUNDCNT_X *(vu16*)(REG_BASE+0x0084)
|
||||
#define REG_SOUNDBIAS *(vu16*)(REG_BASE+0x0088)
|
||||
|
||||
#define REG_WAVE (vu32*)(REG_BASE+0x0090)
|
||||
#define REG_FIFOA *(vu32*)(REG_BASE+0x00A0)
|
||||
#define REG_FIFOB *(vu32*)(REG_BASE+0x00A4)
|
||||
|
||||
|
||||
#define REG_DMA0CNT_L *(vu16*)(REG_BASE+0x00B8) // count
|
||||
#define REG_DMA0CNT_H *(vu16*)(REG_BASE+0x00BA) // flags
|
||||
#define REG_DMA1CNT_L *(vu16*)(REG_BASE+0x00C4)
|
||||
#define REG_DMA1CNT_H *(vu16*)(REG_BASE+0x00C6)
|
||||
#define REG_DMA2CNT_L *(vu16*)(REG_BASE+0x00D0)
|
||||
#define REG_DMA2CNT_H *(vu16*)(REG_BASE+0x00D2)
|
||||
#define REG_DMA3CNT_L *(vu16*)(REG_BASE+0x00DC)
|
||||
#define REG_DMA3CNT_H *(vu16*)(REG_BASE+0x00DE)
|
||||
|
||||
#define REG_TM0CNT_L *(vu16*)(REG_BASE+0x0100)
|
||||
#define REG_TM0CNT_H *(vu16*)(REG_BASE+0x0102)
|
||||
|
||||
#define REG_TM1CNT_L *(vu16*)(REG_BASE+0x0104)
|
||||
#define REG_TM1CNT_H *(vu16*)(REG_BASE+0x0106)
|
||||
|
||||
#define REG_TM2CNT_L *(vu16*)(REG_BASE+0x0108)
|
||||
#define REG_TM2CNT_H *(vu16*)(REG_BASE+0x010a)
|
||||
|
||||
#define REG_TM3CNT_L *(vu16*)(REG_BASE+0x010c)
|
||||
#define REG_TM3CNT_H *(vu16*)(REG_BASE+0x010e)
|
||||
|
||||
|
||||
#define REG_KEYS *(vu16*)(REG_BASE+0x0130) // Key status
|
||||
#define REG_P1 *(vu16*)(REG_BASE+0x0130) // for backward combatibility
|
||||
#define REG_P1CNT *(vu16*)(REG_BASE+0x0132) // ditto
|
||||
|
||||
#define REG_SCD0 *(vu16*)(REG_BASE+0x0120)
|
||||
#define REG_SCD1 *(vu16*)(REG_BASE+0x0122)
|
||||
#define REG_SCD2 *(vu16*)(REG_BASE+0x0124)
|
||||
#define REG_SCD3 *(vu16*)(REG_BASE+0x0126)
|
||||
#define REG_SCCNT *(vu32*)(REG_BASE+0x0128)
|
||||
#define REG_SCCNT_L *(vu16*)(REG_BASE+0x0128)
|
||||
#define REG_SCCNT_H *(vu16*)(REG_BASE+0x012A)
|
||||
|
||||
#define REG_R *(vu16*)(REG_BASE+0x0134)
|
||||
#define REG_HS_CTRL *(vu16*)(REG_BASE+0x0140)
|
||||
#define REG_JOYRE *(vu32*)(REG_BASE+0x0150)
|
||||
#define REG_JOYRE_L *(vu16*)(REG_BASE+0x0150)
|
||||
#define REG_JOYRE_H *(vu16*)(REG_BASE+0x0152)
|
||||
#define REG_JOYTR *(vu32*)(REG_BASE+0x0154)
|
||||
#define REG_JOYTR_L *(vu16*)(REG_BASE+0x0154)
|
||||
#define REG_JOYTR_H *(vu16*)(REG_BASE+0x0156)
|
||||
#define REG_JSTAT *(vu16*)(REG_BASE+0x0158)
|
||||
|
||||
#define REG_WSCNT *(vu16*)(REG_BASE+0x0204)
|
||||
|
||||
/*! \} */
|
||||
|
||||
#endif // TONC_MEMMAP
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,231 @@
|
|||
//
|
||||
// Basic video functions
|
||||
//
|
||||
//! \file tonc_oam.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060604 - 20060604
|
||||
//
|
||||
// === NOTES ===
|
||||
// * Basic video-IO, color, background and object functionality
|
||||
|
||||
#ifndef TONC_OAM
|
||||
#define TONC_OAM
|
||||
|
||||
#include "tonc_memmap.h"
|
||||
#include "tonc_memdef.h"
|
||||
#include "tonc_core.h"
|
||||
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||
#include "tonc_math_stub.h"
|
||||
#else
|
||||
#include "tonc_math.h"
|
||||
#endif
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// OBJECTS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
//! \addtogroup grpVideoObj
|
||||
/*! \{ */
|
||||
|
||||
#define OAM_CLEAR() memset32(oam_mem, 0, OAM_SIZE/4)
|
||||
|
||||
// --- Prototypes -----------------------------------------------------
|
||||
|
||||
// --- Full OAM ---
|
||||
void oam_init(OBJ_ATTR *obj, uint count);
|
||||
INLINE void oam_copy(OBJ_ATTR *dst, const OBJ_ATTR *src, uint count);
|
||||
|
||||
// --- Obj attr only ---
|
||||
INLINE OBJ_ATTR *obj_set_attr(OBJ_ATTR *obj, u16 a0, u16 a1, u16 a2);
|
||||
INLINE void obj_set_pos(OBJ_ATTR *obj, int x, int y);
|
||||
INLINE void obj_hide(OBJ_ATTR *oatr);
|
||||
INLINE void obj_unhide(OBJ_ATTR *obj, u16 mode);
|
||||
|
||||
INLINE const u8 *obj_get_size(const OBJ_ATTR *obj);
|
||||
INLINE int obj_get_width(const OBJ_ATTR *obj);
|
||||
INLINE int obj_get_height(const OBJ_ATTR *obj);
|
||||
|
||||
void obj_copy(OBJ_ATTR *dst, const OBJ_ATTR *src, uint count);
|
||||
void obj_hide_multi(OBJ_ATTR *obj, u32 count);
|
||||
void obj_unhide_multi(OBJ_ATTR *obj, u16 mode, uint count);
|
||||
|
||||
// --- Obj affine only ---
|
||||
void obj_aff_copy(OBJ_AFFINE *dst, const OBJ_AFFINE *src, uint count);
|
||||
|
||||
INLINE void obj_aff_set(OBJ_AFFINE *oaff,
|
||||
FIXED pa, FIXED pb, FIXED pc, FIXED pd);
|
||||
INLINE void obj_aff_identity(OBJ_AFFINE *oaff);
|
||||
INLINE void obj_aff_scale(OBJ_AFFINE *oaff, FIXED sx, FIXED sy);
|
||||
INLINE void obj_aff_shearx(OBJ_AFFINE *oaff, FIXED hx);
|
||||
INLINE void obj_aff_sheary(OBJ_AFFINE *oaff, FIXED hy);
|
||||
|
||||
void obj_aff_rotate(OBJ_AFFINE *oaff, u16 alpha);
|
||||
void obj_aff_rotscale(OBJ_AFFINE *oaff, FIXED sx, FIXED sy, u16 alpha);
|
||||
void obj_aff_premul(OBJ_AFFINE *dst, const OBJ_AFFINE *src);
|
||||
void obj_aff_postmul(OBJ_AFFINE *dst, const OBJ_AFFINE *src);
|
||||
|
||||
void obj_aff_rotscale2(OBJ_AFFINE *oaff, const AFF_SRC *as);
|
||||
void obj_rotscale_ex(OBJ_ATTR *obj, OBJ_AFFINE *oaff, const AFF_SRC_EX *asx);
|
||||
|
||||
|
||||
// inverse (object -> screen) functions, could be useful
|
||||
// inverses (prototypes)
|
||||
INLINE void obj_aff_scale_inv(OBJ_AFFINE *oa, FIXED wx, FIXED wy);
|
||||
INLINE void obj_aff_rotate_inv(OBJ_AFFINE *oa, u16 theta);
|
||||
INLINE void obj_aff_shearx_inv(OBJ_AFFINE *oa, FIXED hx);
|
||||
INLINE void obj_aff_sheary_inv(OBJ_AFFINE *oa, FIXED hy);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// INLINES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpVideoObj */
|
||||
/*! \{ */
|
||||
|
||||
//! Set the attributes of an object.
|
||||
INLINE OBJ_ATTR *obj_set_attr(OBJ_ATTR *obj, u16 a0, u16 a1, u16 a2)
|
||||
{
|
||||
obj->attr0= a0; obj->attr1= a1; obj->attr2= a2;
|
||||
return obj;
|
||||
}
|
||||
|
||||
//! Set the position of \a obj
|
||||
INLINE void obj_set_pos(OBJ_ATTR *obj, int x, int y)
|
||||
{
|
||||
BFN_SET(obj->attr0, y, ATTR0_Y);
|
||||
BFN_SET(obj->attr1, x, ATTR1_X);
|
||||
}
|
||||
|
||||
//! Copies \a count OAM entries from \a src to \a dst.
|
||||
INLINE void oam_copy(OBJ_ATTR *dst, const OBJ_ATTR *src, uint count)
|
||||
{ memcpy32(dst, src, count*2); }
|
||||
|
||||
//! Hide an object.
|
||||
INLINE void obj_hide(OBJ_ATTR *obj)
|
||||
{ BFN_SET2(obj->attr0, ATTR0_HIDE, ATTR0_MODE); }
|
||||
|
||||
//! Unhide an object.
|
||||
/*! \param obj Object to unhide.
|
||||
* \param mode Object mode to unhide to. Necessary because this affects
|
||||
* the affine-ness of the object.
|
||||
*/
|
||||
INLINE void obj_unhide(OBJ_ATTR *obj, u16 mode)
|
||||
{ BFN_SET2(obj->attr0, mode, ATTR0_MODE); }
|
||||
|
||||
|
||||
//! Get object's sizes as a byte array
|
||||
INLINE const u8 *obj_get_size(const OBJ_ATTR *obj)
|
||||
{ return oam_sizes[obj->attr0>>14][obj->attr1>>14]; }
|
||||
|
||||
//! Get object's width
|
||||
INLINE int obj_get_width(const OBJ_ATTR *obj)
|
||||
{ return obj_get_size(obj)[0]; }
|
||||
|
||||
//! Gets object's height
|
||||
INLINE int obj_get_height(const OBJ_ATTR *obj)
|
||||
{ return obj_get_size(obj)[1]; }
|
||||
|
||||
|
||||
// --- Affine only ---
|
||||
|
||||
|
||||
//! Set the elements of an \a object affine matrix.
|
||||
INLINE void obj_aff_set(OBJ_AFFINE *oaff,
|
||||
FIXED pa, FIXED pb, FIXED pc, FIXED pd)
|
||||
{
|
||||
oaff->pa= pa; oaff->pb= pb;
|
||||
oaff->pc= pc; oaff->pd= pd;
|
||||
}
|
||||
|
||||
//! Set an object affine matrix to the identity matrix
|
||||
INLINE void obj_aff_identity(OBJ_AFFINE *oaff)
|
||||
{
|
||||
oaff->pa= 0x0100l; oaff->pb= 0;
|
||||
oaff->pc= 0; oaff->pd= 0x0100;
|
||||
}
|
||||
|
||||
//! Set an object affine matrix for scaling.
|
||||
INLINE void obj_aff_scale(OBJ_AFFINE *oaff, FIXED sx, FIXED sy)
|
||||
{
|
||||
oaff->pa= sx; oaff->pb= 0;
|
||||
oaff->pb= 0; oaff->pd= sy;
|
||||
}
|
||||
|
||||
INLINE void obj_aff_shearx(OBJ_AFFINE *oaff, FIXED hx)
|
||||
{
|
||||
oaff->pa= 0x0100; oaff->pb= hx;
|
||||
oaff->pc= 0; oaff->pd= 0x0100;
|
||||
}
|
||||
|
||||
INLINE void obj_aff_sheary(OBJ_AFFINE *oaff, FIXED hy)
|
||||
{
|
||||
oaff->pa= 0x0100; oaff->pb= 0;
|
||||
oaff->pc= hy; oaff->pd= 0x0100;
|
||||
}
|
||||
|
||||
|
||||
// --- Inverse operations ---
|
||||
|
||||
INLINE void obj_aff_scale_inv(OBJ_AFFINE *oaff, FIXED wx, FIXED wy)
|
||||
{ obj_aff_scale(oaff, ((1<<24)/wx)>>8, ((1<<24)/wy)>>8); }
|
||||
|
||||
INLINE void obj_aff_rotate_inv(OBJ_AFFINE *oaff, u16 theta)
|
||||
{ obj_aff_rotate(oaff, -theta); }
|
||||
|
||||
INLINE void obj_aff_shearx_inv(OBJ_AFFINE *oaff, FIXED hx)
|
||||
{ obj_aff_shearx(oaff, -hx); }
|
||||
|
||||
INLINE void obj_aff_sheary_inv(OBJ_AFFINE *oaff, FIXED hy)
|
||||
{ obj_aff_sheary(oaff, -hy); }
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
void obj_aff_copy(OBJ_AFFINE *dst, const OBJ_AFFINE *src, u32 count)
|
||||
{
|
||||
int ii;
|
||||
for(ii=0; ii<count; ii++)
|
||||
{
|
||||
dst->pa= src->pa;
|
||||
dst->pb= src->pb;
|
||||
dst->pc= src->pc;
|
||||
dst->pd= src->pd;
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
//! Set obj matrix to counter-clockwise rotation.
|
||||
/*!
|
||||
\param oaff Object affine struct to set.
|
||||
\param alpha CCW angle. full-circle is 10000h.
|
||||
*/
|
||||
void obj_aff_rotate(OBJ_AFFINE *oaff, u16 alpha)
|
||||
{
|
||||
int ss= lu_sin(alpha)>>4, cc= lu_cos(alpha)>>4;
|
||||
oaff->pa= cc; oaff->pb= -ss;
|
||||
oaff->pc= ss; oaff->pd= cc;
|
||||
}
|
||||
|
||||
//! Post-multiply \a dst by \a src: D= D*S
|
||||
void obj_aff_postmul(OBJ_AFFINE *dst, const OBJ_AFFINE *src)
|
||||
{
|
||||
FIXED tmp_a, tmp_b, tmp_c, tmp_d;
|
||||
tmp_a= dst->pa; tmp_b= dst->pb;
|
||||
tmp_c= dst->pc; tmp_d= dst->pd;
|
||||
|
||||
dst->pa= (tmp_a*src->pa + tmp_b*src->pc)>>8;
|
||||
dst->pb= (tmp_a*src->pb + tmp_b*src->pd)>>8;
|
||||
dst->pc= (tmp_c*src->pa + tmp_d*src->pc)>>8;
|
||||
dst->pd= (tmp_c*src->pb + tmp_d*src->pd)>>8;
|
||||
}
|
||||
|
||||
#endif // TONC_OAM
|
||||
|
|
@ -0,0 +1,377 @@
|
|||
//
|
||||
// Basic structs and typedefs
|
||||
//
|
||||
//! \file tonc_types.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20080111
|
||||
//
|
||||
// === NOTES ===
|
||||
// * When doing anything, always, ALWAYS!!! check the type.
|
||||
// Especially when you're combining things from different sources.
|
||||
// Look around on the forum and count the number of times people
|
||||
// have copied, say, from a u32 source to a u16 destination.
|
||||
|
||||
|
||||
#ifndef TONC_TYPES
|
||||
#define TONC_TYPES
|
||||
|
||||
|
||||
/*! \defgroup grpTypes Types and attributes */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// GCC ATTRIBUTES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpTypeAttr Type attributes
|
||||
* \ingroup grpTypes
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
// If you want your data in specific sections, add this
|
||||
// to your variables or functions.
|
||||
// Example:
|
||||
//
|
||||
// //Declaration
|
||||
// IWRAM_CODE void function(int x, int y, etc);
|
||||
//
|
||||
// //Definition
|
||||
// IWRAM_CODE void function(int x, int y, etc)
|
||||
// {
|
||||
// // code
|
||||
// }
|
||||
|
||||
|
||||
//! Put variable in IWRAM (default).
|
||||
#define IWRAM_DATA __attribute__((section(".iwram")))
|
||||
|
||||
//! Put variable in EWRAM.
|
||||
#define EWRAM_DATA __attribute__((section(".ewram")))
|
||||
|
||||
//! Put <b>non</b>-initialized variable in EWRAM.
|
||||
#define EWRAM_BSS __attribute__((section(".sbss")))
|
||||
|
||||
//! Put function in IWRAM.
|
||||
#define IWRAM_CODE __attribute__((section(".iwram"), long_call))
|
||||
|
||||
//! Put function in EWRAM.
|
||||
#define EWRAM_CODE __attribute__((section(".ewram"), long_call))
|
||||
|
||||
//! Force a variable to an \a n-byte boundary
|
||||
#define ALIGN(n) __attribute__((aligned(n)))
|
||||
|
||||
//! Force word alignment.
|
||||
/*! \note In the old days, GCC aggregates were always word aligned.
|
||||
In the EABI environment (devkitPro r19 and higher), they are
|
||||
aligned to their widest member. While technically a good thing,
|
||||
it may cause problems for struct-copies. If you have aggregates
|
||||
that can multiples of 4 in size but don't have word members,
|
||||
consider using this attribute to make struct-copies possible again.
|
||||
*/
|
||||
#define ALIGN4 __attribute__((aligned(4)))
|
||||
|
||||
//! Pack aggregate members
|
||||
/*! By default, members in aggregates are aligned to their native
|
||||
boundaries. Adding this prevents that. It will slow access though.
|
||||
*/
|
||||
#define PACKED __attribute__((packed))
|
||||
|
||||
//! Deprecated notice.
|
||||
/*! Indicates that this function/type/variable should not be used anymore.
|
||||
Replacements are (usually) present somewhere as well.
|
||||
*/
|
||||
#define DEPRECATED __attribute__((deprecated))
|
||||
|
||||
//! Inline function declarator
|
||||
/*! `inline' inlines the function when -O > 0 when called,
|
||||
but also creates a body for the function itself
|
||||
`static' removes the body as well
|
||||
*/
|
||||
#define INLINE static inline
|
||||
|
||||
/* \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TYPES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
// === primary typedefs ===============================================
|
||||
|
||||
/*! \defgroup grpTypePrim Primary types
|
||||
\ingroup grpTypes
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
/*! \name Base types
|
||||
Basic signed and unsigned types for 8, 16, 32 and 64-bit integers.
|
||||
<ul>
|
||||
<li>s# : signed #-bit integer. </li>
|
||||
<li>u#/u{type} : unsigned #-bit integer.</li>
|
||||
<li>e{type} : enum'ed #-bit integer.</li>
|
||||
|
||||
</ul>
|
||||
*/
|
||||
//\{
|
||||
typedef unsigned char u8, byte, uchar, echar;
|
||||
typedef unsigned short u16, hword, ushort, eshort;
|
||||
typedef unsigned int u32, word, uint, eint;
|
||||
typedef unsigned long long u64;
|
||||
|
||||
typedef signed char s8;
|
||||
typedef signed short s16;
|
||||
typedef signed int s32;
|
||||
typedef signed long long s64;
|
||||
//\}
|
||||
|
||||
/*! \name Volatile types
|
||||
* Volatile types for registers
|
||||
*/
|
||||
//\{
|
||||
typedef volatile u8 vu8;
|
||||
typedef volatile u16 vu16;
|
||||
typedef volatile u32 vu32;
|
||||
typedef volatile u64 vu64;
|
||||
|
||||
typedef volatile s8 vs8;
|
||||
typedef volatile s16 vs16;
|
||||
typedef volatile s32 vs32;
|
||||
typedef volatile s64 vs64;
|
||||
//\}
|
||||
|
||||
/*! \name Const types
|
||||
* Const types for const function aprameters
|
||||
*/
|
||||
//\{
|
||||
typedef const u8 cu8;
|
||||
typedef const u16 cu16;
|
||||
typedef const u32 cu32;
|
||||
typedef const u64 cu64;
|
||||
|
||||
typedef const s8 cs8;
|
||||
typedef const s16 cs16;
|
||||
typedef const s32 cs32;
|
||||
typedef const s64 cs64;
|
||||
//\}
|
||||
|
||||
//! 8-word type for fast struct-copies
|
||||
typedef struct { u32 data[8]; } BLOCK;
|
||||
|
||||
//! Type for consting a string as well as the pointer than points to it.
|
||||
typedef const char * const CSTR;
|
||||
|
||||
/* \} */
|
||||
|
||||
|
||||
// === secondary typedefs =============================================
|
||||
|
||||
/*! \defgroup grpTypeSec Secondary types
|
||||
* \ingroup grpTypes
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
typedef s32 FIXED; //!< Fixed point type
|
||||
typedef u16 COLOR; //!< Type for colors
|
||||
typedef u16 SCR_ENTRY, SE; //!< Type for screen entries
|
||||
typedef u8 SCR_AFF_ENTRY, SAE; //!< Type for affine screen entries
|
||||
|
||||
//! 4bpp tile type, for easy indexing and copying of 4-bit tiles
|
||||
typedef struct { u32 data[8]; } TILE, TILE4;
|
||||
|
||||
//! 8bpp tile type, for easy indexing and 8-bit tiles
|
||||
typedef struct { u32 data[16]; } TILE8;
|
||||
|
||||
|
||||
#ifndef __cplusplus
|
||||
//! Boolean type
|
||||
typedef enum { false, true } bool;
|
||||
#endif
|
||||
|
||||
#ifndef BOOL
|
||||
typedef u8 BOOL; // C++ bool == u8 too, that's why
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
// --- function pointer ---
|
||||
|
||||
typedef void (*fnptr)(void); //!< void foo() function pointer
|
||||
typedef void (*fn_v_i)(int); //!< void foo(int x) function pointer
|
||||
typedef int (*fn_i_i)(int); //!< int foo(int x) function pointer
|
||||
|
||||
|
||||
//! \name affine structs
|
||||
//\{
|
||||
//! Simple scale-rotation source struct.
|
||||
/*! This can be used with ObjAffineSet, and several of tonc's
|
||||
* affine functions
|
||||
*/
|
||||
typedef struct AFF_SRC
|
||||
{
|
||||
s16 sx; //!< Horizontal zoom (8.8f)
|
||||
s16 sy; //!< Vertical zoom (8.8f)
|
||||
u16 alpha; //!< Counter-clockwise angle ( range [0, 0xFFFF] )
|
||||
} ALIGN4 AFF_SRC, ObjAffineSource;
|
||||
|
||||
|
||||
//! Extended scale-rotate source struct
|
||||
/*! This is used to scale/rotate around an arbitrary point. See
|
||||
* tonc's main text for all the details.
|
||||
*/
|
||||
typedef struct AFF_SRC_EX
|
||||
{
|
||||
s32 tex_x; //!< Texture-space anchor, x coordinate (.8f)
|
||||
s32 tex_y; //!< Texture-space anchor, y coordinate (.8f)
|
||||
s16 scr_x; //!< Screen-space anchor, x coordinate (.0f)
|
||||
s16 scr_y; //!< Screen-space anchor, y coordinate (.0f)
|
||||
s16 sx; //!< Horizontal zoom (8.8f)
|
||||
s16 sy; //!< Vertical zoom (8.8f)
|
||||
u16 alpha; //!< Counter-clockwise angle ( range [0, 0xFFFF] )
|
||||
} ALIGN4 AFF_SRC_EX, BgAffineSource;
|
||||
|
||||
//! Simple scale-rotation destination struct, BG version.
|
||||
/*! This is a P-matrix with continuous elements, like the BG matrix.
|
||||
* It can be used with ObjAffineSet.
|
||||
*/
|
||||
typedef struct AFF_DST
|
||||
{
|
||||
s16 pa, pb;
|
||||
s16 pc, pd;
|
||||
} ALIGN4 AFF_DST, ObjAffineDest;
|
||||
|
||||
//! Extended scale-rotate destination struct
|
||||
/*! This contains the P-matrix and a fixed-point offset , the
|
||||
* combination can be used to rotate around an arbitrary point.
|
||||
* Mainly intended for BgAffineSet, but the struct cna be used
|
||||
* for object transforms too.
|
||||
*/
|
||||
typedef struct AFF_DST_EX
|
||||
{
|
||||
s16 pa, pb;
|
||||
s16 pc, pd;
|
||||
s32 dx, dy;
|
||||
} ALIGN4 AFF_DST_EX, BgAffineDest;
|
||||
|
||||
//\}
|
||||
|
||||
/* \} */
|
||||
|
||||
|
||||
// === memory map structs ============================================
|
||||
|
||||
/*! \defgroup grpTypeTert Tertiary types
|
||||
* These types are used for memory mapping of VRAM, affine registers
|
||||
* and other areas that would benefit from logical memory mapping.
|
||||
* \ingroup grpTypes
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
|
||||
//! \name IO register types
|
||||
//\{
|
||||
|
||||
//! Regular bg points; range: :0010 - :001F
|
||||
typedef struct POINT16 { s16 x, y; } ALIGN4 POINT16, BG_POINT;
|
||||
|
||||
//! Affine parameters for backgrounds; range : 0400:0020 - 0400:003F
|
||||
typedef struct AFF_DST_EX BG_AFFINE;
|
||||
|
||||
//! DMA struct; range: 0400:00B0 - 0400:00DF
|
||||
typedef struct DMA_REC
|
||||
{
|
||||
const void *src;
|
||||
void *dst;
|
||||
u32 cnt;
|
||||
} DMA_REC;
|
||||
|
||||
//! Timer struct, range: 0400:0100 - 0400:010F
|
||||
/*! \note The attribute is required, because union's counted as u32 otherwise.
|
||||
*/
|
||||
typedef struct TMR_REC
|
||||
{
|
||||
union { u16 start, count; } PACKED;
|
||||
u16 cnt;
|
||||
} ALIGN4 TMR_REC;
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
//! \name PAL types
|
||||
//\{
|
||||
|
||||
//! Palette bank type, for 16-color palette banks
|
||||
typedef COLOR PALBANK[16];
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name VRAM array types
|
||||
* These types allow VRAM access as arrays or matrices in their
|
||||
* most natural types.
|
||||
*/
|
||||
//\{
|
||||
typedef SCR_ENTRY SCREENLINE[32];
|
||||
typedef SCR_ENTRY SCREENMAT[32][32];
|
||||
typedef SCR_ENTRY SCREENBLOCK[1024];
|
||||
|
||||
typedef COLOR M3LINE[240];
|
||||
typedef u8 M4LINE[240]; // NOTE: u8, not u16!!
|
||||
typedef COLOR M5LINE[160];
|
||||
|
||||
typedef TILE CHARBLOCK[512];
|
||||
typedef TILE8 CHARBLOCK8[256];
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name OAM structs
|
||||
* \note These OBJ_ATTR and OBJ_AFFINE structs are interlaced in OAM.
|
||||
* When using affine objs, struct/DMA/mem copies will give bad results.
|
||||
*/
|
||||
//\{
|
||||
|
||||
//! Object attributes.
|
||||
/*! \note attribute 3 is padding for the interlace with OBJ_AFFINE. If
|
||||
* not using affine objects, it can be used as a free field
|
||||
*/
|
||||
typedef struct OBJ_ATTR
|
||||
{
|
||||
u16 attr0;
|
||||
u16 attr1;
|
||||
u16 attr2;
|
||||
s16 fill;
|
||||
} ALIGN4 OBJ_ATTR;
|
||||
|
||||
|
||||
//! Object affine parameters.
|
||||
/*! \note most fields are padding for the interlace with OBJ_ATTR.
|
||||
*/
|
||||
typedef struct OBJ_AFFINE
|
||||
{
|
||||
u16 fill0[3]; s16 pa;
|
||||
u16 fill1[3]; s16 pb;
|
||||
u16 fill2[3]; s16 pc;
|
||||
u16 fill3[3]; s16 pd;
|
||||
} ALIGN4 OBJ_AFFINE;
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DEFINES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void*)0
|
||||
#endif
|
||||
|
||||
|
||||
#endif // TONC_TYPES
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_GBAENGINE_H
|
||||
#define GBA_SPRITE_ENGINE_GBAENGINE_H
|
||||
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memmap.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#include "scene.h"
|
||||
#include "sound_control.h"
|
||||
#include "timer.h"
|
||||
|
||||
#define GBA_SCREEN_WIDTH 240
|
||||
#define GBA_SCREEN_HEIGHT 160
|
||||
|
||||
class GBAEngine {
|
||||
private:
|
||||
// WHY raw pointers? the engine does the transition and cleanup work itself
|
||||
Scene* currentScene;
|
||||
Scene* sceneToTransitionTo;
|
||||
|
||||
static std::unique_ptr<Timer> timer;
|
||||
static std::unique_ptr<SoundControl> activeChannelA;
|
||||
static std::unique_ptr<SoundControl> activeChannelB;
|
||||
|
||||
void vsync();
|
||||
void cleanupPreviousScene();
|
||||
void enqueueSound(const s8 *data, int totalSamples, int sampleRate, SoundChannel channel);
|
||||
|
||||
void enableTimer0AndVBlank();
|
||||
void disableTimer0AndVBlank();
|
||||
static void startOnVBlank() { REG_IME = 1; }
|
||||
static void stopOnVBlank() { REG_IME = 0; }
|
||||
static void onVBlank();
|
||||
|
||||
public:
|
||||
GBAEngine();
|
||||
|
||||
Timer* getTimer();
|
||||
void setScene(Scene* scene);
|
||||
|
||||
void dequeueAllSounds();
|
||||
void enqueueMusic(const s8 *data, int totalSamples, int sampleRate = 16000) {
|
||||
enqueueSound(data, totalSamples, sampleRate, ChannelA);
|
||||
}
|
||||
void enqueueSound(const s8 *data, int totalSamples, int sampleRate = 16000) {
|
||||
enqueueSound(data, totalSamples, sampleRate, ChannelB);
|
||||
}
|
||||
|
||||
u16 readKeys();
|
||||
void update();
|
||||
void delay(int times) {
|
||||
for(int i = 0; i < times; i++){}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_GBAENGINE_H
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 14/12/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||
|
||||
#include <deque>
|
||||
|
||||
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||
#else
|
||||
#include <libgba-sprite-engine/gba/tonc_math.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
class GBAVector {
|
||||
private:
|
||||
VECTOR v;
|
||||
public:
|
||||
GBAVector() : v({}) {}
|
||||
GBAVector(VECTOR v) : v(v) {}
|
||||
|
||||
std::deque<VECTOR> bresenhamLineTo(VECTOR dest);
|
||||
VECTOR rotateAsCenter(VECTOR point, uint angle);
|
||||
|
||||
std::string to_string() {
|
||||
return "(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")";
|
||||
}
|
||||
};
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 05/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_COMBINED_PALETTE_H
|
||||
#define GBA_SPRITE_ENGINE_COMBINED_PALETTE_H
|
||||
|
||||
class PaletteManager;
|
||||
|
||||
class CombinedPalette {
|
||||
private:
|
||||
// WHY use references here? lifetimes not bound, not owned by CombinedPalette
|
||||
PaletteManager& palette1;
|
||||
PaletteManager& palette2;
|
||||
|
||||
void increaseBrightness(PaletteManager& palette, int bank, int index, u32 intensity);
|
||||
public:
|
||||
CombinedPalette(PaletteManager& one, PaletteManager& two) : palette1(one), palette2(two) {}
|
||||
CombinedPalette(const CombinedPalette& other) = delete;
|
||||
|
||||
void increaseBrightness(u32 intensity);
|
||||
};
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_COMBINED_PALETTE_H
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 27/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PALETTE_MANAGER_H
|
||||
#define GBA_SPRITE_ENGINE_PALETTE_MANAGER_H
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memmap.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||
#include "combined_palette.h"
|
||||
|
||||
#define PALETTE_BANK_SIZE 16
|
||||
#define PALETTE_MAX_SIZE 256
|
||||
|
||||
int getBits(int number, int k, int p);
|
||||
|
||||
class CombinedPalette;
|
||||
|
||||
class PaletteManager {
|
||||
protected:
|
||||
const COLOR *data;
|
||||
int size;
|
||||
|
||||
virtual void* paletteAddress() = 0;
|
||||
virtual PALBANK* paletteBank() = 0;
|
||||
public:
|
||||
PaletteManager();
|
||||
PaletteManager(const COLOR paletteData[]) : PaletteManager(paletteData, PALETTE_MAX_SIZE) {}
|
||||
PaletteManager(const COLOR paletteData[], int size);
|
||||
|
||||
CombinedPalette* operator+(const PaletteManager& other);
|
||||
|
||||
void persist();
|
||||
void persistToBank(int bank);
|
||||
COLOR change(int bank, int index, COLOR newColor);
|
||||
COLOR get(int bank, int index) { return paletteBank()[bank][index]; }
|
||||
void increaseBrightness(u32 intensity);
|
||||
|
||||
static COLOR modify(COLOR color, u32 intensity);
|
||||
static COLOR color(u32 r, u32 g, u32 b);
|
||||
static u32 red(COLOR r);
|
||||
static u32 green(COLOR r);
|
||||
static u32 blue(COLOR r);
|
||||
};
|
||||
|
||||
class BackgroundPaletteManager : public PaletteManager {
|
||||
protected:
|
||||
void *paletteAddress() override {
|
||||
return pal_bg_mem;
|
||||
}
|
||||
|
||||
PALBANK *paletteBank() override {
|
||||
return pal_bg_bank;
|
||||
}
|
||||
|
||||
public:
|
||||
BackgroundPaletteManager() : PaletteManager() {}
|
||||
BackgroundPaletteManager(const COLOR paletteData[]) : PaletteManager(paletteData) {}
|
||||
BackgroundPaletteManager(const COLOR paletteData[], int size) : PaletteManager(paletteData, size) {}
|
||||
};
|
||||
|
||||
|
||||
class ForegroundPaletteManager : public PaletteManager {
|
||||
protected:
|
||||
void *paletteAddress() override {
|
||||
return pal_obj_mem;
|
||||
}
|
||||
|
||||
PALBANK *paletteBank() override {
|
||||
return pal_obj_bank;
|
||||
}
|
||||
|
||||
public:
|
||||
ForegroundPaletteManager() : PaletteManager() {}
|
||||
ForegroundPaletteManager(const COLOR paletteData[]) : PaletteManager(paletteData) {}
|
||||
ForegroundPaletteManager(const COLOR paletteData[], int size) : PaletteManager(paletteData, size) {}
|
||||
};
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_PALETTE_MANAGER_H
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SCRENE_H
|
||||
#define GBA_SPRITE_ENGINE_SCRENE_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
|
||||
class GBAEngine;
|
||||
|
||||
class Scene {
|
||||
protected:
|
||||
std::unique_ptr<ForegroundPaletteManager> foregroundPalette;
|
||||
std::unique_ptr<BackgroundPaletteManager> backgroundPalette;
|
||||
std::shared_ptr<GBAEngine> engine;
|
||||
|
||||
public:
|
||||
ForegroundPaletteManager* getForegroundPalette() { return foregroundPalette.get(); }
|
||||
BackgroundPaletteManager* getBackgroundPalette() { return backgroundPalette.get(); }
|
||||
|
||||
virtual void load() = 0;
|
||||
virtual void tick(u16 keys) = 0;
|
||||
|
||||
Scene(std::shared_ptr<GBAEngine> engine) :
|
||||
engine(engine),
|
||||
foregroundPalette(std::unique_ptr<ForegroundPaletteManager>(new ForegroundPaletteManager())),
|
||||
backgroundPalette(std::unique_ptr<BackgroundPaletteManager>(new BackgroundPaletteManager())) { }
|
||||
virtual ~Scene() {
|
||||
// scenes should manage their own resources - use std::unique_ptr
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_SCRENE_H
|
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 07/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SOUND_H
|
||||
#define GBA_SPRITE_ENGINE_SOUND_H
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#include <memory>
|
||||
#include <libgba-sprite-engine/gba/tonc_memmap.h>
|
||||
|
||||
#define CLOCK 16777216
|
||||
#define CYCLES_PER_BLANK 280806
|
||||
#define OVERFLOW_16_BIT_VALUE 65536
|
||||
#define DISPLAY_INTERRUPT_VBLANK_ENABLE 0x08
|
||||
#define INTERRUPT_VBLANK 0x1
|
||||
#define DMA_SYNC_TO_TIMER 0x30000000
|
||||
|
||||
#define IRQ_CALLBACK ((volatile unsigned int*) 0x3007FFC)
|
||||
|
||||
enum SoundChannel {
|
||||
ChannelA, ChannelB
|
||||
};
|
||||
|
||||
class SoundControl {
|
||||
private:
|
||||
vu32* DMAControl; // ex. ®_DMA1CNT
|
||||
vu32* DMASourceAddress; // ex. ®_DMA1SAD
|
||||
vu32* DMADestinationAddress; // ex. ®_DMA1DAD
|
||||
vu32* FiFoBuffer; // ex. ®_FIFOA
|
||||
u16 controlFlags;
|
||||
u32 vblanksRemaning; // updated each vblank, counts down to 0
|
||||
u32 vblanksTotal; // calculated once when enqueueing
|
||||
|
||||
const void* data;
|
||||
|
||||
public:
|
||||
SoundControl(vu32* dma, vu32* src, vu32* dest, vu32* fifo, u16 flags)
|
||||
: DMAControl(dma), DMASourceAddress(src), DMADestinationAddress(dest), FiFoBuffer(fifo), controlFlags(flags), vblanksRemaning(0), vblanksTotal(0) {}
|
||||
|
||||
u16 getControlFlags() { return controlFlags; }
|
||||
u32 getVBlanksRemaning() { return vblanksRemaning; }
|
||||
void reset();
|
||||
void step() { vblanksRemaning--; }
|
||||
bool done() { return vblanksRemaning <= 0; }
|
||||
u32 getVBlanksTotal() { return vblanksTotal; }
|
||||
|
||||
void disable() {
|
||||
*(DMAControl) = 0;
|
||||
vblanksRemaning = 0;
|
||||
REG_SNDDSCNT &= ~(controlFlags);
|
||||
};
|
||||
void enable() {
|
||||
*DMAControl = DMA_DST_FIXED | DMA_REPEAT | DMA_32 | DMA_SYNC_TO_TIMER | DMA_ENABLE;
|
||||
};
|
||||
void accept(const void* data, int totalSamples, int ticksPerSample);
|
||||
|
||||
static std::unique_ptr<SoundControl> channelAControl();
|
||||
static std::unique_ptr<SoundControl> channelBControl();
|
||||
|
||||
static std::unique_ptr<SoundControl> soundControl(SoundChannel channel) {
|
||||
return channel == ChannelA ? channelAControl() : channelBControl();
|
||||
};
|
||||
};
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_SOUND_H
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 06/12/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_TIMER_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_TIMER_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
class Timer {
|
||||
private:
|
||||
int microsecs, msecs, secs, minutes, hours;
|
||||
bool active;
|
||||
|
||||
public:
|
||||
|
||||
Timer() : active(false) {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset();
|
||||
void start();
|
||||
void toggle() {
|
||||
if(isActive()) stop();
|
||||
else start();
|
||||
}
|
||||
bool isActive() { return active; }
|
||||
void stop();
|
||||
void onvblank();
|
||||
|
||||
std::string to_string();
|
||||
|
||||
int getTotalMsecs();
|
||||
int getMsecs() { return msecs; }
|
||||
int getSecs() { return secs; }
|
||||
int getMinutes() { return minutes; }
|
||||
int getHours() { return hours; }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, Timer& timer);
|
||||
};
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_PROJECT_TIMER_H
|
|
@ -0,0 +1,90 @@
|
|||
@ ======================================================================
|
||||
@ Look-Up Tables
|
||||
@ sin_lut: sin(x*pi/256)
|
||||
@
|
||||
@ Exported by Cearn's excellut v1.0
|
||||
@ (comments, kudos, flames to daytshen@hotmail.com)
|
||||
@
|
||||
@ ======================================================================
|
||||
|
||||
.section .rodata
|
||||
@ -----------------------------------------------------------------------
|
||||
@ sin_lut: a 514 long LUT of 16bit values in 4.12 format
|
||||
@ sin(x*pi/256)
|
||||
.global sin_lut
|
||||
.align 2
|
||||
sin_lut:
|
||||
.hword 0x0000,0x0032,0x0064,0x0096,0x00C8,0x00FB,0x012D,0x015F
|
||||
.hword 0x0191,0x01C3,0x01F5,0x0227,0x0259,0x028A,0x02BC,0x02ED
|
||||
.hword 0x031F,0x0350,0x0381,0x03B2,0x03E3,0x0413,0x0444,0x0474
|
||||
.hword 0x04A5,0x04D5,0x0504,0x0534,0x0563,0x0593,0x05C2,0x05F0
|
||||
.hword 0x061F,0x064D,0x067B,0x06A9,0x06D7,0x0704,0x0731,0x075E
|
||||
.hword 0x078A,0x07B7,0x07E2,0x080E,0x0839,0x0864,0x088F,0x08B9
|
||||
.hword 0x08E3,0x090D,0x0936,0x095F,0x0987,0x09B0,0x09D7,0x09FF
|
||||
.hword 0x0A26,0x0A4D,0x0A73,0x0A99,0x0ABE,0x0AE3,0x0B08,0x0B2C
|
||||
|
||||
.hword 0x0B50,0x0B73,0x0B96,0x0BB8,0x0BDA,0x0BFC,0x0C1D,0x0C3E
|
||||
.hword 0x0C5E,0x0C7D,0x0C9D,0x0CBB,0x0CD9,0x0CF7,0x0D14,0x0D31
|
||||
.hword 0x0D4D,0x0D69,0x0D84,0x0D9F,0x0DB9,0x0DD2,0x0DEB,0x0E04
|
||||
.hword 0x0E1C,0x0E33,0x0E4A,0x0E60,0x0E76,0x0E8B,0x0EA0,0x0EB4
|
||||
.hword 0x0EC8,0x0EDB,0x0EED,0x0EFF,0x0F10,0x0F21,0x0F31,0x0F40
|
||||
.hword 0x0F4F,0x0F5D,0x0F6B,0x0F78,0x0F85,0x0F91,0x0F9C,0x0FA7
|
||||
.hword 0x0FB1,0x0FBA,0x0FC3,0x0FCB,0x0FD3,0x0FDA,0x0FE1,0x0FE7
|
||||
.hword 0x0FEC,0x0FF0,0x0FF4,0x0FF8,0x0FFB,0x0FFD,0x0FFE,0x0FFF
|
||||
|
||||
.hword 0x1000,0x0FFF,0x0FFE,0x0FFD,0x0FFB,0x0FF8,0x0FF4,0x0FF0
|
||||
.hword 0x0FEC,0x0FE7,0x0FE1,0x0FDA,0x0FD3,0x0FCB,0x0FC3,0x0FBA
|
||||
.hword 0x0FB1,0x0FA7,0x0F9C,0x0F91,0x0F85,0x0F78,0x0F6B,0x0F5D
|
||||
.hword 0x0F4F,0x0F40,0x0F31,0x0F21,0x0F10,0x0EFF,0x0EED,0x0EDB
|
||||
.hword 0x0EC8,0x0EB4,0x0EA0,0x0E8B,0x0E76,0x0E60,0x0E4A,0x0E33
|
||||
.hword 0x0E1C,0x0E04,0x0DEB,0x0DD2,0x0DB9,0x0D9F,0x0D84,0x0D69
|
||||
.hword 0x0D4D,0x0D31,0x0D14,0x0CF7,0x0CD9,0x0CBB,0x0C9D,0x0C7D
|
||||
.hword 0x0C5E,0x0C3E,0x0C1D,0x0BFC,0x0BDA,0x0BB8,0x0B96,0x0B73
|
||||
|
||||
.hword 0x0B50,0x0B2C,0x0B08,0x0AE3,0x0ABE,0x0A99,0x0A73,0x0A4D
|
||||
.hword 0x0A26,0x09FF,0x09D7,0x09B0,0x0987,0x095F,0x0936,0x090D
|
||||
.hword 0x08E3,0x08B9,0x088F,0x0864,0x0839,0x080E,0x07E2,0x07B7
|
||||
.hword 0x078A,0x075E,0x0731,0x0704,0x06D7,0x06A9,0x067B,0x064D
|
||||
.hword 0x061F,0x05F0,0x05C2,0x0593,0x0563,0x0534,0x0504,0x04D5
|
||||
.hword 0x04A5,0x0474,0x0444,0x0413,0x03E3,0x03B2,0x0381,0x0350
|
||||
.hword 0x031F,0x02ED,0x02BC,0x028A,0x0259,0x0227,0x01F5,0x01C3
|
||||
.hword 0x0191,0x015F,0x012D,0x00FB,0x00C8,0x0096,0x0064,0x0032
|
||||
|
||||
.hword 0x0000,0xFFCE,0xFF9C,0xFF6A,0xFF38,0xFF05,0xFED3,0xFEA1
|
||||
.hword 0xFE6F,0xFE3D,0xFE0B,0xFDD9,0xFDA7,0xFD76,0xFD44,0xFD13
|
||||
.hword 0xFCE1,0xFCB0,0xFC7F,0xFC4E,0xFC1D,0xFBED,0xFBBC,0xFB8C
|
||||
.hword 0xFB5B,0xFB2B,0xFAFC,0xFACC,0xFA9D,0xFA6D,0xFA3E,0xFA10
|
||||
.hword 0xF9E1,0xF9B3,0xF985,0xF957,0xF929,0xF8FC,0xF8CF,0xF8A2
|
||||
.hword 0xF876,0xF849,0xF81E,0xF7F2,0xF7C7,0xF79C,0xF771,0xF747
|
||||
.hword 0xF71D,0xF6F3,0xF6CA,0xF6A1,0xF679,0xF650,0xF629,0xF601
|
||||
.hword 0xF5DA,0xF5B3,0xF58D,0xF567,0xF542,0xF51D,0xF4F8,0xF4D4
|
||||
|
||||
.hword 0xF4B0,0xF48D,0xF46A,0xF448,0xF426,0xF404,0xF3E3,0xF3C2
|
||||
.hword 0xF3A2,0xF383,0xF363,0xF345,0xF327,0xF309,0xF2EC,0xF2CF
|
||||
.hword 0xF2B3,0xF297,0xF27C,0xF261,0xF247,0xF22E,0xF215,0xF1FC
|
||||
.hword 0xF1E4,0xF1CD,0xF1B6,0xF1A0,0xF18A,0xF175,0xF160,0xF14C
|
||||
.hword 0xF138,0xF125,0xF113,0xF101,0xF0F0,0xF0DF,0xF0CF,0xF0C0
|
||||
.hword 0xF0B1,0xF0A3,0xF095,0xF088,0xF07B,0xF06F,0xF064,0xF059
|
||||
.hword 0xF04F,0xF046,0xF03D,0xF035,0xF02D,0xF026,0xF01F,0xF019
|
||||
.hword 0xF014,0xF010,0xF00C,0xF008,0xF005,0xF003,0xF002,0xF001
|
||||
|
||||
.hword 0xF000,0xF001,0xF002,0xF003,0xF005,0xF008,0xF00C,0xF010
|
||||
.hword 0xF014,0xF019,0xF01F,0xF026,0xF02D,0xF035,0xF03D,0xF046
|
||||
.hword 0xF04F,0xF059,0xF064,0xF06F,0xF07B,0xF088,0xF095,0xF0A3
|
||||
.hword 0xF0B1,0xF0C0,0xF0CF,0xF0DF,0xF0F0,0xF101,0xF113,0xF125
|
||||
.hword 0xF138,0xF14C,0xF160,0xF175,0xF18A,0xF1A0,0xF1B6,0xF1CD
|
||||
.hword 0xF1E4,0xF1FC,0xF215,0xF22E,0xF247,0xF261,0xF27C,0xF297
|
||||
.hword 0xF2B3,0xF2CF,0xF2EC,0xF309,0xF327,0xF345,0xF363,0xF383
|
||||
.hword 0xF3A2,0xF3C2,0xF3E3,0xF404,0xF426,0xF448,0xF46A,0xF48D
|
||||
|
||||
.hword 0xF4B0,0xF4D4,0xF4F8,0xF51D,0xF542,0xF567,0xF58D,0xF5B3
|
||||
.hword 0xF5DA,0xF601,0xF629,0xF650,0xF679,0xF6A1,0xF6CA,0xF6F3
|
||||
.hword 0xF71D,0xF747,0xF771,0xF79C,0xF7C7,0xF7F2,0xF81E,0xF849
|
||||
.hword 0xF876,0xF8A2,0xF8CF,0xF8FC,0xF929,0xF957,0xF985,0xF9B3
|
||||
.hword 0xF9E1,0xFA10,0xFA3E,0xFA6D,0xFA9D,0xFACC,0xFAFC,0xFB2B
|
||||
.hword 0xFB5B,0xFB8C,0xFBBC,0xFBED,0xFC1D,0xFC4E,0xFC7F,0xFCB0
|
||||
.hword 0xFCE1,0xFD13,0xFD44,0xFD76,0xFDA7,0xFDD9,0xFE0B,0xFE3D
|
||||
.hword 0xFE6F,0xFEA1,0xFED3,0xFF05,0xFF38,0xFF6A,0xFF9C,0xFFCE
|
||||
.hword 0x0000,0x0032
|
||||
|
||||
.size sin_lut, .-sin_lut
|
|
@ -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)
|
|
@ -0,0 +1,150 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
|
||||
std::unique_ptr<SoundControl> GBAEngine::activeChannelA;
|
||||
std::unique_ptr<SoundControl> GBAEngine::activeChannelB;
|
||||
std::unique_ptr<Timer> GBAEngine::timer;
|
||||
|
||||
void GBAEngine::vsync() {
|
||||
while (REG_VCOUNT >= 160);
|
||||
while (REG_VCOUNT < 160);
|
||||
}
|
||||
|
||||
Timer* GBAEngine::getTimer() {
|
||||
return GBAEngine::timer.get();
|
||||
}
|
||||
|
||||
void GBAEngine::onVBlank() {
|
||||
// WARNING this is a very dangerous piece of code.
|
||||
// GBA IRQs seem eager to crash or eat up CPU. Get in, disable stuff, work, enable, get out!
|
||||
stopOnVBlank();
|
||||
|
||||
unsigned short tempInterruptState = REG_IF;
|
||||
|
||||
if((REG_IF & INTERRUPT_VBLANK) == INTERRUPT_VBLANK) {
|
||||
GBAEngine::timer->onvblank();
|
||||
|
||||
if(GBAEngine::activeChannelA) {
|
||||
if(GBAEngine::activeChannelA->done()) {
|
||||
GBAEngine::activeChannelA->reset();
|
||||
} else {
|
||||
GBAEngine::activeChannelA->step();
|
||||
}
|
||||
}
|
||||
if(GBAEngine::activeChannelB) {
|
||||
if(GBAEngine::activeChannelB->done()) {
|
||||
GBAEngine::activeChannelB->disable();
|
||||
GBAEngine::activeChannelB = nullptr; // never delete, let unique_ptr do that, known to flip here
|
||||
} else {
|
||||
GBAEngine::activeChannelB->step();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REG_IF = tempInterruptState;
|
||||
startOnVBlank();
|
||||
}
|
||||
|
||||
u16 GBAEngine::readKeys() {
|
||||
return ~REG_KEYS & KEY_ANY;
|
||||
}
|
||||
|
||||
void GBAEngine::dequeueAllSounds() {
|
||||
if(GBAEngine::activeChannelA) {
|
||||
GBAEngine::activeChannelA->disable();
|
||||
} if(GBAEngine::activeChannelB) {
|
||||
GBAEngine::activeChannelB->disable();
|
||||
}
|
||||
}
|
||||
|
||||
void GBAEngine::enqueueSound(const s8 *data, int totalSamples, int sampleRate, SoundChannel channel) {
|
||||
SoundControl* control;
|
||||
|
||||
if(channel == ChannelA) { // repeating bg music can be restarted
|
||||
GBAEngine::activeChannelA = SoundControl::channelAControl();
|
||||
control = GBAEngine::activeChannelA.get();
|
||||
} else { // sound still playing, don't stop that
|
||||
if(GBAEngine::activeChannelB) {
|
||||
if(!GBAEngine::activeChannelB->done()) return;
|
||||
GBAEngine::activeChannelB = nullptr;
|
||||
}
|
||||
GBAEngine::activeChannelB = SoundControl::channelBControl();
|
||||
control = GBAEngine::activeChannelB.get();
|
||||
}
|
||||
|
||||
disableTimer0AndVBlank();
|
||||
control->disable();
|
||||
|
||||
REG_SNDDSCNT |= control->getControlFlags(); // output to both sides, reset fifo
|
||||
REG_SNDSTAT = SSTAT_ENABLE; // enable all sound
|
||||
u16 ticksPerSample = CLOCK / sampleRate; // divide the clock (ticks/second) by the sample rate (samples/second)
|
||||
|
||||
control->accept(data, totalSamples, ticksPerSample);
|
||||
control->enable();
|
||||
|
||||
REG_TM0D = OVERFLOW_16_BIT_VALUE - ticksPerSample;
|
||||
|
||||
enableTimer0AndVBlank();
|
||||
}
|
||||
|
||||
void GBAEngine::disableTimer0AndVBlank() {
|
||||
stopOnVBlank();
|
||||
REG_TM0CNT = 0;
|
||||
}
|
||||
|
||||
void GBAEngine::enableTimer0AndVBlank() {
|
||||
REG_TM0CNT = TM_ENABLE | TM_FREQ_1; // enable timer - dma auto-syncs to this thanks to DMA_SYNC_TO_TIMER
|
||||
startOnVBlank();
|
||||
}
|
||||
|
||||
GBAEngine::GBAEngine() {
|
||||
GBAEngine::timer = std::unique_ptr<Timer>(new Timer());
|
||||
// setup screen control flags
|
||||
REG_DISPCNT = DCNT_MODE4 | DCNT_OBJ | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_BG3;
|
||||
|
||||
// setup interrupt control flags for vblank IRQing (started only when sound played)
|
||||
REG_DISPSTAT |= DISPLAY_INTERRUPT_VBLANK_ENABLE;
|
||||
REG_IE |= INTERRUPT_VBLANK;
|
||||
*IRQ_CALLBACK = (u32) &GBAEngine::onVBlank;
|
||||
|
||||
enableTimer0AndVBlank();
|
||||
|
||||
REG_SNDDSCNT = 0;
|
||||
}
|
||||
|
||||
void GBAEngine::update() {
|
||||
// main update loop, in while(true) {}.
|
||||
// WARNING - keep amount of instructions as minimal as possible in here!
|
||||
|
||||
u16 keys = readKeys();
|
||||
// main scene update loop call. This *might* take a while.
|
||||
currentScene->tick(keys);
|
||||
|
||||
// TODO use software interrupt Vsyncing instead of 2 wasteful whiles
|
||||
vsync();
|
||||
}
|
||||
|
||||
void GBAEngine::cleanupPreviousScene() {
|
||||
delete currentScene;
|
||||
sceneToTransitionTo = nullptr;
|
||||
}
|
||||
|
||||
void GBAEngine::setScene(Scene* scene) {
|
||||
dequeueAllSounds();
|
||||
|
||||
if(this->currentScene) {
|
||||
cleanupPreviousScene();
|
||||
}
|
||||
scene->load();
|
||||
|
||||
auto fgPalette = scene->getForegroundPalette();
|
||||
fgPalette->persist();
|
||||
auto bgPalette = scene->getBackgroundPalette();
|
||||
bgPalette->persist();
|
||||
|
||||
this->currentScene = scene;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 14/12/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/gbavector.h>
|
||||
|
||||
VECTOR GBAVector::rotateAsCenter(VECTOR point, uint angle) {
|
||||
auto center = this->v;
|
||||
s32 centerx = center.x, centery = center.y;
|
||||
s32 defaultx = point.x, defaulty = point.y;
|
||||
|
||||
s32 cos = lu_cos(angle) >> 4;
|
||||
s32 sin = lu_sin(angle) >> 4;
|
||||
|
||||
// affine matriches are 8.8 fixed point numbers, so shift all input 8 spaces up and forth
|
||||
// possibilities: instead of between [-1.0, 1.0] it's between [-256, +256]
|
||||
// 90° rotation in inversed y-axis needs to flip sin sign
|
||||
return {
|
||||
( cos * (defaultx - centerx) + sin * (defaulty - centery) + (centerx << 8)) >> 8,
|
||||
(-sin * (defaultx - centerx) + cos * (defaulty - centery) + (centery << 8)) >> 8};
|
||||
}
|
||||
|
||||
std::deque<VECTOR> GBAVector::bresenhamLineTo(VECTOR dest) {
|
||||
// https://www.coranac.com/tonc/text/bitmaps.htm - Bresenham's line algorithm with fixed points
|
||||
VECTOR src = this->v;
|
||||
VECTOR step, delta;
|
||||
|
||||
std::deque<VECTOR> coords;
|
||||
|
||||
if(src.x > dest.x) {
|
||||
step.x = -1;
|
||||
delta.x = (src.x - dest.x);
|
||||
} else {
|
||||
step.x = +1;
|
||||
delta.x = (dest.x - src.x);
|
||||
}
|
||||
if(src.y > dest.y) {
|
||||
step.y = -1;
|
||||
delta.y = (src.y - dest.y);
|
||||
} else {
|
||||
step.y = +1;
|
||||
delta.y = (dest.y - src.y);
|
||||
}
|
||||
|
||||
int dd, x = src.x, y = src.y, ii;
|
||||
|
||||
if(delta.y == 0) {
|
||||
// horizontal
|
||||
for(ii = 0; ii <= delta.x; ii++) {
|
||||
coords.push_back({x, y});
|
||||
x += step.x;
|
||||
}
|
||||
} else if(delta.x == 0) {
|
||||
// vertical
|
||||
for(ii = 0; ii <= delta.y; ii++) {
|
||||
coords.push_back({x, y});
|
||||
y += step.y;
|
||||
}
|
||||
} else if(delta.x >= delta.y) {
|
||||
// Diagonal, slope <= 1
|
||||
dd = 2 * delta.y - delta.x;
|
||||
|
||||
for(ii = 0; ii <= delta.x; ii++) {
|
||||
coords.push_back({x, y});
|
||||
if(dd >= 0) {
|
||||
dd -= 2 * delta.x;
|
||||
y += step.y;
|
||||
}
|
||||
dd += 2 * delta.y;
|
||||
x += step.x;
|
||||
}
|
||||
} else {
|
||||
// Diagonal, slope > 1
|
||||
dd = 2 * delta.x - delta.y;
|
||||
|
||||
for(ii = 0; ii <= delta.y; ii++) {
|
||||
coords.push_back({x, y});
|
||||
if(dd >= 0) {
|
||||
dd -= 2 * delta.y;
|
||||
x += step.x;
|
||||
}
|
||||
dd += 2 * delta.x;
|
||||
y += step.y;
|
||||
}
|
||||
}
|
||||
|
||||
return coords;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 05/08/18.
|
||||
//
|
||||
|
||||
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
|
||||
void CombinedPalette::increaseBrightness(PaletteManager& palette, int bank, int index, u32 intensity) {
|
||||
auto current = palette.get(bank, index);
|
||||
auto next = PaletteManager::modify(current, intensity);
|
||||
|
||||
palette.change(bank, index, next);
|
||||
}
|
||||
|
||||
void CombinedPalette::increaseBrightness(u32 intensity) {
|
||||
for(int bank = 0; bank < PALETTE_BANK_SIZE; bank++) {
|
||||
for(int index = 0; index < PALETTE_BANK_SIZE; index++) {
|
||||
increaseBrightness(palette1, bank, index, intensity);
|
||||
increaseBrightness(palette2, bank, index, intensity);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 27/07/18.
|
||||
//
|
||||
|
||||
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||
#include <libgba-sprite-engine/gba/tonc_core_stub.h>
|
||||
#else
|
||||
#include <libgba-sprite-engine/gba/tonc_core.h>
|
||||
#endif
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
|
||||
const COLOR defaultPaletteData[PALETTE_MAX_SIZE] __attribute__((aligned(4))) = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
PaletteManager::PaletteManager() : PaletteManager(defaultPaletteData, PALETTE_MAX_SIZE) {
|
||||
}
|
||||
|
||||
|
||||
int getBits(int number, int k, int p) {
|
||||
return (((1 << k) - 1) & (number >> p));
|
||||
}
|
||||
|
||||
PaletteManager::PaletteManager(const COLOR *paletteData, int size) : data(paletteData), size(size) {
|
||||
|
||||
}
|
||||
|
||||
CombinedPalette* PaletteManager::operator+(const PaletteManager &other) {
|
||||
return new CombinedPalette(*this, const_cast<PaletteManager&>(other));
|
||||
}
|
||||
|
||||
void PaletteManager::persist() {
|
||||
dma3_cpy(this->paletteAddress(), this->data, this->size);
|
||||
}
|
||||
|
||||
COLOR PaletteManager::change(int bank, int index, COLOR newColor) {
|
||||
auto palBank = this->paletteBank();
|
||||
COLOR oldColor = palBank[bank][index];
|
||||
palBank[bank][index] = newColor;
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
COLOR PaletteManager::color(u32 red, u32 green, u32 blue) {
|
||||
if(red > 31) red = 31;
|
||||
if(green > 31) green = 31;
|
||||
if(blue > 31) blue = 31;
|
||||
return red | (green<<5) | (blue<<10);
|
||||
}
|
||||
|
||||
u32 PaletteManager::red(COLOR r) {
|
||||
return getBits(r, 5, 0);
|
||||
}
|
||||
|
||||
u32 PaletteManager::green(COLOR r) {
|
||||
return getBits(r, 5, 5);
|
||||
}
|
||||
|
||||
u32 PaletteManager::blue(COLOR r) {
|
||||
return getBits(r, 5, 10);
|
||||
}
|
||||
|
||||
COLOR PaletteManager::modify(COLOR color, u32 intensity) {
|
||||
return PaletteManager::color(PaletteManager::red(color) + intensity,
|
||||
PaletteManager::green(color) + intensity, PaletteManager::blue(color) + intensity);
|
||||
}
|
||||
|
||||
void PaletteManager::increaseBrightness(u32 intensity) {
|
||||
for(int bank = 0; bank < PALETTE_BANK_SIZE; bank++) {
|
||||
for(int index = 0; index < PALETTE_BANK_SIZE; index++) {
|
||||
auto current = get(bank, index);
|
||||
auto next = PaletteManager::modify(current, intensity);
|
||||
|
||||
change(bank, index, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteManager::persistToBank(int bank) {
|
||||
auto palBank = this->paletteBank();
|
||||
dma3_cpy(palBank[bank], this->data, PALETTE_BANK_SIZE);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 09/08/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/scene.h>
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 07/08/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memmap.h>
|
||||
#include <libgba-sprite-engine/sound_control.h>
|
||||
|
||||
void SoundControl::accept(const void *data, int totalSamples, int ticksPerSample) {
|
||||
this->data = data;
|
||||
*DMASourceAddress = (u32) data;
|
||||
*DMADestinationAddress = (u32) FiFoBuffer;
|
||||
vblanksTotal = vblanksRemaning = totalSamples * ticksPerSample * (1.0 / CYCLES_PER_BLANK);
|
||||
};
|
||||
|
||||
void SoundControl::reset() {
|
||||
vblanksRemaning = vblanksTotal;
|
||||
*(DMAControl) = 0;
|
||||
*DMASourceAddress = (u32) data;
|
||||
enable();
|
||||
}
|
||||
|
||||
std::unique_ptr<SoundControl> SoundControl::channelAControl() {
|
||||
return std::unique_ptr<SoundControl>(new SoundControl{
|
||||
®_DMA1CNT,
|
||||
®_DMA1SAD,
|
||||
®_DMA1DAD,
|
||||
®_FIFOA,
|
||||
// Left/Right, timed, tone 100% vol, channel A 50%, channel B 100% (only one directsound reg)
|
||||
SDS_AR | SDS_AL | SDS_ARESET | SDS_DMG100 | SDS_A50 | SDS_B100
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<SoundControl> SoundControl::channelBControl() {
|
||||
return std::unique_ptr<SoundControl>(new SoundControl{
|
||||
®_DMA2CNT,
|
||||
®_DMA2SAD,
|
||||
®_DMA2DAD,
|
||||
®_FIFOB,
|
||||
// Left/Right, timed, tone 100% vol, channel A 50%, channel B 100% (only one directsound reg)
|
||||
SDS_BR | SDS_BL | SDS_BRESET | SDS_DMG100 | SDS_A50 | SDS_B100
|
||||
});
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 06/12/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/timer.h>
|
||||
#include <sstream>
|
||||
|
||||
void Timer::onvblank() {
|
||||
if(!active) return;
|
||||
|
||||
// each VBlank occurs every 280806 cycles (CYCLES_PER_BLANK), each cycle is 59.59ns
|
||||
// So, each VBlank occurs every 16.73322954 miliseconds or 16733.22954 microseconds
|
||||
// So, each second is 59,76132686219041 vblanks.
|
||||
// to avoid any big rounding errors, divisions and modulos, estimate!
|
||||
msecs += 16;
|
||||
microsecs += 733;
|
||||
if(microsecs >= 1000) {
|
||||
msecs++;
|
||||
microsecs -= 1000;
|
||||
}
|
||||
|
||||
if(msecs >= 1000) {
|
||||
secs++;
|
||||
msecs -= 1000;
|
||||
}
|
||||
if(secs >= 60) {
|
||||
minutes++;
|
||||
secs -= 60;
|
||||
}
|
||||
if(minutes >= 60) {
|
||||
hours++;
|
||||
minutes -= 60;
|
||||
}
|
||||
}
|
||||
|
||||
int Timer::getTotalMsecs() {
|
||||
return msecs + (hours * 60 * 60 + minutes * 60 + secs) * 1000;
|
||||
}
|
||||
|
||||
std::string Timer::to_string() {
|
||||
std::ostringstream stringStream;
|
||||
stringStream << *this;
|
||||
return stringStream.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, Timer &timer) {
|
||||
os << timer.hours << "h:" << timer.minutes << "m:" << timer.secs << "s:" << timer.msecs;
|
||||
return os;
|
||||
}
|
||||
|
||||
void Timer::reset() {
|
||||
microsecs = msecs = secs = minutes = hours = 0;
|
||||
}
|
||||
|
||||
void Timer::start() {
|
||||
active = true;
|
||||
}
|
||||
|
||||
void Timer::stop() {
|
||||
active = false;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing -Wno-int-to-pointer-cast")
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
project(Unittest)
|
||||
enable_testing()
|
||||
|
||||
SET(GTEST_LIBRARY "$ENV{GTEST_DIR}")
|
||||
|
||||
# reset linker flags; ARM + GTest doesn't work
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${BASE_CMAKE_LINK_FLAGS}")
|
||||
SET(CMAKE_C_COMPILER gcc)
|
||||
SET(CMAKE_CXX_COMPILER g++)
|
||||
|
||||
add_definitions(-DCODE_COMPILED_AS_PART_OF_TEST)
|
||||
|
||||
include_directories(${GTEST_LIBRARY}/include)
|
||||
include_directories(../engine/include)
|
||||
|
||||
# compile including library source because it's cross-compiled
|
||||
add_executable(unittest
|
||||
maintest.cpp
|
||||
gbatest.cpp
|
||||
palettetest.cpp
|
||||
real_data.h
|
||||
../engine/src/gba/sin_lut.s
|
||||
../engine/src/palette/palette_manager.cpp
|
||||
../engine/src/palette/combined_palette.cpp
|
||||
../engine/src/timer.cpp
|
||||
../engine/src/gbavector.cpp
|
||||
timertest.cpp gbavectortest.cpp)
|
||||
|
||||
target_link_libraries(unittest ${GTEST_LIBRARY}/build/libgtest.a ${GTEST_LIBRARY}/build/libgtest_main.a)
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
class GBASuite : public ::testing::Test {
|
||||
protected:
|
||||
protected:
|
||||
virtual void TearDown() {
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(GBASuite, AssertionWorks) {
|
||||
ASSERT_TRUE(true);
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 14/12/18.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <libgba-sprite-engine/gbavector.h>
|
||||
|
||||
class GBAVectorSuite : public ::testing::Test {
|
||||
protected:
|
||||
GBAVector vector;
|
||||
VECTOR bottomHalf;
|
||||
|
||||
virtual void TearDown() {
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
vector = GBAVector({120, 80});
|
||||
bottomHalf = { 120, 200 };
|
||||
}
|
||||
};
|
||||
|
||||
// Angle in DEGREES for readability - converted in tonc_math_stub!
|
||||
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_0_Degrees) {
|
||||
auto result = vector.rotateAsCenter(bottomHalf, 0);
|
||||
ASSERT_EQ(120, result.x);
|
||||
ASSERT_EQ(200, result.y);
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_90_Degrees) {
|
||||
auto result = vector.rotateAsCenter(bottomHalf, 90);
|
||||
ASSERT_EQ(240, result.x);
|
||||
ASSERT_EQ(80, result.y);
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_180_Degrees) {
|
||||
auto result = vector.rotateAsCenter(bottomHalf, 180);
|
||||
ASSERT_EQ(120, result.x);
|
||||
ASSERT_EQ(-40, result.y);
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, Rotate_FromBottomHalf_270_Degrees) {
|
||||
auto result = vector.rotateAsCenter(bottomHalf, 270);
|
||||
ASSERT_EQ(0, result.x);
|
||||
ASSERT_EQ(80, result.y);
|
||||
}
|
||||
// ---- //
|
||||
|
||||
TEST_F(GBAVectorSuite, ToString) {
|
||||
ASSERT_EQ(std::string("(120,80)"), vector.to_string());
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToTopRightCorner) {
|
||||
auto points = vector.bresenhamLineTo({240, 0});
|
||||
ASSERT_EQ(121, points.size());
|
||||
VECTOR pt;
|
||||
|
||||
// some sampling
|
||||
pt = points.at(1);
|
||||
ASSERT_EQ(121, pt.x);
|
||||
ASSERT_EQ(79, pt.y);
|
||||
pt = points.at(2);
|
||||
ASSERT_EQ(122, pt.x);
|
||||
ASSERT_EQ(79, pt.y);
|
||||
pt = points.at(10);
|
||||
ASSERT_EQ(130, pt.x);
|
||||
ASSERT_EQ(73, pt.y);
|
||||
pt = points.at(100);
|
||||
ASSERT_EQ(220, pt.x);
|
||||
ASSERT_EQ(13, pt.y);
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToTopLeftCorner) {
|
||||
auto points = vector.bresenhamLineTo({0, 0});
|
||||
ASSERT_EQ(121, points.size());
|
||||
VECTOR pt;
|
||||
|
||||
// some sampling
|
||||
pt = points.at(1);
|
||||
ASSERT_EQ(119, pt.x);
|
||||
ASSERT_EQ(79, pt.y);
|
||||
pt = points.at(2);
|
||||
ASSERT_EQ(118, pt.x);
|
||||
ASSERT_EQ(79, pt.y);
|
||||
pt = points.at(10);
|
||||
ASSERT_EQ(110, pt.x);
|
||||
ASSERT_EQ(73, pt.y);
|
||||
pt = points.at(100);
|
||||
ASSERT_EQ(20, pt.x);
|
||||
ASSERT_EQ(13, pt.y);
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToBottomLeftCorner) {
|
||||
auto points = vector.bresenhamLineTo({0, 160});
|
||||
ASSERT_EQ(121, points.size());
|
||||
VECTOR pt;
|
||||
|
||||
// some sampling
|
||||
pt = points.at(1);
|
||||
ASSERT_EQ(119, pt.x);
|
||||
ASSERT_EQ(81, pt.y);
|
||||
pt = points.at(2);
|
||||
ASSERT_EQ(118, pt.x);
|
||||
ASSERT_EQ(81, pt.y);
|
||||
pt = points.at(10);
|
||||
ASSERT_EQ(110, pt.x);
|
||||
ASSERT_EQ(87, pt.y);
|
||||
pt = points.at(100);
|
||||
ASSERT_EQ(20, pt.x);
|
||||
ASSERT_EQ(147, pt.y);
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, LineBetween_Diagonal_ToBottomRightCorner) {
|
||||
auto points = vector.bresenhamLineTo({240, 160});
|
||||
ASSERT_EQ(121, points.size());
|
||||
VECTOR pt;
|
||||
|
||||
// some sampling
|
||||
pt = points.at(1);
|
||||
ASSERT_EQ(121, pt.x);
|
||||
ASSERT_EQ(81, pt.y);
|
||||
pt = points.at(2);
|
||||
ASSERT_EQ(122, pt.x);
|
||||
ASSERT_EQ(81, pt.y);
|
||||
pt = points.at(10);
|
||||
ASSERT_EQ(130, pt.x);
|
||||
ASSERT_EQ(87, pt.y);
|
||||
pt = points.at(100);
|
||||
ASSERT_EQ(220, pt.x);
|
||||
ASSERT_EQ(147, pt.y);
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, LineBetween_Horizontal_FromCenterToHalfYZeroX) {
|
||||
auto points = vector.bresenhamLineTo({0, 80});
|
||||
ASSERT_EQ(121, points.size());
|
||||
for(int i = 0; i <= 120; i++) {
|
||||
auto &vec = points.front();
|
||||
ASSERT_EQ(80, vec.y);
|
||||
ASSERT_EQ(120 - i, vec.x);
|
||||
points.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GBAVectorSuite, LineBetween_Vertical_FromCenterToHalfXFullY) {
|
||||
auto points = vector.bresenhamLineTo({120, 160});
|
||||
ASSERT_EQ(81, points.size());
|
||||
for(int i = 0; i <= (160 - 80); i++) {
|
||||
auto &vec = points.front();
|
||||
ASSERT_EQ(120, vec.x);
|
||||
ASSERT_EQ(80 + i, vec.y);
|
||||
points.pop_front();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#include "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 04/08/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
class SomePaletteManager : public PaletteManager {
|
||||
public:
|
||||
PALBANK* palette;
|
||||
SomePaletteManager() : SomePaletteManager({}) {};
|
||||
SomePaletteManager(const u16 *paletteData) : PaletteManager(paletteData) {
|
||||
palette = (PALBANK*) malloc(sizeof(PALBANK) * 16);
|
||||
}
|
||||
|
||||
virtual ~SomePaletteManager() {
|
||||
delete[] palette;
|
||||
}
|
||||
|
||||
protected:
|
||||
PALBANK *paletteBank() override {
|
||||
return palette;
|
||||
}
|
||||
|
||||
void *paletteAddress() override {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class PaletteSuite : public ::testing::Test {
|
||||
protected:
|
||||
SomePaletteManager* palette;
|
||||
|
||||
virtual void TearDown() {
|
||||
delete palette;
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
palette = new SomePaletteManager();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PaletteSuite, Increase_Intensity_Updates_For_RGB_Values) {
|
||||
palette->palette[0][0] = PaletteManager::color(10, 10, 10);
|
||||
palette->palette[1][1] = PaletteManager::color(11, 11, 11);
|
||||
palette->palette[2][2] = PaletteManager::color(12, 12, 12);
|
||||
|
||||
palette->increaseBrightness(1);
|
||||
|
||||
ASSERT_EQ(11, PaletteManager::red(palette->palette[0][0]));
|
||||
ASSERT_EQ(11, PaletteManager::green(palette->palette[0][0]));
|
||||
ASSERT_EQ(11, PaletteManager::blue(palette->palette[0][0]));
|
||||
|
||||
ASSERT_EQ(12, PaletteManager::red(palette->palette[1][1]));
|
||||
ASSERT_EQ(12, PaletteManager::green(palette->palette[1][1]));
|
||||
ASSERT_EQ(12, PaletteManager::blue(palette->palette[1][1]));
|
||||
|
||||
ASSERT_EQ(13, PaletteManager::red(palette->palette[2][2]));
|
||||
ASSERT_EQ(13, PaletteManager::green(palette->palette[2][2]));
|
||||
ASSERT_EQ(13, PaletteManager::blue(palette->palette[2][2]));
|
||||
}
|
||||
|
||||
TEST_F(PaletteSuite, Extract_Individual_Colors) {
|
||||
auto color = PaletteManager::color(10, 20, 30);
|
||||
|
||||
ASSERT_EQ(10, PaletteManager::red(color));
|
||||
ASSERT_EQ(20, PaletteManager::green(color));
|
||||
ASSERT_EQ(30, PaletteManager::blue(color));
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
|
||||
const unsigned short sharedPal[84] __attribute__((aligned(4)))=
|
||||
{
|
||||
0x0000,0x3AE2,0x7BBD,0x4042,0x008C,0x3614,0x633B,0x1151,
|
||||
0x36FD,0x4AB8,0x21B2,0x77BE,0x3E56,0x0D0F,0x1971,0x56FA,
|
||||
0x6B7D,0x2DD3,0x7FFF,0x04EE,0x1550,0x1593,0x4697,0x677C,
|
||||
0x52D9,0x5B1A,0x112F,0x1DF5,0x08EE,0x31F4,0x3635,0x08EF,
|
||||
0x739D,0x7BDF,0x371D,0x29B3,0x4677,0x00CD,0x2192,0x5F1A,
|
||||
0x1950,0x675B,0x1130,0x77DE,0x4276,0x3214,0x04CE,0x4EB8,
|
||||
0x4A97,0x56F9,0x25B2,0x3A35,0x5F3B,0x635B,0x3615,0x73BE,
|
||||
0x2DF4,0x1D91,0x25B3,0x6F9D,0x4ED8,0x6B5C,0x1530,0x56D9,
|
||||
|
||||
0x6B7C,0x29D3,0x04CD,0x3A36,0x7BFF,0x00AD,0x4277,0x675C,
|
||||
0x1D71,0x73BD,0x5F1B,0x4256,0x1951,0x5AFA,0x7BDE,0x4A98,
|
||||
0x6F7D,0x2DF3,0x090F,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
const unsigned short bg_palette [] = {
|
||||
0x7c1f, 0x7e4b, 0x0539, 0x1e7f, 0x0000, 0x5aff, 0x7fff, 0x7ee7, 0x02a0,
|
||||
0x0b50, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000
|
||||
};
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 06/12/18.
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <libgba-sprite-engine/timer.h>
|
||||
|
||||
class TimerSuite : public ::testing::Test {
|
||||
protected:
|
||||
Timer *t;
|
||||
|
||||
virtual void TearDown() {
|
||||
delete t;
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
t = new Timer();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST_F(TimerSuite, OnVBlankIncreasesMsecsAmountOfTimeIfStarted) {
|
||||
t->start();
|
||||
t->onvblank();
|
||||
t->stop();
|
||||
t->onvblank();
|
||||
|
||||
ASSERT_EQ(t->getMsecs(), 16);
|
||||
}
|
||||
|
||||
TEST_F(TimerSuite, OnVBlankAfterEnoughTimesToGetToSec) {
|
||||
t->start();
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
t->onvblank();
|
||||
}
|
||||
|
||||
ASSERT_EQ(t->getSecs(), 1);
|
||||
ASSERT_EQ(t->getMsecs(), 673);
|
||||
}
|
||||
|
||||
TEST_F(TimerSuite, OnVBlankDoesNothingIfNotEnabled) {
|
||||
t->onvblank();
|
||||
|
||||
ASSERT_EQ(t->getMsecs(), 0);
|
||||
}
|
Loading…
Reference in New Issue