class Renderer3D implements Renderer {

        private TextRenderer renderer;

        @Override
        public void initRenderer(Font font) {
            renderer = new TextRenderer(font, antialised, fractionalMetrics, null, shouldUseMipmapGeneration());
        }

        @Override
        public void reinitRenderer() {
            renderer =
                new TextRenderer(renderer.getFont(), antialised, fractionalMetrics, null, shouldUseMipmapGeneration());
        }

        private boolean shouldUseMipmapGeneration() {
            boolean doMipmap = mipmap;
            if (drawable.getGraphicalConfiguration() != null && drawable.getGraphicalConfiguration().isIntelVendor()) {
                //Disable mipmap generation in intel GPUs. See https://github.com/gephi/gephi/issues/1494 (Some label characters fade away when zooming out)
                doMipmap = false;
            }

            return doMipmap;
        }

        @Override
        public void disposeRenderer() {
            renderer.flush();
            renderer.dispose();
        }

        @Override
        public Font getFont() {
            return renderer.getFont();
        }

        @Override
        public void setFont(Font font) {
            initRenderer(font);
        }

        @Override
        public void beginRendering() {
            renderer.begin3DRendering();
            float cameraLocation = drawable.getCameraLocation()[2];
            if (cachedCameraLocationZ != cameraLocation && model.sizeMode == sizeModes[0]) {
                //Force refresh if camera location changed in fixed mode
                nodeRefresh = true;
                edgeRefresh = true;
            }
            cachedCameraLocationZ = cameraLocation;
        }

        @Override
        public void endRendering() {
            renderer.end3DRendering();
            nodeRefresh = false;
            edgeRefresh = false;
        }

        @Override
        public void drawTextNode(NodeModel objectModel) {
            Node node = objectModel.getNode();
            TextProperties textData = (TextProperties) node.getTextProperties();
            if (textData != null) {
                String txt = textData.getText();
                float width, height, posX, posY;

                if (txt == null || txt.isEmpty()) {
                    return;
                }

                float sizeFactor = drawable.getGlobalScale() * textData.getSize() *
                    model.sizeMode.getSizeFactor3d(model.nodeSizeFactor, objectModel);
                if (nodeRefresh || (objectModel.getTextWidth() == 0f && objectModel.getTextHeight() == 0f)) {
                    Rectangle2D r = renderer.getBounds(txt);

                    width = (float) (sizeFactor * r.getWidth());
                    height = (float) (sizeFactor * r.getHeight());
                    posX = node.x() + (float) width / -2f;
                    posY = node.y() + (float) height / -2f;

                    textData.setDimensions(width, height);
                } else {
                    width = textData.getWidth();
                    height = textData.getHeight();
                    posX = node.x() + (float) width / -2f;
                    posY = node.y() + (float) height / -2f;
                }
                model.colorMode.textNodeColor(this, objectModel);

                renderer.draw3D(txt, posX, posY, (float) node.z(), sizeFactor);
            }
        }

        @Override
        public void drawTextEdge(EdgeModel objectModel) {<FILL_FUNCTION_BODY>}

        @Override
        public void setColor(float r, float g, float b, float a) {
            renderer.setColor(r, g, b, a);
        }

        @Override
        public TextRenderer getJOGLRenderer() {
            return renderer;
        }
    }

            Edge edge = objectModel.getEdge();
            TextProperties textData = (TextProperties) edge.getTextProperties();
            if (textData != null) {
                String txt = textData.getText();
                float width, height, posX, posY;

                if (txt == null || txt.isEmpty()) {
                    return;
                }

                float sizeFactor = drawable.getGlobalScale() * textData.getSize() * model.edgeSizeFactor;
                if (edgeRefresh || (objectModel.getTextWidth() == 0f && objectModel.getTextHeight() == 0f)) {
                    Rectangle2D r = renderer.getBounds(txt);

                    width = (float) (sizeFactor * r.getWidth());
                    height = (float) (sizeFactor * r.getHeight());
                    textData.setDimensions(width, height);
                } else {
                    width = textData.getWidth();
                    height = textData.getHeight();
                }

                model.colorMode.textEdgeColor(this, objectModel);

                float x, y;
                if (edge.isDirected()) {
                    x = (objectModel.getSourceModel().getNode().x() + 2 * objectModel.getTargetModel().getNode().x()) /
                        3f;
                    y = (objectModel.getSourceModel().getNode().y() + 2 * objectModel.getTargetModel().getNode().y()) /
                        3f;
                } else {
                    x = (objectModel.getSourceModel().getNode().x() + objectModel.getTargetModel().getNode().x()) / 2f;
                    y = (objectModel.getSourceModel().getNode().y() + objectModel.getTargetModel().getNode().y()) / 2f;
                }

                posX = x + (float) width / -2;
                posY = y + (float) height / -2;
                float posZ = 0;

                renderer.draw3D(txt, posX, posY, posZ, sizeFactor);
            }
        
<no_super_class>