#9006 - Jakerrzero - Sat Jul 26, 2003 7:19 am
I was wondering how the text systems are done in games like Advance Wars. Im talking about games where the characters are obviously not 8x8 bitmaps. The capital letters are actually bigger than the lower case letters and some lower case letters are wider than others like an 'm' for example in most fonts is usually wider than the other characters. I looked at the bg maps in advance wars with VBA and you can see that they are using tiles to display their text and not sprites however I am still having trouble figuring out how they make their font look so nice. I just find the 8x8 character style font's to be a little hard to read. Does anyone know what I'm talking about on this?
Thanks for any responses :)
-Jake
#9007 - Geno - Sat Jul 26, 2003 7:35 am
They could possibly blit(or draw) the tiles onto the background.
I've not had trouble reading 8x8 fonts, though I always like the bigger ones better.
_________________
Out of Order.
#9029 - DekuTree64 - Sat Jul 26, 2003 7:05 pm
Yeah, I'd just blit them. I tried that a while back though, and never did get it to work. Too confusing to work out the pixel coordinates when you're drawing a letter half in one tile and half in the next, in 16 color mode where you have to access at least 4 pixels at a time.
Tepples, you were talking about using the scaling regs to create a linear map here: http://forum.gbadev.org/viewtopic.php?t=403, which would make it a lot easier. Mind giving a quick explanation?
You would lose one of your BGs using mode 1 though (unless you were using it anyway for a special effects layer or something), and it would take twice the VRAM. Besides, doing it in regular tile mode is more a matter of intelligence than possibility^_^;
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#9039 - mtg101 - Sat Jul 26, 2003 10:27 pm
If it's a bitmap background, then blitting seems like the way forward. If it's a tile background, maybe sprites are used. A full space-thru-tilde ASCII set of sprites leaves about 32 sprites I think, so with missing out a few chars you might be able to use sprites for text. And if you know the width of each char you can position them so that you have thin and wide chars.
_________________
---
Speaker for the Dead
#9040 - abilyk - Sat Jul 26, 2003 10:39 pm
Quote: |
A full space-thru-tilde ASCII set of sprites leaves about 32 sprites I think, so with missing out a few chars you might be able to use sprites for text. And if you know the width of each char you can position them so that you have thin and wide chars. |
No, no, no. That wouldn't work. You can only display 128 sprites at once; the way you described, you could only place one of each letter. You could, however, use a few large sprites as a text window and "draw" letters onto them before displaying them. There are other posts that talk more about this, a couple searches should help you out.
- Andrew
#9041 - mtg101 - Sat Jul 26, 2003 10:53 pm
Only one of each letter? I thought that you could have multiple srpites of the same image?
Granted my dscription of the amount of left over sprites was based on nonsense. But I'm sure you have lots of space in sprite memory for the character set, and can space 32 sprites for writing quick bits of dialog?
_________________
---
Speaker for the Dead
#9049 - tepples - Sun Jul 27, 2003 3:22 am
I've implemented such a sprite text system. A 16-pixel-tall font from space to tilde takes up about 12 KB of sprite cel VRAM, and there's only about 20 KB left for the rest of the sprite cels.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#9067 - col - Sun Jul 27, 2003 8:41 pm
mtg101 wrote: |
Only one of each letter? I thought that you could have multiple srpites of the same image?
Granted my dscription of the amount of left over sprites was based on nonsense. But I'm sure you have lots of space in sprite memory for the character set, and can space 32 sprites for writing quick bits of dialog? |
are you mixing up sprite vram with OAM (Object Attribute Memory)?
there is 32kb of tile data vram for sprites, thats enough for 1024 tiles in 4bit colour or 512 in 8bit colour. (half that if you are in in BG Mode 3-5)
this gives you enough space to store plenty of text characters :)
you can re-use these tiles in multiple times in the sprites you display - however, each of the 128 hardware sprites in OAM can only be in one place at one time, so unless you use some fancy interrupt techniques, you can't have more than 128 sprite based objects on-screen at a time. Even if all your text is the letter 'a' , you can't display more than 128 of them at one time!
now you're probably thinking - 128 characters is plenty? If you're doing very basic dialog, it might be just about enough, but what about oll the other graphics, you might have a lot of stuff going on on-screen and then suddenly want to do some dialog - you will be forced to switch off some of your other graphics....
i think there is a lot more mileage in using a bg layer for your text - much more flexible :)
cheers
Col
#9878 - aeberbach - Thu Aug 21, 2003 12:14 am
GNU Freetype gives you access to truetype fonts in any size, style or rotation. Vera TTF (Bitstream) font is freely distributable - you can find both with google. I wrote a C program using the freetype library to create an include file with the glyphs for each character in 16-pixel height, variable width, 256-grayscale anti-aliased. Once you have the include file it's as simple as blitting the pixels onto the screen, one glyph after the other. Calculating the width of text and handling line wrapping involves adding the widths of the glyphs. I'm planning on working this into a text class that can save the image in the intended display region, pop up a menu, handle choices and then restore the image region when it is dismissed but it is early days yet. This is going to be useful for getting some debug output when I don't want to load up GDB.
For a finished application where the display text is static, maybe create bitmaps of the words you need and blit them into the right places?
#9915 - johnny_north - Thu Aug 21, 2003 7:35 pm
I've used both systems in projects and each have their merrits. The only thing that was slightly annoying about using 8x8 letters in tiles on a background was that I needed to do some bg scrolling when I wanted to center a string of text on the screen that had an odd nomber of characters. I decided to use the hblank intr. to achieve this when there was mulitiple strings of text being displayed on the same bg.
On a new project I just set up 40 Oam enties using 8x8 letter tiles and just reuse these sprite cells as output changes. (I think Golden Sun uses a similar approach for dialog, they might use 8x16)I'm using the rot/scale regs when I need the font to be slightly larger or smaller, but at this point (for text anyway) I'm not sure I'm happy with the look of scaled text. I'll probably replace it latter with custom sized font in a 16x16 cell. In the meantime, I borrowed an 8x8 font from the one of the frogger games. I was suprised by how readable an U&L case font in 8x8 could be.
Anyway, the code is fairly trivial for doing this - nothing dynamic - just grab the refs to a group of tiles and copy in the charcters you need at any given time.
#9922 - tepples - Thu Aug 21, 2003 11:17 pm
col wrote: |
Even if all your text is the letter 'a' , you can't display more than 128 of them at one time! |
False. If you use hblank DMA to overwrite OAM after each line of text, you can display almost as many sprites as you want, possibly up to Neo-Geo or CPS2 sprite density.
johnny_north wrote: |
I needed to do some bg scrolling when I wanted to center a string of text on the screen that had an odd nomber of characters. |
DOS apps accepted the character grid and just placed odd-length lines of text a bit left of center. Still, using a raster effect to scroll each line of text does allow for hardware-accelerated entry/exit effects.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#9926 - sgeos - Fri Aug 22, 2003 12:12 am
johnny_north wrote: |
The only thing that was slightly annoying about using 8x8 letters in tiles on a background was that I needed to do some bg scrolling when I wanted to center a string of text on the screen that had an odd nomber of characters. |
Using sprites, it's trivial have an odd number of characters. Just squeeze an extra character in (or a few). Some of the bounding boxes will overlap by a column of pixels, but it looks fine.
-Brendan
#9929 - johnny_north - Fri Aug 22, 2003 1:20 am
[quote = "sgeos"]Using sprites, it's trivial have an odd number of characters. Just squeeze an extra character in (or a few). Some of the bounding boxes will overlap by a column of pixels, but it looks fine.[/quote]
Aye, I would recommend doing text this way if at all possible. The hblank trick mentioned above would help cover most uses of text. Plus if you have some movement of characters (ie floating scores, text movement or shaking in a HUD) this technique is very useful.
Sorry, tried to do bbcode. Don't think i got it.?
#11702 - ravenq - Thu Oct 16, 2003 5:36 am
Don't know if anyone here is interested in this anymore...
I've just recently posted a variable width font demo to GBAdev which should hopefully appear in a few days. It uses Vera for a font at the moment, and uses BG0 as a layer to display text on.
It still needs some optimization at the moment though. It currently takes up all of char block 0 and the first two screen blocks of char block 1. However, you can place text anywhere on the screen without using the scrolling registers, so text all over the place is possible! *lol*
Download it if you like (when it comes online), I've included the source code with it so you can see how it works.
Regards,
Tim Crockford
_________________
The Game is Nothing.
The Playing of it Everything
#11721 - poslundc - Thu Oct 16, 2003 7:52 pm
ravenq has got me thinking more about this text-background dealy... I had pretty much committed myself to going with sprites and using hblank for my text system, but I have so much extra background VRAM that I'm not doing anything with, it'd be nice to put it to good use and free up the sprite VRAM, not to mention the sprite pixels as well.
I think the trick to making it efficient might be drawing the text into an intermediate buffer, and then blitting that buffer out to each of the tiles. That buffer could be made quite small if you impose some restrictions on it (do you really need a font with more than four colours?).
A 600-tile tileset would consume 18.75K of bg VRAM... or a bit more than a quarter.
Ever since I realized that a 1024x1024 rot map took 16K of VRAM (and not 32K like my initial calculation misled me to believe), and then I downgraded to using a 512x512 (so now I'm down to 4K) I've had a whole extra 28K to play around with. Gotta use it for something... :)
I will have to explore this some more and get back to all of you on it...
Dan.
#11722 - Gopher - Thu Oct 16, 2003 9:02 pm
Just thought I'd throw out a comment about my current project. I'm working on a text system specifically for debugging purposes. I'm setting up a console module in C that can come up to display information and return the system settings when it's done. For it to be useful it needs to have as tiny a memory footprint as possible - every byte it uses is a byte the app I'm debugging can't use. On the other hand, speed is not a big concern. As a result it's rather different from most of the systems described here, but still related I think.
I store my font at 1 bit per pixel. Initially I was using an 8x8 font. Now I have switched to a 16x8 font and am rendering it as sub-pixels. Each char spans 5 and 1/3 screen pixels (16 sub-pixels); I haven't decided yet if I want to pad out the space between characters to fill 6, or to allow adjacent chars to overlap into the same screen pixel. On my laptop screen the results look decent either way but the overlap does make it somewhat less readable. It hasn't been tested on ctual hardware yet, but I'll probably go with the padding as overlap only gains 5 more characters per row.
I am rendering the characters directly to the screen in mode4, and keeping a buffer of the screen contents in a 40x20 char array. I wanted to avoid using sprites or tiles altogether, so the apps I use the debugger in can use all the sprite and tile memory without the debugger having to save a copy of any data it overwrites. As a result the renderer is very slow, but also very small and unintrusive.
When I get the console module finished, I'll try to clean it up and submit it as a sample program for anyone who might be interested.
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein
#11723 - Lord Graga - Thu Oct 16, 2003 9:06 pm
as far as I know, then all the "customsize-letters" from the official games consist of "clusters" of sprites, who is loaded to suit the needs of the current sentence. Try to see how Golden Sun did it (You have to own it). It has 2 letters in one sprite at the time.
#11732 - ravenq - Fri Oct 17, 2003 4:32 am
poslundc wrote: |
A 600-tile tileset would consume 18.75K of bg VRAM... or a bit more than a quarter. |
Actually, the engine I've written uses 22k (not all at once, but it, allows for that much), but that still leaves 42k vram for any other map data you have on the screen, plus it won't mess with your sprite data.
_________________
The Game is Nothing.
The Playing of it Everything
#11798 - poslundc - Sun Oct 19, 2003 5:41 am
Well, I've started writing my text engine. I'm pretty excited about it, actually, although I don't know if it will work in practice. So far I've written the font encoder, which I like to think is half the battle, although we shall soon see about that.
If you haven't read my previous posts, my goal is to find a practical and efficient way to do a non-monospace font using a 16-colour text background.
My strategy is to exploit the fact that a font will have a characteristic line height, and draw the text into a transposed buffer. In other words, I will be mapping the columns of text to the rows of the buffer.
Then to blit the tiles out to the map, it's simply a matter of operating on one tile at a time. A tile can be represented by eight sequential registers in ASM. Load a column that belongs in that tile into another register (this is simply a matter of loading the word from memory, since the columns are mapped to rows in the buffer), and place each nibble from the loaded word into that column's spot in each of the tile's registers. Then stmia them all back out to VRAM.
My hope that it will be fast enough in ARM assembler. Hopefully I will be finished in the next day or two; if it works well I'll release it into the more-or-less-public domain.
Dan.
#11850 - poslundc - Tue Oct 21, 2003 6:00 pm
Well, the results are in...
My font engine using the transposed buffer works, which is amazing enough in and of itself.
Problem is that blitting from the offscreen buffer to VRAM simply takes too long. Even for a moderately-sized window you can easily take up your entire VBlank just blitting to the tiles. (The blitter is already highly optimized ARM code running in IWRAM, so there's not much to improve upon there.)
This is still okay if you just want to display the text and be done with it, but part of what I wanted to accomplish was give the ability to do things like keep the window stationary (so the rest of your status-layer background would remain unaffected), but scroll around the buffer in real time, so that the text moved while the rest of the background didn't.
I haven't given up on the idea... specifically I'm planning on writing a slimmed-down version that ditches the offscreen buffer, and instead forces the line height (including leading) to be a multiple of 8 (which should be okay with most fonts). I'd then just blit directly to the tiles... I'd lose the ability to do things like scroll around the buffer, but it doesn't look like that was happening anyway.
Dan.
#11866 - poslundc - Wed Oct 22, 2003 2:15 pm
OK, for anyone keeping score, here's the new plan:
- I'm ditching the transposed rendering idea. It's simply too much legwork (minimum of three data-processing operations per pixel, no matter how you slice it).
- The new idea is to use to a simple row-major offscreen buffer, then blit the data from that buffer straight out to the tiles in VRAM, without any additional processing. If the tiles are set up correctly (ie. in columns instead of rows), this will also permit vertical scrolling. The reason for using a buffer at all is so that glyphs can be drawn without worrying about which tile you are drawing into, having to render part in one tile, part in another tile, etc.
- Rendering a glyph to the buffer is dead-simple, but only 50% of the time. In the easy case, all that's needed is to copy rows from the font into rows of the buffer, at whatever byte coincides with the x-position of the glyph.
- Keen observers will already see the problem with the other 50% of the time... you can only address specific bytes, but pixels occur every four bits. In the event that you are writing to an odd-numbered pixel, if you attempt to store directly to the correct byte you will lose the pixel that comes before the one you are drawing to.
- My solution is to have a second copy of the font, with all of the pixels shifted right by one space, and empty in the first column. When attempting to write to an odd-numbered x position, load in the byte that you will be writing it to, and OR those first four bits with the rest of your first row before writing back out to the buffer.
It's an imperfect solution, mostly because it requires <height of font> extra byte-load commands to EWRAM for each glyph that begins on an odd-numbered pixel.
This is my second attempt now at designing a font system that uses 16-colour text backgrounds... if anyone has any additional ideas or suggestions, I'd be glad to hear them.
Thanks,
Dan.
#11901 - ravenq - Thu Oct 23, 2003 2:26 pm
Dan,
Haven't had too much of an opportunity to look into ARM assembler too much yet, so I'm not 100% sure how you'd go about implementing a system in assembler to do this.
In my font engine in C++ (source code is on the news page still, download it if it'll help some. It does variable width fonts on a text background, and uses 16 colors. The example uses 2 though.), I have basically used BG0 and split it into a map like this:
Code: |
0 20 .. 580
1 21 .. 581
.. .. .. ...
18 38 .. 598
19 39 .. 599
|
Hopefully that's clear. That map is static. The numbers basically map to different tiles. To display text, I basically blit the glyphs straight into the character base block I've associated BG0 with. Basically, I worked out a formula to determine which area of the of the tiles to start blitting at to get the text to appear in a certain place. Assuming you keep track of the widths of each glyph, you can keep blitting characters, one after the other, regardless of their width.
As for scrolling of the text, you could manage it by manipulating the HOFS and VOFS registers to move it around, and then simply erasing text as it disappears offscreen. Since the map is longer than the width of the screen, you can keep text offscreen easily enough. (Keep in mind the map will wrap, so make sure you erase text as you don't need it!)
Don't know if this helps you out much or not, just thought I'd put my two cents in (again) though.
Regards,
Tim Crockford
_________________
The Game is Nothing.
The Playing of it Everything
#11904 - poslundc - Thu Oct 23, 2003 3:14 pm
That is fairly similar to what I have done now, although I haven't bothered with the map. I just calculate ScreenBB + (20 * tileX + tileY) * 32.
The thing I don't like about using a system like ours is that you can't store the data out to VRAM, or the buffer, or whatever, without first loading whatever is currently in there so you don't overwrite the nearest pixels. It's those memory transfers that are the most costly, see, and wouldn't be necessary if I could just start writing my 32-bit word out at any precise location in memory that I desired.
Unfortunately, it seems I was more wrong than I realized... I thought that I could use str to store a word at any address, not just a 4-byte aligned address. I could've sworn I'd done it before, even though the ARM docs say you shouldn't. But when I tried doing it in an EWRAM buffer, it pooped out on me and started automatically aligning to 4 bytes. :(
So I've given up on the buffer idea. Now I'm just blitting the tiles out to VRAM. In the case that the glyph is word-aligned it knows to just store the data out, but in every other case it needs to load, shift, OR, and store one chunk of it and then shift and store the other chunk. I suppose I could make it also recognize if it is on a two-byte boundary as well, and if stmia doesn't work on a two-byte offset I can always just do a bunch of halfword-stores.
I also decided that it was outside the scope of my purpose to support the "general" case and decided to have it only handle fonts between 9 and 16 pixels tall. :) Anything less than 9 and you wouldn't need it; anything greater than 16 excludes the majority of screen fonts. Actually, it's only the glyph-rendering function that currently has this limit imposed on it, so you could replace that function if you wanted to support taller fonts. (Space between lines is independent of the font's height.)
The engine is pretty much done, I suppose... if people would like to obtain the result I can clean it up for public release and send it to gbadev, or however that works. The renderer is nothing special but probably one of the nicest things about it is the font encoder, which runs in PHP and lets you preview your settings. Maybe gbadev would even be willing to host it here, since my web account doesn't include PHP...
Dan.
#11907 - DekuTree64 - Thu Oct 23, 2003 5:19 pm
Have you ever thought about going at it from the other direction? Like, when you're doing texture mapping, you don't look up a pixel in the map and put it on the screen wherever it needs to be, you go through the screen finding out which texture pixels need to be there. So just go along your text window copying pixels in from the characters as you go. That way you can always write 8 pixels at a time, and if your minimum glyph width is 2 pixels, that means at most 4 characters loaded at a time, so you have enough regs for that. Then you just 'blit' your character pixels to a register, and store it. Hey, if you use a 2-bit font (that should give you like white, gray, black and transparent, which should be plenty) then you could have 16 source pixels loaded into a register to blit to your dest reg, so just limit chars to 16 wide and you won't have to worry about loading new pixels to blit from in the middle of a row. Then use some clever ANDing and shifting and you'll have it. I think. I might have to try that myself later (though in C, of course)
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#11912 - poslundc - Thu Oct 23, 2003 7:31 pm
That's more or less the strategy I was originally going for. I can think of two ways of doing it:
1. Render the font as tiles. Draw one tile in VRAM, then move on to the next, etc.
2. Render the font as scanlines. Draw the first row for the first tile, then draw the first row in the next horizontally-adjacent tile, etc. until you are done the screen, then advance to the second row of the first tile, etc.
In addition there is the hybrid-column method I tried earlier, but that wouldn't work so well going directly to VRAM, I don't think.
In any case, both share the same problem, which is lots of non-sequential access to the font stored in ROM.
The system I'm currently using (which draws the glyph to the tiles in VRAM) uses only sequential accesses when loading the glyph from the ROM. Each 8x8 chunk of font it draws is loaded in with one ldmia, and the next chunk is always located right after the current one. The drawing routine then still has a bunch of loads and stores to do, but those are to VRAM, which is relatively fast, and has the same timing for both sequential and non-sequential accesses.
If I were to try another method, I would probably move the font to EWRAM, but EWRAM is so much slower than sequential ROM access I don't know if it would be worthwhile.
Do you think there is a case for doing it that way? Or some other way? My solution works, but I am far from satisfied with it.
Thanks,
Dan.
#11913 - poslundc - Thu Oct 23, 2003 7:46 pm
I should probably add that I tried the whole compressed pixel method you were describing, and it turned out to be dirt slow. Each pixel required at least three data-processing operations to get it into its proper position, which I guess tends to add up over the course of an entire screen more than a load/store per 8 pixels does.
The three operations were usually shift, AND, and OR. I don't think the shift could be combined with the AND because there weren't enough registers to store the masking constant. Maybe I can revisit that, though... although I'm not sure two operations instead of three would make all that much difference.
Dan.