@@ -4,6 +4,8 @@ Integrating hUGEDriver into your project depends on what you are using. |
| 4 |
|
4 |
|
| 5 |
<details><summary>RGBDS (assembly)</summary> |
5 |
<details><summary>RGBDS (assembly)</summary> |
| 6 |
|
6 |
|
|
|
7 |
Get the [release of hUGEDriver](https://github.com/SuperDisk/hUGEDriver/releases) that matches your version of hUGETracker. |
|
|
8 |
|
| 7 |
Import [`hUGEDriver.asm`](https://github.com/SuperDisk/hUGEDriver/blob/master/hUGEDriver.asm) and [`hUGE.inc`](https://github.com/SuperDisk/hUGEDriver/blob/master/include/hUGE.inc) (in the `include` directory) into your project (songs need the latter as well). |
9 |
Import [`hUGEDriver.asm`](https://github.com/SuperDisk/hUGEDriver/blob/master/hUGEDriver.asm) and [`hUGE.inc`](https://github.com/SuperDisk/hUGEDriver/blob/master/include/hUGE.inc) (in the `include` directory) into your project (songs need the latter as well). |
| 8 |
You will additionally need [`hardware.inc`](https://github.com/gbdev/hardware.inc) 4.2 or later, if you don't already. |
10 |
You will additionally need [`hardware.inc`](https://github.com/gbdev/hardware.inc) 4.2 or later, if you don't already. |
| 9 |
|
11 |
|
@@ -13,15 +15,17 @@ Then, simply compile `hUGEDriver.asm` with the rest of your code, and you're don |
| 13 |
|
15 |
|
| 14 |
<details><summary>GBDK (C)</summary> |
16 |
<details><summary>GBDK (C)</summary> |
| 15 |
|
17 |
|
| 16 |
> **Note**: some people circulate pre-compiled versions of `hUGEDriver.o` / `hUGEDriver.lib`; this is fine, but you must be sure to use the right version. |
18 |
hUGEDriver releases contain a pre-compiled `.lib` for use with GBDK-2020. Link it while compiling, include `hUGEDriver.h`, and you're done: |
| 17 |
Also, if you want to modify the driver yourself for any reason, you will need to compile it yourself afterwards. |
19 |
|
|
|
20 |
```sh |
|
|
21 |
lcc ... -Wl-lhUGEDriver.lib |
|
|
22 |
``` |
| 18 |
|
23 |
|
| 19 |
hUGEDriver is written in RGBDS assembly, which is not compatible with SDCC's assembler (SDAS); so a few extra steps are necessary. |
24 |
If you want to compile the driver yourself, a few extra steps are necessary. |
| 20 |
|
25 |
|
| 21 |
0. You will need [RGBDS](https://rgbds.gbdev.io), and the [FreePascal](https://www.freepascal.org) compiler. |
26 |
0. You will need [RGBDS](https://rgbds.gbdev.io), and [Python](https://www.python.org/) |
| 22 |
1. Assemble hUGEDriver: `rgbasm -o hUGEDriver.obj hUGEDriver.asm` |
27 |
1. Assemble hUGEDriver: `rgbasm -o hUGEDriver.obj hUGEDriver.asm` |
| 23 |
2. Compile `rgb2sdas`: `make -C tools` |
28 |
3. Convert the object file: `python tools\rgb2sdas.py -o hUGEDriver.o hUGEDriver.obj` |
| 24 |
3. Convert the object file: `tools/rgb2sdas hUGEDriver.obj` |
|
|
| 25 |
4. Import `hUGEDriver.h` into your project |
29 |
4. Import `hUGEDriver.h` into your project |
| 26 |
5. Simply link `hUGEDriver.o` with the rest of your code, and you're done! |
30 |
5. Simply link `hUGEDriver.o` with the rest of your code, and you're done! |
| 27 |
|
31 |
|
@@ -42,7 +46,7 @@ So if your song descriptor was, say, `ryukenden`: |
| 42 |
<table><thead><tr><th>Assembly</th><th>C</th></tr></thead><tbody><tr><td> |
46 |
<table><thead><tr><th>Assembly</th><th>C</th></tr></thead><tbody><tr><td> |
| 43 |
|
47 |
|
| 44 |
```avrasm |
48 |
```avrasm |
| 45 |
ld de, ryukenden |
49 |
ld hl, ryukenden |
| 46 |
call hUGE_init |
50 |
call hUGE_init |
| 47 |
``` |
51 |
``` |
| 48 |
|
52 |
|
@@ -57,22 +61,18 @@ hUGE_init(ryukenden); |
| 57 |
### Playing |
61 |
### Playing |
| 58 |
|
62 |
|
| 59 |
The function `hUGE_dosound` plays a single tick of the current song when called. |
63 |
The function `hUGE_dosound` plays a single tick of the current song when called. |
| 60 |
Sounds simple? |
|
|
| 61 |
Well, unfortunately, there are a few of gotchas. |
|
|
| 62 |
|
64 |
|
| 63 |
First and foremost, *how often* should that function be called? |
65 |
First and foremost, *how often* should that function be called? That actually depends on what the song expects! |
| 64 |
That actually depends on what the song expects! |
|
|
| 65 |
|
66 |
|
| 66 |
**TODO: screenshot** |
67 |
**TODO: screenshot** |
| 67 |
|
68 |
|
| 68 |
If the song does not use "timer playback", then `hUGE_dosound` must be called once per frame. |
69 |
If the song does not use "timer playback", then `hUGE_dosound` must be called once per frame. |
| 69 |
This is usually done either by calling it from your game's main loop (or whatever), or by calling it from your VBlank interrupt handler. |
70 |
This is usually done either by calling it from your game's main loop, or by calling it from your VBlank interrupt handler. |
| 70 |
However, if the song *does* use timer playback, then you must set the timer registers appropriately (TODO), and call `hUGE_dosound` from the timer interrupt handler. |
71 |
However, if the song *does* use timer playback, then you must set the timer registers appropriately (TODO), and call `hUGE_dosound` from the timer interrupt handler. |
| 71 |
|
72 |
|
| 72 |
Using any interrupt handler exposes you to two additional gotchas: |
73 |
Using an interrupt handler exposes you to two additional constraints: |
| 73 |
|
74 |
|
| 74 |
- `hUGE_dosound` must not run in the middle of `hUGE_init`. |
75 |
- `hUGE_dosound` must not run in the middle of `hUGE_init`. |
| 75 |
- `hUGE_dosound` must not be called before the first call ever to `hUGE_init` complete. |
76 |
- `hUGE_dosound` must not be called before the first call ever to `hUGE_init`. |
| 76 |
|
77 |
|
| 77 |
Preferably, create a variable that you set to 0 on boot & before calling `hUGE_init`, and to 1 after `hUGE_init` returns; in the interrupt handler, skip calling `hUGE_dosound` if the variable isn't 0. |
78 |
Preferably, create a variable that you set to 0 on boot before calling `hUGE_init`, and to 1 after `hUGE_init` returns; in the interrupt handler, skip calling `hUGE_dosound` if the variable isn't 0. An alternative is to disable interrupts (ASM: `di`+`ei`, GBDK: `__critical`) while you call `hUGE_init`. |
| 78 |
An alternative (popular, but with several drawbacks) is to disable interrupts (ASM: `di`+`ei`, GBDK: `__critical`) while you call `hUGE_init`. |
|
|