Hello Guest

Author Topic: Loading Fonts during runtime through code  (Read 8881 times)

Keripo

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 3
    • View Profile
Loading Fonts during runtime through code
« on: December 02, 2012, 03:25:22 pm »
Hi, I'm wondering if its possible to somehow load fonts during runtime through code (C#). Ideally the end setup would require no creation of any prefabs and minimal font file preparation (e.g. drop-in .ttf file or even .fnt/.tga pair that is loaded through file path). I would assume a two-part process: 1) load a font file into a data format tk2dTextMesh can handle, then 2) instantiate a tk2dTextMesh object using the loaded font data. I tried playing around with this but ended up getting confused with figuring out tk2dSpriteCollectionData.

I am currently able to do this for sprites through loading external PNG/JPGs as Texture2D, then using tk2dBaseSprite.CreateFromTexture to create a GameObject with a tk2dSprite attached purely through code and during runtime without needing any prefabs or tk2dSpriteCollectionData. There's a bit of issues with cloning sprites with an attached BoxCollider but I was able to fix it through modifying the tk2dSprite code directly (yay for source code availability!).

I'm aware that any solution may result in lost of optimizations that the tk2d toolkit provides (e.g. batching, indexing, etc.), but I believe my app is lightweight enough that sacrificing speed for customization is worth it.

~Keripo

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Loading Fonts during runtime through code
« Reply #1 on: December 02, 2012, 08:23:19 pm »
You can do it with a bit of work, but if you were going to attempt it, a few notes which will hopefully help.

1. Don't bother with ttf - thats a no go unless you wanna do a lot of work.
2. Use .fnt, .png - but MAKE SURE you use the text file format. Including the xml stuff into the runtime = massive library code bloat.
3. The class which constructs this data into a tk2dFontData object is tk2dFontBuilder. This is currently an editor class, I suggest making a copy and deleting all the Xml related bits.
4. At runtime, create a tk2dFontData object on a new gameobject, and feed this into your version of tk2dEditor.Font.Builder.BuildFont.
5. Create a material and assign it to tk2dFontData.material. Assign the texture to this material.
6. The font will now be ready, you can create a tk2dTextMesh using this:
Code: [Select]
GameObject go = new GameObject("TextMesh");
        tk2dTextMesh textMesh = go.AddComponent<tk2dTextMesh>();
textMesh.font = newlyCreatedFontData;
textMesh.text = "New TextMesh";
textMesh.Commit();

There won't be any performance issues doing this.

Keripo

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Loading Fonts during runtime through code
« Reply #2 on: December 17, 2012, 09:29:03 am »
You can do it with a bit of work, but if you were going to attempt it, a few notes which will hopefully help.

1. Don't bother with ttf - thats a no go unless you wanna do a lot of work.
2. Use .fnt, .png - but MAKE SURE you use the text file format. Including the xml stuff into the runtime = massive library code bloat.
3. The class which constructs this data into a tk2dFontData object is tk2dFontBuilder. This is currently an editor class, I suggest making a copy and deleting all the Xml related bits.
4. At runtime, create a tk2dFontData object on a new gameobject, and feed this into your version of tk2dEditor.Font.Builder.BuildFont.
5. Create a material and assign it to tk2dFontData.material. Assign the texture to this material.
6. The font will now be ready, you can create a tk2dTextMesh using this:
Code: [Select]
GameObject go = new GameObject("TextMesh");
        tk2dTextMesh textMesh = go.AddComponent<tk2dTextMesh>();
textMesh.font = newlyCreatedFontData;
textMesh.text = "New TextMesh";
textMesh.Commit();

There won't be any performance issues doing this.
After a bit of experimenting around, I was able to load fonts without any problems. The BMFont program generates nice compatible .fnt files but the .tga files have to be converted to .png. To do this with Photoshop
  • Open the .tga file
  • Duplicate the layer and delete the original "Background" layer
  • Menu item Select -> Load Selection...
  • Select the .tga as the "Document" and check the "Invert" checkbox
  • Delete your selection by pressing the delete button on your keyboard
  • Save the resulting image as a .png

Here's a sample code snippet without the actual file loading part:
Code: [Select]
// You can use Unity's WWW class to load textures and text files
Texture2D texture = null;
string textInfo = null;

// Create an object to hold the font data
GameObject fontDataObj = new GameObject();
fontDataObj.name = "TextData";
tk2dFontData fontData = fontDataObj.AddComponent<tk2dFontData>();

// Set the font info from a string read from .fnt file
// FontBuilder is a stripped down version of tk2dEditor.Font.Builder
FontInfo fontInfo = FontBuilder.ParseBMFont(textInfo);
FontBuilder.BuildFont(fontInfo, fontData, 1, 0, false, false, null, 0);

// Set the font texture from a Texture2D loaded .png file
Material fontMaterial = new Material(Shader.Find("tk2d/BlendVertexColor"));
fontMaterial.mainTexture = texture;
fontData.material = fontMaterial;

// Create an object that will have a tk2dTextMesh component
GameObject textObj = new GameObject();
tk2dTextMesh textMesh = textObj.AddComponent<tk2dTextMesh>();
textMesh.font = fontData;
textMesh.text = "Hello World";
textMesh.Commit();

Here's the code snippets I use for loading text and texture files:
Code: [Select]
public static string LoadText(string url) {
string text;
WWW www = new WWW(url);
while (!www.isDone);
text = www.text;
www.Dispose();
return text;
}

public static Texture2D LoadTexture(string url, bool repeat) {
Texture2D texture;
WWW www = new WWW(url);
while (!www.isDone); // FIXME: Blocks, thread this?
texture = www.texture; // Compare with www.LoadImageIntoTexture(texture)?
texture.wrapMode = (repeat) ? TextureWrapMode.Repeat : TextureWrapMode.Clamp;
texture.Compress(true);
www.Dispose();
return texture;
}

The final result is that I've been able to set up my code such that all resources (graphics, font, audio, text) are loaded from local storage instead. Apart from the Camera prefab, my Unity project contains no pre-generated prefabs, materials, or other assets other than tk2d; its all pure code.
Here's a screenshot of a test project running:


Here's a screenshot of the same test project the second before I press the Run button. Note the hierarchy tree:


Just figured I'd update this for others who might have the same question and come across this thread ^_^

~Keripo

unikronsoftware

  • Administrator
  • Hero Member
  • *****
  • Posts: 9709
    • View Profile
Re: Loading Fonts during runtime through code
« Reply #3 on: December 17, 2012, 11:45:57 am »
Just to add to that post, please do remember to remove all the xml stuff including the using directive right at the top of the file (best to duplicate the file, rename the class, etc). The xml stuff will pull in all the .net xml libraries and a whole lot more stuff into your build, massively bloating it.