-
-
Notifications
You must be signed in to change notification settings - Fork 92
Text and Variable Width Text Engines
The output system is only available for BG_MODE1. If you need it in other mode, you need to develop it.
It is managed via a map of 32x32 characters. The console functions are used to display text.
When you want to display a text, you must specify the x,y coordinates of the text in this map.
You've got two ways to display text on screen :
- using the default map shipped with PVSnesLib (text are sent to display during Vblank)
- using your own map and send it to screen after waiting for vblank with the DMA functions.
The first thing to use the display system is to init the console with the background that will handle the text, and of course, the font to use. We will see later how to customize the font. PVSneslib is shipped with a default font named pvsneslibfont.bmp. Just take a look at it to know how characters are.
To init display system, just call consoleInitText(0,0, &snesfont, &snespalfont) where :
- the first parameter is the background that will handle the text (0..2)
- the second one is the palette number (0..16)
- the third one is the address of graphics for font converted with gfx4snes
- the last one is the address of palette for font converted with gfx4snes
.. Somewhere where you initialized variables ...
extern char snesfont;
//---------------------------------------------------------------------------------
.. somewhere in the beginning of your main code ...
// Initialize SNES
consoleInit();
// Initialize text console with our font
consoleInitText(0, 0, &snesfont,&snespalfont);You can also change the text graphics and map VRAM address by using the functions:
consoleSetTextVramBGAdr(background graphic address);
consoleSetTextVramAdr(background map address);
consoleSetTextOffset(offset of text in background map address);here is the hello_world example of new vram entries:
// Initialize text console with our font
consoleSetTextVramBGAdr(0x6800);
consoleSetTextVramAdr(0x3000);
consoleSetTextOffset(0x0100);
consoleInitText(0, 16 * 2, &tilfont, &palfont);This is done with the consoleDrawText function, just call it with text coordinates and text value. For example consoleDrawText(5,10,"hello world") to display at column 5, row 10 the text hello world.
Also, you can format the string to display with generic format options :
For example, %d is used to display integer like consoleDrawText(1,1,"X=%d",varx) that will display X=10 if varx equals 10.
To display a string, you must use %s and %c for a char. For example :
char name[32];
strcpy(name,"PVSneslib");
consoleDrawText(1,1,"Name of lib=%s",name);Just take a look at standard printf options of C language to know exactly what you can do.
You can use only two colors, the text and background color with the consoleSetTextCol function. But only text color is important.
Color is designed with the Red, Green and Blue parameters.
Each parameter must be a number between 0 and 31. And you must call function RGB15 to have the final correct color. So, RGB15(0,0,0) is the black color and RGB15(31,31,31) is the white color. For example, to use a red text color with black background, just put :
consoleSetTextCol(RGB15(31,0,0), RGB15(0,0,0));Basically, a custom font is a tiled background, each tile representing a specific character.
The layout is very important, each character must be 8x8 pixels and only from ascii code 32 to 127. You also have only two colors, the background color (which is the transparent color) and the font color. We are not going to use the palette for the text font, but you must know that the background color must be the first color (entry #0) and the text color the next one (entry #1 of palette).
For a more accurate editing, I suggest you to display a grid (8×8 pixels) in your favourite graphics editor.
One more thing to know about this layout, it must be compiled with the "non optimized" -R flag of gfx4snes (to avoid lost of characters).
pvsneslibfont.pic: pvsneslibfont.bmp
@echo convert font with no tile reduction ... $(notdir $@)
$(GFXCONV) -u 16 -s 8 -o 2 -e 1 -R -m -t bmp -i $<In addition to the fixed 8x8-tile console text described above, PVSnesLib now offers a Variable Width Font (VWF) text system, inspired by untoxa's GB VWF engine.
Instead of every character occupying a fixed 8-pixel-wide tile, each glyph only takes up the horizontal space it actually needs (based on a per-character width table), which gives much more natural-looking, proportionally-spaced text — useful for dialogue boxes, menus, and any place where dense or nicer-looking text is desirable.
A complete working sample is available in snes-examples/systems/textvwfont.
The VWF system renders text into an internal line buffer (scr_txt_font_map, 0x800 bytes) rather than writing directly to VRAM.
You draw one or more lines of text into that buffer with consoleDrawvwText, and then flush ("update") the dirty lines to VRAM via DMA with consolevwTextUpdate, typically once per frame near VBlank. Up to 5 independent lines (index 0..4) can be managed at a time, each with its own VRAM tile destination.
Call consoleInitvwText(fnttileadr, fntwidthadr) once, before using any other VWF function:
-
fnttileadr— pointer to the font tile graphics data (converted with gfx4snes) -
fntwidthadr— pointer to the font width table (one byte per character, giving its pixel width)
This loads the variable width table into an internal table and stores the pointer to the tiles in ROM.
extern char vwfonttiles;
extern char vwfontwidths;
// Initialize the variable width font text system
consoleInitvwText(&vwfonttiles, &vwfontwidths);For each line you plan to use, tell the system where its tile pixel data should be DMA'd in VRAM with consoleSetvwTextLineAddr(lineidx, tilevram):
-
lineidx— the line ID (0..4) -
tilevram— the VRAM word-address for that line's tile pixel data
consoleSetvwTextLineAddr(0, 0x4000);
consoleSetvwTextLineAddr(1, 0x4400);Before drawing new text into a line, it's good practice to clear it with consoleSetvwTextClearLine(lineidx). This zeroes the tile & map buffers for that line and resets its metadata.
consoleSetvwTextClearLine(0);You can control which tilemap word is used to blank the unused columns of a line with consoleSetvwTextBlkTile(tileEntry) (default is 0).
Use consoleDrawvwText(lineidx, xcol, ycol, text) to render a null-terminated string into a line buffer:
-
lineidx— the line ID (0..4) -
xcol— the starting pixel column (0–255) -
ycol— the starting line (0–27) -
text— the text to display
Characters outside ASCII 0x20–0x7F are silently skipped, and drawing stops at the null terminator or once the line is full (32 tiles).
consoleDrawvwText(0, 4, 10, "Hello variable width world!");You can also set the high byte (palette / priority / flip bits, VHPC CC00) applied to every tilemap entry written by consoleDrawvwText with consoleSetvwTextMapAttr(mapAttr) (default is 0).
consoleSetvwTextMapAttr(0x20); // e.g. select palette 2
Once your lines are drawn, call consolevwTextUpdate() to DMA all dirty line buffers to VRAM. This should be called during, just before, or just after VBlank (it internally calls dmaCopyVram()).
while (1) {
// ... game logic, maybe redraw some lines with consoleDrawvwText ...
WaitForVBlank();
consolevwTextUpdate();
}Basically, a variable width font is a tiled background, each tile representing a specific character.
But, a specific tool named fnt4snes is use to convert the graphics and also export a table with the width of each character. Only characters from ascii code 32 to 127 are usable. This is the reason why the bimtap must be 768 pixels width and 8 pixel sheight.
pvsneslibfont.pic: pvsneslibfont.png
@echo convert font ... $(notdir $@)
$(FNTCONV) -o 16 -u 4 -p -i $<To allow PVSnesLib to calculate the width of each character, you need to put a red dot on first line, when you want to finish one charcater. A charecter can't exceed 7 pixels width.
You can change the RED color for another one with the -b parameter to fnt4snes.
Here is a complete example for drawing a text on screen.
#include <snes.h>
extern char vwfonttiles;
extern char vwfontwidths;
int main(void)
{
// Initialize the variable width font system
consoleInitvwText(&vwfonttiles, &vwfontwidths);
// Assign a VRAM destination to line 0 and clear it
consoleSetvwTextLineAddr(0, 0x4000);
consoleSetvwTextClearLine(0);
// Draw some text into the line buffer
consoleDrawvwText(0, 4, 10, "Hello variable width world!");
setScreenOn();
while (1) {
WaitForVBlank();
consolevwTextUpdate();
}
return 0;
}