/* * Copyright 2016 Nathan Howard * * This file is part of OpenGrave * * OpenGrave is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenGrave 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenGrave. If not, see <http://www.gnu.org/licenses/>. */ package com.opengrave.og.terrain; import java.io.File; import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import com.opengrave.common.config.Config; import com.opengrave.common.world.CommonAreaLoc; import com.opengrave.og.MainThread; import com.opengrave.og.Util; import com.opengrave.og.base.BoringWall; import com.opengrave.og.base.Wall; import com.opengrave.og.engine.Camera; import com.opengrave.og.engine.Location; import com.opengrave.og.engine.Node; import com.opengrave.og.engine.Surface; import com.opengrave.og.light.Shadow; import com.opengrave.og.resources.RenderStyle; import com.opengrave.og.resources.Resources; import com.opengrave.og.resources.Texture; import com.opengrave.og.resources.TextureAtlas; import com.opengrave.og.util.Matrix4f; public class TerrainWorld extends Node { enum LiquidType { SEA, LAVA, SLIME }; enum LightType { DAYCYCLE, PERMADAY, HELLISH }; LightType light = LightType.PERMADAY; LiquidType liquid = LiquidType.SEA; Location last = null; String worldName = ""; String directory = ""; private ConcurrentHashMap<CommonAreaLoc, TerrainArea> areasLoaded = new ConcurrentHashMap<CommonAreaLoc, TerrainArea>(); private TextureAtlas terrainAtlas, terrainNormAtlas, liquidAtlas, liquidNormAtlas; private ArrayList<TerrainSurface> surfaces = new ArrayList<TerrainSurface>(); public TerrainWorld(String worldName) { if (worldName.matches("/[^a-zA-Z0-9]/")) { System.out.println("Error with world name \"" + worldName + "\" a-z and 0-9 only!"); worldName = "overworld"; } this.worldName = worldName; touchWorldDir(worldName); Config config = new Config(worldName + "/world.info"); String lightName = config.getString("light", "permaday"); if (lightName.equalsIgnoreCase("daycycle")) { light = LightType.DAYCYCLE; } else if (lightName.equalsIgnoreCase("hellish")) { light = LightType.HELLISH; } else { light = LightType.PERMADAY; } String liquidName = config.getString("watertype", "sea"); if (liquidName.equalsIgnoreCase("lava")) { liquid = LiquidType.LAVA; } else if (liquidName.equalsIgnoreCase("slime")) { liquid = LiquidType.SLIME; } else { liquid = LiquidType.SEA; } ArrayList<String> texturesList = new ArrayList<String>(); texturesList.add("blank"); texturesList.add("tex/smooth.png"); texturesList.add("tex/coarse.png"); texturesList.add("tex/bricks.png"); this.terrainAtlas = (TextureAtlas) Resources.loadTextures(texturesList); ArrayList<String> normList = new ArrayList<String>(); normList.add("tex/flat.png"); normList.add("tex/smooth-norm.png"); normList.add("tex/coarse-norm.png"); normList.add("tex/bricks-norm.png"); this.terrainNormAtlas = (TextureAtlas) Resources.loadTextures(normList); ArrayList<String> texturesList2 = new ArrayList<String>(); texturesList2.add("blank"); texturesList2.add("tex/cloud.png"); texturesList2.add("tex/smooth.png"); this.liquidAtlas = (TextureAtlas) Resources.loadTextures(texturesList2); ArrayList<String> normList2 = new ArrayList<String>(); normList2.add("tex/flat.png"); normList2.add("tex/cloud-norm.png"); normList2.add("tex/smooth-norm.png"); this.liquidNormAtlas = (TextureAtlas) Resources.loadTextures(normList2); } private void touchWorldDir(String name) { File f = new File(MainThread.cache, name); f.mkdirs(); } public Texture getLiquidTextures() { return liquidAtlas; } @Override public void doUpdate(float delta) { // if(cam.equals(last)){ // last = cam.clone(); // int mapx = (int)(Math.floor(lastcx/((TerrainArea.size-1)*10f))); // int mapy = (int)(Math.floor(lastcy/((TerrainArea.size-1)*10f))); Camera cam = context.getCam(); float scale = 1f * (TerrainLayer.size - 1); // The last element joins // with the first of the // next grid... ignore the // one int mapx = (int) Math.floor(cam.getLocation().getTileX() / scale); int mapy = (int) Math.floor(cam.getLocation().getTileY() / scale); // children.clear(); for (int x = -1; x < 2; x++) { for (int y = -1; y < 2; y++) { loadAreaForce(mapx + x, mapy + y); } } // } } @Override public void doRender(Matrix4f parent) { Camera cam = context.getCam(); float scale = 1f * (TerrainLayer.size - 1); int mapx = (int) Math.floor(cam.getLocation().getTileX() / scale); int mapy = (int) Math.floor(cam.getLocation().getTileY() / scale); for (int x = -1; x < 2; x++) { for (int y = -1; y < 2; y++) { TerrainArea area = loadAreaForce(mapx + x, mapy + y); ArrayList<TerrainArea> connected = new ArrayList<TerrainArea>(); synchronized (this) { for (TerrainArea area2 : areasLoaded.values()) { int ax = area2.getAreaLoc().getX(), ay = area2.getAreaLoc().getY(); if (ax <= x + 1 && ax >= x && ay <= y + 1 && ay >= y) { connected.add(area2); } } area.forceLiquidEdges(connected); } } } } @Override public void doRenderSemiTransparent(Matrix4f matrix) { } @Override public void doRenderForPicking(Matrix4f matrix) { } @Override public void doRenderShadows(Matrix4f matrix, Shadow shadow) { } public TerrainArea loadAreaForce(int x, int y) { TerrainArea a = loadArea(x, y); addChild(a); a.load(); return a; } public synchronized TerrainArea loadArea(int x, int y) { // System.out.println("Loading "+x+" "+y); if (hasAreaLoaded(x, y)) { return getArea(x, y); } // System.out.println("Creating new"); CommonAreaLoc tac = new CommonAreaLoc(x, y); TerrainArea ta = new TerrainArea(this, tac); areasLoaded.put(tac, ta); return ta; } public synchronized TerrainArea getArea(int x, int y) { CommonAreaLoc tac = getAreaLocation(x, y); if (tac == null) { return null; } return areasLoaded.get(tac); } public synchronized boolean hasAreaLoaded(int x, int y) { return getAreaLocation(x, y) != null; } /* * public TerrainEditableVertex getVertexAt(int x, int y, int layer, boolean ignoreEdge) { * int mapx = (int) (Math.floor(x / ((TerrainLayer.size - 1) * 1f))); * int mapy = (int) (Math.floor(y / ((TerrainLayer.size - 1) * 1f))); * CommonAreaLoc tac = getAreaLocation(mapx, mapy); * if (tac == null) { * System.out.println("Couldn't get TerrainArea location with " + mapx + ":" + mapy); * return null; * } * int inmapx = x - (mapx * (TerrainLayer.size - 1)); * int inmapy = y - (mapy * (TerrainLayer.size - 1)); * * synchronized (this) { * synchronized (areasLoaded) { * TerrainArea ta = areasLoaded.get(tac); * return ta.getVertexAt(inmapx, inmapy, layer, ignoreEdge); * } * } * } */ /* * public synchronized TerrainLiquidEditableVertex getLiquidVertexAt(int x, int y, int layer, boolean ignoreEdge) { * int mapx = (int) (Math.floor(x / ((TerrainLayer.size - 1) * 1f))); * int mapy = (int) (Math.floor(y / ((TerrainLayer.size - 1) * 1f))); * CommonAreaLoc tac = getAreaLocation(mapx, mapy); * if (tac == null) { * System.out.println("Couldn't get TerrainArea location with " + mapx + ":" + mapy); * return null; * } * int inmapx = x - (mapx * (TerrainLayer.size - 1)); * int inmapy = y - (mapy * (TerrainLayer.size - 1)); * TerrainArea ta; * ta = areasLoaded.get(tac); * return ta.getLiquidVertexAt(inmapx, inmapy, layer, ignoreEdge); * } */ public synchronized CommonAreaLoc getAreaLocation(int x, int y) { for (CommonAreaLoc tac : areasLoaded.keySet()) { if (tac.isEquals(x, y)) { return tac; } } return null; } public TextureAtlas getTextures() { return terrainAtlas; } public synchronized void saveAll() { for (TerrainArea ta : areasLoaded.values()) { ta.save(); } } public synchronized TerrainArea getArea(CommonAreaLoc cal) { return getArea(cal.getX(), cal.getY()); } // public CommonAreaLoc getAreaLocationOfLocation(Location l) { // int mapx = (int) (Math.floor(l.getFullXAsFloat() / ((TerrainLayer.size - 1) * 1f))); // int mapy = (int) (Math.floor(l.getFullYAsFloat() / ((TerrainLayer.size - 1) * 1f))); // return new CommonAreaLoc(mapx, mapy); // } public synchronized TerrainArea getAreaOfLocation(Location l) { int mapx = (int) (Math.floor(l.getFullXAsFloat() / ((TerrainLayer.size) * 1f))); int mapy = (int) (Math.floor(l.getFullYAsFloat() / ((TerrainLayer.size) * 1f))); return getArea(mapx, mapy); } public synchronized Wall createWallAt(Location l) { Wall wall = new BoringWall(); TerrainArea ta = getAreaOfLocation(l); ta.addWall(wall); wall.setLocation(ta.relativeLocationOf(l)); return wall; } public synchronized void setAllObjectsRenderStyle(RenderStyle renderStyle) { for (TerrainArea ta : areasLoaded.values()) { ta.setAllObjectsRenderStyle(renderStyle); } } public File getDirectory() { return new File(MainThread.cache, worldName); } /* * public Location getLocationOf(BaseObject object) { * synchronized (this) { * synchronized (areasLoaded) { * for (TerrainArea area : areasLoaded.values()) { * if (area.ownsObject(object)) { return object.getLocation().add(area.getLocation()); } * } * } * } * return null; * } */ /** * Returns all objects in loaded memory with given identifier * * @param ident * @return */ /* * public ArrayList<BaseObject> getObjectsByIdentifier(String ident) { * ArrayList<BaseObject> objList = new ArrayList<BaseObject>(); * synchronized (this) { * synchronized (areasLoaded) { * for (TerrainArea area : areasLoaded.values()) { * area.getObjectsByIdentifier(objList, ident); * } * } * } * return objList; * } */ public synchronized float getHeightAt(Location loc) { TerrainArea area = getAreaOfLocation(loc); if (area == null) { return 0f; } return area.getHeightAt(area.relativeLocationOf(loc)); } @Override public Matrix4f getMatrix() { return Util.createMatrixFor(new Location(), null, null, context); } public String getFileName() { return worldName; } public TextureAtlas getNormalTextures() { return terrainNormAtlas; } public TextureAtlas getLiquidNormTextures() { return liquidNormAtlas; } public synchronized void alter(int x, int y, int layer, TerrainLayerAlteration alter) { // TODO Done edges - need to care about corners (4 layers as one vertex) int mapx = (int) (Math.floor(x / ((TerrainLayer.size - 1) * 1f))); int mapy = (int) (Math.floor(y / ((TerrainLayer.size - 1) * 1f))); CommonAreaLoc mloc = getAreaLocation(mapx, mapy); TerrainArea area = getArea(mloc); if (area == null) { return; } int size = TerrainLayer.size - 1; x = x - (mapx * size); y = y - (mapy * size); if (x == 0) { // Also affect the next area over CommonAreaLoc loc = new CommonAreaLoc(mapx - 1, mapy); TerrainArea areaAlso = getArea(loc); areaAlso.alter(TerrainLayer.size - 1, y, layer, alter); } if (x == TerrainLayer.size - 1) { CommonAreaLoc loc = new CommonAreaLoc(mapx + 1, mapy); TerrainArea areaAlso = getArea(loc); areaAlso.alter(0, y, layer, alter); } if (y == 0) { CommonAreaLoc loc = new CommonAreaLoc(mapx, mapy - 1); TerrainArea areaAlso = getArea(loc); areaAlso.alter(x, TerrainLayer.size - 1, layer, alter); } if (y == TerrainLayer.size - 1) { CommonAreaLoc loc = new CommonAreaLoc(mapx, mapy + 1); TerrainArea areaAlso = getArea(loc); areaAlso.alter(x, 0, layer, alter); } area.alter(x, y, layer, alter); } public synchronized void alter(int x, int y, int layer, TerrainLiquidLayerAlteration alter) { // TODO Done edges - need to care about corners (4 layers as one vertex) int mapx = (int) (Math.floor(x / ((TerrainLayer.size - 1) * 1f))); int mapy = (int) (Math.floor(y / ((TerrainLayer.size - 1) * 1f))); CommonAreaLoc mloc = getAreaLocation(mapx, mapy); TerrainArea area = getArea(mloc); if (area == null) { return; } int size = TerrainLayer.size - 1; x = x - (mapx * size); y = y - (mapy * size); if (x == 0) { // Also affect the next area over CommonAreaLoc loc = new CommonAreaLoc(mapx - 1, mapy); TerrainArea areaAlso = getArea(loc); areaAlso.alter(TerrainLayer.size - 1, y, layer, alter); } if (x == TerrainLayer.size - 1) { CommonAreaLoc loc = new CommonAreaLoc(mapx + 1, mapy); TerrainArea areaAlso = getArea(loc); areaAlso.alter(0, y, layer, alter); } if (y == 0) { CommonAreaLoc loc = new CommonAreaLoc(mapx, mapy - 1); TerrainArea areaAlso = getArea(loc); areaAlso.alter(x, TerrainLayer.size - 1, layer, alter); } if (y == TerrainLayer.size - 1) { CommonAreaLoc loc = new CommonAreaLoc(mapx, mapy + 1); TerrainArea areaAlso = getArea(loc); areaAlso.alter(x, 0, layer, alter); } area.alter(x, y, layer, alter); } public Surface getSurface(int i) { if (i < 0) { return null; } while (i >= surfaces.size()) { int a = surfaces.size(); TerrainSurface ts = new TerrainSurface(this, a); surfaces.add(ts); } return surfaces.get(i); } }