gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Frequently Asked Questions *READ FIRST!*

#2628 - tepples - Sun Feb 09, 2003 5:28 pm

Answers to forum.gbadev.org Frequently Asked Questions
By Damian Yerrick
Updated 2007-08-08


To help beginners, I've decided to cook up a list of frequently asked questions with their answers. As more questions come up often, I will add them to this list.

Table of Contents
  • The basics
  • C and C++
  • ARM7TDMI assembly language
  • Testing your code
  • Graphics
  • Audio
  • Saving
  • Miscellaneous

_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Wed Aug 08, 2007 5:20 am; edited 5 times in total

#6770 - tepples - Mon Jun 02, 2003 5:57 pm

The basics

Q: I have made a game in The Games Factory, Multimedia Fusion, RPG Maker, or Game Maker. How do I run it on a Game Boy Advance or Nintendo DS system?

As of this writing, there is no simple way to do this. Those development environments are optimized for the larger memory of PCs. You will have to rewrite the code from the ground up.

Q: I'm brand new to this. How do I start developing for the GBA?

Here's how I learned it, one step at a time:
  1. Learn the C programming language. A member has found this tutorial helpful. Make some simple text-based programs for the PC. If you are looking for a PC-targeted compiler, and you're on Windows, try MinGW.
  2. Get the 'curses' library (which may be called 'ncurses' on GNU/Linux or 'pdcurses' on DJGPP or MinGW) and make more sophisticated text-based programs for the PC.
  3. Try making some graphical programs for the PC with the Allegro library.
  4. Once you're comfortable with all of the previous steps, now go get a GBA-targeted cross-compiler and some graphics tools. There's a list of tutorials near the bottom of this FAQ.

Q: How do I perform input and output?

The GBA has memory-mapped input and output registers. Read the GBATEK document for information on every publicly known GBA register. The GBA is in general emulated accurately, although some CPU timing issues still persist, and it's hard to find an emulator that supports the Game Link cable.

Q: How do I implement game logic?

Familiarity with finite state machines will help greatly.

Q: I've downloaded a program, but when I double-click its icon in Windows Explorer, a window filled with black opens and closes so quickly that I cannot read it. How do I use this program?

It's probably a command line tool. If you don't know how to work the Windows command line, please work through any of these DOS tutorials.

Q: I've got an error message!

We can't help you very well unless you paste the exact text of the error message. If you don't already know how to copy and paste from a Command Prompt window and paste it into a forum post, here's how:
  1. Click the C:\ icon at the upper left to open the terminal menu.
  2. Choose Edit > Mark.
  3. Drag a box around what you want to copy.
  4. Press Enter to copy the boxed text.
  5. Switch to another program and paste.

Q: Want my ROMz?
Q: Do you have this ROM?
Q: Want my official tool or library?
Q: Do you have the Nintendo SDK?

No. If it's copyrighted under all-rights-reserved terms, such as a commercial GBA ROM or parts of the official Nintendo SDK, then you're not allowed to distribute it on gbadev.org. Please read the official forum rules.

Q: If this FAQ doesn't answer my question, what should I do?

Try a few search queries. You might find just the answer you're looking for.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Thu Jul 26, 2007 10:41 pm; edited 10 times in total

#6772 - tepples - Mon Jun 02, 2003 5:58 pm

C and C++

Q: What compiler should I use?

GCC is a compiler suite, created by the Free Software Foundation, which has support for the ARM7TDMI processor in the GBA. Most developers, both professional and amateur, use a version of GCC. If you run Microsoft Windows or Linux on the x86 architecture, try the "devkitARM" distribution of GCC, which you can download at http://www.devkitpro.org/.

Professional developers with a ton of money to spare may use a proprietary compiler. If you are a professional, being paid for your work, it may be worth your while to consider ARM's own compiler or Green Hills compilers.

Q: How do I install devkitARM on Windows?

Use the latest devkitPro Updater, an installer written in NSIS that automatically fetches and installs the required components for you. If you are developing for the Game Boy Advance or Nintendo DS, you probably want everything but devkitPPC and devkitPSP.

This installer places files inside folders called 'bin', 'lib', 'include', etc. inside C:\devkitPro\devkitARM\. There should be a file called C:\devkitPro\devkitARM\bin\arm-eabi-gcc.exe. It's not something to be double-clicked; you'll have to use the command prompt. Most GCC users are familiar with their favorite operating system's command prompt. If you have never used a command prompt, learn DOS; the Windows command prompt is copied nearly wholesale from DOS's.

Ordinarily, you will use GNU Make to build your projects, and a conforming makefile handles the PATH environment variable for you, based on the contents of the DEVKITPRO and DEVKITARM variables. But if you are using devkitARM components outside of a makefile, such as arm-elf-nm to see what is taking up space in the binary, you'll have to add the path of the folder containing arm-eabi-gcc.exe to your PATH. Don't do this system-wide, or builds will fail for mysterious reasons. Instead, make a batch file that adds to the PATH for only one command prompt session:
Code:
@echo off
set PATH=C:\devkitPro\devkitARM\bin;%PATH%
cmd

And then double-click this batch file.

If you are writing your own makefile instead of using the makefile from the libgba project template, there are some more details that apply to cross-compilers such as devkitARM: When linking a program, you'll need to specify the Thumb C library (-mthumb) that supports interworking (-mthumb-interwork) and the GBA memory layout (-specs=gba.specs for ROM or -specs=gba_mb.specs for multiboot), or you'll just get a white screen:
Code:
arm-eabi-gcc -Wall -mthumb -mthumb-interwork -specs=gba_mb.specs hello.c -o hello.elf
arm-eabi-objcopy -O binary hello.elf hello.mb


Q: How do I do XYZ in C or in C++?

See the comp.lang.c FAQ or C++ FAQ Lite.

Q: How do I put multiple files in a program?

Make a header (.h) file containing the class/struct declarations and function prototypes, and #include it from your .c and .cpp files.

DON'T:
Add other C files to your main.c by #include "foo.c".

DO:
Add other C files by compiling them separately (arm-eabi-gcc {options} -c foo.c -o foo.o) and linking them together (arm-eabi-gcc {options} a.o b.o c.o d.o -o game.elf).

Q: How do I put more than one source code file into a project?

Use GNU Make, which comes with MinGW or MSYS. You might find the GNU Make manual and this tutorial by sajiimori helpful.

Q: How do I put large (> 16 KB) arrays into a GBA program without it crashing?

The linker script included with devkitARM puts arrays and other variables into IWRAM unless you tell it otherwise. Trouble is IWRAM is only 32 KiB. For arrays that you don't plan to modify, use the keyword const, which will instruct the linker to put the entire array into ROM (or EWRAM for .mb programs). For arrays that you do plan to modify, put them into EWRAM using a section attribute on the array's definition:
  • __attribute__((section (".sbss"))) char foo[8192];
    Puts the variable in EWRAM and initializes it to zero at program start. (Initializer values are ignored.)
  • __attribute__((section (".ewram"))) char foo[8192] = {3, 4, /*... */ };
    Puts the variable in EWRAM and initializes it to the given values at program start. (This uses space in the binary even if initializer values are not given.)

Q: Where can I get a header file describing the GBA hardware?

Most developers nowadays use the header files that come with libgba or libnds. It contains several useful macros to define the addresses of the memory-mapped I/O registers and to form RGB color values, plus constants that represent bitwise settings.

This paragraph is historical. At one time, the Pin Eight GBA header file by Damian Yerrick (tepples on gbadev forum), distributed with most of his GBA software, was popular. It contains macros much like those in the libgba headers, but with different names, initially for what were thought to be legal purposes. In many cases, where there exist multiple sets of registers for a given task (such as the DMA, timers, background scrolling, background control, etc), the macros simulate a structure in register space, an array of registers, or even an array of structs. It began to fall out of use around the time libfat was adopted because libfat depended on the libgba headers. However, libgba headers do use arrays and structures in many cases.

Q: How do I use C effectively?

Some of these tips will work. But remember that clarity is more important than optimization. According to Donald Knuth, "premature optimization is the root of all evil."

Don't divide too much. Because the ARM architecture has no hardware divider, and Nintendo forgot to put one in the GBA's I/O area like it did on the Super NES, the / and % operators are extremely slow. Don't use them unless you really have to. Alternatives, in order of most preferable to least preferable:
  • For division by a power of 2, bitshifting; for modulus by a power of 2, the & operator.
  • For division by an approximate constant, fixed-point multiplication by its reciprocal. (Recent GCC may do this for you.)
  • For division by an exact constant (as in binary to decimal conversion), 1. multiply by the reciprocal rounded properly, 2. multiply the quotient by the divisor, and 3. add one to the quotient if the dividend is less than the product. (Recent GCC may do this for you as well.)
  • For division by a variable in a small range (as in DDA algorithms), make a lookup table of reciprocals.
  • For division by a variable in a large range, use the BIOS divide call, which is faster than the divide code that GCC inserts into your code, or a custom divider in IWRAM, which is even faster than the BIOS routine (which is optimized for size rather than speed, as is everything else in the BIOS).
  • On the DS, you can use the hardware divider in the I/O area, but be careful with interrupts: there is only one context for both the main thread and for interrupts.

Avoid floating point. Don't use floating-point arithmetic unless you absolutely have to. The GBA has no dedicated floating-point hardware, and all floating-point operations have to be run in a slow software FPU emulator. Use fixed-point arithmetic instead; if you need floating-point arithmetic to create a data table, create it on the host computer before compiling the program.

Avoid trigonometry. Use lookup tables instead. Write a program that runs on the host computer to build a lookup table containing values of cos(x*Pi/512) from x=0..256, and then write cos() and sin() functions that index into that table. This table contains only one quadrant of sin(), so you'll need to perform appropriate reflections.

