diff options
author | Juan J. Martinez <jjm@usebox.net> | 2020-12-30 19:07:31 +0000 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2020-12-30 19:23:41 +0000 |
commit | 2682bc5d1d864341aaeb42a449db73c3ecd16d70 (patch) | |
tree | 9116764364b4ee0ce7f6037305077807b57776de /include | |
download | ubox-msx-lib-ca9b663c147340e92804979a96eee4113ab0b27f.tar.gz ubox-msx-lib-ca9b663c147340e92804979a96eee4113ab0b27f.zip |
Initial import1.0
Diffstat (limited to 'include')
-rw-r--r-- | include/mplayer.h | 181 | ||||
-rw-r--r-- | include/spman.h | 149 | ||||
-rw-r--r-- | include/ubox.h | 668 |
3 files changed, 998 insertions, 0 deletions
diff --git a/include/mplayer.h b/include/mplayer.h new file mode 100644 index 0000000..a8c1dc4 --- /dev/null +++ b/include/mplayer.h @@ -0,0 +1,181 @@ +/* + * mplayer lib + * Copyright (C) 2020 by Juan J. Martinez <jjm@usebox.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Arkos 2 AKM + * Copyright (c) 2016-2020 Julien Névo (contact@julien-nevo.com) + * (check mplayer/akm/LICENSE.txt; MIT License) + */ + +#ifndef _MPLAYER_H +#define _MPLAYER_H + +#include <stdint.h> + +// @Initialization + +/** + * Sets the player to play `sub_song` from `song`. + * + * `sub_song` starts from 0. + * + * This function can be called as many times as needed, for example, to change + * the playback to a different sub-song. + * + * It is required to call it at least once before using + * [mplayer_play](#mplayer_play). + * + * Example: + * + * ```c + * // tell the compiler we will use this + * // global symbol + * extern uint8_t SONG[]; + * + * mplayer_init(SONG, 0); + * ``` + * + * See [exporting songs and effects](#exporting-songs-and-effects) for details + * on how to add songs to your project. + */ +void mplayer_init(uint8_t *song, uint8_t sub_song); + +/** + * Inits the effects table. + * + * It is required to call it least once before using + * [mplayer_play](#mplayer_play) or any of the play effect functions. + * + * Example: + * + * ```c + * // tell the compiler we will use this + * // global symbol + * extern uint8_t EFFECTS[]; + * + * mplayer_init_effects(EFFECTS); + * ``` + * + * See [exporting songs and effects](#exporting-songs-and-effects) for details + * on how to add effects to your project. + */ +void mplayer_init_effects(uint8_t *effects) __z88dk_fastcall; + +// @Playback + +/** + * Plays a frame using the PSG. + * + * This must be called from the interrupt handler. See + * [set_user_isr](ubox-lib-ref.html#ubox_set_user_isr). + * + * [mplayer_init](#mplayer_init) must be called before using it. + * + * If the player is stopped, [mplayer_stop](#mplayer_stop) must be called to + * silence the PSG. + */ +void mplayer_play(); + +/** + * Silences the PSG, stopping any sound. + * + * This doesn't stop the player if [mplayer_play](#mplayer_play) is called. + */ +void mplayer_stop(); + +// @Sound effects + +/** + * Plays `effect_no` on `chan` channel at `inv_vol` volume. + * + * `effect_no` starts on 1 and refers to the index in the effects table set by + * [mplayer_init_effects](#mplayer_init_effects). + * + * `chan` can be 0, 1 or 2. It is recommended to use one channel for effects + * and the other two for the music. + * + * `inv_vol` is the inverted volume, with 0 for max volume and 16 for no sound. + * + * If an effects is already playing on the channel, it will be interrupted and + * replaced by this effect. + * + * The effects table must be set with + * [mplayer_init_effects](#mplayer_init_effects) before using this function. + * + * See [mplayer_play_effect_p](#mplayer_play_effect_p) for playing effects with + * priority. + * + * Example: + * + * ```c + * // plays effect 1 on channel 2 at highest volume + * mplayer_play_effect(1, 2, 0); + * ``` + */ +void mplayer_play_effect(uint8_t effect_no, uint8_t chan, uint8_t inv_vol); + +/** + * Plays `effect_no` on `chan` channel at `inv_vol` volume using priority. + * + * `effect_no` starts on 1 and refers to the index in the effects table set by + * [mplayer_init_effects](#mplayer_init_effects). + * + * `effect_no` is used as priority, being effect number 1 the one with + * lowest priority. + * + * `chan` can be 0, 1 or 2. It is recommended to use one channel for effects + * and the other two for the music. + * + * `inv_vol` is the inverted volume, with 0 for max volume and 16 for no sound. + * + * The effect is played if no effect is already being played or if the effect + * being played has less priority. In that case, the effect currently being + * played will be interrupted and replaced by this effect. + * + * The effects table must be set with + * [mplayer_init_effects](#mplayer_init_effects) before using this function. + * + * See [mplayer_play_effect](#mplayer_play_effect) for playing effects without + * priority. + * + * Example: + * + * ```c + * // plays effect 2 on channel 2 at highest volume + * mplayer_play_effect_p(2, 2, 0); + * // won't interrupt effect 2 because it is higher priority than 1 + * mplayer_play_effect_p(1, 2, 0); + * ``` + */ +void mplayer_play_effect_p(uint8_t effect_no, uint8_t chan, uint8_t inv_vol); + +/** + * Stops the effect being played on `chan` channel. + */ +void mplayer_stop_effect_channel(uint8_t chan) __z88dk_fastcall; + +/** + * Returns 0 if there's no sound effect being played on `chan` channel, or + * a value different than 0 otherwise. + */ +uint8_t mplayer_is_sound_effect_on(uint8_t chan) __z88dk_fastcall; + +#endif // _MPLAYER_H diff --git a/include/spman.h b/include/spman.h new file mode 100644 index 0000000..67f5e6d --- /dev/null +++ b/include/spman.h @@ -0,0 +1,149 @@ +/* + * spman lib + * Copyright (C) 2020 by Juan J. Martinez <jjm@usebox.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _SPMAN_H +#define _SPMAN_H + +#include <stdint.h> + +#include "ubox.h" + +// @Initialization and pattern allocation + +/** + * Initialize **spman**. + * + * Sets all the patterns as unused and no allocated sprites. + * + * it needs to be called before using any of the functions of the sprite manager. + */ +void spman_init(); + +/** + * Allocates a pattern for sprite `type` using `data`. + * + * `len` specifies the number of sprite patterns to allocate (16x16 each, + * exactly 32 bytes). + * + * If `flip` is set to a non zero value, the pattern data will be flipped + * horizontally. + * + * The function returns the allocated index in the pattern table, than can be + * used in [struct sprite_attr](ubox-lib-ref.html#struct-sprite_attr). It + * can be called multiple times for the same `type` and the allocation happens + * only once per `type`, returning the previously allocated index. + * + * `type` is an abstraction to group patterns. For example, if our game's + * player character has 3 animation frames per horizontal direction, we could + * use two different types to group those. + * + * Example: + * ```c + * enum sprite_types + * { + * SPRITE_PLAYER = 0, + * SPRITE_PLAYER_FLIP, + * SPRITE_ENEMY, + * }: + * + * spman_alloc_pat(SPRITE_PLAYER, player_sprite, 3, 0); + * // allocate the same frames flipped horizontally, on the next type + * spman_alloc_pat(SPRITE_PLAYER_FLIP, player_sprite, 3, 1); + * + * // only one frame, keep the allocated pattern + * uint8_t enemy_pat = spman_alloc_pat(SPRITE_ENEMY, enemy_sprite, 1, 0); + * ``` + * + * A `type` can't be reused with a different pattern, [spman_init](#spman_init) + * has to be called again to free all the patterns. + */ +uint8_t spman_alloc_pat(uint8_t type, uint8_t *data, uint8_t len, uint8_t flip); + +// @Sprite allocation + +/** + * Allocates a sprite described by `sp` to be shown on the screen on the next + * call to [spman_update](#spman_update). This sprite will be excluded from + * flickering. + * + * It is recommended that the number of fixes sprites per line is below 4, or + * some sprites may never be shown. + * + * The limit of sprites to be allocated is 31, including non-fixed sprites. + * + * The pattern specified in the struct should be allocated with + * [spman_alloc_pat](#spman_alloc_pat). + * + * Allocated sprites are shown on screen by calling to + * [spman_update](#spman_update). + */ +void spman_alloc_fixed_sprite(struct sprite_attr *sp); + +/** + * Allocates a sprite described by `sp` to be shown on the screen on the next + * call to [spman_update](#spman_update). + * + * If more than 4 sprites are drawn on the same line, the sprite manager will + * alternate which ones are drawn, resulting on a "flickering" effect. + * + * The limit of sprites to be allocated is 31, including fixed sprites. + * + * The pattern specified in the struct should be allocated with + * [spman_alloc_pat](#spman_alloc_pat). + * + * Allocated sprites are shown on screen by calling to + * [spman_update](#spman_update). + */ +void spman_alloc_sprite(struct sprite_attr *sp); + +/** + * Any allocated sprite will be freed. + * + * This doesn't affect sprites currently being shown on the screen. + */ +void spman_sprite_flush(); + +// @Sprites on screen + +/** + * Allocated sprites are processed, making the changes visible on screen. + * + * Once the changes have been applied, all the allocations are freed. This + * doesn't affect the sprites being shown on screen. + * + * Sprites must be allocated with + * [spman_alloc_fixed_sprite](#spman_alloc_fixed_sprite) and + * [spman_alloc_sprite](#spman_alloc_sprite). + * + */ +void spman_update(); + +/** + * Hides all the sprites currently shown on screen. + * + * This doesn't affect any allocated sprites. To free allocated sprites use + * [spman_sprite_flush](#spman_sprite_flush). + */ +void spman_hide_all_sprites(); + +#endif // _SPMAN_H diff --git a/include/ubox.h b/include/ubox.h new file mode 100644 index 0000000..2a747c0 --- /dev/null +++ b/include/ubox.h @@ -0,0 +1,668 @@ +/* + * ubox MSX lib + * Copyright (C) 2020 by Juan J. Martinez <jjm@usebox.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _UBOX_MSX_H +#define _UBOX_MSX_H + +#include <stdint.h> + +// @Screen and VDP functions +// +// These functions are not necessarily MSX 1 specific, but only MSX 1 +// functionality is documented. +// +// Both the tiles and sprite functions target Screen 2 (256x192 pixels graphics +// mode). +// +// The VRAM layout for Screen 2 is as follows: +// +// | Address range | Desctiption | +// | --- | --- | +// | <tt>0x0000-0x17ff</tt> | Background tiles | +// | <tt>0x1800-0x1aff</tt> | Background tile map | +// | <tt>0x1b00-0x1b7f</tt> | Sprite attributes | +// | <tt>0x2000-0x37ff</tt> | Background colors | +// | <tt>0x3800-0x3fff</tt> | Sprite patterns | +// + +/** + * Sets the screen mode to `mode`. + * + * This is a list of the different MSX 1 modes: + * + * | Mode | Name | Description | + * | --- | --- | --- | + * | 0 | Screen 0 | 40x24 text mode | + * | 1 | Screen 1 | 32x24 colored text mode | + * | 2 | Screen 2 | 256x192 graphics mode | + * | 3 | Screen 3 | 64*48 block graphics multicolor mode | + * + * Example: + * + * ```c + * // sets Screen 2 + * ubox_set_mode(2); + * ``` + */ +void ubox_set_mode(uint8_t mode) __z88dk_fastcall; + +/** + * Enables the screen. + */ +void ubox_enable_screen(); + +/** + * Disables the screen. + * + * Any content drawn to the screen won't be visible until the screen is enabled + * with [ubox_enable_screen](#ubox_enable_screen). + * + * Note that [ubox_set_mode](#ubox_set_mode) also enables the screen. + */ +void ubox_disable_screen(); + +/** + * Changes the screen colors. + * + * First it sets `FORCLR` (foreground) to `fg`, `BAKCLR` (background) to `bg` + * and `BDRCLR` to `border`, and then makes them active. + * + * Example: + * + * ```c + * // sets all three colours to black + * ubox_set_colors(1, 1, 1); + * ``` + */ +void ubox_set_colors(uint8_t fg, uint8_t bg, uint8_t border); + +/** + * Writes a block of `len` bytes from `src` in memory to `dst` in VRAM (video + * memory). + * + * Example: + * ```c + * // copy 4 sprites attributes from a buffer to the + * // sprite attribute table in Screen 2 mode + * ubox_write_vm((uint8_t*)0x1b00, 4 * 4, buffer); + * ``` + */ +void ubox_write_vm(uint8_t *dst, uint16_t len, uint8_t *src); + +/** + * Reads a block of `len` bytes from `src` in VMEM (video memory) to `dst` + * in memory. + */ +void ubox_read_vm(uint8_t *dst, uint16_t len, uint8_t *src); + +/** + * Writes `data` to the `reg` VDP register. + * + * This function is used to setup the VDP, for example to enable 16x16 sprites. + * + * The VDP has 8 registers, from 0 to 7. For example, it is common to use + * register 1 to enable 16x16 sprites. + * + * The control bits in register 1 are: + * + * | Bit | Description | + * | --- | --- | + * | 0 | Enable sprite zoom (x2) | + * | 1 | Enable 16x16 sprites (default is 8x8) | + * | 2 | Not used | + * | 3 | Enable Mode M2, Screen 3 (block) | + * | 4 | Enable Mode M1, Screen 0 (text) | + * | 5 | Enable v-blank interrupt | + * | 6 | Enable screen output control | + * | 7 | VRAM size control (0: 4K, 1: 16K) | + * + * Please refer to [Portar + * Doc](http://problemkaputt.de/portar.htm#vdpregisters00h07hbasicmsx1msx2videoregisters) + * for further info on VDP registers. + * + * Example: + * ```c + * // reg 1: activate sprites, v-blank int on, 16x16 sprites + * ubox_wvdp(1, 0xe2); + * ``` + */ +void ubox_wvdp(uint8_t reg, uint8_t data); + +/** + * Returns the default interrupt frequency according to the BIOS. + * + * Possible values are: + * + * | Value | Frequency | + * | --- | --- | + * | 0 | 60Hz | + * | 1 | 50Hz | + */ +uint8_t ubox_get_vsync_freq(); + +// *INDENT-OFF* +/** + * This macro waits for the *vsync* interrupt. + * + * Interrupts must be enabled or this code will block indefinitely. + * + * Example: + * ```c + * ubox_wait_vsync(); + * // code to run after the int + * ``` + */ +#define ubox_wait_vsync() do { \ + __asm; \ + halt \ + __endasm; \ +} while(0) +// *INDENT-ON* + +// @Tile functions +// +// All the functions require **screen 2** (256x192 graphics mode, see +// [ubox_set_mode](#ubox_set_mode)). + +/** + * Sets the current tile set to the tile set pointed by `tiles`. + * + * The tile set is expected to have 256 tiles (8x8 pixels, 8 bytes per tile) + * and it will be loaded into the VDP in all three screen sections. + * + * All the tiles functions use an index in this tile set (usually via a `tile` + * parameter). + */ +void ubox_set_tiles(uint8_t *tiles) __z88dk_fastcall; + +/** + * Sets the current color table for current tile set to the color table pointed + * by `colors`. + * + * The color table is expected to have the 8 color rows for each of the 256 tiles + * of the tiles table (8 rows, 8 bytes per tile). The colors will be loaded into + * the VDP in all three screen sections. + */ +void ubox_set_tiles_colors(uint8_t *colors) __z88dk_fastcall; + +/** + * Puts a tile from current tile set on the screen. The tile is identified by + * index `tile` and placed on position (`x`,`y`). + * + * `x` and `y` units are tiles, and both are 0 based. + * + * Example: + * ```c + * // put the tile with index 1 on the top left corner of the screen + * ubox_put_tile(0, 0, 1); + * ``` + * + * This function is expensive and it performs two calls to the VDP that must + * keep the state between them. In case the interrupt handler performs + * operations with the VDP, this function shouldn't be used. + * + * To put multiple tiles in a row, use [ubox_write_vm](#ubox_write_vm) instead. The + * tile map is in the memory address `0x1800`. + * + * Example putting multiple tiles: + * ```c + * ubox_wait_vsync(); + * // write a complete row of tiles (32) from a buffer + * ubox_write_vm((uint8_t *)0x1800, 32, buffer); + * ``` + */ +void ubox_put_tile(uint8_t x, uint8_t y, uint8_t tile); + +/** + * Returns the tile index at position (`x`, `y`). + * + * `x` and `y` units are tiles, and both are 0 based. + */ +uint8_t ubox_get_tile(uint8_t x, uint8_t y); + +/** + * Fills the screen with the tile from current tile set identified by `tile` index. + * + * See [ubox_set_tiles](#ubox_set_tiles) for for information on how to set a + * tile set. + */ +void ubox_fill_screen(uint8_t tile) __z88dk_fastcall; + +// @Interrupt and clock functions + +/** + * Installs and initializes the interrupt handler. + * + * `wait_ticks` is the maximum number of interrupts that [ubox_wait](#ubox_wait) + * will wait. This value divides the frequency at which the machine generates the *vsync* + * interrupt (50Hz for PAL and 60Hz for NTSC). + * + * Some common values are: + * + * | wait ticks | PAL | NTSC | + * | --- | --- | --- | + * | 1 | 50 FPS | 60 FPS | + * | 2 | 25 FPS | 30 FPS | + * | 3 | 16.6 FPS | 20 FPS | + * + * Where FPS is the number of *frames per second* desired to update the game logic. + * + * Example: + * ```c + * // ubox_wait will wait for 2 ints (25 FPS) + * ubox_init_isr(2); + * ``` + * + * This function must be called once before any of the interrupt and clock + * functions are used. + * + * The installed interrupt handler uses `HTIMI_HOOK` instead of replacing the + * BIOS handler. + * + * The interrupt handler will save all registers. The shadow registers are not + * preserved or used. + * + * For performance reasons the BIOS keyboard buffer and key repeat functionality + * are disabled, and because of that the some BIOS functions, such as `CHGET`, + * won't work. + */ +void ubox_init_isr(uint8_t wait_ticks) __z88dk_fastcall; + +/** + * Installs an user interrupt handler. + * + * The function pointed by `fn` doesn't need to preserve any registers because + * that is done by the main interrupt handler. + * + * It is recommended that the user interrupt handler is short and uses the + * minimal amount of CPU cycles. + * + * Example: + * + * ```c + * uint8_t tick = 0; + * + * void my_isr() + * { + * // count interrupts + * ++tick; + * } + * + * ubox_set_user_isr(my_isr); + * ``` + */ +void ubox_set_user_isr(void (*fn)()) __z88dk_fastcall; + +/** + * Waits for a maximum `wait_ticks` interrupts (see [ubox_init_isr](#ubox_init_isr)). + * + * This function counts the interrupts (ticks) between between current call to + * `ubox_wait` and the previous one, and if less than `wait_ticks` ticks have + * passed, it will wait. + * + * This is used to ensure that the game loop used time is constant and hence + * the game plays smooth in case some updates are faster than others. + * + * If the time passed between current `ubox_wait` call and the previous is + * larger than `wait_ticks`, no waiting happens. This may mean that the game + * loop takes longer than expected and, if that happens frequently, it would be + * recommended to increase `wait_ticks` value when calling + * [ubox_init_isr](#ubox_init_isr). + * + * Example: + * ```c + * // 25 FPS on PAL, 30 FPS on NTSC + * ubox_init_isr(2); + * + * // game loop example + * while (1) + * { + * update_controls(); + * + * update_entities(); + * draw_entities(); + * + * // ensure that one loop takes at least 2 interrupts + * ubox_wait(); + * } + * ``` + */ +void ubox_wait(); + +/** + * Waits for `frames` frames. + * + * This is used to wait a fixed amount of time measured in frames. + * + * Because `frames` is 8-bit value, this funcion can only wait for 255 frames + * in one single call. + * + * Example: + * ```c + * // assuming PAL and wait_ticks 2 + * // wait for 10 seconds + * ubox_wait_for(250); + * ``` + */ +void ubox_wait_for(uint8_t frames) __z88dk_fastcall; + +extern uint8_t ubox_tick; + +/** + * Sets `ubox_tick` to zero. + * + * `ubox_tick` is a 8-bit global variable that is incremented on every interrupt. + */ +void ubox_reset_tick(); + +// @Sprite functions +// +// All the functions require **screen 2** (256x192 graphics mode, see +// [ubox_set_mode](#ubox_set_mode)). + +/** + * Structure to define sprite attributes. + * + * | Field | Description | + * | --- | --- | + * | `x` | The horizontal position of the sprite on the screen. | + * | `y` | The vertical position of the sprite on the screen. This coordinate starts in -1 (0xff) instead of 0. | + * | `pattern` | The index in the sprite pattern table. When 16x16 sprites are enabled, the lower two bits are ignored (4 regular 8x8 sprites form one 16x16 sprite). | + * | `attr` | The sprite attributes. The bits 0-3 are used for color and bit 7 is EC (Early Clock). | + * + * When EC is enabled, the sprite is displaced 32 pixels to the left. + */ +struct sprite_attr { + uint8_t y; + uint8_t x; + uint8_t pattern; + uint8_t attr; +}; + +/** + * Sets the sprite pattern data pointed by `data` into pattern number + * `pattern`. + * + * `pattern` is the index in the sprite pattern table of Screen 2. + * + * This function will set a 8x8 pixels pattern. + * + * See [ubox_set_sprite_pat16](#ubox_set_sprite_pat16) to set a 16x16 pixels pattern. + */ +void ubox_set_sprite_pat8(uint8_t *data, uint8_t pattern); + +/** + * Sets the sprite pattern data pointed by `data` into pattern number + * `pattern`, flipping the pattern data horizontally. + * + * `pattern` is the index in the sprite pattern table of Screen 2. + * + * This function will set a 8x8 pixels pattern. + * + * See [ubox_set_sprite_pat16_flip](#ubox_set_sprite_pat16_flip) to set a 16x16 + * pixels pattern. + */ +void ubox_set_sprite_pat8_flip(uint8_t *data, uint8_t pattern); + +/** + * Sets the sprite attributes of sprite number `sprite` using the attributes + * pointed by `attr`. + * + * `sprite` is the index in the sprite table of Screen 2. + * + * See [struct sprite_attr](#struct-sprite_attr) description for details on + * the sprite attributes. + * + * Example: + * ```c + * ubox_set_sprite_attr(&player_sprite_attr, 0); + * ``` + * + * To set the attributes of multiple sprites that are contiguous in the sprite + * table, it is recommended to use [ubox_write_vm](#ubox_write_vm). The sprite + * attribute table is in the memory address `0x1b00`. + */ +void ubox_set_sprite_attr(struct sprite_attr *attr, uint8_t sprite); + +/** + * Sets the sprite pattern data pointed by `data` into pattern number + * `pattern`. + * + * `pattern` is the index in the sprite pattern table of Screen 2. + * + * This function will set a 16x16 pixels pattern. The pattern is equivalent + * to setting four 8x8 patterns (upper left, lower left, upper right and lower right). + * + * See [ubox_set_sprite_pat8](#ubox_set_sprite_pat8) to set a 8x8 pixels pattern. + */ +void ubox_set_sprite_pat16(uint8_t *data, uint8_t pattern); + +/** + * Sets the sprite pattern data pointed by `data` into pattern number + * `pattern`, flipping the pattern data horizontally. + * + * `pattern` is the index in the sprite pattern table of Screen 2. + * + * This function will set a 16x16 pixels pattern. The pattern is equivalent + * to setting four 8x8 patterns (upper left, lower left, upper right and lower right). + * + * See [ubox_set_sprite_pat8_flip](#ubox_set_sprite_pat8_flip) to set a 8x8 + * pixels pattern. + */ +void ubox_set_sprite_pat16_flip(uint8_t *data, uint8_t pattern); + +/** + * Sets the sprite attributes of sprite number `sprite` using the attributes + * pointed by `attr`. + * + * `sprite` is the index in the sprite table of Screen 2. + * + * See [struct sprite_attr](#struct-sprite_attr) description for details on + * the sprite attributes. + * + * Example: + * ```c + * ubox_set_sprite_attr(&player_sprite_attr, 0); + * ``` + * + * To set the attributes of multiple sprites that are contiguous in the sprite + * table, it is recommended to use [ubox_write_vm](#ubox_write_vm). The sprite + * attribute table is in the memory address `0x1b00`. + */ +void ubox_set_sprite_attr(struct sprite_attr *attr, uint8_t sprite); + +// @Control functions +// +// The supported controls are: cursor and joystick (port 1 and port 2). +// +// In the case of cursor, space key is used as fire 1 and the "m" key as fire 2. +// +// For one button joysticks, [ubox_read_keys](#ubox_read_keys) can be used to +// provide an alternative fire 2 button using the keyboard. + +/** + * Waits for trigger on cursor (space or "m") or any of the joysticks, and + * returns the selected control. + * + * See [ubox_read_ctl](#ubox_read_ctl) for possible control values. + */ +uint8_t ubox_select_ctl(); + +/** + * Read the control identified by `control` and return the status of it. + * + * Possible control values are: + * + * | Control | Description | + * | --- | --- | + * | UBOX_MSX_CTL_CURSOR | Cursor for move, space for fire 1 and "m" for fire 2 | + * | UBOX_MSX_CTL_PORT1 | Joystick on port 1 | + * | UBOX_MSX_CTL_PORT2 | Joystick on port 2 | + * | UBOX_MSX_CTL_NONE | No control is selected. This is the default output of [ubox_select_ctl](#ubox_select_ctl) | + * + * The control status is a bit map with the following values: + * + * | Mask | Bit | + * | --- | --- | + * | UBOX_MSX_CTL_UP | 0 | + * | UBOX_MSX_CTL_DOWN | 1 | + * | UBOX_MSX_CTL_LEFT | 2 | + * | UBOX_MSX_CTL_RIGHT | 3 | + * | UBOX_MSX_CTL_FIRE1 | 4 | + * | UBOX_MSX_CTL_FIRE2 | 5 | + * + * Example: + * ```c + * if (ubox_read_ctl(UBOX_MSX_CTL_CURSOR) & UBOX_MSX_CTL_UP) + * { + * // in the cursor, UP is on + * } + * ``` + */ +uint8_t ubox_read_ctl(uint8_t control) __z88dk_fastcall; + +#define UBOX_MSX_CTL_CURSOR 0 +#define UBOX_MSX_CTL_PORT1 1 +#define UBOX_MSX_CTL_PORT2 2 +#define UBOX_MSX_CTL_NONE 0xff + +#define UBOX_MSX_CTL_UP 1 +#define UBOX_MSX_CTL_DOWN 2 +#define UBOX_MSX_CTL_LEFT 4 +#define UBOX_MSX_CTL_RIGHT 8 +#define UBOX_MSX_CTL_FIRE1 16 +#define UBOX_MSX_CTL_FIRE2 32 + +/** + * Reads a row of the keyboard matrix and returns a bit map with the state of + * the keys in that row. + * + * It is important to remember that there are different keyboard layouts and + * that there is no reliable way of detecting 100% of them. + * + * Constants for the QWERTY layout are provided as `UBOX_MSX_KEY_*`, and that covers + * the most common models. + * + * Example: + * ```c + * // read row 7 that includes RET, SEL, BS, STOP, TAB, ESC, F5 and F4 + * uint8_t keys = ubox_read_keys(7); + * + * if (keys & UBOX_MSX_KEY_ESC) + * { + * // ESC key is pressed + * } + * ``` + */ +uint8_t ubox_read_keys(uint8_t row) __z88dk_fastcall; + +// row 0 +#define UBOX_MSX_KEY_7 0x80 +#define UBOX_MSX_KEY_6 0x40 +#define UBOX_MSX_KEY_5 0x20 +#define UBOX_MSX_KEY_4 0x10 +#define UBOX_MSX_KEY_3 0x08 +#define UBOX_MSX_KEY_2 0x04 +#define UBOX_MSX_KEY_1 0x02 +#define UBOX_MSX_KEY_0 0x01 + +// row 1 +#define UBOX_MSX_KEY_SEMI 0x80 // ";" +#define UBOX_MSX_KEY_CSBRACKET 0x40 // "]" +#define UBOX_MSX_KEY_OSBRACKET 0x20 // "[" +#define UBOX_MSX_KEY_BSLASH 0x10 // "\" +#define UBOX_MSX_KEY_EQUAL 0x08 // "=" +#define UBOX_MSX_KEY_MINUS 0x04 // "-" +#define UBOX_MSX_KEY_9 0x02 +#define UBOX_MSX_KEY_8 0x01 + +// row 2 +#define UBOX_MSX_KEY_B 0x80 // "B" +#define UBOX_MSX_KEY_A 0x40 // "A" +#define UBOX_MSX_KEY_FSLASH 0x10 // "/" +#define UBOX_MSX_KEY_DOT 0x08 // "." +#define UBOX_MSX_KEY_COMMA 0x04 // "," +#define UBOX_MSX_KEY_QUOTE 0x02 // "'" +#define UBOX_MSX_KEY_TICK 0x01 // "`" + +// row 3 +#define UBOX_MSX_KEY_J 0x80 // "J" +#define UBOX_MSX_KEY_I 0x40 // "I" +#define UBOX_MSX_KEY_H 0x20 // "H" +#define UBOX_MSX_KEY_G 0x10 // "G" +#define UBOX_MSX_KEY_F 0x08 // "F" +#define UBOX_MSX_KEY_E 0x04 // "E" +#define UBOX_MSX_KEY_D 0x02 // "D" +#define UBOX_MSX_KEY_C 0x01 // "C" + +// row 4 +#define UBOX_MSX_KEY_R 0x80 // "R" +#define UBOX_MSX_KEY_Q 0x40 // "Q" +#define UBOX_MSX_KEY_P 0x20 // "P" +#define UBOX_MSX_KEY_O 0x10 // "O" +#define UBOX_MSX_KEY_N 0x08 // "N" +#define UBOX_MSX_KEY_M 0x04 // "M" +#define UBOX_MSX_KEY_L 0x02 // "L" +#define UBOX_MSX_KEY_K 0x01 // "K" + +// row 5 +#define UBOX_MSX_KEY_Z 0x80 // "Z" +#define UBOX_MSX_KEY_Y 0x40 // "Y" +#define UBOX_MSX_KEY_X 0x20 // "X" +#define UBOX_MSX_KEY_W 0x10 // "W" +#define UBOX_MSX_KEY_V 0x08 // "V" +#define UBOX_MSX_KEY_U 0x04 // "U" +#define UBOX_MSX_KEY_T 0x02 // "T" +#define UBOX_MSX_KEY_S 0x01 // "S" + +// row 6 +#define UBOX_MSX_KEY_F3 0x80 // F3 +#define UBOX_MSX_KEY_F2 0x40 // F2 +#define UBOX_MSX_KEY_F1 0x20 // F1 +#define UBOX_MSX_KEY_CODE 0x10 // CODE +#define UBOX_MSX_KEY_CAP 0x08 // CAP +#define UBOX_MSX_KEY_GRAPH 0x04 // GRAPH +#define UBOX_MSX_KEY_CTRL 0x02 // CTRL +#define UBOX_MSX_KEY_SHIFT 0x01 // SHIFT + +// row 7 +#define UBOX_MSX_KEY_RET 0x80 // RET +#define UBOX_MSX_KEY_SEL 0x40 // SEL +#define UBOX_MSX_KEY_BS 0x20 // BS +#define UBOX_MSX_KEY_STOP 0x10 // STOP +#define UBOX_MSX_KEY_TAB 0x08 // TAB +#define UBOX_MSX_KEY_ESC 0x04 // ESC +#define UBOX_MSX_KEY_F5 0x02 // F5 +#define UBOX_MSX_KEY_F4 0x01 // F4 + +// row 8 +#define UBOX_MSX_KEY_RIGHT 0x80 // RIGHT +#define UBOX_MSX_KEY_DOWN 0x40 // DOWN +#define UBOX_MSX_KEY_UP 0x20 // UP +#define UBOX_MSX_KEY_LEFT 0x10 // LEFT +#define UBOX_MSX_KEY_DEL 0x08 // DEL +#define UBOX_MSX_KEY_INS 0x04 // INS +#define UBOX_MSX_KEY_HOME 0x02 // HOME +#define UBOX_MSX_KEY_SPACE 0x01 // SPACE + +#endif // _UBOX_MSX_H |