es.eucm.ead.editor.utils.TexturedShapeEditor.java Source code

Java tutorial

Introduction

Here is the source code for es.eucm.ead.editor.utils.TexturedShapeEditor.java

Source

/**
 * eAdventure is a research project of the
 *    e-UCM research group.
 *
 *    Copyright 2005-2014 e-UCM research group.
 *
 *    You can access a list of all the contributors to eAdventure at:
 *          http://e-adventure.e-ucm.es/contributors
 *
 *    e-UCM is a research group of the Department of Software Engineering
 *          and Artificial Intelligence at the Complutense University of Madrid
 *          (School of Computer Science).
 *
 *          CL Profesor Jose Garcia Santesmases 9,
 *          28040 Madrid (Madrid), Spain.
 *
 *          For more info please visit:  <http://e-adventure.e-ucm.es> or
 *          <http://www.e-ucm.es>
 *
 * ****************************************************************************
 *
 *  This file is part of eAdventure
 *
 *      eAdventure 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 3 of the License, or
 *      (at your option) any later version.
 *
 *      eAdventure 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 eAdventure.  If not, see <http://www.gnu.org/licenses/>.
 */
package es.eucm.ead.editor.utils;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
import com.badlogic.gdx.graphics.g2d.PolygonSprite;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Polygon;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.async.AsyncExecutor;
import com.badlogic.gdx.utils.async.AsyncResult;
import com.badlogic.gdx.utils.async.AsyncTask;
import com.vividsolutions.jts.geom.Geometry;
import es.eucm.ead.engine.utils.GeometryUtils;

import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Edits shapes. Use left-click to add area, right-click to erase an area
 */
public class TexturedShapeEditor extends GeoTester.GeoViewer implements InputProcessor {

    private AsyncExecutor executor = null;
    private AsyncResult<PolygonRegion> updatedRegion = null;
    private final ConcurrentLinkedQueue<Polygon> pendingMerges = new ConcurrentLinkedQueue<Polygon>();
    private final ConcurrentLinkedQueue<Polygon> pendingRemoves = new ConcurrentLinkedQueue<Polygon>();
    private short[] triangles;

    private final Array<Geometry> geo = new Array<Geometry>();

    /**
     * whatever is added here will be painted in blue
     */
    protected final Array<Polygon> blue = new Array<Polygon>();
    /**
     * whatever is added here will be painted in red, on top of the blue
     */
    protected final Array<Polygon> red = new Array<Polygon>();

    private Texture textureSolid;

    public static void main(String args[]) {
        LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
        config.width = 1000;
        config.height = 800;
        new LwjglApplication(new TexturedShapeEditor(), config);
    }

