From 313a3d28f938b39428e43bfd39bd7d0fe06c875a Mon Sep 17 00:00:00 2001 From: Squeetz Date: Mon, 16 Jun 2025 01:21:12 +0200 Subject: [PATCH 1/2] Document m4a xcmd 12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Waits n frames. Used by Pokémon cries. --- constants/m4a_constants.inc | 2 +- include/gba/m4a_internal.h | 8 ++++---- src/m4a.c | 18 +++++++++--------- src/m4a_tables.c | 7 ++++--- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/constants/m4a_constants.inc b/constants/m4a_constants.inc index 1a744dc7fb6..3add621759c 100644 --- a/constants/m4a_constants.inc +++ b/constants/m4a_constants.inc @@ -178,7 +178,7 @@ struct_field o_MusicPlayerTrack_ToneData_sustain, 1 struct_field o_MusicPlayerTrack_ToneData_release, 1 struct_field o_MusicPlayerTrack_gap, 10 - struct_field o_MusicPlayerTrack_unk_3A, 2 + struct_field o_MusicPlayerTrack_timer, 2 struct_field o_MusicPlayerTrack_unk_3C, 4 struct_field o_MusicPlayerTrack_cmdPtr, 4 struct_field o_MusicPlayerTrack_patternStack, 12 diff --git a/include/gba/m4a_internal.h b/include/gba/m4a_internal.h index fa509e5115d..609259b032a 100644 --- a/include/gba/m4a_internal.h +++ b/include/gba/m4a_internal.h @@ -257,8 +257,8 @@ struct PokemonCrySong u8 tieCmd; // 0x29 u8 tieKeyValue; // 0x2A u8 tieVelocityValue; // 0x2B - u8 unkCmd0C[2]; // 0x2C - u16 unkCmd0CParam; // 0x2E + u8 xwaitCmd[2]; // 0x2C + u16 length; // 0x2E u8 end[2]; // 0x30 }; @@ -306,7 +306,7 @@ struct MusicPlayerTrack struct SoundChannel *chan; struct ToneData tone; u8 gap[10]; - u16 unk_3A; + u16 timer; u32 unk_3C; u8 *cmdPtr; u8 *patternStack[3]; @@ -495,7 +495,7 @@ void ply_xiecv(struct MusicPlayerInfo *, struct MusicPlayerTrack *); void ply_xiecl(struct MusicPlayerInfo *, struct MusicPlayerTrack *); void ply_xleng(struct MusicPlayerInfo *, struct MusicPlayerTrack *); void ply_xswee(struct MusicPlayerInfo *, struct MusicPlayerTrack *); -void ply_xcmd_0C(struct MusicPlayerInfo *, struct MusicPlayerTrack *); +void ply_xwait(struct MusicPlayerInfo *, struct MusicPlayerTrack *); void ply_xcmd_0D(struct MusicPlayerInfo *, struct MusicPlayerTrack *); #endif // GUARD_GBA_M4A_INTERNAL_H diff --git a/src/m4a.c b/src/m4a.c index 00d66f8fce2..ebd3afe291b 100644 --- a/src/m4a.c +++ b/src/m4a.c @@ -1612,26 +1612,26 @@ void ply_xswee(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track track->cmdPtr++; } -void ply_xcmd_0C(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) +void ply_xwait(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track) { - u32 unk; + u32 len; #ifdef UBFIX - unk = 0; + len = 0; #endif - READ_XCMD_BYTE(unk, 0) // UB: uninitialized variable - READ_XCMD_BYTE(unk, 1) + READ_XCMD_BYTE(len, 0) // UB: uninitialized variable + READ_XCMD_BYTE(len, 1) - if (track->unk_3A < (u16)unk) + if (track->timer < (u16)len) { - track->unk_3A++; + track->timer++; track->cmdPtr -= 2; track->wait = 1; } else { - track->unk_3A = 0; + track->timer = 0; track->cmdPtr += 2; } } @@ -1719,7 +1719,7 @@ void SetPokemonCryPitch(s16 val) void SetPokemonCryLength(u16 val) { - gPokemonCrySong.unkCmd0CParam = val; + gPokemonCrySong.length = val; } void SetPokemonCryRelease(u8 val) diff --git a/src/m4a_tables.c b/src/m4a_tables.c index 55eae171ff5..286e938bad9 100644 --- a/src/m4a_tables.c +++ b/src/m4a_tables.c @@ -251,6 +251,7 @@ const u8 gClockTable[] = #define xRELE 0x07 #define xIECV 0x08 #define xIECL 0x09 +#define xWAIT 0x0c #define EOT 0xce #define TIE 0xcf @@ -283,8 +284,8 @@ const struct PokemonCrySong gPokemonCrySongTemplate = TIE, 60, // TIE key (default is Cn3) 127, // TIE velocity - {XCMD, 0x0C}, - 60, // unk value + {XCMD, xWAIT}, + 60, // frames to wait {EOT, FINE} // end }; @@ -302,6 +303,6 @@ const XcmdFunc gXcmdTable[] = ply_xiecl, ply_xleng, ply_xswee, - ply_xcmd_0C, + ply_xwait, ply_xcmd_0D, }; From 39c22794e688d813962f40645cf975a730ee89da Mon Sep 17 00:00:00 2001 From: Squeetz Date: Sun, 21 Jun 2026 20:33:54 +0200 Subject: [PATCH 2/2] Fix latin_small font, add gbagfx support This commit lets gbagfx support half-width latin fonts. --- .gitignore | 3 +- Makefile | 2 +- graphics/fonts/latin_small.png | Bin 3285 -> 3021 bytes graphics_file_rules.mk | 8 +-- src/text.c | 10 +-- tools/gbagfx/font.c | 107 +++++++++++++++++++++++++++++++-- tools/gbagfx/font.h | 6 +- tools/gbagfx/main.c | 38 ++++++++++-- 8 files changed, 149 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 5ed9cf3ffdd..fe1ba8224ee 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,8 @@ *.id0 *.id1 *.id2 -*.latfont +*.hwlatfont +*.fwlatfont *.lz *.map *.nam diff --git a/Makefile b/Makefile index 26b1e4ca096..53353fc1b3b 100644 --- a/Makefile +++ b/Makefile @@ -214,7 +214,7 @@ clean-assets: rm -f $(DATA_ASM_SUBDIR)/layouts/layouts.inc $(DATA_ASM_SUBDIR)/layouts/layouts_table.inc rm -f $(DATA_ASM_SUBDIR)/maps/connections.inc $(DATA_ASM_SUBDIR)/maps/events.inc $(DATA_ASM_SUBDIR)/maps/groups.inc $(DATA_ASM_SUBDIR)/maps/headers.inc find sound -iname '*.bin' -exec rm {} + - find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.rl' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} + + find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.rl' -o -iname '*.hwlatfont' -o -iname '*.fwlatfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} + find $(DATA_ASM_SUBDIR)/maps \( -iname 'connections.inc' -o -iname 'events.inc' -o -iname 'header.inc' \) -exec rm {} + tidy: diff --git a/graphics/fonts/latin_small.png b/graphics/fonts/latin_small.png index 7a79f23891d7306ba1ae0e0d64f7790d568632c8..dfb997c053a70d5effb7da76895900fdb40956dc 100644 GIT binary patch delta 2994 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 -$(FONTGFXDIR)/latin_small.latfont: $(FONTGFXDIR)/latin_small.png +$(FONTGFXDIR)/latin_small.hwlatfont: $(FONTGFXDIR)/latin_small.png $(GFX) $< $@ $(FONTGFXDIR)/japanese_small.fwjpnfont: $(FONTGFXDIR)/japanese_small.png @@ -70,19 +70,19 @@ $(FONTGFXDIR)/japanese_small.fwjpnfont: $(FONTGFXDIR)/japanese_small.png $(FONTGFXDIR)/japanese_tall.fwjpnfont: $(FONTGFXDIR)/japanese_tall.png $(GFX) $< $@ -$(FONTGFXDIR)/latin_normal.latfont: $(FONTGFXDIR)/latin_normal.png +$(FONTGFXDIR)/latin_normal.fwlatfont: $(FONTGFXDIR)/latin_normal.png $(GFX) $< $@ $(FONTGFXDIR)/japanese_normal.fwjpnfont: $(FONTGFXDIR)/japanese_normal.png $(GFX) $< $@ -$(FONTGFXDIR)/latin_male.latfont: $(FONTGFXDIR)/latin_male.png +$(FONTGFXDIR)/latin_male.fwlatfont: $(FONTGFXDIR)/latin_male.png $(GFX) $< $@ $(FONTGFXDIR)/japanese_male.fwjpnfont: $(FONTGFXDIR)/japanese_male.png $(GFX) $< $@ -$(FONTGFXDIR)/latin_female.latfont: $(FONTGFXDIR)/latin_female.png +$(FONTGFXDIR)/latin_female.fwlatfont: $(FONTGFXDIR)/latin_female.png $(GFX) $< $@ $(FONTGFXDIR)/japanese_female.fwjpnfont: $(FONTGFXDIR)/japanese_female.png diff --git a/src/text.c b/src/text.c index baaefe2e6a4..f3eef07ce6d 100644 --- a/src/text.c +++ b/src/text.c @@ -97,7 +97,7 @@ struct const u8 gKeypadIconTiles[] = INCBIN_U8("graphics/fonts/keypad_icons.4bpp"); -static const u16 sFontSmallLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_small.latfont"); +static const u16 sFontSmallLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_small.hwlatfont"); static const u8 sFontSmallLatinGlyphWidths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 4, 4, 5, @@ -140,7 +140,7 @@ static const u8 sFontSmallLatinGlyphWidths[] = }; static const u16 sFontSmallJapaneseGlyphs[] = INCBIN_U16("graphics/fonts/japanese_small.fwjpnfont"); -static const u16 sFontNormalCopy1LatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_normal.latfont"); +static const u16 sFontNormalCopy1LatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_normal.fwlatfont"); static const u8 sFontNormalCopy1LatinGlyphWidths[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, @@ -183,7 +183,7 @@ static const u8 sFontNormalCopy1LatinGlyphWidths[] = }; static const u16 sFontTallJapaneseGlyphs[] = INCBIN_U16("graphics/fonts/japanese_tall.fwjpnfont"); -static const u16 sFontNormalLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_normal.latfont"); +static const u16 sFontNormalLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_normal.fwlatfont"); static const u8 sFontNormalLatinGlyphWidths[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, @@ -249,7 +249,7 @@ static const u8 sFontNormalJapaneseGlyphWidths[] = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0 }; -static const u16 sFontMaleLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_male.latfont"); +static const u16 sFontMaleLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_male.fwlatfont"); static const u8 sFontMaleLatinGlyphWidths[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, @@ -315,7 +315,7 @@ static const u8 sFontMaleJapaneseGlyphWidths[] = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0 }; -static const u16 sFontFemaleLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_female.latfont"); +static const u16 sFontFemaleLatinGlyphs[] = INCBIN_U16("graphics/fonts/latin_female.fwlatfont"); static const u8 sFontFemaleLatinGlyphWidths[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, diff --git a/tools/gbagfx/font.c b/tools/gbagfx/font.c index 0dd6fbc3ee0..6ce42d642ea 100644 --- a/tools/gbagfx/font.c +++ b/tools/gbagfx/font.c @@ -16,7 +16,53 @@ unsigned char gFontPalette[][3] = { {0xFF, 0xFF, 0xFF} // box (white) }; -static void ConvertFromLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +static void ConvertFromHalfWidthLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + unsigned int srcPixelsOffset = 0; + + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 32; column++) { + for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) { + unsigned int pixelsX = (column * 8); + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i; + unsigned int destPixelsOffset = (pixelsY * 64) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + srcPixelsOffset += 2; + } + } + } + } +} + +static void ConvertToHalfWidthLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +{ + unsigned int destPixelsOffset = 0; + + for (unsigned int row = 0; row < numRows; row++) { + for (unsigned int column = 0; column < 32; column++) { + for (unsigned int glyphTile = 0; glyphTile < 2; glyphTile++) { + unsigned int pixelsX = (column * 8); + + for (unsigned int i = 0; i < 8; i++) { + unsigned int pixelsY = (row * 16) + (glyphTile * 8) + i; + unsigned int srcPixelsOffset = (pixelsY * 64) + (pixelsX / 4); + + dest[destPixelsOffset] = src[srcPixelsOffset + 1]; + dest[destPixelsOffset + 1] = src[srcPixelsOffset]; + + destPixelsOffset += 2; + } + } + } + } +} + +static void ConvertFromFullWidthLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) { unsigned int srcPixelsOffset = 0; @@ -39,7 +85,7 @@ static void ConvertFromLatinFont(unsigned char *src, unsigned char *dest, unsign } } -static void ConvertToLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) +static void ConvertToFullWidthLatinFont(unsigned char *src, unsigned char *dest, unsigned int numRows) { unsigned int destPixelsOffset = 0; @@ -173,7 +219,56 @@ static void SetFontPalette(struct Image *image) image->hasTransparency = false; } -void ReadLatinFont(char *path, struct Image *image) +void ReadHalfWidthLatinFont(char *path, struct Image *image) +{ + int fileSize; + unsigned char *buffer = ReadWholeFile(path, &fileSize); + + int numGlyphs = fileSize / 32; + + if (numGlyphs % 16 != 0) + FATAL_ERROR("The number of glyphs (%d) is not a multiple of 16.\n", numGlyphs); + + int numRows = numGlyphs / 16; + + image->width = 256; + image->height = numRows * 16; + image->bitDepth = 2; + image->pixels = malloc(fileSize); + + if (image->pixels == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertFromHalfWidthLatinFont(buffer, image->pixels, numRows); + + free(buffer); + + SetFontPalette(image); +} + +void WriteHalfWidthLatinFont(char *path, struct Image *image) +{ + if (image->width != 256) + FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width); + + if (image->height % 16 != 0) + FATAL_ERROR("The height of the font image (%d) is not a multiple of 16.\n", image->height); + + int numRows = image->height / 16; + int bufferSize = numRows * 16 * 64; + unsigned char *buffer = malloc(bufferSize); + + if (buffer == NULL) + FATAL_ERROR("Failed to allocate memory for font.\n"); + + ConvertToHalfWidthLatinFont(image->pixels, buffer, numRows); + + WriteWholeFile(path, buffer, bufferSize); + + free(buffer); +} + +void ReadFullWidthLatinFont(char *path, struct Image *image) { int fileSize; unsigned char *buffer = ReadWholeFile(path, &fileSize); @@ -193,14 +288,14 @@ void ReadLatinFont(char *path, struct Image *image) if (image->pixels == NULL) FATAL_ERROR("Failed to allocate memory for font.\n"); - ConvertFromLatinFont(buffer, image->pixels, numRows); + ConvertFromFullWidthLatinFont(buffer, image->pixels, numRows); free(buffer); SetFontPalette(image); } -void WriteLatinFont(char *path, struct Image *image) +void WriteFullWidthLatinFont(char *path, struct Image *image) { if (image->width != 256) FATAL_ERROR("The width of the font image (%d) is not 256.\n", image->width); @@ -215,7 +310,7 @@ void WriteLatinFont(char *path, struct Image *image) if (buffer == NULL) FATAL_ERROR("Failed to allocate memory for font.\n"); - ConvertToLatinFont(image->pixels, buffer, numRows); + ConvertToFullWidthLatinFont(image->pixels, buffer, numRows); WriteWholeFile(path, buffer, bufferSize); diff --git a/tools/gbagfx/font.h b/tools/gbagfx/font.h index 45086d02acb..adcea0ce89c 100644 --- a/tools/gbagfx/font.h +++ b/tools/gbagfx/font.h @@ -6,8 +6,10 @@ #include #include "gfx.h" -void ReadLatinFont(char *path, struct Image *image); -void WriteLatinFont(char *path, struct Image *image); +void ReadHalfWidthLatinFont(char *path, struct Image *image); +void WriteHalfWidthLatinFont(char *path, struct Image *image); +void ReadFullWidthLatinFont(char *path, struct Image *image); +void WriteFullWidthLatinFont(char *path, struct Image *image); void ReadHalfwidthJapaneseFont(char *path, struct Image *image); void WriteHalfwidthJapaneseFont(char *path, struct Image *image); void ReadFullwidthJapaneseFont(char *path, struct Image *image); diff --git a/tools/gbagfx/main.c b/tools/gbagfx/main.c index 98a1a1edf9f..0dba4c8aea0 100644 --- a/tools/gbagfx/main.c +++ b/tools/gbagfx/main.c @@ -350,18 +350,18 @@ void HandleJascToGbaPaletteCommand(char *inputPath, char *outputPath, int argc, WriteGbaPalette(outputPath, &palette); } -void HandleLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +void HandleHalfWidthLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { struct Image image; image.tilemap.data.affine = NULL; // initialize to NULL to avoid issues in FreeImage - ReadLatinFont(inputPath, &image); + ReadHalfWidthLatinFont(inputPath, &image); WritePng(outputPath, &image); FreeImage(&image); } -void HandlePngToLatinFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +void HandlePngToHalfWidthLatinFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) { struct Image image; image.tilemap.data.affine = NULL; // initialize to NULL to avoid issues in FreeImage @@ -369,7 +369,31 @@ void HandlePngToLatinFontCommand(char *inputPath, char *outputPath, int argc UNU image.bitDepth = 2; ReadPng(inputPath, &image); - WriteLatinFont(outputPath, &image); + WriteHalfWidthLatinFont(outputPath, &image); + + FreeImage(&image); +} + +void HandleFullWidthLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; + image.tilemap.data.affine = NULL; // initialize to NULL to avoid issues in FreeImage + + ReadFullWidthLatinFont(inputPath, &image); + WritePng(outputPath, &image); + + FreeImage(&image); +} + +void HandlePngToFullWidthLatinFontCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ + struct Image image; + image.tilemap.data.affine = NULL; // initialize to NULL to avoid issues in FreeImage + + image.bitDepth = 2; + + ReadPng(inputPath, &image); + WriteFullWidthLatinFont(outputPath, &image); FreeImage(&image); } @@ -605,8 +629,10 @@ int main(int argc, char **argv) { "png", "pal", HandlePngToJascPaletteCommand }, { "gbapal", "pal", HandleGbaToJascPaletteCommand }, { "pal", "gbapal", HandleJascToGbaPaletteCommand }, - { "latfont", "png", HandleLatinFontToPngCommand }, - { "png", "latfont", HandlePngToLatinFontCommand }, + { "hwlatfont", "png", HandleHalfWidthLatinFontToPngCommand }, + { "png", "hwlatfont", HandlePngToHalfWidthLatinFontCommand }, + { "fwlatfont", "png", HandleFullWidthLatinFontToPngCommand }, + { "png", "fwlatfont", HandlePngToFullWidthLatinFontCommand }, { "hwjpnfont", "png", HandleHalfwidthJapaneseFontToPngCommand }, { "png", "hwjpnfont", HandlePngToHalfwidthJapaneseFontCommand }, { "fwjpnfont", "png", HandleFullwidthJapaneseFontToPngCommand },