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

Java tutorial

Introduction

Here is the source code for fr.ign.cogit.geoxygene.appli.render.DisplayableRenderer.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_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBlendFunc;
import static org.lwjgl.opengl.GL11.glDisable;
import static org.lwjgl.opengl.GL11.glEnable;

import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.WeakHashMap;

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

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.setters.GLProgramUniformSetter;
import fr.ign.cogit.geoxygene.appli.render.groups.RenderingGroup;
import fr.ign.cogit.geoxygene.appli.render.groups.RenderingGroupFactory;
import fr.ign.cogit.geoxygene.appli.render.methods.NamedRenderingParametersMap;
import fr.ign.cogit.geoxygene.appli.render.methods.RenderingMethodDescriptor;
import fr.ign.cogit.geoxygene.appli.render.methods.RenderingMethodParameterDescriptor;
import fr.ign.cogit.geoxygene.appli.render.primitive.GLDisplayable;
import fr.ign.cogit.geoxygene.appli.render.stats.RenderingStatistics;
import fr.ign.cogit.geoxygene.util.gl.GLComplex;
import fr.ign.cogit.geoxygene.util.gl.GLException;
import fr.ign.cogit.geoxygene.util.gl.GLMesh;
import fr.ign.cogit.geoxygene.util.gl.GLProgram;
import fr.ign.cogit.geoxygene.util.gl.GLTools;
import fr.ign.cogit.geoxygene.util.gl.RenderingException;

/**
 * @author Bertrand Dumnieu. Render a Displayable
 */
public abstract class DisplayableRenderer<T extends GLDisplayable> implements GeoxygeneGLRenderer {

    protected boolean wireframe_rendering = false;
    protected Viewport viewport = null;

    private Map<Object, RenderingGroup> groups; // One group pet object

    // Global renderingParameters
    private static final RenderingMethodParameterDescriptor global_opacity = new RenderingMethodParameterDescriptor(
            "globalOpacity");
    private static final RenderingMethodParameterDescriptor fboWidth = new RenderingMethodParameterDescriptor(
            GeoxygeneConstants.GL_VarName_FboWidth);
    private static final RenderingMethodParameterDescriptor fboHeight = new RenderingMethodParameterDescriptor(
            GeoxygeneConstants.GL_VarName_FboHeight);
    private static final RenderingMethodParameterDescriptor screenWidth = new RenderingMethodParameterDescriptor(
            GeoxygeneConstants.GL_VarName_ScreenWidth);
    private static final RenderingMethodParameterDescriptor screenHeight = new RenderingMethodParameterDescriptor(
            GeoxygeneConstants.GL_VarName_ScreenHeight);
    private static final RenderingMethodParameterDescriptor time = new RenderingMethodParameterDescriptor("time");

