package gui.screens; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.*; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import game.Hakd; import game.Internet; import game.Noise; import game.gameplay.City; import gui.input.MapInput; import libnoiseforjava.exception.ExceptionInvalidParam; import libnoiseforjava.module.ModuleBase; import libnoiseforjava.util.ColorCafe; import libnoiseforjava.util.ImageCafe; import libnoiseforjava.util.NoiseMap; import libnoiseforjava.util.RendererImage; import networks.BackboneProviderNetwork; import networks.InternetProviderNetwork; import networks.Network; import org.jdelaunay.delaunay.ConstrainedMesh; import org.jdelaunay.delaunay.error.DelaunayError; import org.jdelaunay.delaunay.geometries.DEdge; import org.jdelaunay.delaunay.geometries.DPoint; import other.Line; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class MapScreen extends HakdScreen { private final Internet internet; private final GameScreen gameScreen; private final MapInput input; private float time = 0; private final SpriteBatch territoryBatch; private final Set<Sprite> networkSprites; private final Set<Sprite> ispSprites; private final Set<Sprite> territorySprites; private final Set<Sprite> backboneSprites; private final Set<Line> connectionLines; // change this to a line set private final Set<Line> parentLines; private final Set<Line> backboneLines; private Mesh connectionLinesMesh; private Mesh parentLinesMesh; private Mesh backboneLinesMesh; private Texture land; private Texture density; private Texture politics; private Texture ethics; private Texture country; private Texture income; private Texture crime; BitmapFont textFont = assets.get("skins/font/Fonts_7.fnt", BitmapFont.class); private Noise.NoiseType currentBackground; public static final int NOISE_GENERATION_SIZE = 800; // how many points to draw. default: 800, best quality would be around 2500 public static final int NOISE_DISPLAY_SIZE = 50000; // how large of an area to spread the points out on. default: 50000 public static final int INITIAL_TRIANGLE_SIZE = MapScreen.NOISE_DISPLAY_SIZE * 1000; // private overlay mapOverlay; public MapScreen(Hakd game, Internet internet) { super(game); this.internet = internet; this.gameScreen = (GameScreen) game.getScreen(); territoryBatch = new SpriteBatch(); networkSprites = new HashSet<Sprite>(internet.getNetworkMap().size()); ispSprites = new HashSet<Sprite>(internet.getInternetProviderNetworksMap().size()); territorySprites = new HashSet<Sprite>(internet.getInternetProviderNetworksMap().size()); backboneSprites = new HashSet<Sprite>(internet.getBackboneProviderNetworksMap().size()); connectionLines = new HashSet<Line>(50); parentLines = new HashSet<Line>(internet.getBackboneProviderNetworksMap().size()); backboneLines = new HashSet<Line>(internet.getBackboneProviderNetworksMap().size()); try { generateNoiseTexture(Noise.NoiseType.TERRAIN); generateNoiseTexture(Noise.NoiseType.DENSITY); generateNoiseTexture(Noise.NoiseType.COUNTRY); generateNoiseTexture(Noise.NoiseType.ETHICS); generateNoiseTexture(Noise.NoiseType.POLITICS); generateNoiseTexture(Noise.NoiseType.INCOME); generateNoiseTexture(Noise.NoiseType.CRIME); } catch (ExceptionInvalidParam exceptionInvalidParam) { exceptionInvalidParam.printStackTrace(); } currentBackground = Noise.NoiseType.TERRAIN; cam = new OrthographicCamera(); ((OrthographicCamera) cam).setToOrtho(false, width, height); input = new MapInput(this); } @Override public void show() { super.show(); cam.position.set(gameScreen.getPlayer().getNetwork().getPos(), 0); ((OrthographicCamera) cam).zoom = 2; cam.update(); reloadSprites(); // mapOverlay = new overlay(); Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.input.setInputProcessor(input); } @Override public void render(float delta) { super.render(delta); // System.out.println((int) (1 / delta)); time += delta; if (time >= 1) { reloadSprites(); time = 0; } renderBackground(); renderSprites(); renderLines(); // mapOverlay.render(); } private void renderBackground() { territoryBatch.setProjectionMatrix(cam.combined); territoryBatch.begin(); switch (currentBackground) { case TERRAIN: territoryBatch.draw(land, -NOISE_DISPLAY_SIZE / 2, -NOISE_DISPLAY_SIZE / 2, NOISE_DISPLAY_SIZE, NOISE_DISPLAY_SIZE); break; case DENSITY: territoryBatch.draw(density, -NOISE_DISPLAY_SIZE / 2, -NOISE_DISPLAY_SIZE / 2, NOISE_DISPLAY_SIZE, NOISE_DISPLAY_SIZE); break; case POLITICS: territoryBatch.draw(politics, -NOISE_DISPLAY_SIZE / 2, -NOISE_DISPLAY_SIZE / 2, NOISE_DISPLAY_SIZE, NOISE_DISPLAY_SIZE); break; case ETHICS: territoryBatch.draw(ethics, -NOISE_DISPLAY_SIZE / 2, -NOISE_DISPLAY_SIZE / 2, NOISE_DISPLAY_SIZE, NOISE_DISPLAY_SIZE); break; case COUNTRY: territoryBatch.draw(country, -NOISE_DISPLAY_SIZE / 2, -NOISE_DISPLAY_SIZE / 2, NOISE_DISPLAY_SIZE, NOISE_DISPLAY_SIZE); break; case INCOME: territoryBatch.draw(income, -NOISE_DISPLAY_SIZE / 2, -NOISE_DISPLAY_SIZE / 2, NOISE_DISPLAY_SIZE, NOISE_DISPLAY_SIZE); } territoryBatch.end(); } private void renderSprites() { batch.setProjectionMatrix(cam.combined); batch.begin(); // for (Sprite s : territorySprites) { // s.draw(batch); // } for (Sprite s : backboneSprites) { s.draw(batch); } for (Sprite s : ispSprites) { s.draw(batch); } for (Sprite s : networkSprites) { s.draw(batch); } // for (Sprite s : connectionLineSprites) { // s.draw(batch); // } for (City c : game.getGamePlay().getCityMap().values()) { c.getIcon().draw(batch); textFont.draw(batch, c.getName(), c.getPosition().x, c.getPosition().y + 80); } batch.end(); } private void renderLines() { ShaderProgram lines = shaders.get("lines"); lines.begin(); lines.setUniformMatrix("u_worldView", cam.combined); if (backboneLinesMesh != null && backboneLinesMesh.getNumVertices() > 0) { lines.setAttributef("a_color", 255f / 255f, 149f / 255f, 38f / 255f, 1); backboneLinesMesh.render(lines, GL20.GL_LINES); } if (parentLinesMesh != null && parentLinesMesh.getNumVertices() > 0) { lines.setAttributef("a_color", 0f / 255f, 255f / 255f, 142f / 255f, 1); parentLinesMesh.render(lines, GL20.GL_LINES); } // if (connectionLinesMesh != null && connectionLinesMesh.getNumVertices() > 0) { // lines.setAttributef("a_color", 0f / 255f, 255f / 255f, 142f / 255f, 1); // connectionLinesMesh.render(shaders.getCurrent(), GL20.GL_LINES); // } lines.end(); } private void reloadSprites() { networkSprites.clear(); ispSprites.clear(); territorySprites.clear(); backboneSprites.clear(); backboneLines.clear(); parentLines.clear(); connectionLines.clear(); for (Network n : internet.getNetworkMap().values()) { if (n instanceof BackboneProviderNetwork) { backboneSprites.add(n.getMapIcon()); } else if (n instanceof InternetProviderNetwork) { ispSprites.add(n.getMapIcon()); parentLines.add(n.getMapParentLine()); } else { networkSprites.add(n.getMapIcon()); parentLines.add(n.getMapParentLine()); } } drawBackboneLines(); // create backbone line mesh float[] vertexArray = fillLineVertexArray(backboneLines, new Color(255f / 255f, 149f / 255f, 38f / 255f, 1)); backboneLinesMesh = new Mesh(true, vertexArray.length, 0, VertexAttribute.Position()); backboneLinesMesh.setVertices(vertexArray); // create parent line mesh vertexArray = fillLineVertexArray(parentLines, new Color(0f / 255f, 255f / 255f, 142f / 255f, 1)); parentLinesMesh = new Mesh(true, vertexArray.length, 0, VertexAttribute.Position()); parentLinesMesh.setVertices(vertexArray); // create connection line mesh vertexArray = fillLineVertexArray(connectionLines, new Color(0f / 255f, 0f / 255f, 0f / 255f, 1)); connectionLinesMesh = new Mesh(true, vertexArray.length, 0, VertexAttribute.Position()); connectionLinesMesh.setVertices(vertexArray); } /** * Fills a vertex array to be used in openGL rendering for the lines. * * @param lineList which line list to use * @param color the color to use * @return */ private float[] fillLineVertexArray(Set<Line> lineList, Color color) { List<Float> vertexList = new ArrayList<Float>(); for (Line line : lineList) { // position A vertexList.add(line.getPointA().x); vertexList.add(line.getPointA().y); vertexList.add(0f); // position B vertexList.add(line.getPointB().x); vertexList.add(line.getPointB().y); vertexList.add(0f); } float[] vertexArray = new float[vertexList.size()]; // probably could only use an array and set the size to linelist.size*3 or something int i = 0; for (Float v : vertexList) { vertexArray[i++] = (v != null ? v : 0f); // Or whatever default you want. } return vertexArray; } /** * Generate the noise texture to use for the map, then renders it * * @param type * @throws ExceptionInvalidParam */ private void generateNoiseTexture(Noise.NoiseType type) throws ExceptionInvalidParam { ModuleBase noise = null; RendererImage renderer = new RendererImage(); double[][] noiseArray = new double[NOISE_GENERATION_SIZE][NOISE_GENERATION_SIZE]; switch (type) { case TERRAIN: if (land != null) { return; } noise = Noise.TERRAIN; renderer.clearGradient(); renderer.addGradientPoint(-1, new ColorCafe(10, 10, 80, 255)); renderer.addGradientPoint(1, new ColorCafe(39, 140, 255, 255)); break; case DENSITY: if (density != null) { return; } noise = Noise.DENSITY; renderer.clearGradient(); renderer.clearGradient(); renderer.addGradientPoint(-1, new ColorCafe(0, 0, 0, 255)); renderer.addGradientPoint(1, new ColorCafe(50, 50, 255, 255)); break; case COUNTRY: if (country != null) { return; } noise = Noise.COUNTRY; renderer.clearGradient(); renderer.clearGradient(); renderer.addGradientPoint(-1, new ColorCafe(0, 0, 0, 255)); renderer.addGradientPoint(1, new ColorCafe(0, 0, 0, 255)); break; case POLITICS: if (politics != null) { return; } noise = Noise.POLITICS; renderer.clearGradient(); renderer.clearGradient(); renderer.addGradientPoint(-1, new ColorCafe(0, 0, 0, 255)); renderer.addGradientPoint(1, new ColorCafe(255, 0, 0, 255)); break; case ETHICS: if (ethics != null) { return; } noise = Noise.ETHICS; renderer.clearGradient(); renderer.clearGradient(); renderer.addGradientPoint(-1, new ColorCafe(0, 0, 0, 255)); renderer.addGradientPoint(1, new ColorCafe(255, 255, 255, 255)); break; case INCOME: if (income != null) { return; } noise = Noise.INCOME; renderer.clearGradient(); renderer.clearGradient(); renderer.addGradientPoint(-1, new ColorCafe(0, 0, 0, 255)); renderer.addGradientPoint(1, new ColorCafe(0, 255, 0, 255)); break; case CRIME: if (income != null) { return; } noise = Noise.INCOME; renderer.clearGradient(); renderer.clearGradient(); renderer.addGradientPoint(-1, new ColorCafe(0, 0, 0, 255)); renderer.addGradientPoint(1, new ColorCafe(255, 160, 80, 255)); break; } // fill noise array for (int y = 0; y < NOISE_GENERATION_SIZE; y++) { for (int x = 0; x < NOISE_GENERATION_SIZE; x++) { // maybe use separate threads to get the values and set them to arrays. e.g. float[250][5000] ten times float f = (float) noise.getValue( (x - NOISE_GENERATION_SIZE / 2) * NOISE_DISPLAY_SIZE / NOISE_GENERATION_SIZE, 0, (y - NOISE_GENERATION_SIZE / 2) * NOISE_DISPLAY_SIZE / NOISE_GENERATION_SIZE); noiseArray[x][NOISE_GENERATION_SIZE - y - 1] = f; } Gdx.app.debug("Filling Noise Array", (float) y / NOISE_GENERATION_SIZE * 100 + "% done"); } Pixmap pixmap = new Pixmap(NOISE_GENERATION_SIZE, NOISE_GENERATION_SIZE, Pixmap.Format.RGBA8888); NoiseMap noiseMap = new NoiseMap(NOISE_GENERATION_SIZE, NOISE_GENERATION_SIZE); noiseMap.setNoiseMap(noiseArray); ImageCafe imageCafe = new ImageCafe(NOISE_GENERATION_SIZE, NOISE_GENERATION_SIZE); renderer.setSourceNoiseMap(noiseMap); renderer.setDestImage(imageCafe); renderer.render(); // fill color array for (int y = 0; y < NOISE_GENERATION_SIZE; y++) { for (int x = 0; x < NOISE_GENERATION_SIZE; x++) { // maybe use separate threads to get the values and set them to arrays. e.g. float[250][5000] ten times ColorCafe color = imageCafe.getValue(x, y); int c = Color.rgba8888( (float) color.getRed() / 255f, (float) color.getGreen() / 255f, (float) color.getBlue() / 255f, (float) color.getAlpha() / 255f); pixmap.drawPixel(x, y, c); } Gdx.app.debug("Filling Pixmap", (float) y / NOISE_GENERATION_SIZE * 100 + "% done"); } switch (type) { case TERRAIN: land = new Texture(pixmap); land.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); break; case DENSITY: density = new Texture(pixmap); density.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); break; case COUNTRY: country = new Texture(pixmap); country.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); break; case POLITICS: politics = new Texture(pixmap); politics.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); break; case ETHICS: ethics = new Texture(pixmap); ethics.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); break; case INCOME: income = new Texture(pixmap); income.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); break; case CRIME: income = new Texture(pixmap); income.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); break; } pixmap.dispose(); } private void drawBackboneLines() { ConstrainedMesh mesh = new ConstrainedMesh(); // everything will be on the x/y plane, so z will always be zero try { mesh.addConstraintEdge(new DEdge(-INITIAL_TRIANGLE_SIZE, -INITIAL_TRIANGLE_SIZE, 0, INITIAL_TRIANGLE_SIZE, -INITIAL_TRIANGLE_SIZE, 0)); mesh.addConstraintEdge(new DEdge(-INITIAL_TRIANGLE_SIZE, -INITIAL_TRIANGLE_SIZE, 0, -INITIAL_TRIANGLE_SIZE, INITIAL_TRIANGLE_SIZE, 0)); mesh.addConstraintEdge(new DEdge(INITIAL_TRIANGLE_SIZE, INITIAL_TRIANGLE_SIZE, 0, INITIAL_TRIANGLE_SIZE, -INITIAL_TRIANGLE_SIZE, 0)); mesh.addConstraintEdge(new DEdge(INITIAL_TRIANGLE_SIZE, INITIAL_TRIANGLE_SIZE, 0, -INITIAL_TRIANGLE_SIZE, INITIAL_TRIANGLE_SIZE, 0)); for (BackboneProviderNetwork backbone : game.getGamePlay().getInternet().getBackboneProviderNetworksMap().values()) { // iterate through backbones and add points to set and triangulation mesh.addPoint(new DPoint(backbone.getPos().x, backbone.getPos().y, 0)); } mesh.processDelaunay();// run delaunay algorithm List<DEdge> edges = mesh.getEdges(); // hold edges for (DEdge e : edges) { if (!backboneLines.contains(e)) { backboneLines.add(new Line(e)); } } } catch (DelaunayError delaunayError) { delaunayError.printStackTrace(); } } @Override public void dispose() { super.dispose(); } @Override public void hide() { Gdx.input.setInputProcessor(gameScreen.getInput()); time = 0; } public GameScreen getGameScreen() { return gameScreen; } public Noise.NoiseType getCurrentBackground() { return currentBackground; } public void setCurrentBackground(Noise.NoiseType currentBackground) { this.currentBackground = currentBackground; } }