Re: TextRenderer and memory issues

Posted by r.jaoui on
URL: https://forum.jogamp.org/TextRenderer-and-memory-issues-tp4041129p4041136.html

Hm well I may have a solution and I just need to make sure that it's not totally ridiculous and slow.

So I have already created 2D polygon renderer for both the odd-even winding rule and the non-zero winding rule for another project (using the stencil test, and benchmarking them show that they're pretty fast. They could of course be better but they're still good enough for now), as well as (CPU-based) adaptative tesselation of paths (calculating the curvature of the path to get a point density with the current screen "resolution" in mind), and I just saw that from an AWT Font objet it is possible to get single glyphs as Shape objects, containing lines, quadratic and cubic sections and so on... I made a quick Swing test (non OpenGL) to see if what I had in mind seems possible (note that I am not using the tesselation here, and only rendering the quadratic and cubic sections as lines) :



The left text is rendered using Swing, the left one is only rendering the corresponding Shape Object (as I said, not tessellated yet). The colors correspond to different types of segments (red for closing loop sections, yellow for cubic sections, green for lines and blue for quadratic sections). Would this be a possible way to render text in OpenGL (therefore only using basic rendering such as with triangles and so on) or would either the gathering of the Shape or it's rendering be way too slow (also considering that I don't need for a book to be rendered to the screen at each frame).

Note that if I were to use this, I would save into my Font objects the array of shapes at once so that when rendering text, only the actual path would have to be tesselated and drawn, but I won't need to gather the vertices themselves every time. I assume that even if this may be slower than the more "modern" approaches, it should still be better than storing an array of bitmap glyphs...

EDIT : I'm adding the section of code that manages rendering the shape,

        public void drawCharShape(Graphics g, char c, int x, int y) {
                g.setColor(new Color(0, 0, 0, 40));
                g.drawString(Character.toString(c), x, y);
                GlyphVector v = f.createGlyphVector(new FontRenderContext(null, false, false), Character.toString(c));
                Shape glyph = v.getGlyphOutline(0);
                PathIterator pi = glyph.getPathIterator(null);
                double[] cache = new double[4];
                double[] pos = new double[6];
                while(!pi.isDone()) {
                        int type = pi.currentSegment(pos);
                        //DRAW THE CURRENT SECTION
                        switch(type) {
                        case PathIterator.SEG_CLOSE:
                                g.setColor(new Color(255, 0, 0));
                                g.drawLine((int) cache[0]+x, (int) cache[1]+y, (int) pos[0]+x, (int) pos[1]+y);
                                break;
                        case PathIterator.SEG_CUBICTO:
                                g.setColor(new Color(255, 255, 0));
                                g.drawLine((int) cache[2]+x, (int) cache[3]+y, (int) pos[4]+x, (int) pos[5]+y);
                                g.drawLine((int) pos[0]+x, (int) pos[1]+y, (int) pos[4]+x, (int) pos[5]+y);
                                break;
                        case PathIterator.SEG_LINETO:
                                g.setColor(new Color(0, 255, 0));
                                g.drawLine((int) cache[2]+x, (int) cache[3]+y, (int) pos[0]+x, (int) pos[1]+y);
                                break;
                        case PathIterator.SEG_QUADTO:
                                g.setColor(new Color(0, 0, 255));
                                g.drawLine((int) cache[2]+x, (int) cache[3]+y, (int) pos[2]+x, (int) pos[3]+y);
                                break;
                        }
                        g.setColor(new Color(0, 0, 0));
                        //UPDATE CACHE POSITIONS
                        switch(type) {
                        case PathIterator.SEG_CUBICTO:
                                g.fillOval((int) pos[0]+x-2, (int) pos[1]+y-2, 5, 5);
                                g.fillOval((int) pos[2]+x-2, (int) pos[3]+y-2, 5, 5);
                                g.fillOval((int) pos[4]+x-2, (int) pos[5]+y-2, 5, 5);
                                cache[2] = pos[4];
                                cache[3] = pos[5];
                                break;
                        case PathIterator.SEG_LINETO:
                                g.fillOval((int) pos[0]+x-2, (int) pos[1]+y-2, 5, 5);
                                cache[2] = pos[0];
                                cache[3] = pos[1];
                                break;
                        case PathIterator.SEG_MOVETO:
                                g.fillOval((int) pos[0]+x-2, (int) pos[1]+y-2, 5, 5);
                                cache[0] = pos[0];
                                cache[1] = pos[1];
                                cache[2] = pos[0];
                                cache[3] = pos[1];
                                break;
                        case PathIterator.SEG_QUADTO:
                                g.fillOval((int) pos[0]+x-2, (int) pos[1]+y-2, 5, 5);
                                g.fillOval((int) pos[2]+x-2, (int) pos[3]+y-2, 5, 5);
                                cache[2] = pos[2];
                                cache[3] = pos[3];
                                break;
                        }
                        pi.next();
                }
        }


Thanks again for any feedback :)