3D Font

I would be happy to do the integration into jME if the other developers don't see any problem with getting this added?



I've been wanting 3D font support for quite a long time.



Have you finished the preliminary development or are you still adding things?



darkfrog

Seems fine for jmex

Ok - imagination is carrying me away.



How would one go about making a shattering/exploding effect from a letter.



Presumably you would have to get all the triangles and then put each into a spatial transformer.

Darkfrog: Well, you are very welcome to do the integration, but first I think we need to clarify a few things. Here is a list of things (along with how its done at the moment) that I think the devs should decide.



The process is now: static call to a loadFont(…) method, Static method to createText(…) to get a peace of text with the given font. This is not very intuitive, and it has several "problems". First of all, doing it this way, does not make it possible to reuse each glyph (as a shared GeomBatch, or as a display-list) since its at the "createText(…)" call the geometry is being made. Also, the Font3D makes a static library of cached fonts… this is good for the purpose I am using it (where I create loads of text during the game) but it would not be as good for someone who wants only a little text and then that is it.



Scaling: Currently the font is being made in size 1 and then scaling is applied to get other sizes. This is done to make sure we could actually reuse the geometry, no matter what size the text would be (display-lists again…). But this means you get a TExt3D that already has a local scaling… hence if you do setLocalScale(2.0f) you text might get smaller… again not very intuitive.



Effects: Right now I just make simple 3D geometry from the font, but it would make a lot of sense to do more interesting things than just what I have done. Therefor I think some kind of Text3DFactory-design to it would make it possible to easily write now factories, that made even more kewl geometry (but with a somewhat common interface for the developer).



Spacing: Right now I am just knocking through all the characters from 0-255 and from them I read the geometry (shape) and some bounds. This is actully not good enough (when using really interesting fonts) because the bounds/spacing might be different between different letters (that is the spacing after an "E" might depend on the following glyph). That is where the GlyphVector commes in. To make this "correctly" the geometry could be reused, but we would have to call Font.createGlyphVector(…) for each text-chuck to get the correct spacing.



So, if some of the core developers could give their five cents about how the design should be to resemble the rest of jME as best as possible. And then hopefully we can get this thing up and running in jmex soon.

kidneybean said:

Ok - imagination is carrying me away.

How would one go about making a shattering/exploding effect from a letter.

Presumably you would have to get all the triangles and then put each into a spatial transformer.


You could also see where you would fare with a hack of the particle-system. Maybe you could have the particle-system mess up all the vertices of the letter. Except then you would have to "duplicate" the verts, so that no two triangles shared any of them. This could be done as a more general thing, a method where you supply some Mesh and then you get a particle-system in return. This particle system will intially look the same, but once the particles start moving, the object "explodes". Could be cool.

You can always use the letters as an emitter for the particle system. That on it's own would be a cool effect already :slight_smile:

Well, yes that is cool, but it only emits from the vertices, hence a good improvement would be to make an other utility class that from a trimesh created an even sampling of the surface into a new vertex-buffer (used for emitting). That way, the emitting will be evenly spaced over the surface of the object. But… well, still easier to tell the graphics dude to put in more vertices :slight_smile:

You know, this is very cool, and the fact that it supports proper fonts is great. What I'd like to see is the ability to use this for both 3d and 2d text rendering. Replacing the current Text class.

Very good idea.  :-o



Perhaps not entirely replacing the bitmapped stuff as I can imagine it might be useful for certain situations (for example, someone wants a custom font, but would rather design rasters for it than create vectors and generate a ttf), but having the ability to use either one would be awesome.



darkfrog

maybe a combination of the current Text and this technique could do it. like rendering to texture and letting Text use that texture.

it could generate the display lists for it to so we could support variable width fonts.

mojomonk said:

You know, this is very cool, and the fact that it supports proper fonts is great. What I'd like to see is the ability to use this for both 3d and 2d text rendering. Replacing the current Text class.


Well, this could easily be done, if you only get the front (that is true to front, false to sides and back) and put the resulting text in ortho-space you are home. But I guess what you want is also some methods like:


Text3D mytext = Font3D.createText(......true, false, false);

// Make it 2D
mytext.make2D(); // this just makes it end up in the ortho render-bucket.

// Now manipulate the text "responsible" for the geometry
mytext.setText("Now with new text");
mytext.clearText();
mytext.appendText("Even more stuffn"); // Notice the newline.... multiline text... hmmm this calls for alignment.
mytext.setAlignment("center");
mytext.setFontSize(12);
mytext.setLetterSpacing(2.1f); // mutiplier on the implicit spacing due to the bounds of a glyph.



With methods like this, the text will almost be like a text-field, and one could use them for like we use the 2D text today (debugging, FPS, other OSD info displaying). I think I like it (though that was not the intention when first making it).

How about this. We make a very spefic interface that the Font3D implement, maybe called JmeFont, JmeTextFactory, or something. Then we specify an other interface JmeText that the Text3D implement. Then later on, we can use instances implementing the JmeFont/JmeTextFactory as factories for creating objects implementing the JmeText interface. The good thing about this is that we can reuse the existing 2D text implementation under the new interfaces and we can easily create new Text-factories with all kinds of caching, cool layouts, reuse, preloading, etc. etc.



There is one thing that bothers me about it, but I cannot seem to find a better solution. The combination of Font and TextFactory is not very nice. It would seem more resonable that a TextFactory used a Font to create Text elements. But due to the variarity of how the Text interface can be implemented (my Font3D is just one way of visualizing text in JME as I see it) and the strong connection between TextFactory, Text and Font I cannot see how it would be possible to create a TextFactory-class that could take any Font and create some Text from it, without knowing something about how the Font and Text were implemented. Please, if anyone can see how the factoring of Text can be separated out of the Font without loosing too much generality, let me know.



Here is my suggestion for these two interfaces:



public interface JmeFont
{
   /**
    * Method for creating new Text-objects.
    *
    * @param text the text that should be visualized.
    * @param size the size of the text generated.
    * @param flags  Can be Font.BOLD, Font.ITALIC, Font.PLAIN
    * @return the new text object.
    */
   JmeText createText(String text, int size, int flags);
}




public interface JmeText
{
   /**
    * @return the factory where this text was created, or null if it does not know.
    */
   JmeFont getFactory();
   /**
    * @return the string of text that this object is visualizing.
    */
   String getText();
   /**
    * Sets the string of text that this object is visualizing, the geometry of the object should change to reflect the change.
    * @param text
    */
   void setText(String text);
   /**
    * Append text to the string of text that this object is visualizing.
    * @param text
    */
   void appendText(String text);
   /**
    * @return the flags that were given when this text was created.
    */
   int getFlags();
   /**
    * @return the size of the text (normally size 12 refers to 12pt, in jme I guess it refers to jme-units).
    */
   int getSize();
   /**
    * change the size of the font, this will most likely be implemented with scaling, so watch out when using this and setLocalScale(...).
    * @param size
    */
   void setSize(int size);
   
   // For compatability with Spatial/Geometry
   void setLocalRotation(Matrix3f rotation);
   void setLocalRotation(Quaternion quaternion);
   void setLocalScale(float localScale);
   void setLocalScale(Vector3f trans);
   void setLocalTranslation(Vector3f trans);
}

Just a short note. Looking at the example of a text and text-factory implemented by me, it is easy to add static helper methods to allow quick access:



Here is how one would create some text (not using any shortcuts)


Font basefont = new Font("Arial", 12, Font.PLAIN);
Font3D myfont = new Font3D(basefont, true, false, true);
Text3D mytext = myfont.createText("Here is my text !", 12, Font.ITALIC);



Because of the tight link between Font3D and Text3D it makes sense to add simple static factoryGetters, and one could do:


Text3D mytext  = Text3D.getFactory("Arial", 12, Font.ITALIC).createText("Here is my text");



Or even have a contructor doing that, and thereby hidding the factory:


Text3D mytext  = new Text3D("Arial", 12, Font.ITALIC, "Here is my text");



This is only to demonstrate that even if we go with the factory paradigm, its still possible in the implementation to add short-cuts for easy access. But for some Text/Factory pairs, doing it might not be a good idea.

Ok, I have made some improvements on the whole Interface abstraction. Also I have made the Font3D into a display-list using thing. It is quite a hack, so if someone could tell me a better way of doing this, please feel free.



http://emanuelgreisen.dk/stuff/Font3D.tgz



There is also a test-program for the test-part of jME. If the developers think it would make sense to include in the trunk of jME, please include it. If you think it still needs some work, then let me know what needs fixing.



Here is a screenshot from the test program, the loading of the font is still very slow (because all 256 glyphs are loaded from Arial):



152fps?  :-o



Either you've got a freakin' awesome machine or you did a freakin' awesome job on the fonts. :wink:



I've been extremely busy the past couple weeks, but if the other developers are satisfied that it's ready and they don't think they'll have time for a couple weeks I would be happy to try to get to it when I can.



darkfrog

Looks great, Oak. I'll take a look sometime next week (if someone else doesn't evaluate it before then). Does this abstract include the 2D support layer?

i like when stuff gets accepted into jmex it's like a little success story

First off, the machine I am running this on is a laptop with a "GeForce7800GTX GO" hence the 180 FPS. Also every glyph is a display-list, so there is little to no traffic on the bus.



The TGZ did not contain a 2D Bitmap font, but it does now.



http://emanuelgreisen.dk/stuff/Font3D.tgz



The implementation is only a wrapping of the old Text-impl, it should most likely be merged together a little more, especially the creating of Text objects should be taken care of by a factory, not a static method in the Text class.



Here is a list of things that are not currently working, or stuff that is not designed good enough:

  • JmeText is an interface, it would be better if it was an abstract class (subclass of Geometry). But this makes it impossible to inherit from both JmeText and TriMesh, which is an obvious thing to do when implementing 3D fonts.
  • The Text2D/Font2D is based on the Text class, which uses the LWJGLFont font, and hence has native implementation of the display-lists and requires special drawing methods in Renderer.
  • The Text3D uses a hack to render it self fast enough. A batch for each glyph is stored in the Font3D factory, and the text then refers to it. It is a hack, because there should be no reason to use SharedBatch, but its just not possible to do it some other way. Also, when rendering with this SharedBatch method, the real batches must live in a Geometry, hence we need some hack-geom container… A more proper way would be to just render the batches (locked as display-lists) by reference on the glyph they correspond to.
  • The Text2D is based on fixed-width fonts. An implementation with variable width fonts would be great. Either with glyphs renderes to texture or with a font-format that jMe could load.
  • The Text3D cannot be saved/loaded due to the binding to its factory. At best it can be saved as a trimesh and then loaded as one again, thereby loosing all its JmeText properties/methods.



    Aside from all these things the Font3D/Text3D/Font2D/Text2D is pretty good.



    I have one idea that might make it easier to make fonts (both 3D and 2D). What these fonts/texts have in common is that they are best implemented as display-lists. This is because they have a limited amount of glyphs, and these glyphs do not change. Also we would like some progress during the rendering (each glyph should add something to the model-view matrix, to allow the next glyph to be positioned correctly). How about making a Batch that could contain such a glyph, and then create a new primitive (like TriangleBatch, Text, Point, Line, Curve, etc.) that was a list of these. Then the LWJGL renderer would have a method "draw(…)" for this primitive, doing almost the same as the "draw(Text)" does now. I propose GeomSequence or something similar. This should be almost the same as the LWJGLFont but with all the font-specific stuff taken out, so it could be used as a general thing. What does the core-developers think of this ? It would avoid having to do terrible hacks like the one I did with Text3D/Font3D to get the power of the display-lists.

Here is a patch for the 3DFont stuff, but it also contains some other stuff for jME so be warned:



http://emanuelgreisen.dk/stuff/Jme_2006.06.05.diff.gz