mirror of
https://github.com/afska/gba-link-connection.git
synced 2026-04-25 16:23:41 -05:00
Renewing design to support retransmission and multiple messages per frame
This commit is contained in:
parent
af29b8cd31
commit
1811eb30bc
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,5 +1,8 @@
|
|||
build/
|
||||
# Directories
|
||||
build
|
||||
.vscode
|
||||
|
||||
# Files
|
||||
*.elf
|
||||
*.gba
|
||||
*.sav
|
||||
.vscode/
|
||||
25
README.md
25
README.md
|
|
@ -1,17 +1,30 @@
|
|||
# gba-link-connection
|
||||
|
||||
A GBA Link Cable library to add multiplayer support to homebrew games.
|
||||
A GameBoy Advance Link Cable library to add multiplayer support to homebrew games.
|
||||
|
||||

|
||||
The library uses message queues to send/receive data and transmits when it's possible. As it uses CPU interrupts, the connection is alive even if a console drops a frame or gets stucked in a long iteration loop. After such event, all nodes end up receiving all the pending messages, so a lockstep communication protocol can be used.
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
All the complexity is abstracted in a single header file that exposes an easy-to-use interface.
|
||||
|
||||
- Include [LinkConnection.h](src/lib/LinkConnection.h) in your game code.
|
||||
- Check out an example implementation in [main.cpp](src/main.cpp).
|
||||
* A build is available in *Releases*.
|
||||
* It can be tested on real GBAs or with the *NO$GBA* emulator.
|
||||
- Include [LinkConnection.h](lib/LinkConnection.h) in your game code, and read its comment with instructions.
|
||||
- Check out the [examples](examples) folder
|
||||
* Builds are available in *Releases*.
|
||||
* They can be tested on real GBAs or with emulators (*NO$GBA*, *mGBA*, or *VBA-M*).
|
||||
|
||||
## Constructor options
|
||||
|
||||
`new LinkConnection(...)` accepts these **optional** parameters:
|
||||
|
||||
Name | Type | Default | Description
|
||||
--- | --- | --- | ---
|
||||
`startNow` | **bool** | `true` | Automatically starts serial communication. Otherwise, you'll need to call `linkConnection->activate()`.
|
||||
`baudRate` | **BaudRate** | `BaudRate::BAUD_RATE_3` | Sets a specific baud rate.
|
||||
`timeout` | **u32** | `3` | Number of frames without an `II_SERIAL` IRQ to reset the connection.
|
||||
`bufferSize` | **u32** | `60` | Number of messages that the queues will be able to store.
|
||||
|
||||
## Makefile actions
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ LIBS := -ltonc
|
|||
BUILD := build
|
||||
SRCDIRS := src
|
||||
DATADIRS := data
|
||||
INCDIRS := src
|
||||
INCDIRS := src lib
|
||||
LIBDIRS := $(TONCLIB)
|
||||
|
||||
# --- switches ---
|
||||
1
examples/basic/lib/LinkConnection.h
Symbolic link
1
examples/basic/lib/LinkConnection.h
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../../lib/LinkConnection.h
|
||||
64
examples/basic/src/main.cpp
Normal file
64
examples/basic/src/main.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#include <tonc.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// (0) Include the header
|
||||
#include "../lib/LinkConnection.h"
|
||||
|
||||
void log(std::string text);
|
||||
|
||||
// (1) Create a LinkConnection instance
|
||||
LinkConnection* linkConnection = new LinkConnection();
|
||||
|
||||
void init() {
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
|
||||
tte_init_se_default(0, BG_CBB(0) | BG_SBB(31));
|
||||
|
||||
irq_init(NULL);
|
||||
|
||||
// (2) Add the interrupt service routines
|
||||
irq_add(II_VBLANK, LINK_ISR_VBLANK);
|
||||
irq_add(II_SERIAL, LINK_ISR_SERIAL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
u16 data[LINK_MAX_PLAYERS];
|
||||
|
||||
while (1) {
|
||||
// (3) Send/read messages messages
|
||||
u16 keys = ~REG_KEYS & KEY_ANY;
|
||||
u16 message = (keys << 1) | 1;
|
||||
linkConnection->send(message);
|
||||
auto linkState = linkConnection->linkState.get();
|
||||
|
||||
std::string output = "";
|
||||
if (linkState->isConnected()) {
|
||||
output += "Players: " + std::to_string(linkState->playerCount) + "\n";
|
||||
|
||||
for (u32 i = 0; i < linkState->playerCount; i++) {
|
||||
while (linkState->hasMessage(i))
|
||||
data[i] = linkState->readMessage(i) >> 1;
|
||||
|
||||
output += "Player " + std::to_string(i) + ": " +
|
||||
std::to_string(data[i]) + "\n";
|
||||
}
|
||||
|
||||
output += "_sent: " + std::to_string(message) + "\n";
|
||||
output += "_self pID: " + std::to_string(linkState->currentPlayerId);
|
||||
} else
|
||||
output += std::string("Waiting...");
|
||||
log(output);
|
||||
|
||||
VBlankIntrWait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log(std::string text) {
|
||||
tte_erase_screen();
|
||||
tte_write("#{P:0,0}");
|
||||
tte_write(text.c_str());
|
||||
}
|
||||
297
examples/full/Makefile
Normal file
297
examples/full/Makefile
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
# === SETUP ===========================================================
|
||||
|
||||
# --- No implicit rules ---
|
||||
.SUFFIXES:
|
||||
|
||||
# --- Paths ---
|
||||
export TONCLIB := $(DEVKITPRO)/libtonc
|
||||
|
||||
# === TONC RULES ======================================================
|
||||
#
|
||||
# Yes, this is almost, but not quite, completely like to
|
||||
# DKP's base_rules and gba_rules
|
||||
#
|
||||
|
||||
export PATH := $(DEVKITARM)/bin:$(PATH)
|
||||
|
||||
|
||||
# --- Executable names ---
|
||||
|
||||
PREFIX ?= arm-none-eabi-
|
||||
|
||||
export CC := $(PREFIX)gcc
|
||||
export CXX := $(PREFIX)g++
|
||||
export AS := $(PREFIX)as
|
||||
export AR := $(PREFIX)ar
|
||||
export NM := $(PREFIX)nm
|
||||
export OBJCOPY := $(PREFIX)objcopy
|
||||
|
||||
# LD defined in Makefile
|
||||
|
||||
|
||||
# === LINK / TRANSLATE ================================================
|
||||
|
||||
%.gba : %.elf
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
@echo built ... $(notdir $@)
|
||||
@gbafix $@ -t$(TITLE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.mb.elf :
|
||||
@echo Linking multiboot
|
||||
$(LD) -specs=gba_mb.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.elf :
|
||||
@echo Linking cartridge
|
||||
$(LD) -specs=gba.specs $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
$(NM) -Sn $@ > $(basename $(notdir $@)).map
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.a :
|
||||
@echo $(notdir $@)
|
||||
@rm -f $@
|
||||
$(AR) -crs $@ $^
|
||||
|
||||
|
||||
# === OBJECTIFY =======================================================
|
||||
|
||||
%.iwram.o : %.iwram.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
%.iwram.o : %.iwram.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(IARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.cpp
|
||||
@echo $(notdir $<)
|
||||
$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.c
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(RARCH) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.s
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
%.o : %.S
|
||||
@echo $(notdir $<)
|
||||
$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# canned command sequence for binary data
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(<F) | tr . _)`.h
|
||||
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(<F) | tr . _)`.h
|
||||
endef
|
||||
# =====================================================================
|
||||
|
||||
# === PROJECT DETAILS =================================================
|
||||
# PROJ : Base project name
|
||||
# TITLE : Title for ROM header (12 characters)
|
||||
# LIBS : Libraries to use, formatted as list for linker flags
|
||||
# BUILD : Directory for build process temporaries. Should NOT be empty!
|
||||
# SRCDIRS : List of source file directories
|
||||
# DATADIRS : List of data file directories
|
||||
# INCDIRS : List of header file directories
|
||||
# LIBDIRS : List of library directories
|
||||
# General note: use `.' for the current dir, don't leave the lists empty.
|
||||
|
||||
export PROJ ?= $(notdir $(CURDIR))
|
||||
TITLE := $(PROJ)
|
||||
|
||||
LIBS := -ltonc -lgba-sprite-engine
|
||||
|
||||
BUILD := build
|
||||
SRCDIRS := src \
|
||||
src/scenes \
|
||||
src/utils
|
||||
|
||||
DATADIRS :=
|
||||
INCDIRS := src
|
||||
LIBDIRS := $(TONCLIB) $(BASE_DIR)/lib/libgba-sprite-engine
|
||||
|
||||
# --- switches ---
|
||||
|
||||
bMB := 0 # Multiboot build
|
||||
bTEMPS := 0 # Save gcc temporaries (.i and .S files)
|
||||
bDEBUG2 := 0 # Generate debug info (bDEBUG2? Not a full DEBUG flag. Yet)
|
||||
|
||||
# === BUILD FLAGS =====================================================
|
||||
# This is probably where you can stop editing
|
||||
# NOTE: I've noticed that -fgcse and -ftree-loop-optimize sometimes muck
|
||||
# up things (gcse seems fond of building masks inside a loop instead of
|
||||
# outside them for example). Removing them sometimes helps
|
||||
|
||||
# --- Architecture ---
|
||||
|
||||
ARCH := -mthumb-interwork -mthumb
|
||||
RARCH := -mthumb-interwork -mthumb
|
||||
IARCH := -mthumb-interwork -marm -mlong-calls
|
||||
|
||||
# --- Main flags ---
|
||||
|
||||
CFLAGS := -mcpu=arm7tdmi -mtune=arm7tdmi -Ofast
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += $(INCLUDE)
|
||||
CFLAGS += -ffast-math -fno-strict-aliasing
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := $(ARCH) $(INCLUDE)
|
||||
LDFLAGS := $(ARCH) -Wl,-Map,$(PROJ).map
|
||||
|
||||
# --- switched additions ----------------------------------------------
|
||||
|
||||
# --- Multiboot ? ---
|
||||
ifeq ($(strip $(bMB)), 1)
|
||||
TARGET := $(PROJ).mb
|
||||
else
|
||||
TARGET := $(PROJ)
|
||||
endif
|
||||
|
||||
# --- Save temporary files ? ---
|
||||
ifeq ($(strip $(bTEMPS)), 1)
|
||||
CFLAGS += -save-temps
|
||||
CXXFLAGS += -save-temps
|
||||
endif
|
||||
|
||||
# --- Debug info ? ---
|
||||
|
||||
ifeq ($(strip $(bDEBUG)), 1)
|
||||
CFLAGS += -DDEBUG -g
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
ASFLAGS += -DDEBUG -g
|
||||
LDFLAGS += -g
|
||||
else
|
||||
CFLAGS += -DNDEBUG
|
||||
CXXFLAGS += -DNDEBUG
|
||||
ASFLAGS += -DNDEBUG
|
||||
endif
|
||||
|
||||
# --- Custom vars ? ---
|
||||
|
||||
GAMETITLE=test-multi-link
|
||||
GAMEMAKER=AGB
|
||||
GAMECODE=AZCE # Megaman Zero (SRAM - 64kb)
|
||||
ENV ?= development
|
||||
|
||||
ifeq ($(ENV), debug)
|
||||
CXXFLAGS += -DENV_DEBUG=true -DENV_DEVELOPMENT=true
|
||||
else ifeq ($(ENV), development)
|
||||
CXXFLAGS += -DENV_DEVELOPMENT=true
|
||||
else
|
||||
|
||||
endif
|
||||
|
||||
# CXXFLAGS += -DCUSTOM_VAR_DEFINE
|
||||
|
||||
# === BUILD PROC ======================================================
|
||||
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
|
||||
# Still in main dir:
|
||||
# * Define/export some extra variables
|
||||
# * Invoke this file again from the build dir
|
||||
# PONDER: what happens if BUILD == "" ?
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export VPATH := \
|
||||
$(foreach dir, $(SRCDIRS) , $(CURDIR)/$(dir)) \
|
||||
$(foreach dir, $(DATADIRS), $(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
# --- List source and data files ---
|
||||
|
||||
CFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir, $(SRCDIRS) , $(notdir $(wildcard $(dir)/*.S)))
|
||||
BINFILES := $(foreach dir, $(DATADIRS), $(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
# --- Set linker depending on C++ file existence ---
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
export LD := $(CC)
|
||||
else
|
||||
export LD := $(CXX)
|
||||
endif
|
||||
|
||||
# --- Define object file list ---
|
||||
export OFILES := $(addsuffix .o, $(BINFILES)) \
|
||||
$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) \
|
||||
$(SFILES:.S=.o)
|
||||
|
||||
# --- Create include and library search paths ---
|
||||
export INCLUDE := $(foreach dir,$(INCDIRS),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := -L$(CURDIR) $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
# --- Create BUILD if necessary, and run this makefile from there ---
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
arm-none-eabi-nm -Sn $(OUTPUT).elf > $(BUILD)/$(TARGET).map
|
||||
|
||||
all : $(BUILD)
|
||||
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -rf $(BUILD) $(TARGET).elf $(TARGET).gba $(TARGET).sav
|
||||
|
||||
else # If we're here, we should be in the BUILD dir
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
# --- Main targets ----
|
||||
|
||||
$(OUTPUT).gba : $(OUTPUT).elf
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
endif # End BUILD switch
|
||||
|
||||
# --- More targets ----------------------------------------------------
|
||||
|
||||
.PHONY: clean rebuild start check-env
|
||||
|
||||
check-env:
|
||||
ifndef BASE_DIR
|
||||
$(warning Please export a BASE_DIR environment variable pointing to this directory.)
|
||||
$(warning Example:)
|
||||
$(warning export BASE_DIR="D:\work\gba\projects\gba-link-connection\examples\full")
|
||||
$(error "Aborting")
|
||||
endif
|
||||
|
||||
rebuild: check-env clean $(BUILD)
|
||||
|
||||
start: check-env
|
||||
start "$(TARGET).gba"
|
||||
|
||||
restart: check-env rebuild start
|
||||
|
||||
# EOF
|
||||
1
examples/full/lib/LinkConnection.h
Symbolic link
1
examples/full/lib/LinkConnection.h
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../../lib/LinkConnection.h
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 27/07/18.
|
||||
// very loosely based on:
|
||||
// https://github.com/Jambo51/GBA-Pokemon-Engine/blob/master/source/Entities/OAMObject.cpp
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_ALLOCATOR_H
|
||||
#define GBA_SPRITE_ENGINE_ALLOCATOR_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memmap.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||
#include <vector>
|
||||
|
||||
#define MEM_OBJ_VRAM_BASE (MEM_VRAM + VRAM_BG_SIZE)
|
||||
|
||||
u32 voidPtrToU32(void* ptr);
|
||||
|
||||
class AllocatedData {
|
||||
public:
|
||||
void* pointer() const { return (void*)currentAddress; };
|
||||
u32 size, currentAddress, baseAddress;
|
||||
|
||||
const int getTileLocation() const {
|
||||
return (currentAddress - baseAddress) >> 5;
|
||||
}
|
||||
|
||||
AllocatedData(u32 address, u32 size, u32 base)
|
||||
: currentAddress(address), size(size), baseAddress(base) {}
|
||||
};
|
||||
|
||||
class Allocator {
|
||||
private:
|
||||
Allocator() = delete;
|
||||
Allocator(Allocator& other) = delete;
|
||||
Allocator(Allocator&& other) = delete;
|
||||
|
||||
static u32 currentSpriteIndex;
|
||||
|
||||
public:
|
||||
static void free();
|
||||
static u32 getCurrentSpriteIndex() { return currentSpriteIndex; }
|
||||
static int getAllocatedSprites() { return allocatedSprites.size(); }
|
||||
static AllocatedData& allocateObjectTiles(u32 size);
|
||||
static std::vector<AllocatedData> allocatedSprites;
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_ALLOCATOR_H
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_BACKGROUND_H
|
||||
#define GBA_SPRITE_ENGINE_BACKGROUND_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||
|
||||
#define MAPLAYOUT_32X32 0
|
||||
#define MAPLAYOUT_32X64 1
|
||||
#define MAPLAYOUT_64X32 2
|
||||
#define MAPLAYOUT_64X64 3
|
||||
|
||||
class Background {
|
||||
private:
|
||||
void buildRegister();
|
||||
u32 getBgControlRegisterIndex();
|
||||
|
||||
protected:
|
||||
const void* data;
|
||||
const void* map;
|
||||
int size, bgIndex;
|
||||
int mapSize, mapLayout;
|
||||
int screenBlockIndex, charBlockIndex, priority;
|
||||
bool mosaicEnabled = false;
|
||||
|
||||
public:
|
||||
const int getScreenBlock() { return screenBlockIndex; }
|
||||
const int getCharBlock() { return charBlockIndex; }
|
||||
void useMapScreenBlock(int block) { screenBlockIndex = block; }
|
||||
void useCharBlock(int block) { charBlockIndex = block; }
|
||||
void usePriority(int value) { priority = value; }
|
||||
void scroll(int x, int y);
|
||||
void scrollSpeed(int dx, int dy);
|
||||
void setMosaic(bool enabled) { mosaicEnabled = enabled; }
|
||||
|
||||
Background(int bgIndex,
|
||||
const void* data,
|
||||
int size,
|
||||
const void* map,
|
||||
int mapSize,
|
||||
int screenBlockIndex,
|
||||
int charBlockIndex,
|
||||
int mapLayout)
|
||||
: Background(bgIndex, data, size, map, mapSize) {
|
||||
this->screenBlockIndex = screenBlockIndex;
|
||||
this->charBlockIndex = charBlockIndex;
|
||||
this->mapLayout = mapLayout;
|
||||
}
|
||||
|
||||
Background(int bgIndex,
|
||||
const void* data,
|
||||
int size,
|
||||
const void* map,
|
||||
int mapSize)
|
||||
: data(data),
|
||||
bgIndex(bgIndex),
|
||||
size(size),
|
||||
map(map),
|
||||
mapLayout(MAPLAYOUT_32X32),
|
||||
screenBlockIndex(0),
|
||||
charBlockIndex(bgIndex),
|
||||
priority(bgIndex),
|
||||
mapSize(mapSize) {}
|
||||
virtual void persist();
|
||||
void updateMap(const void* map);
|
||||
void clearMap();
|
||||
void clearData();
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_BACKGROUND_H
|
||||
|
|
@ -0,0 +1,530 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_TEXT_H
|
||||
#define GBA_SPRITE_ENGINE_TEXT_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#define text_background_width 256
|
||||
#define text_background_height 24
|
||||
|
||||
#define text_bg_palette_default_color 0x7fff
|
||||
|
||||
const unsigned char text_data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_TEXT_H
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_TEXT_STREAM_H
|
||||
#define GBA_SPRITE_ENGINE_TEXT_STREAM_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include "background.h"
|
||||
#include "text.h"
|
||||
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#define CHAR_OFFSET_INDEX 32
|
||||
#define TILE_WIDTH 32
|
||||
#define PALETTE_COLOR_INDEX 15
|
||||
#define PALETTE_TEXT_BANK 15
|
||||
|
||||
#define failure_gba(__mess) \
|
||||
(consoleLog_func(__FILE__, __LINE__, __PRETTY_FUNCTION__, #__mess))
|
||||
void log_text(const char* text);
|
||||
void consoleLog_func(const char* fileName,
|
||||
const int lineNr,
|
||||
const char* fnName,
|
||||
const char* msg);
|
||||
|
||||
class TextStream : public Background {
|
||||
private:
|
||||
int currRow, currCol;
|
||||
std::unique_ptr<BackgroundPaletteManager> palette;
|
||||
|
||||
static TextStream* inst;
|
||||
TextStream();
|
||||
TextStream(TextStream& other) = delete;
|
||||
TextStream(TextStream&& other) = delete;
|
||||
|
||||
public:
|
||||
void clear();
|
||||
void setText(std::string text, int row, int col);
|
||||
void setText(const char* text, int row, int col);
|
||||
|
||||
void setFontColor(COLOR color);
|
||||
void setFontStyle(const void* data, int size);
|
||||
|
||||
static TextStream& instance();
|
||||
|
||||
void persist() override;
|
||||
|
||||
TextStream& operator<<(const char* s);
|
||||
TextStream& operator<<(const int s);
|
||||
TextStream& operator<<(const u32 s);
|
||||
TextStream& operator<<(const bool s);
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_TEXT_STREAM_H
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 04/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_FADE_OUT_SCENE_H
|
||||
#define GBA_SPRITE_ENGINE_FADE_OUT_SCENE_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/scene.h>
|
||||
|
||||
#include "scene_effect.h"
|
||||
|
||||
enum FadeOutType { ToWhite, ToBlack };
|
||||
|
||||
class FadeOutScene : public SceneEffect {
|
||||
private:
|
||||
FadeOutType type;
|
||||
int timesUpdated;
|
||||
int speed;
|
||||
std::unique_ptr<CombinedPalette> palette;
|
||||
|
||||
public:
|
||||
FadeOutScene(int speed);
|
||||
FadeOutScene(int speed, FadeOutType type);
|
||||
void update() override;
|
||||
bool isDone() override { return timesUpdated >= (32 / speed); }
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_FADE_OUT_SCENE_H
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 04/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SCENE_EFFECT_H
|
||||
#define GBA_SPRITE_ENGINE_SCENE_EFFECT_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/scene.h>
|
||||
|
||||
class SceneEffect {
|
||||
protected:
|
||||
// WHY no reference? Scene& operator= is implicitly deleted and no intentions
|
||||
// to use that
|
||||
Scene* sceneToAffect;
|
||||
|
||||
public:
|
||||
void setSceneToAffect(Scene* scene) { sceneToAffect = scene; };
|
||||
|
||||
virtual void update() = 0;
|
||||
virtual bool isDone() = 0;
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_SCENE_EFFECT_H
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
//
|
||||
// tonc_asminc.h : header file with goodies for assembly.
|
||||
//
|
||||
//! \file tonc_asminc.h
|
||||
//! \author J Vijn
|
||||
//! \date 20081019 - 20120519
|
||||
//
|
||||
/* === NOTES ===
|
||||
* Cleaned up the macros so that they work with comma-directives as well.
|
||||
* For use in assembly only!
|
||||
*/
|
||||
|
||||
#ifndef TONC_ASMINC_H
|
||||
#define TONC_ASMINC_H
|
||||
|
||||
#if !__ASSEMBLER__
|
||||
#error This header file is for use in assembly only!
|
||||
#endif // /asm only
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MACROS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#define DEF_SIZE(_name) .size _name, .-_name
|
||||
|
||||
//! \name Section definitions for assembly.
|
||||
//\{
|
||||
|
||||
#define CSEC_TEXT .text //!< Standard code section directive.
|
||||
#define CSEC_EWRAM .section .ewram , "ax", %progbits //!< EWRAM code section directive.
|
||||
#define CSEC_IWRAM .section .iwram, "ax", %progbits //!< IWRAM code section directive.
|
||||
|
||||
#define DSEC_DATA .data //<! 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,104 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_GBAENGINE_H
|
||||
#define GBA_SPRITE_ENGINE_GBAENGINE_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/effects/scene_effect.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_memmap.h>
|
||||
#include <libgba-sprite-engine/sprites/sprite_manager.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;
|
||||
SceneEffect* currentEffectForTransition;
|
||||
|
||||
bool disableTextBg;
|
||||
SpriteManager spriteManager;
|
||||
|
||||
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 dynamicallyAddSprite(Sprite* s) { spriteManager.add(s); }
|
||||
void transitionIntoScene(Scene* scene, SceneEffect* effect);
|
||||
bool isTransitioning() { return currentEffectForTransition != nullptr; }
|
||||
void disableText() { this->disableTextBg = true; }
|
||||
void enableText() { this->disableTextBg = false; }
|
||||
|
||||
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();
|
||||
|
||||
inline void update() {
|
||||
// main update loop, in while(true) {}.
|
||||
// WARNING - keep amount of instructions as minimal as possible in here!
|
||||
if (sceneToTransitionTo) {
|
||||
currentEffectForTransition->update();
|
||||
|
||||
if (currentEffectForTransition->isDone()) {
|
||||
setScene(sceneToTransitionTo);
|
||||
}
|
||||
}
|
||||
|
||||
u16 keys = readKeys();
|
||||
// main scene update loop call. This *might* take a while.
|
||||
currentScene->tick(keys);
|
||||
|
||||
// Intentionally commented out: asking the scene for sprites() rebuilds the
|
||||
// vector each time Causing a big performance hit. Instead, you should call
|
||||
// updateSpritesInScene() yourself! if(currentScene->sprites().size() !=
|
||||
// spriteManager.getSpriteSize()) {
|
||||
// updateSpritesInScene();
|
||||
// }
|
||||
|
||||
// VSync disabled (you should handle it externally)
|
||||
// vsync();
|
||||
spriteManager.render();
|
||||
}
|
||||
|
||||
void updateSpritesInScene();
|
||||
void delay(int times) {
|
||||
for (int i = 0; i < times; i++) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_GBAENGINE_H
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 14/12/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#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,31 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 05/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_COMBINED_PALETTE_H
|
||||
#define GBA_SPRITE_ENGINE_COMBINED_PALETTE_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
class PaletteManager;
|
||||
|
||||
class CombinedPalette {
|
||||
private:
|
||||
// WHY use references here? lifetimes not bound, not owned by CombinedPalette
|
||||
PaletteManager& palette1;
|
||||
PaletteManager& palette2;
|
||||
|
||||
void changeBrightness(PaletteManager& palette,
|
||||
int bank,
|
||||
int index,
|
||||
int intensity);
|
||||
|
||||
public:
|
||||
CombinedPalette(PaletteManager& one, PaletteManager& two)
|
||||
: palette1(one), palette2(two) {}
|
||||
CombinedPalette(const CombinedPalette& other) = delete;
|
||||
|
||||
void changeBrightness(int 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
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#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 changeBrightness(int intensity);
|
||||
|
||||
static COLOR modify(COLOR color, int 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,53 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SCRENE_H
|
||||
#define GBA_SPRITE_ENGINE_SCRENE_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/background/background.h>
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
#include <libgba-sprite-engine/sprites/sprite.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class GBAEngine;
|
||||
|
||||
class Scene {
|
||||
protected:
|
||||
std::unique_ptr<ForegroundPaletteManager> foregroundPalette;
|
||||
std::unique_ptr<BackgroundPaletteManager> backgroundPalette;
|
||||
std::shared_ptr<GBAEngine> engine;
|
||||
|
||||
void addSprite(Sprite* sprite);
|
||||
|
||||
public:
|
||||
ForegroundPaletteManager* getForegroundPalette() {
|
||||
return foregroundPalette.get();
|
||||
}
|
||||
BackgroundPaletteManager* getBackgroundPalette() {
|
||||
return backgroundPalette.get();
|
||||
}
|
||||
|
||||
// WHY raw pointers? they're unwrapped unique_ptrs managed by the scene
|
||||
// implementation - will be cleaned up in engine
|
||||
virtual std::vector<Sprite*> sprites() = 0;
|
||||
virtual std::vector<Background*> backgrounds() = 0;
|
||||
|
||||
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,74 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 07/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SOUND_H
|
||||
#define GBA_SPRITE_ENGINE_SOUND_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_memmap.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||
#include <memory>
|
||||
|
||||
#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,41 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_AFFINE_SPRITE_H
|
||||
#define GBA_SPRITE_ENGINE_AFFINE_SPRITE_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include "sprite.h"
|
||||
|
||||
class SpriteManager;
|
||||
|
||||
class AffineSprite : public Sprite {
|
||||
private:
|
||||
int affIndex;
|
||||
std::unique_ptr<OBJ_AFFINE> affine;
|
||||
void setTransformationMatrix(OBJ_AFFINE* matrix);
|
||||
|
||||
void rebuildOamAttr1ForAffineIndex();
|
||||
|
||||
protected:
|
||||
void buildOam(int tileIndex) override;
|
||||
void syncOam() override;
|
||||
|
||||
public:
|
||||
void setAffineIndex(int index) { this->affIndex = index; }
|
||||
void identity();
|
||||
void rotate(u16 alpha);
|
||||
explicit AffineSprite(const AffineSprite& other);
|
||||
explicit AffineSprite(const void* imgData,
|
||||
int imgSize,
|
||||
int xC,
|
||||
int yC,
|
||||
SpriteSize spriteSize);
|
||||
OBJ_AFFINE* getMatrix() { return affine.get(); }
|
||||
|
||||
friend class SpriteManager;
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_AFFINE_SPRITE_H
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 26/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SPRITE_H
|
||||
#define GBA_SPRITE_ENGINE_SPRITE_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
// inline-functions---
|
||||
#include <libgba-sprite-engine/background/text_stream.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#define GBA_SCREEN_WIDTH 240
|
||||
#define GBA_SCREEN_HEIGHT 160
|
||||
// -------------------
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||
|
||||
#include <memory>
|
||||
#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 <libgba-sprite-engine/gbavector.h>
|
||||
|
||||
#define COLOR_MODE_16 0
|
||||
#define COLOR_MODE_256 1
|
||||
#define GFX_MODE 0
|
||||
#define MOSAIC_MODE 1
|
||||
#define AFFINE_FLAG_NONE_SET_YET 0
|
||||
#define HORIZONTAL_FLIP_FLAG 0
|
||||
#define VERTICAL_FLIP_FLAG 0
|
||||
|
||||
#define FLIP_VERTICAL_CLEAR 0xdfff
|
||||
#define FLIP_HORIZONTAL_CLEAR 0xefff
|
||||
#define OAM_TILE_OFFSET_CLEAR 0xfc00
|
||||
#define OAM_TILE_OFFSET_NEW 0x03ff
|
||||
|
||||
enum SpriteSize {
|
||||
SIZE_8_8,
|
||||
SIZE_16_16,
|
||||
SIZE_32_32,
|
||||
SIZE_64_64,
|
||||
SIZE_16_8,
|
||||
SIZE_32_8,
|
||||
SIZE_32_16,
|
||||
SIZE_64_32,
|
||||
SIZE_8_16,
|
||||
SIZE_8_32,
|
||||
SIZE_16_32,
|
||||
SIZE_32_64
|
||||
};
|
||||
|
||||
class SpriteManager;
|
||||
|
||||
class Sprite {
|
||||
private:
|
||||
inline void updateAnimation();
|
||||
inline void syncPosition();
|
||||
|
||||
protected:
|
||||
const void* data;
|
||||
int x, y;
|
||||
u8 animation_offset;
|
||||
u32 priority, w, h, size_bits, shape_bits;
|
||||
u32 imageSize, tileIndex;
|
||||
SpriteSize spriteSize;
|
||||
u8 animationDelay, numberOfFrames, beginFrame, currentFrame, previousFrame,
|
||||
animationCounter;
|
||||
bool animating;
|
||||
|
||||
inline void syncAnimation();
|
||||
inline void syncOam();
|
||||
inline void buildOam(int tileIndex);
|
||||
inline void setAttributesBasedOnSize(SpriteSize size);
|
||||
|
||||
public:
|
||||
OBJ_ATTR oam;
|
||||
bool enabled = true;
|
||||
explicit Sprite(const Sprite& other);
|
||||
explicit Sprite(const void* imageData,
|
||||
int imageSize,
|
||||
int x,
|
||||
int y,
|
||||
SpriteSize size);
|
||||
virtual ~Sprite() {}
|
||||
|
||||
inline const void* getData() { return data; }
|
||||
inline void setData(void* newData) { data = newData; }
|
||||
inline u32 getImageSize() { return imageSize; }
|
||||
inline void setImageSize(u32 size) { imageSize = size; }
|
||||
|
||||
inline void setPriority(u32 priority) { this->priority = priority; }
|
||||
inline void makeAnimated(int beginFrame,
|
||||
int numberOfFrames,
|
||||
int animationDelay);
|
||||
inline void setBeginFrame(int frame) { this->beginFrame = frame; }
|
||||
inline void animateToFrame(int frame) { this->currentFrame = frame; }
|
||||
inline void animate() { this->animating = true; }
|
||||
inline void stopAnimating() { this->animating = false; }
|
||||
inline void update();
|
||||
|
||||
inline void moveTo(int x, int y);
|
||||
inline void moveTo(VECTOR location);
|
||||
inline bool collidesWith(Sprite& s2);
|
||||
|
||||
inline void flipVertically(bool flip);
|
||||
inline void flipHorizontally(bool flip);
|
||||
|
||||
inline u32 getTileIndex() { return tileIndex; }
|
||||
inline VECTOR getPos() { return {x, y}; }
|
||||
inline GBAVector getPosAsVector() { return GBAVector(getPos()); }
|
||||
inline VECTOR getCenter() { return {x + w / 2, y + h / 2}; }
|
||||
inline int getX() { return x; }
|
||||
inline int getY() { return y; }
|
||||
inline u32 getWidth() { return w; }
|
||||
inline u32 getHeight() { return h; }
|
||||
inline u32 getAnimationDelay() { return animationDelay; }
|
||||
inline u32 getNumberOfFrames() { return numberOfFrames; }
|
||||
inline u32 getCurrentFrame() { return currentFrame; }
|
||||
inline bool isAnimating() { return animating; };
|
||||
inline bool isOffScreen();
|
||||
|
||||
friend class SpriteManager;
|
||||
};
|
||||
|
||||
inline void Sprite::moveTo(VECTOR location) {
|
||||
moveTo(location.x, location.y);
|
||||
}
|
||||
|
||||
inline void Sprite::moveTo(int x, int y) {
|
||||
if (x == this->x && y == this->y)
|
||||
return;
|
||||
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
inline bool Sprite::isOffScreen() {
|
||||
return x < 0 || x > GBA_SCREEN_WIDTH || y < 0 || y > GBA_SCREEN_HEIGHT;
|
||||
}
|
||||
|
||||
inline void Sprite::flipHorizontally(bool flip) {
|
||||
if (flip) {
|
||||
oam.attr1 |= ATTR1_HFLIP;
|
||||
} else {
|
||||
oam.attr1 &= FLIP_HORIZONTAL_CLEAR;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Sprite::flipVertically(bool flip) {
|
||||
if (flip) {
|
||||
oam.attr1 |= ATTR1_VFLIP;
|
||||
} else {
|
||||
oam.attr1 &= FLIP_VERTICAL_CLEAR;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Sprite::makeAnimated(int beginFrame,
|
||||
int numberOfFrames,
|
||||
int animationDelay) {
|
||||
previousFrame = -1;
|
||||
setBeginFrame(beginFrame);
|
||||
animateToFrame(beginFrame);
|
||||
this->numberOfFrames = numberOfFrames;
|
||||
this->animationDelay = animationDelay;
|
||||
animate();
|
||||
}
|
||||
|
||||
inline void Sprite::syncPosition() {
|
||||
oam.attr0 = (oam.attr0 & ~ATTR0_Y_MASK) | (y & ATTR0_Y_MASK);
|
||||
oam.attr1 = (oam.attr1 & ~ATTR1_X_MASK) | (x & ATTR1_X_MASK);
|
||||
oam.attr2 =
|
||||
(oam.attr2 & ~ATTR2_PRIO_MASK) | (ATTR2_PRIO(priority) & ATTR2_PRIO_MASK);
|
||||
}
|
||||
|
||||
inline void Sprite::syncAnimation() {
|
||||
if (previousFrame == currentFrame)
|
||||
return;
|
||||
|
||||
int newTileIndex =
|
||||
this->tileIndex + (currentFrame * (this->animation_offset * 2));
|
||||
oam.attr2 &= OAM_TILE_OFFSET_CLEAR;
|
||||
oam.attr2 |= (newTileIndex & OAM_TILE_OFFSET_NEW);
|
||||
|
||||
previousFrame = currentFrame;
|
||||
}
|
||||
|
||||
inline void Sprite::syncOam() {
|
||||
syncPosition();
|
||||
syncAnimation();
|
||||
}
|
||||
|
||||
inline void Sprite::updateAnimation() {
|
||||
if (!animating)
|
||||
return;
|
||||
|
||||
animationCounter++;
|
||||
if (animationCounter > animationDelay) {
|
||||
currentFrame++;
|
||||
if (currentFrame > (numberOfFrames - 1) + beginFrame) {
|
||||
currentFrame = beginFrame;
|
||||
}
|
||||
if (currentFrame < beginFrame) {
|
||||
currentFrame = beginFrame;
|
||||
}
|
||||
|
||||
animationCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Sprite::update() {
|
||||
updateAnimation();
|
||||
syncOam();
|
||||
}
|
||||
|
||||
inline void Sprite::setAttributesBasedOnSize(SpriteSize size) {
|
||||
switch (size) {
|
||||
case SIZE_8_8:
|
||||
size_bits = 0;
|
||||
shape_bits = 0;
|
||||
w = 8;
|
||||
h = 8;
|
||||
animation_offset = 1;
|
||||
break;
|
||||
case SIZE_16_16:
|
||||
size_bits = 1;
|
||||
shape_bits = 0;
|
||||
w = 16;
|
||||
h = 16;
|
||||
animation_offset = 4;
|
||||
break;
|
||||
case SIZE_32_32:
|
||||
size_bits = 2;
|
||||
shape_bits = 0;
|
||||
w = 32;
|
||||
h = 32;
|
||||
animation_offset = 16;
|
||||
break;
|
||||
case SIZE_64_64:
|
||||
size_bits = 3;
|
||||
shape_bits = 0;
|
||||
w = 64;
|
||||
h = 64;
|
||||
animation_offset = 64;
|
||||
break;
|
||||
case SIZE_16_8:
|
||||
size_bits = 0;
|
||||
shape_bits = 1;
|
||||
w = 16;
|
||||
h = 8;
|
||||
animation_offset = 2;
|
||||
break;
|
||||
case SIZE_32_8:
|
||||
size_bits = 1;
|
||||
shape_bits = 1;
|
||||
w = 32;
|
||||
h = 8;
|
||||
animation_offset = 4;
|
||||
break;
|
||||
case SIZE_32_16:
|
||||
size_bits = 2;
|
||||
shape_bits = 1;
|
||||
w = 32;
|
||||
h = 16;
|
||||
animation_offset = 8;
|
||||
break;
|
||||
case SIZE_64_32:
|
||||
size_bits = 3;
|
||||
shape_bits = 1;
|
||||
w = 64;
|
||||
h = 32;
|
||||
animation_offset = 32;
|
||||
break;
|
||||
case SIZE_8_16:
|
||||
size_bits = 0;
|
||||
shape_bits = 2;
|
||||
w = 8;
|
||||
h = 16;
|
||||
animation_offset = 2;
|
||||
break;
|
||||
case SIZE_8_32:
|
||||
size_bits = 1;
|
||||
shape_bits = 2;
|
||||
w = 8;
|
||||
h = 32;
|
||||
animation_offset = 4;
|
||||
break;
|
||||
case SIZE_16_32:
|
||||
size_bits = 2;
|
||||
shape_bits = 2;
|
||||
w = 16;
|
||||
h = 32;
|
||||
animation_offset = 8;
|
||||
break;
|
||||
case SIZE_32_64:
|
||||
size_bits = 3;
|
||||
shape_bits = 2;
|
||||
w = 32;
|
||||
h = 64;
|
||||
animation_offset = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Sprite::collidesWith(Sprite& s2) {
|
||||
const Sprite& s1 = *this;
|
||||
|
||||
if (s1.x < s2.x + s2.w && s1.x + s1.w > s2.x && s1.y < s2.y + s2.h &&
|
||||
s1.h + s1.y > s2.y) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Sprite::buildOam(int tileIndex) {
|
||||
this->tileIndex = tileIndex;
|
||||
|
||||
oam.attr0 = ATTR0_Y(this->y & 0x00FF) | ATTR0_MODE(0) | (GFX_MODE << 10) |
|
||||
(MOSAIC_MODE << 12) | (COLOR_MODE_256 << 13) |
|
||||
(this->shape_bits << 14);
|
||||
oam.attr1 = (this->x & 0x01FF) | (AFFINE_FLAG_NONE_SET_YET << 9) |
|
||||
(HORIZONTAL_FLIP_FLAG << 12) | (VERTICAL_FLIP_FLAG << 13) |
|
||||
(this->size_bits << 14);
|
||||
|
||||
oam.attr2 = ATTR2_ID(tileIndex) | ATTR2_PRIO(priority) | ATTR2_PALBANK(0);
|
||||
}
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_SPRITE_H
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 28/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SPRITE_BUILDER_H
|
||||
#define GBA_SPRITE_ENGINE_SPRITE_BUILDER_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include "sprite.h"
|
||||
|
||||
template <typename T>
|
||||
class SpriteBuilder {
|
||||
private:
|
||||
u32 imageSize;
|
||||
const void* imageData;
|
||||
u32 x, y;
|
||||
u32 beginFrame, numberOfFrames, animationDelay;
|
||||
SpriteSize size;
|
||||
|
||||
void setProperties(T* sprite);
|
||||
void reset() {
|
||||
imageSize = x = y = beginFrame = numberOfFrames = animationDelay = 0;
|
||||
imageData = nullptr;
|
||||
size = SIZE_16_16;
|
||||
}
|
||||
|
||||
public:
|
||||
SpriteBuilder() { reset(); }
|
||||
SpriteBuilder& withData(const void* imageData, int imageSize) {
|
||||
this->imageData = imageData;
|
||||
this->imageSize = imageSize;
|
||||
return *this;
|
||||
}
|
||||
SpriteBuilder& withLocation(u32 x, u32 y) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
return *this;
|
||||
}
|
||||
SpriteBuilder& withSize(const SpriteSize& size) {
|
||||
this->size = size;
|
||||
return *this;
|
||||
}
|
||||
SpriteBuilder& withAnimated(int numberOfFrames, int animationDelay) {
|
||||
this->beginFrame = 0;
|
||||
this->numberOfFrames = numberOfFrames;
|
||||
this->animationDelay = animationDelay;
|
||||
return *this;
|
||||
}
|
||||
SpriteBuilder& withAnimated(int beginFrame,
|
||||
int numberOfFrames,
|
||||
int animationDelay) {
|
||||
this->beginFrame = beginFrame;
|
||||
this->numberOfFrames = numberOfFrames;
|
||||
this->animationDelay = animationDelay;
|
||||
return *this;
|
||||
}
|
||||
T build();
|
||||
std::unique_ptr<T> buildPtr();
|
||||
std::unique_ptr<T> buildWithDataOf(const Sprite& other);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::unique_ptr<T> SpriteBuilder<T>::buildWithDataOf(const Sprite& other) {
|
||||
auto s = new T(other);
|
||||
s->moveTo(this->x, this->y);
|
||||
setProperties(s);
|
||||
|
||||
reset();
|
||||
return std::unique_ptr<T>(s);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SpriteBuilder<T>::setProperties(T* s) {
|
||||
if (this->numberOfFrames > 0) {
|
||||
s->makeAnimated(this->beginFrame, this->numberOfFrames,
|
||||
this->animationDelay);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::unique_ptr<T> SpriteBuilder<T>::buildPtr() {
|
||||
auto s =
|
||||
new T(this->imageData, this->imageSize, this->x, this->y, this->size);
|
||||
setProperties(s);
|
||||
|
||||
reset();
|
||||
return std::unique_ptr<T>(s);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T SpriteBuilder<T>::build() {
|
||||
T s(this->imageData, this->imageSize, this->x, this->y, this->size);
|
||||
setProperties(&s);
|
||||
|
||||
reset();
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_SPRITE_BUILDER_H
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 26/07/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SPRITE_MANAGER_H
|
||||
#define GBA_SPRITE_ENGINE_SPRITE_MANAGER_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_types.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "sprite.h"
|
||||
|
||||
class SpriteManager {
|
||||
private:
|
||||
bool initialized;
|
||||
std::vector<Sprite*> sprites;
|
||||
|
||||
inline void copyOverSpriteOAMToVRAM() {
|
||||
int i = 0;
|
||||
|
||||
for (auto sprite : this->sprites) {
|
||||
if (sprite->enabled) {
|
||||
sprite->update();
|
||||
oam_mem[i] = sprite->oam;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void copyOverImageDataToVRAM(Sprite* s);
|
||||
void copyOverImageDataToVRAM();
|
||||
|
||||
public:
|
||||
int getSpriteSize() { return sprites.size(); }
|
||||
|
||||
void hideAll();
|
||||
void add(Sprite* sprite);
|
||||
void set(std::vector<Sprite*> sprites);
|
||||
void persist(); // copies over image and palette data to VRAM, modifies
|
||||
// sprite OAM indiches
|
||||
|
||||
inline void
|
||||
render() { // copies over OAM buffer to OAM RAM, called in game loop
|
||||
// WARNING - This is called every time in the main update loop; keep amount
|
||||
// of instructions as minimal as possible in here!
|
||||
copyOverSpriteOAMToVRAM();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // GBA_SPRITE_ENGINE_SPRITE_MANAGER_H
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 06/12/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_TIMER_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_TIMER_H
|
||||
|
||||
#pragma GCC system_header
|
||||
|
||||
#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
|
||||
Binary file not shown.
84
examples/full/src/main.cpp
Normal file
84
examples/full/src/main.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#include <tonc.h>
|
||||
|
||||
#include "../lib/LinkConnection.h"
|
||||
#include "../lib/libgba-sprite-engine/include/libgba-sprite-engine/gba_engine.h"
|
||||
#include "scenes/TestScene.h"
|
||||
#include "utils/SceneUtils.h"
|
||||
|
||||
void setUpInterrupts();
|
||||
void printTutorial();
|
||||
static std::shared_ptr<GBAEngine> engine{new GBAEngine()};
|
||||
static std::unique_ptr<TestScene> testScene{new TestScene(engine)};
|
||||
LinkConnection* linkConnection = new LinkConnection(false);
|
||||
|
||||
int main() {
|
||||
setUpInterrupts();
|
||||
|
||||
engine->setScene(testScene.get());
|
||||
|
||||
printTutorial();
|
||||
|
||||
while (true) {
|
||||
u16 keys = ~REG_KEYS & KEY_ANY;
|
||||
|
||||
if ((keys & KEY_DOWN) && linkConnection->isActive()) {
|
||||
linkConnection->deactivate();
|
||||
DEBULOG("! stopped");
|
||||
}
|
||||
// enable and disable
|
||||
if ((keys & KEY_START) && !linkConnection->isActive()) {
|
||||
linkConnection->activate();
|
||||
DEBULOG("! started");
|
||||
}
|
||||
|
||||
// log player count at important REG_SIOCNT bits
|
||||
TextStream::instance().setText(
|
||||
"P" + asStr(linkConnection->linkState->currentPlayerId) + "/" +
|
||||
asStr(linkConnection->linkState->playerCount) + "-R" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_BIT_READY)) + "-S" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_BIT_START)) + "-E" +
|
||||
asStr(isBitHigh(REG_SIOCNT, LINK_BIT_ERROR)) + "-I" +
|
||||
asStr(linkConnection->linkState->_IRQFlag),
|
||||
0, 11);
|
||||
|
||||
engine->update();
|
||||
|
||||
VBlankIntrWait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void ISR_reset() {
|
||||
RegisterRamReset(RESET_REG | RESET_VRAM);
|
||||
SoftReset();
|
||||
}
|
||||
|
||||
inline void setUpInterrupts() {
|
||||
irq_init(NULL);
|
||||
|
||||
// VBlank
|
||||
irq_add(II_VBLANK, LINK_ISR_VBLANK);
|
||||
|
||||
// Link connection
|
||||
irq_add(II_SERIAL, LINK_ISR_SERIAL);
|
||||
|
||||
// A+B+START+SELECT
|
||||
REG_KEYCNT = 0b1100000000001111;
|
||||
irq_add(II_KEYPAD, ISR_reset);
|
||||
}
|
||||
|
||||
void printTutorial() {
|
||||
DEBULOG("gba-link-connection demo");
|
||||
DEBULOG("");
|
||||
DEBULOG("START: turn on connection");
|
||||
DEBULOG("(on connection, p1 sends 999)");
|
||||
DEBULOG("");
|
||||
DEBULOG("A: send 555 once per frame");
|
||||
DEBULOG("B: send counter once");
|
||||
DEBULOG("L: send 1, then 2");
|
||||
DEBULOG("R: send 43981, then 257");
|
||||
DEBULOG("SELECT: force lag (9k lines)");
|
||||
DEBULOG("DOWN: turn off connection");
|
||||
DEBULOG("");
|
||||
}
|
||||
99
examples/full/src/scenes/TestScene.cpp
Normal file
99
examples/full/src/scenes/TestScene.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#include "TestScene.h"
|
||||
|
||||
#include <libgba-sprite-engine/background/text_stream.h>
|
||||
|
||||
#include "../lib/LinkConnection.h"
|
||||
#include "utils/InputHandler.h"
|
||||
#include "utils/SceneUtils.h"
|
||||
|
||||
TestScene::TestScene(std::shared_ptr<GBAEngine> engine) : Scene(engine) {}
|
||||
|
||||
static std::unique_ptr<InputHandler> aHandler =
|
||||
std::unique_ptr<InputHandler>(new InputHandler());
|
||||
static std::unique_ptr<InputHandler> bHandler =
|
||||
std::unique_ptr<InputHandler>(new InputHandler());
|
||||
static std::unique_ptr<InputHandler> lHandler =
|
||||
std::unique_ptr<InputHandler>(new InputHandler());
|
||||
static std::unique_ptr<InputHandler> rHandler =
|
||||
std::unique_ptr<InputHandler>(new InputHandler());
|
||||
static std::unique_ptr<InputHandler> selectHandler =
|
||||
std::unique_ptr<InputHandler>(new InputHandler());
|
||||
|
||||
inline void send(u16 data) {
|
||||
DEBULOG("-> " + asStr(data));
|
||||
linkConnection->send(data);
|
||||
}
|
||||
|
||||
std::vector<Background*> TestScene::backgrounds() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Sprite*> TestScene::sprites() {
|
||||
std::vector<Sprite*> sprites;
|
||||
return sprites;
|
||||
}
|
||||
|
||||
void TestScene::load() {
|
||||
SCENE_init();
|
||||
BACKGROUND_enable(true, false, false, false);
|
||||
}
|
||||
|
||||
void TestScene::tick(u16 keys) {
|
||||
if (engine->isTransitioning())
|
||||
return;
|
||||
|
||||
// check keys
|
||||
aHandler->setIsPressed(keys & KEY_A);
|
||||
bHandler->setIsPressed(keys & KEY_B);
|
||||
lHandler->setIsPressed(keys & KEY_L);
|
||||
rHandler->setIsPressed(keys & KEY_R);
|
||||
selectHandler->setIsPressed(keys & KEY_SELECT);
|
||||
|
||||
// log events
|
||||
auto linkState = linkConnection->linkState.get();
|
||||
if (!isConnected && linkState->isConnected()) {
|
||||
isConnected = true;
|
||||
initialized = false;
|
||||
DEBULOG("! connected (" + asStr(linkState->playerCount) + " players)");
|
||||
}
|
||||
if (isConnected && !linkState->isConnected()) {
|
||||
isConnected = false;
|
||||
DEBULOG("! disconnected");
|
||||
}
|
||||
if (selectHandler->hasBeenPressedNow()) {
|
||||
DEBULOG("! lagging...");
|
||||
SCENE_wait(9000);
|
||||
}
|
||||
|
||||
// get data
|
||||
u16 value = LINK_NO_DATA;
|
||||
if (!initialized && linkConnection->linkState->currentPlayerId == 1) {
|
||||
initialized = true;
|
||||
value = 999;
|
||||
}
|
||||
if (aHandler->getIsPressed())
|
||||
value = 555;
|
||||
if (bHandler->hasBeenPressedNow()) {
|
||||
counter++;
|
||||
value = counter;
|
||||
}
|
||||
|
||||
// send data
|
||||
if (lHandler->hasBeenPressedNow()) {
|
||||
send(1);
|
||||
send(2);
|
||||
} else if (rHandler->hasBeenPressedNow()) {
|
||||
send(43981);
|
||||
send(257);
|
||||
} else if (value != LINK_NO_DATA)
|
||||
send(value);
|
||||
|
||||
// process received data
|
||||
if (linkState->isConnected())
|
||||
for (u32 i = 0; i < linkState->playerCount; i++)
|
||||
while (linkState->hasMessage(i)) {
|
||||
u16 message = linkState->readMessage(i);
|
||||
if (i != linkState->currentPlayerId)
|
||||
DEBULOG("<-p" + asStr(i) + ": " + asStr(message));
|
||||
}
|
||||
}
|
||||
30
examples/full/src/scenes/TestScene.h
Normal file
30
examples/full/src/scenes/TestScene.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef TEST_SCENE_H
|
||||
#define TEST_SCENE_H
|
||||
|
||||
#include <libgba-sprite-engine/background/background.h>
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include <libgba-sprite-engine/scene.h>
|
||||
#include <libgba-sprite-engine/sprites/sprite.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
class TestScene : public Scene {
|
||||
public:
|
||||
u16 data = 0;
|
||||
TestScene(std::shared_ptr<GBAEngine> engine);
|
||||
|
||||
std::vector<Background*> backgrounds() override;
|
||||
std::vector<Sprite*> sprites() override;
|
||||
|
||||
void load() override;
|
||||
void tick(u16 keys) override;
|
||||
|
||||
private:
|
||||
u32 counter = 0;
|
||||
bool isConnected = false;
|
||||
bool initialized = false;
|
||||
|
||||
void log(std::string text);
|
||||
};
|
||||
|
||||
#endif // TEST_SCENE_H
|
||||
14
examples/full/src/utils/BackgroundUtils.h
Normal file
14
examples/full/src/utils/BackgroundUtils.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef BACKGROUND_UTILS_H
|
||||
#define BACKGROUND_UTILS_H
|
||||
|
||||
#include <tonc_memdef.h>
|
||||
#include <tonc_memmap.h>
|
||||
|
||||
inline void BACKGROUND_enable(bool bg0, bool bg1, bool bg2, bool bg3) {
|
||||
REG_DISPCNT = bg0 ? REG_DISPCNT | DCNT_BG0 : REG_DISPCNT & ~DCNT_BG0;
|
||||
REG_DISPCNT = bg1 ? REG_DISPCNT | DCNT_BG1 : REG_DISPCNT & ~DCNT_BG1;
|
||||
REG_DISPCNT = bg2 ? REG_DISPCNT | DCNT_BG2 : REG_DISPCNT & ~DCNT_BG2;
|
||||
REG_DISPCNT = bg3 ? REG_DISPCNT | DCNT_BG3 : REG_DISPCNT & ~DCNT_BG3;
|
||||
}
|
||||
|
||||
#endif // BACKGROUND_UTILS_H
|
||||
34
examples/full/src/utils/InputHandler.h
Normal file
34
examples/full/src/utils/InputHandler.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef INPUT_HANDLER_H
|
||||
#define INPUT_HANDLER_H
|
||||
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
|
||||
class InputHandler {
|
||||
public:
|
||||
InputHandler() { this->isPressed = false; }
|
||||
|
||||
inline bool getIsPressed() { return isPressed; }
|
||||
|
||||
inline bool hasBeenPressedNow() { return isNewPressEvent; }
|
||||
inline bool hasBeenReleasedNow() { return isNewReleaseEvent; }
|
||||
|
||||
inline bool getHandledFlag() { return handledFlag; }
|
||||
inline void setHandledFlag(bool value) { handledFlag = value; }
|
||||
|
||||
inline void setIsPressed(bool isPressed) {
|
||||
bool isNewPressEvent = !this->isPressed && isPressed;
|
||||
bool isNewReleaseEvent = this->isPressed && !isPressed;
|
||||
this->isPressed = isPressed;
|
||||
|
||||
this->isNewPressEvent = isNewPressEvent;
|
||||
this->isNewReleaseEvent = isNewReleaseEvent;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isPressed = false;
|
||||
bool isNewPressEvent = false;
|
||||
bool isNewReleaseEvent;
|
||||
bool handledFlag = false;
|
||||
};
|
||||
|
||||
#endif // INPUT_HANDLER_H
|
||||
14
examples/full/src/utils/SceneUtils.cpp
Normal file
14
examples/full/src/utils/SceneUtils.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "SceneUtils.h"
|
||||
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
|
||||
int DEBULOG_LINE = 2;
|
||||
|
||||
void DEBULOG(std::string string) {
|
||||
TextStream::instance().setText(string, DEBULOG_LINE, -3);
|
||||
DEBULOG_LINE++;
|
||||
for (u32 i = DEBULOG_LINE; i < 20; i++)
|
||||
TextStream::instance().setText(" ", i, -3);
|
||||
if (DEBULOG_LINE >= 20)
|
||||
DEBULOG_LINE = 2;
|
||||
}
|
||||
50
examples/full/src/utils/SceneUtils.h
Normal file
50
examples/full/src/utils/SceneUtils.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef SCENE_UTILS_H
|
||||
#define SCENE_UTILS_H
|
||||
|
||||
#include <libgba-sprite-engine/background/text_stream.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "BackgroundUtils.h"
|
||||
#include "SpriteUtils.h"
|
||||
|
||||
const u32 TEXT_MIDDLE_COL = 12;
|
||||
|
||||
extern int DEBULOG_LINE;
|
||||
void DEBULOG(std::string string);
|
||||
|
||||
inline std::string asStr(u16 data) {
|
||||
return std::to_string(data);
|
||||
}
|
||||
|
||||
inline bool isBitHigh(u16 data, u8 bit) {
|
||||
return (data >> bit) & 1;
|
||||
}
|
||||
|
||||
inline void SCENE_init() {
|
||||
TextStream::instance().clear();
|
||||
TextStream::instance().scroll(0, 0);
|
||||
TextStream::instance().setMosaic(false);
|
||||
|
||||
BACKGROUND_enable(false, false, false, false);
|
||||
SPRITE_disable();
|
||||
}
|
||||
|
||||
inline void SCENE_write(std::string text, u32 row) {
|
||||
TextStream::instance().setText(text, row,
|
||||
TEXT_MIDDLE_COL - text.length() / 2);
|
||||
}
|
||||
|
||||
inline void SCENE_wait(u32 verticalLines) {
|
||||
u32 lines = 0;
|
||||
u32 vCount = REG_VCOUNT;
|
||||
|
||||
while (lines < verticalLines) {
|
||||
if (REG_VCOUNT != vCount) {
|
||||
lines++;
|
||||
vCount = REG_VCOUNT;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SCENE_UTILS_H
|
||||
11
examples/full/src/utils/SpriteUtils.h
Normal file
11
examples/full/src/utils/SpriteUtils.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef SPRITE_UTILS_H
|
||||
#define SPRITE_UTILS_H
|
||||
|
||||
#include <tonc_memdef.h>
|
||||
#include <tonc_memmap.h>
|
||||
|
||||
inline void SPRITE_disable() {
|
||||
REG_DISPCNT = REG_DISPCNT & ~DCNT_OBJ;
|
||||
}
|
||||
|
||||
#endif // SPRITE_UTILS_H
|
||||
274
lib/LinkConnection.h
Normal file
274
lib/LinkConnection.h
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
#ifndef LINK_CONNECTION_H
|
||||
#define LINK_CONNECTION_H
|
||||
|
||||
#include <tonc_core.h>
|
||||
#include <tonc_memdef.h>
|
||||
#include <tonc_memmap.h>
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#define LINK_MAX_PLAYERS 4
|
||||
#define LINK_DISCONNECTED 0xFFFF
|
||||
#define LINK_NO_DATA 0x0
|
||||
#define LINK_TRANSFER_VCOUNT_WAIT 2
|
||||
#define LINK_DEFAULT_TIMEOUT 3
|
||||
#define LINK_DEFAULT_BUFFER_SIZE 60
|
||||
#define LINK_BIT_SLAVE 2
|
||||
#define LINK_BIT_READY 3
|
||||
#define LINK_BITS_PLAYER_ID 4
|
||||
#define LINK_BIT_ERROR 6
|
||||
#define LINK_BIT_START 7
|
||||
#define LINK_BIT_MULTIPLAYER 13
|
||||
#define LINK_BIT_IRQ 14
|
||||
#define LINK_BIT_GENERAL_PURPOSE_LOW 14
|
||||
#define LINK_BIT_GENERAL_PURPOSE_HIGH 15
|
||||
#define LINK_SET_HIGH(REG, BIT) REG |= 1 << BIT
|
||||
#define LINK_SET_LOW(REG, BIT) REG &= ~(1 << BIT)
|
||||
|
||||
// A Link Cable connection for Multi-player mode.
|
||||
|
||||
// Usage:
|
||||
// - 1) Include this header in your main.cpp file and add:
|
||||
// LinkConnection* linkConnection = new LinkConnection();
|
||||
// - 2) Add the interrupt service routines:
|
||||
// irq_add(II_VBLANK, LINK_ISR_VBLANK);
|
||||
// irq_add(II_SERIAL, LINK_ISR_SERIAL);
|
||||
// - 3) Send/read messages by using:
|
||||
// linkConnection->send(...);
|
||||
// linkConnection->linkState
|
||||
|
||||
// `data` restrictions:
|
||||
// 0xFFFF and 0x0 are reserved values, so don't use them
|
||||
// (they mean 'disconnected' and 'no data' respectively)
|
||||
|
||||
void LINK_ISR_VBLANK();
|
||||
void LINK_ISR_SERIAL();
|
||||
u16 LINK_QUEUE_POP(std::queue<u16>& q);
|
||||
void LINK_QUEUE_CLEAR(std::queue<u16>& q);
|
||||
|
||||
struct LinkState {
|
||||
u8 playerCount;
|
||||
u8 currentPlayerId;
|
||||
std::queue<u16> _incomingMessages[LINK_MAX_PLAYERS];
|
||||
std::queue<u16> _outgoingMessages;
|
||||
bool _IRQFlag;
|
||||
u32 _IRQTimeout;
|
||||
|
||||
bool isConnected() {
|
||||
return playerCount > 1 && currentPlayerId < playerCount;
|
||||
}
|
||||
|
||||
bool hasMessage(u8 playerId) {
|
||||
if (playerId >= playerCount)
|
||||
return false;
|
||||
|
||||
return !_incomingMessages[playerId].empty();
|
||||
}
|
||||
|
||||
u16 readMessage(u8 playerId) {
|
||||
return LINK_QUEUE_POP(_incomingMessages[playerId]);
|
||||
}
|
||||
};
|
||||
|
||||
class LinkConnection {
|
||||
public:
|
||||
enum BaudRate {
|
||||
BAUD_RATE_0, // 9600 bps
|
||||
BAUD_RATE_1, // 38400 bps
|
||||
BAUD_RATE_2, // 57600 bps
|
||||
BAUD_RATE_3 // 115200 bps
|
||||
};
|
||||
std::unique_ptr<struct LinkState> linkState{new LinkState()};
|
||||
|
||||
explicit LinkConnection(bool startNow = true,
|
||||
BaudRate baudRate = BAUD_RATE_3,
|
||||
u32 timeout = LINK_DEFAULT_TIMEOUT,
|
||||
u32 bufferSize = LINK_DEFAULT_BUFFER_SIZE) {
|
||||
this->baudRate = baudRate;
|
||||
this->timeout = timeout;
|
||||
this->bufferSize = bufferSize;
|
||||
|
||||
if (startNow)
|
||||
activate();
|
||||
else
|
||||
stop();
|
||||
}
|
||||
|
||||
bool isActive() { return isEnabled; }
|
||||
|
||||
void activate() {
|
||||
isEnabled = true;
|
||||
reset();
|
||||
}
|
||||
|
||||
void deactivate() {
|
||||
isEnabled = false;
|
||||
resetState();
|
||||
stop();
|
||||
}
|
||||
|
||||
void send(u16 data) {
|
||||
if (data == LINK_DISCONNECTED || data == LINK_NO_DATA)
|
||||
return;
|
||||
|
||||
push(linkState->_outgoingMessages, data);
|
||||
}
|
||||
|
||||
bool isReady() {
|
||||
return isBitHigh(LINK_BIT_READY) && !isBitHigh(LINK_BIT_ERROR);
|
||||
}
|
||||
|
||||
void _onVBlank() {
|
||||
if (!isEnabled || resetIfNeeded())
|
||||
return;
|
||||
|
||||
if (!linkState->_IRQFlag) {
|
||||
linkState->_IRQTimeout++;
|
||||
|
||||
if (linkState->_IRQTimeout >= timeout)
|
||||
reset();
|
||||
else if (isMaster())
|
||||
transfer(LINK_NO_DATA, true);
|
||||
}
|
||||
|
||||
linkState->_IRQFlag = false;
|
||||
}
|
||||
|
||||
void _onSerial() {
|
||||
if (!isEnabled || resetIfNeeded())
|
||||
return;
|
||||
|
||||
linkState->_IRQFlag = true;
|
||||
linkState->_IRQTimeout = 0;
|
||||
|
||||
linkState->playerCount = 0;
|
||||
linkState->currentPlayerId =
|
||||
(REG_SIOCNT & (0b11 << LINK_BITS_PLAYER_ID)) >> LINK_BITS_PLAYER_ID;
|
||||
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++) {
|
||||
u16 data = REG_SIOMULTI[i];
|
||||
|
||||
if (data != LINK_DISCONNECTED) {
|
||||
if (data != LINK_NO_DATA)
|
||||
push(linkState->_incomingMessages[i], data);
|
||||
linkState->playerCount++;
|
||||
} else
|
||||
LINK_QUEUE_CLEAR(linkState->_incomingMessages[i]);
|
||||
}
|
||||
|
||||
if (linkState->isConnected())
|
||||
sendPendingData();
|
||||
}
|
||||
|
||||
private:
|
||||
BaudRate baudRate;
|
||||
u32 timeout;
|
||||
u32 bufferSize;
|
||||
bool isEnabled = false;
|
||||
|
||||
void sendPendingData() {
|
||||
transfer(LINK_QUEUE_POP(linkState->_outgoingMessages));
|
||||
}
|
||||
|
||||
void transfer(u16 data, bool force = false) {
|
||||
bool shouldNotify = isMaster() && (data != LINK_NO_DATA || force);
|
||||
|
||||
if (shouldNotify)
|
||||
setBitLow(LINK_BIT_START);
|
||||
|
||||
wait(LINK_TRANSFER_VCOUNT_WAIT);
|
||||
REG_SIOMLT_SEND = data;
|
||||
|
||||
if (shouldNotify)
|
||||
setBitHigh(LINK_BIT_START);
|
||||
}
|
||||
|
||||
bool resetIfNeeded() {
|
||||
if (!isReady()) {
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
resetState();
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
|
||||
void resetState() {
|
||||
linkState->playerCount = 0;
|
||||
linkState->currentPlayerId = 0;
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++)
|
||||
LINK_QUEUE_CLEAR(linkState->_incomingMessages[i]);
|
||||
LINK_QUEUE_CLEAR(linkState->_outgoingMessages);
|
||||
linkState->_IRQFlag = false;
|
||||
linkState->_IRQTimeout = 0;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
LINK_SET_LOW(REG_RCNT, LINK_BIT_GENERAL_PURPOSE_LOW);
|
||||
LINK_SET_HIGH(REG_RCNT, LINK_BIT_GENERAL_PURPOSE_HIGH);
|
||||
}
|
||||
|
||||
void start() {
|
||||
LINK_SET_LOW(REG_RCNT, LINK_BIT_GENERAL_PURPOSE_HIGH);
|
||||
REG_SIOCNT = baudRate;
|
||||
REG_SIOMLT_SEND = 0;
|
||||
setBitHigh(LINK_BIT_MULTIPLAYER);
|
||||
setBitHigh(LINK_BIT_IRQ);
|
||||
}
|
||||
|
||||
void push(std::queue<u16>& q, u16 value) {
|
||||
if (q.size() >= bufferSize)
|
||||
LINK_QUEUE_POP(q);
|
||||
|
||||
q.push(value);
|
||||
}
|
||||
|
||||
void wait(u32 verticalLines) {
|
||||
u32 lines = 0;
|
||||
u32 vCount = REG_VCOUNT;
|
||||
|
||||
while (lines < verticalLines) {
|
||||
if (REG_VCOUNT != vCount) {
|
||||
lines++;
|
||||
vCount = REG_VCOUNT;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool isMaster() { return !isBitHigh(LINK_BIT_SLAVE); }
|
||||
bool isBitHigh(u8 bit) { return (REG_SIOCNT >> bit) & 1; }
|
||||
void setBitHigh(u8 bit) { LINK_SET_HIGH(REG_SIOCNT, bit); }
|
||||
void setBitLow(u8 bit) { LINK_SET_LOW(REG_SIOCNT, bit); }
|
||||
};
|
||||
|
||||
extern LinkConnection* linkConnection;
|
||||
|
||||
inline void LINK_ISR_VBLANK() {
|
||||
linkConnection->_onVBlank();
|
||||
}
|
||||
|
||||
inline void LINK_ISR_SERIAL() {
|
||||
linkConnection->_onSerial();
|
||||
}
|
||||
|
||||
inline u16 LINK_QUEUE_POP(std::queue<u16>& q) {
|
||||
if (q.empty())
|
||||
return LINK_NO_DATA;
|
||||
|
||||
u16 value = q.front();
|
||||
q.pop();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline void LINK_QUEUE_CLEAR(std::queue<u16>& q) {
|
||||
while (!q.empty())
|
||||
LINK_QUEUE_POP(q);
|
||||
}
|
||||
|
||||
#endif // LINK_CONNECTION_H
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
#ifndef LINK_CONNECTION_H
|
||||
#define LINK_CONNECTION_H
|
||||
|
||||
#include <tonc_core.h>
|
||||
#include <tonc_memmap.h>
|
||||
|
||||
#define LINK_MAX_PLAYERS 4
|
||||
#define LINK_NO_DATA 0xffff
|
||||
#define LINK_HEART_BIT 0xf
|
||||
#define LINK_HEART_BIT_UNKNOWN 2
|
||||
#define LINK_BIT_SLAVE 2
|
||||
#define LINK_BIT_READY 3
|
||||
#define LINK_BITS_PLAYER_ID 4
|
||||
#define LINK_BIT_ERROR 6
|
||||
#define LINK_BIT_START 7
|
||||
#define LINK_BIT_MULTIPLAYER 13
|
||||
#define LINK_BIT_IRQ 14
|
||||
|
||||
// A Link Cable connection for Multi-player mode.
|
||||
|
||||
// Usage:
|
||||
// - 1) Include this header in your main.cpp file and add:
|
||||
// LinkConnection* linkConnection = new LinkConnection();
|
||||
// - 2) Add the interrupt service routine:
|
||||
// irq_add(II_SERIAL, ISR_serial);
|
||||
// - 3) Add to your update loop:
|
||||
// auto linkState = linkConnection->tick(data);
|
||||
// - 4) Use `linkState` to process updates
|
||||
|
||||
// `data` restrictions:
|
||||
// - 0xFFFF means 'disconnected', so don't use it
|
||||
// - Bit 0xF will be ignored: it'll be used as a heartbeat
|
||||
|
||||
void ISR_serial();
|
||||
u16 _withHeartBit(u16 data, bool heartBit);
|
||||
bool _isBitHigh(u16 data, u8 bit);
|
||||
|
||||
struct LinkState {
|
||||
u8 playerCount;
|
||||
u8 currentPlayerId;
|
||||
u16 data[4];
|
||||
u8 _heartBits[4];
|
||||
u32 _tick;
|
||||
u32 _lastIRQTick;
|
||||
|
||||
bool isConnected() { return playerCount > 1; }
|
||||
bool hasData(u8 playerId) { return data[playerId] != LINK_NO_DATA; }
|
||||
|
||||
bool _isOutOfSync() {
|
||||
return isConnected() &&
|
||||
(_lastIRQTick != _tick || currentPlayerId >= playerCount);
|
||||
}
|
||||
void _sync() { _lastIRQTick = _tick; }
|
||||
void _reset() {
|
||||
playerCount = 0;
|
||||
currentPlayerId = 0;
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++) {
|
||||
data[i] = LINK_NO_DATA;
|
||||
_heartBits[i] = LINK_HEART_BIT_UNKNOWN;
|
||||
}
|
||||
_tick = 0;
|
||||
_lastIRQTick = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class LinkConnection {
|
||||
public:
|
||||
enum BaudRate {
|
||||
BAUD_RATE_0, // 9600 bps
|
||||
BAUD_RATE_1, // 38400 bps
|
||||
BAUD_RATE_2, // 57600 bps
|
||||
BAUD_RATE_3 // 115200 bps
|
||||
};
|
||||
struct LinkState _linkState;
|
||||
|
||||
explicit LinkConnection(BaudRate baudRate = BAUD_RATE_3) {
|
||||
_linkState._reset();
|
||||
REG_RCNT = 0;
|
||||
REG_SIOCNT = (u8)baudRate;
|
||||
setBitHigh(LINK_BIT_MULTIPLAYER);
|
||||
setBitHigh(LINK_BIT_IRQ);
|
||||
}
|
||||
|
||||
LinkState tick(u16 data) {
|
||||
bool shouldForceReset = !isBitHigh(LINK_BIT_READY) ||
|
||||
isBitHigh(LINK_BIT_ERROR) ||
|
||||
_linkState._isOutOfSync();
|
||||
|
||||
if (shouldForceReset) {
|
||||
resetCommunicationCircuit();
|
||||
_linkState._reset();
|
||||
return _linkState;
|
||||
}
|
||||
|
||||
REG_SIOMLT_SEND = _withHeartBit(data, heartBit);
|
||||
_linkState._tick++;
|
||||
heartBit = !heartBit;
|
||||
|
||||
if (!isBitHigh(LINK_BIT_SLAVE))
|
||||
setBitHigh(LINK_BIT_START);
|
||||
|
||||
return _linkState;
|
||||
}
|
||||
|
||||
private:
|
||||
bool heartBit = 0;
|
||||
|
||||
void resetCommunicationCircuit() {
|
||||
REG_RCNT = 0xf;
|
||||
REG_RCNT = 0;
|
||||
}
|
||||
|
||||
bool isBitHigh(u8 bit) { return _isBitHigh(REG_SIOCNT, bit); }
|
||||
void setBitHigh(u8 bit) { REG_SIOCNT |= 1 << bit; }
|
||||
};
|
||||
|
||||
extern LinkConnection* linkConnection;
|
||||
|
||||
inline void ISR_serial() {
|
||||
linkConnection->_linkState.playerCount = 0;
|
||||
linkConnection->_linkState.currentPlayerId =
|
||||
(REG_SIOCNT & (0b11 << LINK_BITS_PLAYER_ID)) >> LINK_BITS_PLAYER_ID;
|
||||
|
||||
for (u32 i = 0; i < LINK_MAX_PLAYERS; i++) {
|
||||
auto data = REG_SIOMULTI[i];
|
||||
u8 oldHeartBit = linkConnection->_linkState._heartBits[i];
|
||||
u8 newHeartBit = _isBitHigh(data, LINK_HEART_BIT);
|
||||
bool isConnectionAlive =
|
||||
data != LINK_NO_DATA &&
|
||||
(oldHeartBit == LINK_HEART_BIT_UNKNOWN || oldHeartBit != newHeartBit);
|
||||
|
||||
linkConnection->_linkState.data[i] =
|
||||
isConnectionAlive ? _withHeartBit(data, 0) : LINK_NO_DATA;
|
||||
linkConnection->_linkState._heartBits[i] =
|
||||
isConnectionAlive ? newHeartBit : LINK_HEART_BIT_UNKNOWN;
|
||||
|
||||
if (linkConnection->_linkState.hasData(i))
|
||||
linkConnection->_linkState.playerCount++;
|
||||
}
|
||||
|
||||
linkConnection->_linkState._sync();
|
||||
}
|
||||
|
||||
inline bool _isBitHigh(u16 data, u8 bit) {
|
||||
return (data >> bit) & 1;
|
||||
}
|
||||
|
||||
inline u16 _withHeartBit(u16 data, bool heartBit) {
|
||||
return (data & ~(1 << LINK_HEART_BIT)) | (heartBit << LINK_HEART_BIT);
|
||||
}
|
||||
|
||||
#endif // LINK_CONNECTION_H
|
||||
56
src/main.cpp
56
src/main.cpp
|
|
@ -1,56 +0,0 @@
|
|||
#include <tonc.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// (0) Include the header
|
||||
#include "lib/LinkConnection.h"
|
||||
|
||||
void log(std::string text);
|
||||
|
||||
// (1) Create a LinkConnection instance
|
||||
LinkConnection* linkConnection = new LinkConnection();
|
||||
|
||||
void init() {
|
||||
REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
|
||||
tte_init_se_default(0, BG_CBB(0) | BG_SBB(31));
|
||||
|
||||
irq_init(NULL);
|
||||
irq_add(II_VBLANK, NULL);
|
||||
|
||||
// (2) Add the interrupt service routine
|
||||
irq_add(II_SERIAL, ISR_serial);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init();
|
||||
|
||||
while (1) {
|
||||
// (3) Run the `tick` method in your update loop
|
||||
u16 dataToBeSent = ~REG_KEYS & KEY_ANY; // (keys state)
|
||||
auto linkState = linkConnection->tick(dataToBeSent);
|
||||
|
||||
// (4) Process results
|
||||
std::string output = "";
|
||||
if (linkState.isConnected()) {
|
||||
output += "Players: " + std::to_string(linkState.playerCount) + "\n";
|
||||
|
||||
for (u32 i = 0; i < linkState.playerCount; i++)
|
||||
output += "Player " + std::to_string(i) + ": " +
|
||||
std::to_string(linkState.data[i]) + "\n";
|
||||
|
||||
output += "Self pID: " + std::to_string(linkState.currentPlayerId);
|
||||
} else
|
||||
output += std::string("Waiting...");
|
||||
log(output);
|
||||
|
||||
VBlankIntrWait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log(std::string text) {
|
||||
tte_erase_screen();
|
||||
tte_write("#{P:0,0}");
|
||||
tte_write(text.c_str());
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user