Avoid calling small functions in an inner loop. Calling a function flushes the processor's instruction pipeline and saves the contents of registers to the stack, and returning reads the stack and flushes the pipeline. Inline functions, on the other hand, are pasted directly into your code stream. For a small performance boost, make your smallest functions inline functions wherever it makes sense. At higher optimization settings (-O2 and especially -O3), GCC will try to do this for you when the caller and callee are in the same file. Use the static keyword to give GCC a hint that a function will be called only from one file; use static inline to give GCC an even stronger hint.

Use fast RAM. On the Game Boy Advance, compiling your code as ARM and putting it in IWRAM will make it faster. However, you have only 32 KB of IWRAM, so choose what to put in IWRAM wisely. But once you've profiled your program and decided which speed-critical functions to put in IWRAM, there are two ways to do it:
  • arm-eabi-gcc -Wall -O2 -marm -mthumb-interwork -c mixer.c -o mixer.iwram.o
    Puts everything in the compiled module into IWRAM.
  • __attribute__((section (".iwram"),long_call))
    int mixer(void) { /*...*/ }
    Puts only one function's binary code into IWRAM.

Likewise, code that manipulates savegame data or flash cart bankswitch registers should usually run in EWRAM:
  • __attribute__((section (".ewram"),long_call))
    void bytecpy(void *restrict in_dst, const void *restrict in_src, unsigned int length) { /*...*/ }
    Puts the function's binary code into EWRAM.

Less of this should be necessary on the Nintendo DS, which has an instruction and data cache.

Q: How do I use C++ effectively?

C++ is a powerful language, but with great power comes great responsibility. Too many novices read through a "21-day" C++ book and come out of it with just enough knowledge to be dangerous. StoneCypher is a big fan of C++, and he has written a post clearing up some people's misconceptions.

Use whatever features of C and C++ that you're comfortable with, but know the cost of what you use. C++ is a big language; to help you find your way around, StoneCypher recommends the Effective C++ books by Scott Meyers. Not everybody considers C++ as maintainable as C, especially due to the larger context required to understand a given piece of code. I've read that Linus Torvalds isn't a big fan either, but that might be in part because Linux is older than the C++ standard.

Template types may produce large code, filling available RAM, unless you're very careful. Unfortunately, a lot of people are not. Know where your templates are instantiated, and know which classes are actually template instantiations (such as std::string).

The C++ standard library itself is a maze of templates. DevkitARM includes GNU libstdc++, which unfortunately is tuned for use as a shared library on Linux, not as a static library on an embedded system. A Hello World program for GBA that uses <iostream> compiles to over 180,000 bytes on devkitARM, even if you use -Os -Wl,-gc-sections to make ld try harder at removing unreachable code. A quick pass through arm-eabi-nm reveals that much of this space is used for locale support and the floating-point emulator. StoneCypher claimed that he and Wintermute were able to work around this, but he refused to give any details other than "RTFM". It may be possible to fix this if you have a lot of time on your hands, such as by replacing GNU libstdc++ with uClibc++.

But it's perfectly fine to use C++ with the parts of the standard library that it inherits from the C language, such as <cstdio> and <cstdlib>. In this environment, you can use C-style error handling through return values instead of exceptions. Consider T foo = new(std::nothrow) T;, which returns NULL if it can't allocate an object, just like malloc does. If you know you're not using exceptions in a program, give g++ the -fno-exceptions flag when you compile and link for a minor performance boost.

Run-time type identification (RTTI) is used for the dynamic_cast<> and typeid operators. One can often refactor an object-oriented design so as not to use these operators. If you know you're not using RTTI in a program, give g++ the -fno-rtti flag when you compile and link for a minor performance boost.

If declaring a pure virtual method gives "undefined reference to 'write'", you are using old devkitARM. If you cannot upgrade, see this topic for a solution.

If your C++ program is much larger than you expect, or you start running out of RAM (especially in a GBA multiboot or on the DS ARM7), see tepples' list of six space-saving tips.

Q: In C++, what is the difference between a struct and a class?

A class can contain data members (also called fields), member functions (also called methods), and virtual member functions; so can a struct. A class can contain members with public, protected (subclass API), or private (internal) privilege; so can a struct. A class can inherit or be inherited; so can a struct.

In fact, C++ sees only one difference between a struct and a class: A struct's members before the first privilege declaration are public; those of a class are private.

The other difference is that the C language accepts only struct. C and C++ are officially separate languages, but often, code in the C++ language must work together with code in the C language. Programmers tend to apply the term "struct" to data types that match the "Plain Old Data" (POD) semantics inherited from C. The difference between POD and non-POD is orthogonal to the difference between class and struct, but this distinction remains a good practice in order to mark types as safe for use in C.

