Text in a 2D app.

I don’t know if any of you have ever seen the slick little ASCII graphics game called Angband. (A derivative of UMoria if anybody knows that one instead) It’s a fun little game and I figured it was a good candidate for conversion into Java. I’m having just one little problem.

I can’t print text with any kind of speed. I need to be able to print out a roughly 100x50 grid of characters with each character possibly being a different color than the one next to it. I have explored the following options.

1 - Graphics.drawString for each character. Very slow. About 3 fps.
2 - Graphics.drawString for each line, which would be an AttributedString. That works too, but setting attributes for each character is ALSO freakin’ slow. I may be able to optimize that, but if there’s not much to optimize, I might be screwed.
3 - Haven’t tried this yet, but using a bunch of offscreen “layers”. Draw the dungeon on a Buffered image, then just cut & paste appropriate parts each frame. I’m sure that will be at least decent speed, but that means if my users want to scale their window size up, I could be having to paste images in excess of 1280x1024. That’s not an appealing thought for a simple text game.

I figure there HAS to be an easy solution I’m just not coming up with. Again, there’s a lot of optimizations I could make. for example, on average, out of that whole 100x50 grid, only 2 or three characters will ever change. That’s easy enough to just change those, but I should be able to COMPLETELY redraw the screen at a rate faster than 3 FPS.

Am I approaching this wrong? Does anybody have any suggestions? I have a few niftly little tricks I could try if I were doing this in C++ and had pointers to play with. Is there anything even SLIGHTLY comparable here?

Suggestions?

-Nate

I would put all letters in one 1bit image (you can “render” 'em on startup)… the letter itself is transparent and the surrounding space is black (at least I would use it this way).

When drawing I would use so called dirty rectangles to minimize the drawing itself… then I would first replace the spot with a rectangular solid shape in the desired color… after that I would apply the letter image (after that the letter would be let’s say red… and the rest of the rectangle is black).

In the worst case it’s like a full clear (+overhead) + drawing alot of images… well that’s not a prob… you can draw tons of volatile images at hi framerates easily (even on old comps).

So… in short:
-dirty rectangles
-Canvas2D / Graphics2D
-AA off
-volatile images
-fullscreen if possible

Well… doing that in openGL (LWJGL or JOGL) would be even faster (yes you can do 2d in openGL) :wink:

A lot of things happen when you draw text with an actual font via Graphics.drawString(). Standard fonts have considerations for hinting, scaling, anti-aliasing, vector to pixmap, etc.

The font is stored on your computer in a vector format and is converted to pixmap as needed. Some types of fonts have both vector (the “print” font) and pixmap (the “screen” font), but the pixmaps are only in a few sizes, and any other size requires you to revert to the vector or scale the pixmap. I don’t know how much of this Java takes into consideration, but more than you’d like for sure. Basically, fonts are dead slow and have pretty much no place in real time games.

I agree with oNyx, that’s pretty much how I’d do it.

Hee Hee!

That works quite well . . . thank you much.

I’m just going to have to create my own fonts. Not a great loss, it’ll just take some time. It goes rather quickly now. Not quite as fast as I’d like, but with a bunch of optimizations, I don’t think that will be a problem. I can redraw the entire grid of 1600+ characters at a good enough FPS to be worth doing. Given that on average, only 10-50 of those change per refresh, there’s a TON of optimizations I can make. Even if I wanted to make my screen scroll, that’s not that big a deal. It might take a slightly different implementation, but still . . . I think we’re okay here.

So basically what I’ve done, is created a font . . . a transparent GIF where the letters are transparent and everything else is black. I’m cutting it apart, dumping each letter into a teeny-weeny BufferedImage, and writing each one of those to it’s appropriate place on the screen as display circumstances warrant. (via Graphics2D.drawImage(img,x,y,Color,null); ) I’m getting about 10-15 fps. Now, that works, and it’ll only get faster, so I won’t complain . . . but . . .

Is there a different method I should use to do this? It seems like I ought to be able to do it a lot faster. Upwards of 30 fps if I wanted. There’s no real REASON to do it that fast, but . . . y’know . . . it’s the principle of the thing.

Anyway . . . thanx for the help, both previous and future.

-Nate

1600 blits per frame is quite a bit.

I’d change it to blitting rows at a time, creating intermediate images of the rows and redoing them each time a row changes, like you tried with the text. I image that’d help a lot.

Is this under Windows? Are you sure you’re making the images correctly so they’re accelerated?

What about making it a console application? I wonder if System.out into an ansi terminal could be colored, it should be able to. I wonder if that’d actually be faster though…

if your images are accelerated, you should be able to handle 1600 blits per frame @30fps with ease.

(my athlon 1.33 with gf2gts can get 7000 blits per frame @30fps [thats running at 1152x864 fullscreen])

Don’t redraw the whole grid - only redraw the bits that change between frames/turns.

That’s how old scrollers on 3MHz machines managed… they used the graphics hardware for scrolling the size of a single tile with no blitting, then they had to redraw the whole screen to step by a tile size - but only by blitting what was actually different could they keep up.

I sat down this weekend and started actually figuring out what I needed to be able to draw on my screen at any given point in time, and how fast it needed to be able to run. This solution should work perfectly, and the good part is that it makes substituting in graphical tiles a breeze later. If I use swpalmer’s suggestion (which I had actually concluded on myown, but it’s good to have experienced ppl agreeing with me) I should be able to absolutely blast the graphics up onto the screen. :slight_smile: (WAY beyond even 30 fps . . . ridiculously fast.)

So . . . with that I passed my final technical hurdle. JavAngband is officially in development. :slight_smile: If I ever release it, I’ll be sure to let y’all know. ::slight_smile: In the meantime, thx for all the help.

You could also try creating GlyphVector’s in advance and drawing those (Graphics2D.drawGlyphVector). I think some of the Swing code is accelarated by this means.