Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411613 Posts in 69390 Topics- by 58447 Members - Latest Member: sinsofsven

May 09, 2024, 07:23:21 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Making A Font [tutorial]
Pages: [1] 2
Print
Author Topic: Making A Font [tutorial]  (Read 3318 times)
Aquin
Level 10
*****


Aquin is over here.


View Profile WWW
« on: August 16, 2009, 09:17:33 PM »

Really, anybody can figure this out on their own given enough time.  However, this simple tutorial lays the groundwork for two future tutorials (advanced dialog manipulation and animations.)

Make your own font for OpenGL!

http://www.aquinhasa.com/?p=126
« Last Edit: November 11, 2009, 05:30:24 PM by Aquin » Logged

I'd write a devlog about my current game, but I'm too busy making it.
Mr. Yes
Level 5
*****



View Profile WWW
« Reply #1 on: August 17, 2009, 06:49:05 AM »

Nice. I was just thinking of implementing this kind of thing, so this tutorial will help if I get stuck or something (up until now I've just been using TTFs).
Logged

Gravious
Level 2
**


"Swedish meatballs"


View Profile WWW
« Reply #2 on: November 11, 2009, 03:58:45 PM »

Oh Noes, what happened to that link? i was just about to read through it!
Logged

One day I'll think about doing something to stop procrastinating.
Strom
Level 0
***



View Profile
« Reply #3 on: November 11, 2009, 05:00:32 PM »

Broken link. Sad
Logged

See my Assemblee 2009 2D and 3D work Here. My A Game By Its Cover compo entry Journal of Shikoku.
Aquin
Level 10
*****


Aquin is over here.


View Profile WWW
« Reply #4 on: November 11, 2009, 05:29:22 PM »

Aw sorry guys!

I moved my website to it's own location:  http://www.aquinhasa.com/

I suspect my ragdoll tutorial is broken too.  I go fix it now.
Logged

I'd write a devlog about my current game, but I'm too busy making it.
handCraftedRadio
The Ultimate Samurai
Level 10
*



View Profile WWW
« Reply #5 on: November 12, 2009, 10:29:32 AM »

A+ article. I made my own bitmap font system a while back but I mainly gave it up whenever I couldn't get the spacing right. I didn't really think about setting the spacing for every single character individually, seems so obvious now. You also have a great method in there for handling things like different colors within the same text string. Such an easy and simple way of doing it, why didn't I think of that?

Great work, very helpful. I'm definitely looking foward to your next articles.  Wizard Hand Thumbs Up Right
Logged

Aquin
Level 10
*****


Aquin is over here.


View Profile WWW
« Reply #6 on: November 12, 2009, 10:41:39 AM »

Heh, I actually got the color idea from my days of writing MUDs.  As for the letter spacing, that's simply the easiest way to do it.

I would love to have the length of each character be determined by a function instead of doing it by hand.  How is that possible?  A part 2 is coming.

Part 2 will have - variable length (determined by a procedure), writing the text slowly (like an RPG), and scrolling text inside the same textbox.  I got some other stuff planned too.  Sadly, this probably won't get written until December (currently doing nanowrimo.)
Logged

I'd write a devlog about my current game, but I'm too busy making it.
handCraftedRadio
The Ultimate Samurai
Level 10
*



View Profile WWW
« Reply #7 on: November 12, 2009, 02:17:29 PM »

I guess it would be possible to go from one side to the other and check each pixel to see where the letter actually ends. I might try something like this, just write a small program to do it once and then copy-paste the values.
Logged

powly
Level 4
****



View Profile WWW
« Reply #8 on: November 12, 2009, 02:26:01 PM »

I'll write a little pseudo of my method, Aquin. This is at least a simple way to do it, might not be the fastest but it doesn't matter that much as it's probably precalculated to an array anyways.

So, do this for every glyph/letter/tile, whatever you call them:

Code:
first_x = -1
last_x = 0
empty = 1
for(every x in glyph)
    for(every y in glyph)
        if(pixelinglyph(x,y))
            if(first_x = -1) first_x = x
            if(last_x < x) last_x = x
            empty = 0
        endif
    next
next
if(empty = 1)
    last_x = maxwidth
    first_x = 0
endif

(this can also be used to determine the heights, but that's not needed for anything I could think off)

Feel free to ask if you don't understand or want to show a much better system (no such thing as a too short loading time, is there Grin), this was just the first solution I came up with.

Btw, the tutorial is very nice, if I'd had this when I first started drawing text with OpenGL it wouldn't have caused nearly as much frustration :3

(Heavy editing done, I should learn to write my posts with a single try instead of constantly editing them for 15 minutes after the original version.)
« Last Edit: November 12, 2009, 02:40:11 PM by msqrt » Logged
Glaiel-Gamer
Guest
« Reply #9 on: November 12, 2009, 02:43:28 PM »

I'll write a little pseudo of my method, Aquin. This is at least a simple way to do it, might not be the fastest but it doesn't matter that much as it's probably precalculated to an array anyways.

i wrote a flash program that outputs c++ code for me Tongue

flash code: (bitmap font placed on the stage and named "clip")
Code:
var a:BitmapData = new BitmapData(32, 32, true, 0x00000000);

var str:String = "static const float widths[] = {";

for(var i:int = 0; i<16; i++){
for(var j:int = 0; j<16; j++){
var m:Matrix = new Matrix();
m.translate(-j*32, -i*32);
a.draw(clip, m);
var n:Number = a.getColorBoundsRect(0xFFFFFFFF, 0xFFFFFFFF).width/32;
if(n == 0) n = .35;
str += (n) + ((j==15&&i==15)?"};":", ");
}
}
trace(str);

output:
Code:
static const float widths[] = {0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.35, 0.35, 0.4375, 0.4375, 0.35, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.4375, 0.35, 0.09375, 0.21875, 0.5, 0.375, 0.46875, 0.46875, 0.0625, 0.15625, 0.15625, 0.3125, 0.4375, 0.09375, 0.21875, 0.09375, 0.34375, 0.40625, 0.34375, 0.40625, 0.40625, 0.4375, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.09375, 0.09375, 0.4375, 0.4375, 0.4375, 0.34375, 0.46875, 0.40625, 0.40625, 0.375, 0.40625, 0.375, 0.375, 0.40625, 0.40625, 0.34375, 0.34375, 0.4375, 0.375, 0.4375, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.46875, 0.375, 0.40625, 0.4375, 0.4375, 0.40625, 0.40625, 0.1875, 0.34375, 0.1875, 0.375, 0.4375, 0.125, 0.40625, 0.40625, 0.34375, 0.40625, 0.40625, 0.375, 0.40625, 0.34375, 0.40625, 0.40625, 0.375, 0.40625, 0.46875, 0.34375, 0.40625, 0.40625, 0.40625, 0.3125, 0.34375, 0.40625, 0.34375, 0.375, 0.4375, 0.375, 0.375, 0.34375, 0.34375, 0.0625, 0.34375, 0.4375, 0.4375, 0.375, 0.4375, 0.09375, 0.5, 0.28125, 0.40625, 0.375, 0.375, 0.125, 0.53125, 0.40625, 0.15625, 0.46875, 0.4375, 0.40625, 0.4375, 0.4375, 0.09375, 0.09375, 0.28125, 0.28125, 0.25, 0.5, 0.5, 0.28125, 0.4375, 0.34375, 0.15625, 0.5, 0.4375, 0.34375, 0.40625, 0.35, 0.09375, 0.34375, 0.40625, 0.28125, 0.40625, 0.0625, 0.34375, 0.25, 0.5, 0.3125, 0.34375, 0.4375, 0.21875, 0.5, 0.25, 0.25, 0.4375, 0.21875, 0.1875, 0.125, 0.40625, 0.375, 0.09375, 0.1875, 0.25, 0.3125, 0.34375, 0.4375, 0.40625, 0.375, 0.34375, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.4375, 0.375, 0.375, 0.375, 0.375, 0.375, 0.34375, 0.34375, 0.34375, 0.34375, 0.46875, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.3125, 0.4375, 0.375, 0.375, 0.375, 0.375, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.46875, 0.34375, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.34375, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.40625, 0.34375, 0.34375, 0.34375, 0.34375, 0.375, 0.40625, 0.375};

Logged
Sar
Level 3
***


Likes Violins


View Profile WWW
« Reply #10 on: November 17, 2009, 05:09:07 AM »

I'll write a little pseudo of my method, Aquin. This is at least a simple way to do it, might not be the fastest but it doesn't matter that much as it's probably precalculated to an array anyways.

I went for the extra step myself of saving all the glyph information - height, width, position on the texture, etc. - into an XML file. So I leave the two in the same location on the HDD, then construct my 'font' class passing in the path to the XML file, which then contains the relative path to the texture file, and I don't have to do any pixel-checking or anything at runtime, just parse the data into in-memory structures. I have a standalone app which constructs the texture and the XML file from a TTF at a given point size, leaving an arbitrary amount of spacing around the edges inside and/or outside of the glyph mappings for decoration I can add later in Photoshop or whatever, and being XML it's not impossible to create the mapping file by hand if necessary.

I went only for that simple an approach becuase it was easily enough for me, but it wouldn't be hard to extend it to do things like ligatures (mapping more than one character in the input text to a single composite character from the texture) or accents and stuff (by patching together two bits of texture from a single input character), and also has the advantage that you can map more than one possible input character to the same part of the texture, so if I want to do an all-caps font I just re-map the lower-case letters to the same texture space as the upper-case letters in the config file.

(If I were feeling particularly nuts, I guess I could encode the texture data into the XML file as well, but I'm not a masochist. ;-))
Logged

Currently working on: Chronicle of Mars
Previous Projects: [Käfer|Tristan and Iseult(TIGS)]
Dacke
Level 10
*****



View Profile
« Reply #11 on: November 17, 2009, 06:04:34 AM »

I stopped using C++/OpenGL a year ago, but I remember struggling with ingame text. Writing a tutorial for it is a really great thing to do  Smiley
Logged

programming • free software
animal liberation • veganism
anarcho-communism • intersectionality • feminism
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #12 on: November 17, 2009, 05:59:20 PM »

Is there any reason why you aren't using display lists and glListBase/glCallLists?  Those two functions are basically designed for printing text.
Logged



What would John Carmack do?
Aquin
Level 10
*****


Aquin is over here.


View Profile WWW
« Reply #13 on: November 17, 2009, 06:13:25 PM »

I left it out because it just brings in something that's needlessly complicated.  I'm more interested in the theory and structure (the idea of how to do it) rather than optimizing a specific implementation.

Although I have to admit, I don't see the huge jump in performance when I use display lists anymore.  I used to, but I suspect OpenGL has been changed regarding that over the years.  I dunno.

Logged

I'd write a devlog about my current game, but I'm too busy making it.
powly
Level 4
****



View Profile WWW
« Reply #14 on: November 18, 2009, 11:52:51 AM »

It's more because of computers becoming so powerful it just doesn't matter if your code is not that optimal. (well, if you don't plan to print a lot of text)
Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #15 on: November 18, 2009, 03:14:47 PM »

I left it out because it just brings in something that's needlessly complicated.  I'm more interested in the theory and structure (the idea of how to do it) rather than optimizing a specific implementation.

Although I have to admit, I don't see the huge jump in performance when I use display lists anymore.  I used to, but I suspect OpenGL has been changed regarding that over the years.  I dunno.



It's not question of performance (although that may be a side effect), it's one of convenience.

Instead of looping through an entire string and printing each character individually, you can just call glCallLists with the whole string and do it in one shot.

Code:
glCallLists(strlen(the_text), GL_UNSIGNED_BYE, the_text);

And you're done!
Logged



What would John Carmack do?
increpare
Guest
« Reply #16 on: November 18, 2009, 03:47:09 PM »

I left it out because it just brings in something that's needlessly complicated.  I'm more interested in the theory and structure (the idea of how to do it) rather than optimizing a specific implementation.
Except that's what you're doing : P  Say you want to use accented characters (much less Asian languages)?  I remember when I was translating something into spanish and wanted to use some accented characters I ended up arbitrarily chopping out some of the numbers to make space : P

I guess bitmap fonts are rarely non-ascii/english friendly anyway, but I think the above is worth saying in any event...good work on the tutorial anyway  Beer!
Logged
handCraftedRadio
The Ultimate Samurai
Level 10
*



View Profile WWW
« Reply #17 on: November 18, 2009, 05:35:38 PM »

I just implemented my text system using similar methods as the tutorial. I wrote a separate program to locate the width of each character by starting from the right side and moving left until it found a non-transparent pixel in a line. The data for each character is saved into a file and loaded by the game engine when the font is created. I also was able to avoid specificly telling each tile what position in the bitmap it was by mapping the characters to their ascii values in the image (i also subtracted 32 from the ascii values since there was a bunch that i wasnt going to need).
Logged

Sar
Level 3
***


Likes Violins


View Profile WWW
« Reply #18 on: November 19, 2009, 03:47:06 AM »

I wrote a separate program to locate the width of each character by starting from the right side and moving left until it found a non-transparent pixel in a line.

Do you have any case to cope with places where two separate marks are actually part of the same glyph? The most common example I can think of is the double quote mark ("), which quite feasibly could have a line of fully-transparent pixels between the two marks in a bitmap font, but there's a whole load of other characters with this potential-problem if you go past the first 128 ASCII chars... not to mention that it would make it more difficult to create stencil-esque bitmap fonts.


Or are you talking about the case where you have your glyphs equally-spaced in your source image and you just need to trim unused space from either side of the character in your texture? (Which in turn means you're not making very efficient use of your texture space.)


(Of course, I'm just talking about the hypothetical perfect case, if what you have is sufficient for your uses there's no point changing it, of course.)
Logged

Currently working on: Chronicle of Mars
Previous Projects: [Käfer|Tristan and Iseult(TIGS)]
handCraftedRadio
The Ultimate Samurai
Level 10
*



View Profile WWW
« Reply #19 on: November 19, 2009, 09:27:49 AM »

Yeah, the characters are on equally spaced tiles, and it starts from the right side to find the first instance of a non-transparent pixel so it doesn't have to deal with the breaks in pixels for certain characters. It does waste a little bit of extra space in the image, but  each tile is only 16x16 so they aren't wasting too many pixels anyway. Also, in my case i'm just using it for dialog in my game so I pretty much am only using the letters numbers and necessary puncuation marks.
Logged

Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic