JOGL textrenderer and lighting, textures and lighting?

UPDATE : SOLVED!

Hi

I hope Im asking this question in the right place.
Right ok, so I’m a completely beginner when it comes to OpenGL
or any kind of graphics. At this point all I have been doing is drawing
lines and triangles in ortho2d mode. Ive been doing it without any
use of textures ( except for what JOGL Textrenderer uses internally ).

What I enjoy most is playing flight sims, so I thought id make some work
and add some new capabilities. What I want to do is draw some 3d flight instruments
to integrate with a flight sim, more specifically, I want to draw these instruments on external
monitors. So I created a very simple class implementing GLEventListener to render 3d.

Now I’m at the point where I can render geometry no problem.
I can also generate the basic lighting and material properties for my geometry.
Textures I have not tried. ( the pictures you see below do not load any textures
except what TextRenderer does internally )
I can draw text “on” my geometry in 3D using the JOGL TextRenderer,

BUT…I have not had any luck whatsoever in having my light source ( I currently use just one fixed light source )
light up the text from the JOGL TextRenderer ( … textures?..) properly.

Below is a picture of the Geometry and text. Everything in that picture is geometry with normals
created by my classes ( no glu/glut, honestly i dont know what those are tbh ) except the letters
and numbers. Notice everything is shaded except the text.

http://yoda.reservoirselite.com/adi10.png

Now if I add gl.glEnable(GL.GL_LIGHTING); after textRenderer.begin3DRendering();
I get other funny issues unless I remove the geometry :
(Without the geometry it renders fine! )

http://yoda.reservoirselite.com/geojetry.png

I’m wondering if you have any suggestions on how to light up this text properly, cause right now it
has me confused :stuck_out_tongue:

The full code of the listener below

Is it possible to use the TextRenderer class together with lighting ?

Thanks!
//
Johan


package display.leavu3d;

import display.*;
import general.Vector;
import transforms.*;
import javax.media.opengl.*;
import com.sun.opengl.util.j2d.TextRenderer;
import java.awt.Font;
import java.awt.geom.Rectangle2D;
import javax.media.opengl.GL;

/**
 *
 * @author jkjolhed
 */
public class Leavu3DRenderer extends display.LeavuRenderer {

    private final static double defaultCameraOffset = 10;
    private final static double defaultXYrange = 1;
    private final double defaultFOVdegrees = 2 * (180.0 / Math.PI) * Math.atan(defaultXYrange / defaultCameraOffset);
    private boolean needToUpdateFOV = true;
    private boolean fillDisplay = false;
    private final TextRenderer textRenderer = new TextRenderer(new Font("SansSerif", Font.PLAIN, 72));
    private final Vector<Text> textsRenderLast = new Vector<Text>();
    private final float textScaleFactor = 0.0017f;

    static class Text {

        private final Text3D text;
        private final double[] modelviewMatrix;

        Text(Text3D text, double[] modelviewMatrix) {
            this.text = text;
            this.modelviewMatrix = modelviewMatrix;
        }
    }

    /**
     * Creates a new LEAVU renderer
     *
     * @param canvas
     * @param graphicsBuffer
     */
    public Leavu3DRenderer(final GLCanvas canvas, final GraphicsBuffer graphicsBuffer) {
        super(canvas, graphicsBuffer);
    }

    public final void setFillDisplay(boolean onOff) {
        fillDisplay = onOff;
        needToUpdateFOV = true;
    }

    public final boolean getFillDisplay() {
        return fillDisplay;
    }

    /**
     * Sets up OpenGL once during creation
     *
     * @param gLDrawable
     */
    @Override
    public void init(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();
        float mat_shininess[] = {550.0f};
        float light_position[] = {0.0f, 1.0f, 3.0f, 0.0f};
        gl.glShadeModel(GL.GL_SMOOTH);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position, 0);
        gl.glEnable(GL.GL_LIGHTING);
        gl.glEnable(GL.GL_LIGHT0);
        gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glEnable(GL.GL_CULL_FACE);
    }

    /**
     * Main drawing loop
     *
     * @param gLDrawable
     */
    @Override
    public void display(GLAutoDrawable drawable) {

        GL gl = drawable.getGL();

        ensureFOV(gl);

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
        for (GraphicsInstruction instr : graphicsBuffer.getInstructions()) {
            draw(gl, (GraphicsInstruction3D) instr);
        }
        gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL.GL_NORMAL_ARRAY);

        // Render texts all at once ( much better performance )
        textRenderer.begin3DRendering();
        //gl.glEnable(GL.GL_LIGHTING);
        gl.glPushMatrix();
        for (Text text : textsRenderLast) {
            renderText(gl, text.text, text.modelviewMatrix);
        }
        gl.glPopMatrix();
        textRenderer.end3DRendering();
        textsRenderLast.removeAllElements();

    }

    private final void ensureFOV(GL gl) {

        if (needToUpdateFOV) {

            int[] oldModeArray = new int[1];
            gl.glGetIntegerv(GL.GL_MATRIX_MODE, oldModeArray, 0);
            int oldMode = oldModeArray[0];

            gl.glMatrixMode(GL.GL_PROJECTION);
            gl.glLoadIdentity();
            gl.glViewport(0, 0, res[0], res[1]);

            double R = Math.min((double) res[0], (double) res[1]) / Math.max((double) res[0], (double) res[1]);
            double aspect = fillDisplay ? 1.0 : (float) res[0] / (float) res[1];

            if (!fillDisplay && res[0] > 0 && res[0] < res[1]) {
                double FOV = 2 * (180.0 / Math.PI) * Math.atan(defaultXYrange / (R * defaultCameraOffset));
                glu.gluPerspective(FOV, aspect, 1, 100);
            } else {
                glu.gluPerspective(defaultFOVdegrees, aspect, 1, 100);
            }

            needToUpdateFOV = false;

            gl.glMatrixMode(oldMode);

        }
    }

    /**
     * This function is called when the window is reshaped.
     *
     * @param gl
     */
    @Override
    public void setMatricesOnReshape(GL gl) {

        needToUpdateFOV = true;

        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
        glu.gluLookAt(0, 0, defaultCameraOffset,
                0, 0, 0,
                0, 1, 0);

    }

    private final void renderText(GL gl, Text3D text, double[] modelviewMatrix) {

        gl.glLoadMatrixd(modelviewMatrix, 0);

   //     textRenderer.setColor(1.0f, 1.0f, 1.0f, 1.0f);
        gl.glColor4d(text.color.R[0], text.color.R[1], text.color.R[2], 1.0f);

        Rectangle2D bounds = textRenderer.getBounds(text.text);

        float alignOffset = 0f, heightOffset = -(0.9f) * textScaleFactor * (float) bounds.getHeight() / 2;

        if (text.align == Text3D.AlignCenter) {
            alignOffset = -textScaleFactor * (float) bounds.getWidth() / 2;
        } else if (text.align == Text3D.AlignRight) {
            alignOffset = -textScaleFactor * (float) bounds.getWidth();
        }

        textRenderer.draw3D(text.text, alignOffset, heightOffset, 0, textScaleFactor);
        textRenderer.flush();

    }

    // This function is only called when the display settings are changed. Again, not often used.
    @Override
    public void displayChanged(GLAutoDrawable drawable, boolean a, boolean b) {
    }

    private void draw(GL gl, GraphicsInstruction3D instr) {

        Vector<Transform> transforms = instr.getTransforms();

        gl.glPushMatrix();

        // Calculate transformation matrix
        for (int i = transforms.size() - 1; i >= 0; i--) {

            Transform cur = transforms.get(i);

            switch (cur.type) {

                case Transform.ROTATION:
                    gl.glRotated(cur.val[0], cur.val[1], cur.val[2], cur.val[3]);
                    break;

                case Transform.TRANSLATION:
                    gl.glTranslated(cur.val[0], cur.val[1], cur.val[2]);
                    break;

                case Transform.SCALE:
                    gl.glScaled(cur.val[0], cur.val[1], cur.val[2]);
                    break;

            }

        }

        DrawType[] drawTypes = instr.getDrawtypes();


        if (instr.numberOfCoords() > 0) {
            if (instr.hasShaderDetails()) {
                gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, instr.getSpecular(), 0);
                gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, instr.getDiffuse(), 0);
                gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, instr.getAmbient(), 0);
                gl.glVertexPointer(3, GL.GL_FLOAT, 0, instr.getVerticesBuffer());
                gl.glNormalPointer(GL.GL_FLOAT, 0, instr.getNormalsBuffer());
                gl.glDrawElements(drawTypes.length > 0 ? drawTypes[0].type : GL.GL_TRIANGLE_STRIP, instr.numElements(), GL.GL_UNSIGNED_INT, instr.getIndicesBuffer());

            } else {
                //This section is likely not entered

                Coordinate[] coordinates = instr.getCoordinates();
                int primType = GL.GL_TRIANGLE_STRIP;
                Color[] colors = instr.getColors();
                gl.glDisable(GL.GL_LIGHTING);
                gl.glBegin(primType);
                for (int i = 0; i < coordinates.length; i++) {
                    if (drawTypes[i].type != primType) {
                        gl.glEnd();
                        gl.glBegin(primType = drawTypes[i].type);
                    }
                    gl.glColor4d(colors[i].R[0], colors[i].R[1], colors[i].R[2], colors[i].R[3]);
                    gl.glVertex3d(coordinates[i].R[0], coordinates[i].R[1], coordinates[i].R[2]);
                }
                gl.glEnd();
                gl.glEnable(GL.GL_LIGHTING);
            }
        }

        if (instr.text != null) {
            double[] modelviewMatrix = new double[16];
            gl.glGetDoublev(gl.GL_MODELVIEW_MATRIX, modelviewMatrix, 0);
            textsRenderLast.add(new Text(instr.text, modelviewMatrix));
        }

        gl.glPopMatrix();

    }
}


I just had a little dig in the JOGL code and it there aren’t any calls to glNormal* that I can see. You should be able to set the normal before each call to textRenderer.draw3D().

Ultimately, your best approach would be to make a texture and map it onto your sphere.

Thank you for the response!

I cannot believe it was so simple. Thanks a lot for this help! :slight_smile:
2 days of work and that was the solution!

result:

http://yoda.reservoirselite.com/adi11.png

Yes I think so too. I will try to learn texturing soon.

Glad to be of help.

Another thing you could do is put everything into a display list which you re-use from frame to frame.

Ok, I just found a nice little guide on display lists.
http://www.lighthouse3d.com/opengl/displaylists/index.php?3

Will definitely try this when I get home, thanks.

Update, done, implemented :).

I should also warn that display lists are actually deprecated in the latest OpenGL… I thought in this case they’d be the quickest and easiest way to make your particular code a bit more efficient (probably didn’t even make that much difference really). Sorry to throw a bit of a red herring :persecutioncomplex:

Since you are just starting to learn, you should know that Vertex Buffer Objects (VBOs) are now basically the correct way to do things; when you make calls to TextRenderer it is out of your hands anyway, but when you are doing lower level GL you should use those. Many tutorials you find will not reflect this…