Q: My program works when compiled without optimizations (-O0), but when compiled with optimizations (-O, -O2, -O3), it misbehaves. How do I fix this?

The following paragraph is historical, as libgba headers handle this correctly.
Most likely: You forgot to declare your registers as volatile. When optimizing your program, GCC removes repeated accesses to memory addresses that it assumes do not change. This is not true of the memory-mapped registers such as the vertical scan position register (REG_VCOUNT) and the joypad data register. To tell GCC that the values of those registers change behind your program's back, you have to declare them as volatile.
Code:
/* Instead of this: */
#define REG_VCOUNT (*(unsigned short *)0x04000006)
/* Do this */
#define REG_VCOUNT (*(volatile unsigned short *)0x04000006)

Also use volatile for variables that an interrupt service routine can change.

Far less likely: You ran into an optimizer bug. Check the GCC mailing lists to see if any ARM optimizer bugs have been reported in the last couple months. You may find that optimizer bugs have been fixed in a version of devkitARM based on a more recent GCC.

Q: How should I specify what files to rebuild?

It used to be common to use batch files that rebuild everything every time, especially for the simplest projects. Nowadays, most projects use GNU Make, an automated rebuilding tool which is included with MSYS. The libgba and libnds project templates include makefiles that automatically discover and compile all C source code files in a specific folder. See also the GNU Make manual.

Q: How do I set up devkitARM with my favorite integrated development environment?

You can try the Eclipse instructions or the Visual Studio instructions.

Q: How do I generate pseudo-random numbers?
See the topics linked from here.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Sat Jan 05, 2008 7:27 am; edited 37 times in total

#6773 - tepples - Mon Jun 02, 2003 6:01 pm

ARM7TDMI assembly language

Q: How do I do XYZ in assembly language?

In addition to the ARM documents listed on gbadev.org, members of this forum have recommended the following tutorials:
Q: Do I need to rewrite XYZ in assembly language?

Candidates for the asm treatment include audio mixers, video rasterizers, and anything that handles a large chunk of data and must do so quickly. But get it working in C first; you may find that GCC's optimizer, along with compiling to ARM and putting the code in IWRAM, is enough.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#6774 - tepples - Mon Jun 02, 2003 6:03 pm

Testing your code

Q: How do I test a GBA program?

The easiest way is through an emulator. The most popular and most accurate free GBA emulator is VisualBoyAdvance by Forgotten.

Once you're confident about writing code that works in an emulator, you should consider purchasing some development hardware. I recommend the MBV2 cable available from Lik Sang. It doesn't give you access to the ROM space, but it's much less expensive for those starting out than using a flash cartridge.

Before introducing a new complicated algorithm, you may want to "unit test" the algorithm in a PC program first, as the PC's publicly available debuggers are more mature than those for the GBA.

Q: I double-click the ROM I just compiled, and a Sega Genesis emulator launches. Why doesn't it launch my GBA emulator?

Q: I've installed VisualBoyAdvance, and now it launches whenever I double-click a Sega Genesis ROM. What did I do wrong?

The problem here arises because before the GBA came out, .bin typically referred to Sega Genesis ROMs, and many people had .bin associated to a Sega Genesis emulator such as DGen.

Solution: Save your GBA ROMs with a .gba extension, save your GBA multiboot binaries with a .mb extension, associate .gba and .mb files to VisualBoyAdvance, and keep .bin associated to your Sega Genesis emulator.

Q: I followed the tutorial and just wrote my first GBA program, but after compiling it and running it, I get a white screen. Why isn't it working?

A. Some emulators (such as recent versions of VisualBoyAdvance) support ROMs in ELF format; others don't. The GBA doesn't. You'll have to convert the output of GCC (in ELF format) to a raw GBA binary before actually using it. The command to do this:

objcopy -v -O binary yourromname.elf yourromname.gba

Q: My program works on the emulator; why doesn't it work when sent over the MBV2 cable?

First of all, is your program compiled as a multiboot program? If you are using something based on Jeff F's linker script, such as the one that comes with DevKit Advance R4 or R5 beta 3, you need to insert the following line of code into one of your source code files:
Code:
int __gba_multiboot = 0;

If you have more questions about multiboot, see Devrs.com MBV2 FAQ

Another less common reason is that the emulator has a bug in it and your program depends on this incorrect behavior. One common bug in VisualBoyAdvance is that it doesn't emulate the various GBA memory areas' wait states, so any code running in EWRAM or ROM will run faster on VBA than on hardware. This can prove disastrous for code designed to run within Hblank.

Q: My program works when compiled without multiboot. Why does it break when compiled with multiboot?

Are you overwriting your program? If your program is 128 KB in size, it should not write to EWRAM before 128 KB. In any case, a multiboot program should not exceed about 240 KB in size.

Q: Which flash cart is the best?

All currently manufactured GBA flash carts are good enough for GBA development. If you are going for some more exact needs, read some reviews of the carts. If you need to talk to someone about your choice, then consider some other forum or channel before forum.gbadev.org or #gbadev. A partial list of such forums can be found in the Flash Equipment section.