    public DisplayableRenderer(Viewport _viewport) {
        this.viewport = _viewport;
        this.groups = new WeakHashMap<>();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * fr.ign.cogit.geoxygene.appli.render.GeoxComplexRenderer#activateRenderer
     * ()
     */
    @Override
    public void activateRenderer() throws RenderingException {
        RenderingStatistics.doActivateRenderer(this);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * fr.ign.cogit.geoxygene.appli.render.GeoxComplexRenderer#swicthRenderer()
     */
    @Override
    public void switchRenderer() throws RenderingException {
        RenderingStatistics.doSwitchRenderer(this);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * fr.ign.cogit.geoxygene.appli.render.GeoxComplexRenderer#activateRenderer
     * ()
     */
    @Override
    public void initializeRendering() throws RenderingException {
        RenderingStatistics.doInitializeRenderer(this);
    }

    /*
     * (non-Javadoc)
     * 
     * @seesymbolizer
     * fr.ign.cogit.geoxygene.appli.render.GeoxComplexRenderer#swicthRenderer()
     */
    @Override
    public void finalizeRendering() throws RenderingException {
        RenderingStatistics.doFinalizeRenderer(this);
    }

    public abstract boolean render(T displayable_to_draw, double global_opacity);

    /**
     * Render a GlDisplayable with a set of RenderingGroups.
     */
    protected boolean render(T displayable_to_draw, double opacity, Object[] displayable_style_elements_to_draw) {
        boolean global_success = true;
        for (Object element : displayable_style_elements_to_draw) {
            RenderingGroup g = this.groups.get(element);
            if (g == null) {
                // Create a new Rendering Group
                g = RenderingGroupFactory.createRenderingGroup(element);
                if (g != null) {
                    this.groups.put(element, g);
                }
            }
            if (g != null) {
                Collection<GLComplex> c = this.getComplexesForGroup(g, displayable_to_draw);
                if (c != null && !c.isEmpty()) {
                    Map<RenderingMethodParameterDescriptor, Object> params = g
                            .getRenderingParameters(displayable_to_draw);
                    params.put(global_opacity, opacity);
                    try {
                        global_success &= this.render(c, g.getRenderingParameters(displayable_to_draw),
                                g.getMethod().getGLProgram());
                    } catch (GLException | NoninvertibleTransformException e) {
                        Logger.getRootLogger().error("Failed to render the group " + g.getName()
                                + " for the GLDisplayable " + displayable_to_draw);
                        e.printStackTrace();
                        global_success = false;
                    }
                } else {
                    // The complexes may not be ready
                    global_success = false;
                    Logger.getRootLogger().debug("Render but no GL primitive is available for drawing!");
                }
            } else {
                Logger.getRootLogger().warn("No RenderingGroup found for the style element " + element
                        + " applied to the Displayable " + displayable_to_draw);
                global_success = false;
            }
            if (!global_success) {
                this.render(displayable_to_draw.getPartialRepresentation());
            }
        }
        return global_success;
    }

    abstract protected Collection<GLComplex> getComplexesForGroup(RenderingGroup g, T displayable_to_draw);

    /**
     * Degraded Rendering
     * 
     * @param collection
     * @return
     */
    boolean render(GLComplex complex) {
        RenderingMethodDescriptor degraded = RenderingMethodDescriptor.retrieveMethod("Degraded");
        if (degraded == null)
            return false;
        GLProgram degraded_program = degraded.getGLProgram();
        if (degraded_program == null)
            return false;
        Collection<GLComplex> comp = new ArrayList<GLComplex>(1);
        comp.add(complex);
        try {
            return this.render(comp, new NamedRenderingParametersMap(), degraded_program);
        } catch (GLException | NoninvertibleTransformException e) {
            e.printStackTrace();
        }
        return false;

    }

    private boolean render(Collection<GLComplex> cComplexes, NamedRenderingParametersMap cParameters,
            GLProgram glpRenderProgram) throws GLException, NoninvertibleTransformException {
        boolean success = false;
        glEnable(GL11.GL_BLEND);
        glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        // Set the general shared uniforms.
        cParameters.put(fboWidth,
                GLContext.getActiveGlContext().getSharedUniform(GeoxygeneConstants.GL_VarName_FboWidth));
        cParameters.put(fboHeight,
                GLContext.getActiveGlContext().getSharedUniform(GeoxygeneConstants.GL_VarName_FboHeight));
        cParameters.put(screenWidth,
                GLContext.getActiveGlContext().getSharedUniform(GeoxygeneConstants.GL_VarName_ScreenWidth));
        cParameters.put(screenHeight,
                GLContext.getActiveGlContext().getSharedUniform(GeoxygeneConstants.GL_VarName_ScreenHeight));
        cParameters.put(time, GLContext.getActiveGlContext().getSharedUniform("time"));
        // Activate the Program
        GLContext active_context = GLContext.getActiveGlContext();
        GLProgram program = null;
        if (this.wireframe_rendering) {
            glDisable(GL_TEXTURE_2D);
            GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
            program = RenderingMethodDescriptor.retrieveMethod("Degraded").getGLProgram();
        } else {
            program = glpRenderProgram;
        }

        // Get the UniformSetter for this program.
        active_context.setCurrentProgram(program);
        GLProgramUniformSetter setter = active_context.getSetter(program);
        success = setter.set(cParameters, program);
        if (success) {
            AffineTransform atWorld2Screen = this.viewport.getModelToViewTransform();
            RenderingStatistics.doStartRendering(this);
            for (GLComplex complex : cComplexes) {
                success &= DisplayableRenderer.rendercomplex(complex, program, atWorld2Screen);
            }
        }
        glDisable(GL11.GL_BLEND);
        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
        active_context.setCurrentProgram(null);
        return success;
    }

    private static boolean rendercomplex(GLComplex c, GLProgram program, AffineTransform modelToViewTransform)
            throws GLException {
        boolean success = true;
        double m00 = modelToViewTransform.getScaleX();
        double m02 = modelToViewTransform.getTranslateX() + c.getMinX() * modelToViewTransform.getScaleX();
        double m11 = modelToViewTransform.getScaleY();
        double m12 = modelToViewTransform.getTranslateY() + c.getMinY() * modelToViewTransform.getScaleY();
        //        success &= GLTools.glCheckError("GL4FeatureRenderer::setGLViewMatrix()");
        program.setUniform(GeoxygeneConstants.GL_VarName_M00ModelToViewMatrix, m00);
        program.setUniform(GeoxygeneConstants.GL_VarName_M02ModelToViewMatrix, m02);
        program.setUniform(GeoxygeneConstants.GL_VarName_M11ModelToViewMatrix, m11);
        program.setUniform(GeoxygeneConstants.GL_VarName_M12ModelToViewMatrix, m12);
        GL30.glBindVertexArray(c.getVaoId());
        //        success &= GLTools.glCheckError("direct rendering binding vaoId = " + c.getVaoId());
        DisplayableRenderer.drawComplex(c);
        //        success &= GLTools.glCheckError("direct rendering drawing GLSimpleComplex class = " + c.getClass().getSimpleName());
        GL30.glBindVertexArray(0);
        success &= GLTools.glCheckError("exiting direct rendering");
        return success;
    }

    /**
     * do a GL draw call for all complex meshes
     * 
     * @param primitive
     *            primitive to render
     */
    protected final static void drawComplex(GLComplex primitive) {
        RenderingStatistics.drawGLComplex(primitive);
        for (GLMesh mesh : primitive.getMeshes()) {
            RenderingStatistics.doDrawCall();
            GL11.glDrawElements(mesh.getGlType(), mesh.getLastIndex() - mesh.getFirstIndex() + 1,
                    GL11.GL_UNSIGNED_INT, mesh.getFirstIndex() * (Integer.SIZE / 8));
        }
    }

    @Override
    public void reset() {
        this.groups.clear();
    }

    public void setWireframeRendering(boolean b) {
        this.wireframe_rendering = b;
    }

}