@elias: so kerneling = advance (advance is the awt terminology - see font metrics). you don't have to generate textures for each character. instead it's enough if you generate one texture and use the proper texture coordinates. that's how Text works in conjunction with LWJGLFont. LWJGLFont also compiles display lists for making things faster. so when generating the font texture, one could compile the correct display lists taking the advanced into account. then you'd have 'kerneling'
@llama: i'm not sure if you were talking to me or elias. but i think the text interfaces could be improved but i didn't give it too much thought. but at least adding BOLD, ITALIC, PLAIN constants to JmeText would be nice. using the awt constants in an opengl context is somehow strange.
@elias again: i suppose llama is reffering to JmeText and not to Text. Text is in there since a long time.
Yes, the whole interface is based on the old jME bitmap font system which has been around very long, but it was never an interface… so right now it's still very oriented towards bitmap fonts systems (which indeed monospace, etc.)
A little late, but hell. Yes the JmeText and TextFactory interfaces was added by me, not long ago. They were added as a means to interface with my implementation classes Text3D and Font3D. I hoped they would serve as guidelines for making text in JME. Hence they are not complete, and I hope that you will take your time to improve on them.
About kerneling, display-lists and such. I think that kerneling is very important, since we are not all using monospaced fonts. Also, I think that rendering characters as display-lists in an OpenGL-context makes perfect sense. Looking at the way LWJGLFont is implemented made me think that if we could just separate the display-list parts out, we would have a perfect base for rendering any kind of text. I am thinking, why not have a primitive pair like TriMesh and TriBatch called something in the lines of: RenderSequence and SequenceBatch. Working together like this:
The SequenceBatch would contain a spatial (hopefully some geometry as well, but that is not a requirement) and a kernel (most likely a Vector3f indicating how to modify the Model-matrix after rendering of the spatial to make the next one render at a correct position).
The RenderSequence holds a list of SequenceBatches. The RenderSequence works as one spatial, and does not directly rely (with regards to bounds and such) on its childen, the SequenceBatches. When it is rendered (yes this assumes there be a new method in Renderer called draw(RenderSequence sequence)) the renderer saves the model-matrix and then renders each SequenceBatch and applies its "kerneling"-offset. Once the render is over, the old model-matrix is restored.
This is how the LWJGLFont works, all I am thinking is, if we could make a more general implementation, then both your fonts, the old Text-class and my Text3D could use exaclty this, all we needed to do was to make a sequence of spacials with kerneling for each of them. Maybe we could support display-lists natively to optimize it further, but this require some preloading, which all the implementations do anyway…
I hope you can see the idea and have some input for how this could be done. We are closing up on a deadline, so for the moment we stick to our (not so perfect) implementation of the Text3D/Font3D, I am just sorry I did not have more time to develop these base-classes for usage amoungst all the different font/text-implementations.
PS.
Have you looked at the implementation in BUI ? It much like yours, but it has support for effect… like shadow, outline (and I added glow) very nice. But very heavy since it does not cache the glyphs, it just renders the bulk of text.
i did not really understand the RednerSequence/RenderBatch idea.
i like the JmeText/TextFactory concept. i think a thing that hast to be done is attaching a font object to the JmeText. that font could be 2d or 3d. that depends only on the impementation. as for 2d text, i think the current Text object is almost everything we need, except it would be nice to modify it to take that kerneling into account when creating display lists. and that Text objects should also be created by a TextFactory.
the usage would be (2d or 3d - it wouldn't make any difference):
- create a TextFactory and configure it using the appropriate (jme)Font
- using the factory create as many JmeText (2d or 3d) objects as you want
- when rendering the JmeText the renderer would have just to let the Font do the rendering, just as LWJGLFont does now.
but actually that's the way text in jme currently works (if i didn't miss anything) and this post is just rantingdon't get me wrong, it's just like i see things.
and i's been a while since i las took a look at BUI. but i will when i get home. last thing i remember about it was that it was a bit slow. but BUI is much more than a bit of text. and effects could be added very simply to JmeText too i suppose. for 3d text there are particles, shadows and bloom effects. for 2d you could also use all that and you could do a lot ofthings the generated texture.
btw: i didn't actually take a close look at Font3D. can it generate fonts with zero 'depth' ?
Sorry about the major update today, but I really wanted to clean up the code and make it more for "standard" use with jME. Now you pass it a font (rather than the font location, so you can handle your own font loading however you like). It's up to you to set it up with an italic, bold, or plain font now (this way, it don't create textures for all the possibilities, but lets you decide what you want). Also, createText() now has an option as to whether or not to center the text or to draw it from the left. And lastly, I removed a bunch of my junk that was specific to my own implementation. Feel free to give any feedback!
I'll keep looking into porting it over to those interfaces. For now though, I went ahead and updated the code in my first post here with some cosmetic enhancements (it's getting better the more I learn jME).
The main class is posted at the beginning of this thread. Here's a test class for you:
import java.awt.Font;
import java.awt.FontFormatException;
import java.io.IOException;
import java.io.InputStream;
import org.lwjgl.Sys;
import tools.FontTT;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
/**
* <code>TestTruetypeFont</code>
* @author Jeremy Adams
*
*/
public class TestTruetypeFont extends SimpleGame {
public static void main(String[] args) {
TestTruetypeFont app = new TestTruetypeFont();
app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
protected void simpleInitGame() {
display.setTitle("A Truetype Font Test");
Font font = new Font("Serif", Font.PLAIN, 32);
long tstarttime = System.currentTimeMillis();
FontTT text = new FontTT(font.deriveFont(Font.PLAIN),64,0);
long tendtime = System.currentTimeMillis() - tstarttime;
System.out.println("Finished loading fonts in " + tendtime);
Node playertext = text.createText("Look at me!", 2, new ColorRGBA(1,1,0.1f,1f),true);
playertext.setLocalTranslation(new Vector3f(0,0,0));
playertext.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
playertext.setModelBound(new BoundingBox());
playertext.updateModelBound();
playertext.updateWorldBound();
rootNode.attachChild(playertext);
}
}
Updated: I simplified it
Ok… questions for the jME team… how do you setup the jME engine to not use black as the alpha color? I'm trying to implement some effects, but it's very hard unless I can tell the engine to use actual "alpha" for "alpha" for these generated textures. (it's also very hard because I've been getting distracted with the Font3D stuff… very fun).
display.getRenderer().setBackgroundColor(ColorRGBA.black) I believe is the default where "display" is the DisplaySystem.
darkfrog
@elias: you have to set the AlphaState:
AlphaState as1 = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();;
as1.setBlendEnabled( true );
as1.setSrcFunction( AlphaState.SB_SRC_ALPHA );
as1.setDstFunction( AlphaState.DB_ONE );
as1.setEnabled( true );
and generate the textures so that the background is painted in "transparent" color.
Yeah, I've got the alphastate going ok… it's just that the alphastate takes the color black as the color to switch to transparent within the texture. And although that's a fairly popular standard, it removes the ability to do darker fonts and outlines in the texture (because it makes it transparent). Is there a way to change that setting just for these textures (so I don't mess up other textures)?
AlphaState.SB_SRC_ALPHA tells opengl to use the alpha as alpha but you have to make sure you use a textureformat with alpha in it (and also that the alphavalues are correct)…do you use an RGBA format for your bufferedimage for example?
I have, but it doesn’t seem to be working. :’(
I get transparency, but anything black in the texture still goes transparent as well. Also, I’m using BufferedImage.TYPE_INT_ARGB - don’t look at the code in this thread, as I know I’m using grayscale for that.
Hmm, maybe try alpha testing instead of blending… if your black still goes away, you might be using a low or 0 alpha when painting black.
debug debug…for example:
*try using a texture loaded from file with both black and transparency and see if it works as expected
*go through the image data and print out the black and alpha values
*save the image to a file and open it in photoshop
Well, I just tried it with a .png that had black and alpha in it… same result. Black comes out as transparent.
Update: Could someone else please try this experiment? I'm wondering if I'm just missing something because of my lack of experience with jMe.
Another update… I tried setting the DstFunction to DB_ONE_MINUS_SRC_ALPHA. It mostly worked. Or, at least, it worked in one example, but not the other. I'm checking to see what the differences are.
And, now that I can make black work… I've included support for outlined fonts as well.
so, what was the bug?
I was using it in the TestThirdPersonController class from the tests. For some reason, it doesn't work there. But if I build my own class, or use some of the other tests, it works in those just fine. So, I don't think there's a bug, just something about that test that I'm missing, because once I changed the DstFunction to DB_ONE_MINUS_SRC_ALPHA in the alphastate, everything else seemed to work fine.