If you want compatibility with the PogoShell software that lets you run multiple GBA programs from one cart, display .txt files, play .wav files, and emulate the NES, the Flash2Advance cart (non-Ultra) is your best bet because its bankswitching method is well understood.

Q: Where should I buy a flash cart?

Read the Retailer Feedback section.

Q: Can I ask you about cart problems?

You can ask any questions about your flash cart as long as you include details about what's wrong. But again, your friend Google is the best choice. Some sites have forums dedicated to flash cart problems. There's also

And no, we don't yet know how to access the real-time clock of the EZ-Flash carts. In fact, the makers of EZ-Flash refuse to disclose this information. (The other flash carts with a real-time clock use the same protocol that Pok?mon uses.)

Q: My program works on the emulator, but when I try it on hardware, the "Nintendo" logo does not appear. How do I fix this?

Q: When I write several programs to a flash cart, how do I change their displayed names?

GBA programs must begin with a valid header. The GBA hardware is more strict about headers than most emulators are, and you'll need to use a "header tool" to fix the header. But watch out: a valid header contains a 156-byte block of data on which Nintendo may claim copyright. Distributing a program with a valid header is considered fair in the United States (see Sega v. Accolade) but may be unlawful in jurisdictions whose copyright laws leave less room for fair use. Know the laws of all jurisdictions where you have assets.

You can find header tools in gbadev.org's header tools section. These will add a valid Nintendo logo to your program; most also have the ability to change the ROM's 12-character name that appears in the flash cart's loader menu.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Sun May 23, 2004 7:59 pm; edited 7 times in total

#6775 - tepples - Mon Jun 02, 2003 6:06 pm

Graphics

Q: How do I write text?

This is one of the most frequently repeated questions on the board. The easiest way is to use a tile mode, reserve 64 tiles out of your tile set (numbered 32 to 95), and put one glyph in each, following the order of ASCII printable characters. Then write your strings to one of the maps using one space per character. My AGBTTY library implements this method.

Other ways include using one sprite per letter or dynamically modifying tile sets.

Q: Why is the display of my first demo all weird?

Video memory must be written 16 or 32 bits a time. If you try to write 8 bits at a time, you'll actually write the same 8 bits to the lower and upper bytes of a 16-bit half word.

Q: How do I convert graphics into a format the GBA can use?

There are several bitmap conversion tools available free of charge in the tools section of http://www.gbadev.org/.

Q: How do I load assets such as audio and graphics from my program?

One way is to convert your data into an array and link it into the executable image, by converting it to a .c file (a C array; deprecated), a .s file (an assembly language array), or a .o file (an object file ready to be linked into a GBA executable). There are several binary asset converters available free of charge in the tools section of http://www.gbadev.org/; the maintainer of this FAQ distributes one as part of GBFS. Make sure that your conversion tool marks the arrays const (if it outputs C code) or puts them in section .rodata (if it outputs .s or .o).

The other way is to append a file system, or archive, to your ROM, which may be easier than linking the data directly, especially when you have programmers and artists working independently. GBFS, developed by this FAQ's maintainer, is popular. However, appended data isn't compatible with common methods of source-level debugging, so your build may have to have a "debug" mode that reads a linked-in GBFS file and a "release" mode that reads an appended GBFS file.

Q: In "text" modes (0, 1, 2), why are my tiles corrupted?

On the GBA, the "pattern tables", which contain tile data, can overlap the "nametables," which hold maps. (In some tutorials, "pattern tables" are called "character base blocks", and "nametables" are called "screen base blocks".) Though a pattern table must start on a 16 KB boundary, a pattern table for a text background actually spans 1024 tiles (32 KB or 64 KB depending on bit depth). A rot/scale background's pattern table is always 256 colors, 256 tiles, and 16 KB. More than one background can use the same pattern table.

Overwriting tiles with maps or vice versa can result in corruption, so don't mix them in the same part of memory unless you really know what you're doing. If you're just starting out, I'd suggest you use the first 48 KB of VRAM (pattern tables 0, 1, and 2) for tile data and the next 16 KB of VRAM (nametables 24-31) for map data.

