Reputation: 122540
I'm trying to display text in my OpenGL / JOGL app. Here is some of the code:
private void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
GLUgl2 glu = new GLUgl2();
float[] rgba = new float[4];
backgroundColor.getRGBComponents(rgba);
gl.glClearColor(rgba[0], rgba[1], rgba[2], 1);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
// Position the camera
glu.gluLookAt(cameraPos.x, cameraPos.y, cameraPos.z, cameraPos.x + cameraForward.x, cameraPos.y + cameraForward.y,
cameraPos.z + cameraForward.z, cameraUp.x, cameraUp.y, cameraUp.z);
gl.glPushMatrix();
GLUT glut = new GLUT();
gl.glTranslatef(0, 0, 0);
gl.glColor3f(1, 0, 0);
glut.glutBitmapString(GLUT.BITMAP_HELVETICA_18, "We're going to the moon!");
gl.glPopMatrix();
// ...
The text appears as soon as rendering begins, then runs off the right hand side of the screen. Why is this happening?
I'd like to display text in front of the user, not as a model in the world.
Upvotes: 2
Views: 3750
Reputation: 6103
There is very easy solution but it "links" your app against awt, which might be bad if you try to stay out of it in favour of newt.
Below example draws player osd using number of text renderers: one for play/pause glyph, one more for some information like time, etc., and yet another one for movie name.
import com.jogamp.opengl.util.awt.TextRenderer;
private static final Color DROP_SHADOW_COLOR = new Color(0, 0, 0, 0.5f);
class CustomRenderDelegate implements TextRenderer.RenderDelegate {
private int dropShadowDepth;
private Color color;
CustomRenderDelegate(int dropShadowDepth, Color color) {
this.dropShadowDepth = dropShadowDepth;
this.color = color;
}
public boolean intensityOnly() {
return false;
}
public Rectangle2D getBounds(CharSequence str, Font font, FontRenderContext frc) {
return getBounds(str.toString(), font, frc);
}
public Rectangle2D getBounds(String str, Font font, FontRenderContext frc) {
return getBounds(font.createGlyphVector(frc, str), frc);
}
public Rectangle2D getBounds(GlyphVector gv, FontRenderContext frc) {
Rectangle2D stringBounds = gv.getPixelBounds(frc, 0, 0);
return new Rectangle2D.Double(stringBounds.getX(), stringBounds.getY(), stringBounds.getWidth()
+ dropShadowDepth, stringBounds.getHeight() + dropShadowDepth);
}
public void drawGlyphVector(Graphics2D graphics, GlyphVector str, int x, int y) {
graphics.setColor(DROP_SHADOW_COLOR);
graphics.drawGlyphVector(str, x + dropShadowDepth, y + dropShadowDepth);
graphics.setColor(color);
graphics.drawGlyphVector(str, x, y);
}
public void draw(Graphics2D graphics, String str, int x, int y) {
graphics.setColor(DROP_SHADOW_COLOR);
graphics.drawString(str, x + dropShadowDepth, y + dropShadowDepth);
graphics.setColor(color);
graphics.drawString(str, x, y);
}
}
public void init(GLAutoDrawable drawable) {
...
pathRenderer = new TextRenderer(new Font("Helvetica", Font.ITALIC, 16), true, true, new CustomRenderDelegate(0,
Color.WHITE));
pathRenderer.setSmoothing(true);
playRenderer = new TextRenderer(new Font("Helvetica", Font.BOLD, 65), true, true, new CustomRenderDelegate(0,
Color.WHITE));
pauseRenderer = new TextRenderer(new Font("Helvetica", Font.BOLD, 50), true, true, new CustomRenderDelegate(0,
Color.WHITE));
osdRenderer = new TextRenderer(new Font("Helvetica", Font.PLAIN, 32), true, true, new CustomRenderDelegate(0,
Color.WHITE));
osdRenderer.setSmoothing(true);
}
private final void updateOsd() {
Time t = currentFrame != null ? currentFrame.getTime() : new Time(0, 0, 0, 0, 0);
String direction = video.direction == DirectionType.DIRECTION_LEFT ? "<" : ">";
String frameNumber = enterFrameNumber != null ? String.format("[%s]", enterFrameNumber)
: String.format("(%d)", t.fn);
osdText = String.format(" %s%s x %d @ %.2f fps < %d/%d (%s) @ %d fps", TimeUtil.hmsms(t.getPtsMillis()), frameNumber, (int) video.getPlaybackRate(), playbackFps, video.readyFrames(), maxFrames, direction, video.getFilterFps());
}
private void renderOsd(GLAutoDrawable drawable) {
updateOsd();
if (isOsdEnabled) {
maxModeWidth = (int) Math.max(maxModeWidth, playRenderer.getBounds("\u25B8").getWidth());
maxOsdHeight = (int) Math.max(maxOsdHeight, playRenderer.getBounds("\u25B8").getHeight());
if (isPaused) {
pauseRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
pauseRenderer.draw("\u2759", 10, drawable.getHeight() - maxOsdHeight - 2);
int barWidth = (int) pauseRenderer.getBounds("\u2759").getWidth();
pauseRenderer.draw("\u2759", 10 + barWidth - 3, drawable.getHeight() - maxOsdHeight - 2);
pauseRenderer.flush();
pauseRenderer.endRendering();
} else {
playRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
playRenderer.draw("\u25B8", 10, drawable.getHeight() - maxOsdHeight - 5);
playRenderer.flush();
playRenderer.endRendering();
}
int y = (int) ((maxOsdHeight + 10) - osdRenderer.getBounds(osdText).getHeight() / 2);
osdRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
osdRenderer.draw(osdText, maxModeWidth + 18, drawable.getHeight() - y - 2);
osdRenderer.flush();
osdRenderer.endRendering();
if (isFullScreen) {
pathRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
pathRenderer.draw(videoFile.getName(), 18, drawable.getHeight() - y - maxOsdHeight + 15);
pathRenderer.flush();
pathRenderer.endRendering();
}
}
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
renderFrame(drawable);
renderOsd(drawable);
gl.glFinish();
}
Upvotes: 1
Reputation: 8642
You need to set the current raster position before invoking glutBitmapString
. The raster position is the pixel where the string will start being drawn. You can set it using the glRasterPos...
family of functions. The reason your text seems to "run off" the right side of the screen is that calling glutBitmapString
implicitly moves the raster position to the end of the string (see here).
Upvotes: 3