fr.ign.cogit.geoxygene.appli.render.DisplayableTextRenderer.java Source code

Java tutorial

Introduction

Here is the source code for fr.ign.cogit.geoxygene.appli.render.DisplayableTextRenderer.java

Source

/*******************************************************************************
 * This file is part of the GeOxygene project source files.
 * 
 * GeOxygene aims at providing an open framework which implements OGC/ISO
 * specifications for the development and deployment of geographic (GIS)
 * applications. It is a open source contribution of the COGIT laboratory at the
 * Institut Gographique National (the French National Mapping Agency).
 * 
 * See: http://oxygene-project.sourceforge.net
 * 
 * Copyright (C) 2005 Institut Gographique National
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library (see file LICENSE if present); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 *******************************************************************************/

package fr.ign.cogit.geoxygene.appli.render;

import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glDisable;
import static org.lwjgl.opengl.GL11.glEnable;

import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.util.Collection;

import org.apache.log4j.Logger;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL30;

import fr.ign.cogit.geoxygene.api.feature.IFeature;
import fr.ign.cogit.geoxygene.appli.GeoxygeneConstants;
import fr.ign.cogit.geoxygene.appli.Viewport;
import fr.ign.cogit.geoxygene.appli.gl.GLContext;
import fr.ign.cogit.geoxygene.appli.gl.ResourcesManager;
import fr.ign.cogit.geoxygene.appli.layer.LayerViewGLPanel;
import fr.ign.cogit.geoxygene.appli.render.groups.RenderingGroup;
import fr.ign.cogit.geoxygene.appli.render.methods.RenderingMethodDescriptor;
import fr.ign.cogit.geoxygene.appli.render.primitive.AbstractDisplayable;
import fr.ign.cogit.geoxygene.style.TextSymbolizer;
import fr.ign.cogit.geoxygene.util.gl.GLComplex;
import fr.ign.cogit.geoxygene.util.gl.GLException;
import fr.ign.cogit.geoxygene.util.gl.GLProgram;
import fr.ign.cogit.geoxygene.util.gl.GLTools;
import fr.ign.cogit.geoxygene.util.gl.RenderingException;

public class DisplayableTextRenderer extends DisplayableRenderer<AbstractDisplayable> {

    private BufferedImage textImage = null;
    private Graphics2D textImageGraphics = null;
    private ByteBuffer buffer = null;
    private int textTextureId = -1;
    private int previousWidth = -1;
    private int previousHeight = -1;
    private int width = 0;
    private int height = 0;
    private int[] pixels = null;
    private GLProgram program;

    public DisplayableTextRenderer(Viewport _viewport) {
        super(_viewport);
        RenderingMethodDescriptor method = (RenderingMethodDescriptor) ResourcesManager.Root()
                .getSubManager(GeoxygeneConstants.GEOX_Const_RenderingMethodsManagerName).getResourceByName("Text");
        program = method.getGLProgram();
    }

    @Override
    public boolean render(AbstractDisplayable displayable_to_draw, double global_opacity) {
        if (displayable_to_draw.getSymbolizer() instanceof TextSymbolizer) {
            GLTools.glCheckError("gl error before text normal rendering");
            Integer width = (Integer) GLContext.getActiveGlContext()
                    .getSharedUniform(GeoxygeneConstants.GL_VarName_ScreenWidth);
            Integer height = (Integer) GLContext.getActiveGlContext()
                    .getSharedUniform(GeoxygeneConstants.GL_VarName_ScreenHeight);
            if (this.textImage == null || width != previousWidth || height != previousHeight) {
                this.createTextImage(width, height);
            }
            // AWT toponyms rendering in the this.textImage
            this.awtRendering(displayable_to_draw.getFeature(),
                    (TextSymbolizer) displayable_to_draw.getSymbolizer(), global_opacity);
            return true;
        }
        return false;
    }

    @Override
    protected Collection<GLComplex> getComplexesForGroup(RenderingGroup g,
            AbstractDisplayable displayable_to_draw) {
        // TODO Auto-generated method stub
        return null;
    }