    @Override
    public void create() {
        super.create();

        executor = new AsyncExecutor(1);

        // create a string of generally-overlapping polygons, will draw in
        // blue
        GeoTester.randomPolys(3, 40, 80, new Vector2(100, 300), blue);
        float s = 10;
        Polygon p0 = new Polygon(new float[] {
                // north-west, low, north-east
                0, 3 * s, 0, 2 * s, 2 * s, 0, 3 * s, 0, 4.5f * s, 2 * s, 6 * s, 0, 7 * s, 0, 9 * s, 2 * s, 9 * s,
                3 * s,
                // north-east, high, north-west
                8 * s, 3 * s, 6.5f * s, 1 * s, 5 * s, 3 * s, 4 * s, 3 * s, 2.5f * s, s, 1 * s, 3 * s });
        blue.add(p0);
        // merge them into a single polygon, will draw in red
        for (Polygon bp : blue) {
            GeometryUtils.merge(geo, bp);
        }
        Geometry collapsed = GeometryUtils.collapse(geo);
        Polygon p = GeometryUtils.jtsCoordsToGdx(collapsed.getCoordinates());
        red.add(p);

        triangles = GeometryUtils.triangulate(collapsed);
        Gdx.app.error("GeoTester", "ready to display triangles worth " + triangles.length + " vertices");

        // use the polygon to clip a randomly-generated texture
        textureSolid = new Texture(GeoTester.randomPixmap(100, 100, null), false);

        PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid), p.getVertices(), triangles);
        poly = new PolygonSprite(polyReg);
        poly.setOrigin(p.getVertices()[0], p.getVertices()[1]);
        polyBatch = new PolygonSpriteBatch();

        // prepare rendering aids
        shapeRenderer = new ShapeRenderer();

        Gdx.input.setInputProcessor(this);
    }

    private float polySize = 30;
    private int lastX, lastY;

    protected String generatePointerString(int x, int y) {
        lastX = x;
        lastY = y;
        return super.generatePointerString(x, y);
    }

    @Override
    public void render() {
        super.render();
        renderPolygonSprite();

        renderTriangles(red.get(0), triangles);
        renderPolygonShapes(blue, Color.BLUE, 0, 0);
        renderPolygonShapes(red, Color.RED, 0, 0);

        Array<Polygon> a = new Array<Polygon>();
        a.add(GeometryUtils.createPoly(6, polySize, new Vector2(lastX, lastY)));
        renderPolygonShapes(a, Color.DARK_GRAY, 0, 0);

        if (Gdx.input.isTouched()) {
            int mouseX = Gdx.input.getX();
            int mouseY = height - Gdx.input.getY();
            if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
                pendingMerges.offer(GeometryUtils.createPoly(6, polySize, new Vector2(mouseX, mouseY)));
            } else if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
                pendingRemoves.offer(GeometryUtils.createPoly(6, polySize, new Vector2(mouseX, mouseY)));
            }
        }

        if (updatedRegion != null && updatedRegion.isDone()) {
            Gdx.app.error("GeoTester", "merging in...");
            poly.setRegion(updatedRegion.get());
            triangles = updatedRegion.get().getTriangles();
            red.clear();
            red.add(new Polygon(updatedRegion.get().getVertices()));
            updatedRegion = null;
        } else if (!pendingMerges.isEmpty() && updatedRegion == null) {
            updatedRegion = executor.submit(new AsyncTask<PolygonRegion>() {
                @Override
                public PolygonRegion call() throws Exception {
                    long t0 = System.nanoTime();
                    while (!pendingMerges.isEmpty()) {
                        GeometryUtils.merge(geo, pendingMerges.poll());
                    }
                    Geometry collapsed = GeometryUtils.collapse(geo);
                    GeometryUtils.simplify(geo, 3);
                    Polygon p = GeometryUtils.jtsCoordsToGdx(collapsed.getCoordinates());
                    short[] ts = GeometryUtils.triangulate(collapsed);
                    PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid), p.getVertices(), ts);
                    long t1 = System.nanoTime() - t0;
                    Gdx.app.error("GeoTester", "ready to display triangles worth " + ts.length
                            + " vertices after merge in " + (t1 / 1000000) + " ms");
                    return polyReg;
                }
            });
        } else if (!pendingRemoves.isEmpty() && updatedRegion == null) {
            updatedRegion = executor.submit(new AsyncTask<PolygonRegion>() {
                @Override
                public PolygonRegion call() throws Exception {
                    long t0 = System.nanoTime();
                    while (!pendingRemoves.isEmpty()) {
                        GeometryUtils.subtract(geo, pendingRemoves.poll());
                    }
                    Geometry collapsed = GeometryUtils.collapse(geo);
                    if (GeoTester.r(0, 10) < 4) {
                        GeometryUtils.simplify(geo, 3);
                    }
                    Polygon p = GeometryUtils.jtsCoordsToGdx(collapsed.getCoordinates());
                    short[] ts = GeometryUtils.triangulate(collapsed);
                    PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid), p.getVertices(), ts);
                    long t1 = System.nanoTime() - t0;
                    Gdx.app.error("GeoTester", "ready to display triangles worth " + ts.length
                            + " vertices after removal in " + (t1 / 1000000) + " ms");
                    return polyReg;
                }
            });
        }
    }

    @Override
    public boolean keyDown(int i) {
        return false;
    }

    @Override
    public boolean keyUp(int i) {
        return false;
    }

    @Override
    public boolean keyTyped(char c) {
        return false;
    }

    @Override
    public boolean touchDown(int i, int i2, int i3, int i4) {
        return false;
    }

    @Override
    public boolean touchUp(int i, int i2, int i3, int i4) {
        return false;
    }

    @Override
    public boolean touchDragged(int i, int i2, int i3) {
        return false;
    }

    @Override
    public boolean mouseMoved(int i, int i2) {
        return false;
    }

    @Override
    public boolean scrolled(int i) {
        if (i > 0) {
            polySize = Math.min(polySize * 1.2f, 100);
        } else if (i < 0) {
            polySize = Math.max(polySize * 0.8f, 5);
        }
        System.err.println("poly size: " + polySize);
        return false;
    }
}