There are 2048 tiles' worth of VRAM (1024 if you're using 256-color tiles); for each map, you lose 64 tile positions (32 if you're using 256-color tiles).

Also, make sure that both your map data, your tile data, and your palette data are aligned to a 4-byte boundary within your binary. If you use assembly language, put .balign 4 on a line before the data; in C do this (recommended only for smaller arrays such as palette data):
  • __attribute__((aligned(4))) const char foo[8192] = { /*...*/ };
    Aligns the start of the array to a 4-byte boundary.

Q: Why do my sprites become corrupt when I move them off the top or the left side of the screen?

On the ARM7 CPU and on most other digital processors used today, negative numbers are stored in a form called "two's complement", which (to simplify things) uses a sequence of 1 bits at the beginning to signify that it's negative. If you try to write a two's complement number directly to an OAM attribute, the 1 bits will interfere with other bitfields within that attribute, which causes the corruption you see.

To draw a sprite that overlaps the left side or the top of the screen, cut off the extra 1 bits before you OR in the other attributes, like this:
Code:
OAM[n].attr0 = other_attr0_attributes | (y_coordinate & 0x00FF);
OAM[n].attr1 = other_attr1_attributes | (x_coordinate & 0x01FF);


Q: What color is transparent?

(answer based on an explanation by sgeos)

For backgrounds in modes 0, 1, 2, and 4, and for sprites in any mode, transparency is not determined by the color of a palette entry. Palette entry zero is always transparent. Any color can be loaded into palette entry zero, but because that color will not be seen, you'll often see black, sky blue, hot pink, or whatever the artist used to represent transparency in palette entry zero. (NOTE: Palette entry zero of background palette zero is used as the backdrop color. This is the only case in which the color of a "transparent" palette entry will be displayed.)

Q: How do I draw things behind things?

In modes 0, 1, and 2, background layers with a lower layer priority number. will appear in front of background layers with a high layer priority number, and sprites will appear in front of a background layer with an equal layer priority number. However, this does not apply to mode 3 or mode 5, the 32 Kicolor bitmapped modes. There's no known way to draw sprites partially hidden by a hi-color (mode 3 or mode 5) background.

Sprite-to-sprite overlapping, on the other hand, is governed by the order in which the sprites appear in OAM. A lower-numbered sprite will appear in front of a higher-numbered sprite. If you want this to interact nicely with the sprite-to-background priorities, you should sort the sprites in order of their layer priority, such that sprites with layer priority 0 come first in OAM. There are some obscure graphics tricks that rely on complex interactions between sprite and background priority, but these should not be nearly as necessary on the GBA as they were on the NES.

And if you're using sprite alpha blending, place opaque sprites in front of translucent sprites; otherwise, the translucent sprites will appear to cut a hole in the opaque sprites.

Q: How do I rotate and scale sprites?

See this tutorial.

Q: I tried to rotate and scale sprites, but all I get is a colored box!

If a sprite looks like a colored box of all one color, typically the color of the center pixel of your sprite cel, then you have either not populated the matrix correctly (in attribute 3) or not chosen a matrix for your sprite (in attribute 1).

Q: My colors look OK on the emulator but too dark on hardware. How do I fix this?

The GBA's screen is darker than a typical CRT or than a PC LCD, which corrects its colors to look like a CRT. You'll need to use some gamma correction on each of the RGB components when writing your palettes to video memory. This can be done at compile time, or you can do it at runtime if you want to change your images' appearance on CRTs (Game Boy Player and emulators) and LCDs (GBA and GBA SP).

True gamma correction involves either transcendental math, which is slow on platforms without an FPU, or lots of lookup tables. A quick approximation to the gamma correction is affine brightness correction. Try this formula on each component:
Code:
new_component = old_component * 3 / 4 + 8;


Q: How do I make a map?

There are several map editors available free of charge in the tools section of http://www.gbadev.org/. However, for maximum efficiency, you may want to develop your own domain-specific map editor.

Q: How do I make a large, continuously scrolling map?

The typical map size is 32x32 tiles, or 256x256 pixels. You can display a window on a larger virtual world by replacing the map entries that just scrolled off the edge of the screen with new map entries that appear on the other edge. To see what I'm talking about, fire up any GBA game that uses this effect and use VisualBoyAdvance's map viewer.

Q: How do I make the "Mode 7" effects of games such as F-Zero and Mario Kart Super Circuit?

"Mode 7" referred to a graphics mode on the Super NES that could rotate and scale a map on each scanline of the screen. The equivalent modes on the GBA are mode 1 (which provides one "mode 7" plane and two standard tiled planes) and mode 2 (which provides two "mode 7" planes).

To create the 3D plane effect, you're going to have to use quite a bit of trigonometry to create coordinates and then use hblank DMA to copy them to VRAM. For a working example with source, look at "Hardware perspective view" in darkfader.net's GBA section.

Q: How do I make 3D graphics?

The GBA does not have Direct3D or OpenGL; you'll have to write your own software 3D engine. I recommend Black Art of 3D Game Programming by Andre LaMothe as a good introduction to software 3D engines.

Q: I'm using a bitmap mode. Why don't my sprites show up?

Sprites in display mode 3, 4, or 5 must use cel data from 0x06014000 to 0x06017FFF because the area in 0x06010000 to 0x06013FFF is reserved for the background. This cel data area corresponds to indices 512 to 1023 in sprite attribute 2.

Again, in mode 3 and 5, sprites will not show up behind the background. Use mode 4 if you want this effect.

Q: How do I time an animation?

There are about 60 vblanks per second on a GBA. After every vblank, increment a frame counter associated to the actor. When it reaches the desired delay, reset the timer to 0 and advance the animation to the next cel. For instance, if you want a 12 frames per second animation, change cels every time you count to 5.

This also works for a game clock. Increase the 'frame' every vblank, increase the 'second' every 60 frames, and increase the 'minute' every 60 seconds.

Synchronizing an animation to one of the GBA's four timers is a bad idea: 1. it eats up a timer, and 2. it can cause a race condition between your main thread and the animation, causing corrupt display or even a crash. The GBA's four timers are best used for PCM sample clocking, for high-resolution profiling, or for interacting with external devices.

Where can I learn more about game graphics techniques?

Look for tutorials written by members of the demo scene. Archeious has suggested this one.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Sat Mar 08, 2008 1:34 pm; edited 23 times in total

#6776 - tepples - Mon Jun 02, 2003 6:08 pm

Audio

Q: How do I play sampled sound on the GBA?

BeLogic's The Audio Advance describes all GBA registers associated with sound.

Q: What audio formats can the GBA use?

For beginners, the best audio format to use on the GBA is 8-bit signed PCM. (Some mixers such as Farb-rausch's use unsigned samples instead, but most use signed.) The .wav PCM format is 8-bit unsigned PCM or 16-bit signed PCM with a header. Converters from wav to something the GBA can use are available in the tools section at http://www.gbadev.org/.

Q: I'm trying to write a small program. How do I make sound without devoting a large amount of my program to samples?

In addition to the GBA's two PCM channels, the GBA also has a few tone generators inherited from the Game Boy Color. The only publicly available GBA emulator that handles the tone generators well is VisualBoyAdvance.

Q: How do I play more than two PCM sound channels?

You'll have to write a software mixer. (This is another thing you're going to want to test on the PC first before you port it to the GBA.)

Q: What music formats can the GBA use?

The GBA BIOS itself has no support for the tracked music formats popular on PCs (mod, s3m, xm, mid), but they can all be translated into formats the GBA can use. Your GBA-side music code will parse your favorite music format (learn how at http://www.wotsit.org/) and translate it into either tone generator instructions or mixer instructions. If you're just starting out, you may want to experiment with Krawall or Fras. (Make .mod, .xm, and .s3m files with a tracker such as Modplug Tracker.)

If you know a thing or two about audio compression, and you have a lot of cart space to work with, you may want to try something based on ADPCM. But don't try to decode MP3 in real time; the GBA's processor just isn't fast enough, and dedicated decoding hardware is too expensive to distribute with each copy of a game.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#6777 - tepples - Mon Jun 02, 2003 6:09 pm

Saving

Q: How do I save information from power-off to next power-on?

GBA carts with SRAM save hardware contain up to 64 KiB of addressable RAM. But unlike other RAM in the system, save RAM can be accessed only one byte at a time. The easiest way to read and write save RAM is to make an array or struct containing all the items you want to save, and then use a byte-at-a-time version of memcpy() to move data in and out. Some programmers prefer to use a struct, as it allows for using multiple data types; others like to serialize the data manually, putting it into a char array.

Code:

/* Example save code, based on an idea by sgeos
   Rewritten by tepples to use same semantics as memcpy()*/

#define SRAM ((unsigned char *)0x0e000000)

/* bytecpy() *****
   Copy a block of data a byte at a time from src to dst.
   Useful for copying data in and out of a cart's SRAM.
*/
__attribute__((section (".ewram"),long_call))
void bytecpy(void *restrict in_dst, const void *restrict in_src, unsigned int length)
{
  unsigned char *restrict src = (unsigned char *)in_src;
  unsigned char *restrict dst = (unsigned char *)in_dst;

  for(; length > 0; length--)
    *dst++ = *src++;
}

typedef struct SaveData
{
  int foo;
  unsigned short bar;
  unsigned char lives;
  unsigned char level;
  char player_name[12];
} SaveData;

SaveData data;

/* to save to offset 4 */
bytecpy(SRAM + 4, &data, sizeof(data));

/* to load from offset 4 */
bytecpy(&data, SRAM + 4, sizeof(data));


char serialized[200];

/* to save already serialized data */
bytecpy(SRAM + 4, serialized, sizeof(serialized));

Another tip: Don't use the first or last byte of SRAM, as those locations can become corrupted in some cases during power-cycle or pak-swapping. Also, if you're trying to get published, realize that official Game Paks have only 32 KiB of SRAM.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Thu Jul 07, 2005 12:44 am; edited 1 time in total

#6778 - tepples - Mon Jun 02, 2003 6:11 pm

Miscellaneous

Q: What else should a newcomer to GBA programming read?

TONC tutorial
Devrs.com GBA FAQ
Google: finite state machine, which defines the structure of most games.

How do I detect single button taps instead of continuous presses?

First define "tap". A "tap" means that a button has just become pressed, which means that the button is pressed now and wasn't pressed before. So to detect a "tap" of a button, compare the state of a button now to the state of the button before. This means you'll have to store the previous states of buttons in order to compare them with the current states the next time through the game loop.

You can detect multiple taps at once by using sets of buttons with the set-difference operator & ~. Given sets A and B represented as active-high bitfields (1 in a given place value representing present and 0 absent), the C language expression A & ~B returns those elements that are present in set A and not present in set B.

Implementation in C follows:
Code:
#define REG_KEYINPUT (*(unsigned short *)0x04000130)

void game_loop(void)
{
  char done = 0;
  unsigned short last_joy = ~0;  /* begin with all bits set */

  while(!done)
  {
    unsigned int j = ~REG_KEYINPUT;  /* fetch the states of buttons and convert to active-high */
    /* each 1 in j corresponds to a pressed button */
    unsigned int j_taps = j & ~last_joy;  /* compute new presses */
    /* each 1 in j_taps corresponds to a newly pressed button */

    last_joy = j;  /* save the previous states */

    /* OMITTED: act on j_taps, do other business logic, and do graphics and sound */
  }
}

Q: How do I reduce a program's power usage?

If you don't need sound, turn off sound.

When waiting for vblank, you can put the GBA's CPU to sleep until an interrupt happens by using the VBlankIntrWait BIOS function, but before calling it, you'll need to install an interrupt handler, as the BIOS doesn't provide one. Refer to the interrupt sections of tutorials to learn how to enable interrupts, and refer to the next question to learn how to write an interrupt handler.

Q. What should an interrupt handler look like?

If you don't use the devkitARM interrupt dispatcher, you can write your own ISR (interrupt service routine) based on the following boilerplate:
Code:
void isr(void)
{
  /* Should read REG_IF *only once* in an ISR. */
  unsigned int interrupts = REG_IF;

  if(interrupts & INT_VBLANK)
  {
    /* do vblank stuff */
  }
  if(interrupts & INT_HBLANK)
  {
    /* do hblank stuff */
  }

  /* Tell the BIOS which interrupts the ISR handled;
     without this, IntrWait and VBlankIntrWait won't work
     on real hardware, but they may work on some
     emulators' inexact high-level emulation of the BIOS.
     Need |= because this is plain old RAM. */
  *(unsigned short *)0x03fffff8 |= interrupts;

  /* Finally tell the hardware which interrupts the ISR handled.
     Need = rather than |= because we don't want to
     acknowledge interrupts that happened while the ISR
     was running. */
  REG_IF = interrupts;
}

See also this post.

Q: Can a GBA emulate a Sega Genesis or Super NES console?

Not likely. Because the host's processor and the Super NES's processors have different instruction sets, the host must interpret the Super NES's instructions. According to Bill Woods, interpreting another instruction set costs a factor of 10 in speed, and the GBA isn't ten times faster than the Super NES. And that's not even counting the subtle semantic differences between GBA graphics and Super NES graphics (e.g. BG priorities per tile) that would seem to require a full emulation rather than a one-to-one mapping of features.

The easiest way to get classic 16-bit games on the GBA is to license the source code and assets and port them yourself. Of course, this is feasible only if you work at a big company and have authority to submit project proposals.

On the other hand: The recently released SNES Advance emulator can run a few games slowly. However, because of the impedance mismatches between the Super NES and GBA ways of doing things, it may never achieve nearly the same level of compatibility as PocketNES.

Q: How do I get a game published commercially?

Stop. Is your game significantly better than 80+ percent of the GBA games you've already tried? If not, it probably won't sell in such a saturated market. Unless you represent a company that has already made a name for itself on another platform, it'll be quite difficult for you to get your foot in the door.

From what I've read, getting a GBA game published is much like getting a book published. Contact several licensed publishers that have published games similar to yours. In a query letter sent to each publisher you're considering, explain your game in the most general terms. If a publisher likes your idea, it will offer you a non-disclosure agreement. Read the agreement, sign it, return it, and then follow up with a game design document. Then send your ROM along with the latest version of VisualBoyAdvance on a CD-R. (The publisher can't steal your game and sell it because copyright in your game comes into effect as soon as it's fixed in a tangible medium.)

More tips here.

Q: Where can I find ROM images of commercial GBA games?

Neither I nor the gbadev.org staff condone unauthorized copying of copyrighted works. If you want ROM images of commercial GBA games, follow these instructions:
  1. Get a linker from any of the retailers listed in the Retailer Feedback section.
  2. Buy some Game Paks.
  3. Copy Game Paks to hard disk using linker.
  4. Do not distribute resulting ROM images to any other person.

_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Fri Oct 15, 2004 9:50 pm; edited 7 times in total

#175368 - jukov - Tue Nov 02, 2010 10:06 am

c++ very intresting )
eyesight correctionастигматизм
восстановление зрения87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b
87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b
87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b
87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b
87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b
87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b
87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b
87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b87b