    private void createTextImage(Integer width, Integer height) {
        this.textImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
        this.textImageGraphics = this.textImage.createGraphics();
        this.textImageGraphics.setBackground(new Color(0, 0, 0, 1));
        this.buffer = BufferUtils.createByteBuffer(width * height * 4);
        this.pixels = new int[width * height];
        this.previousHeight = this.height;
        this.previousWidth = this.width;
        this.width = width;
        this.height = height;
    }

    private void clearTextImage() {
        this.textImageGraphics.clearRect(0, 0, width, height);

    }

    /**
     * Render toponyms into an AWT graphics
     */
    private void awtRendering(IFeature f, TextSymbolizer textSym, double opacity) {
        this.textImageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Object value = f.getAttribute(textSym.getLabel());
        String text = (value == null) ? null : value.toString();
        if (text != null) {
            RenderUtil.paint(textSym, text, f.getGeom(), viewport, this.textImageGraphics, opacity);
        }
    }

    @Override
    public void switchRenderer() throws RenderingException {
        try {
            if (this.textImageGraphics != null) {
                this.drawText();
                this.clearTextImage(); // clear the image for the next
                                       // rendering.
            }
        } catch (GLException e) {
            throw new RenderingException(e);
        }
    }

    private void drawText() throws GLException {
        if (this.program == null || this.textImage == null) {
            Logger.getRootLogger().debug("The GeoxGLTextRenderer " + this.hashCode() + "is not ready yet");
            return;
        }
        this.textImage.getRGB(0, 0, width, height, this.pixels, 0, width);
        this.buffer.rewind();
        for (int y = height - 1; y >= 0; y--) {
            for (int x = 0; x < width; x++) {
                int pixel = this.pixels[y * width + x];
                this.buffer.put((byte) (pixel >> 16 & 0xFF)); // Red component
                this.buffer.put((byte) (pixel >> 8 & 0xFF)); // Green component
                this.buffer.put((byte) (pixel >> 0 & 0xFF)); // Blue component
                this.buffer.put((byte) (pixel >> 24 & 0xFF)); // Alpha component
            }
        }
        this.buffer.rewind();
        glEnable(GL_TEXTURE_2D);
        GL13.glActiveTexture(GL13.GL_TEXTURE0 + 2);
        glBindTexture(GL_TEXTURE_2D, this.getTextTextureId());

        // Setup texture scaling filtering
        GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        GL11.glTexImage2D(GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE,
                this.buffer);

        Integer fbow = (Integer) GLContext.getActiveGlContext()
                .getSharedUniform(GeoxygeneConstants.GL_VarName_FboWidth);
        Integer fboh = (Integer) GLContext.getActiveGlContext()
                .getSharedUniform(GeoxygeneConstants.GL_VarName_FboHeight);
        GL11.glViewport(0, 0, fbow, fboh);
        glDisable(GL11.GL_POLYGON_SMOOTH);
        GLContext.getActiveGlContext().setCurrentProgram(program);
        program.setUniform1i("colorTexture2", 2);
        GLTools.glCheckError("texture binding");

        GL11.glDepthMask(false);
        glDisable(GL11.GL_DEPTH_TEST);

        GL30.glBindVertexArray(LayerViewGLPanel.getScreenQuad().getVaoId());
        GLTools.glCheckError("before drawing textured quad VAO binding");

        program.setUniform(GeoxygeneConstants.GL_VarName_ObjectOpacityVarName, 1f);
        program.setUniform(GeoxygeneConstants.GL_VarName_GlobalOpacityVarName, 1f);
        glEnable(GL_BLEND);
        GL11.glBlendFunc(GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
        GLTools.glCheckError("blending set for textured quad");

        LwjglLayerRenderer.drawComplex(LayerViewGLPanel.getScreenQuad());
        GLTools.glCheckError("Drawing textured quad");

        GL30.glBindVertexArray(0); // unbind VAO
        GLTools.glCheckError("exiting Text rendering");
        glBindTexture(GL_TEXTURE_2D, 0); // unbind texture

    }

    private int getTextTextureId() {
        if (this.textTextureId == -1) {
            this.textTextureId = GL11.glGenTextures();
            if (this.textTextureId < 0) {
                Logger.getRootLogger().error("Unable to use Text texture");
            }
        }
        return this.textTextureId;
    }

}