Prechádzať zdrojové kódy

AABB, particle fix, terrain optimisation

- AABBs are now calculated using the vertex data of the model.
- It is now possible to update the text of a GUIText object without
recreating it completely.
- The particle master is now an object, not a static class.
- Fixed a bug causing particles to not appear.
- Reduced settings to work better on low-end machines.
- Optimised terrain generation.
Tankernn 8 rokov pred
rodič
commit
780ed93201
28 zmenil súbory, kde vykonal 265 pridanie a 213 odobranie
  1. 2 1
      TODO.txt
  2. 31 25
      src/main/java/eu/tankernn/gameEngine/MainLoop.java
  3. 0 2
      src/main/java/eu/tankernn/gameEngine/entities/Car.java
  4. 5 9
      src/main/java/eu/tankernn/gameEngine/entities/Entity.java
  5. 11 11
      src/main/java/eu/tankernn/gameEngine/font/meshCreator/GUIText.java
  6. 4 2
      src/main/java/eu/tankernn/gameEngine/loader/Loader.java
  7. 55 29
      src/main/java/eu/tankernn/gameEngine/loader/models/AABB.java
  8. 3 31
      src/main/java/eu/tankernn/gameEngine/loader/obj/normalMapped/ModelDataNM.java
  9. 0 1
      src/main/java/eu/tankernn/gameEngine/particles/Particle.java
  10. 23 12
      src/main/java/eu/tankernn/gameEngine/particles/ParticleMaster.java
  11. 3 2
      src/main/java/eu/tankernn/gameEngine/particles/ParticleShader.java
  12. 15 5
      src/main/java/eu/tankernn/gameEngine/particles/ParticleSystem.java
  13. 7 2
      src/main/java/eu/tankernn/gameEngine/postProcessing/ContrastChanger.java
  14. 2 1
      src/main/java/eu/tankernn/gameEngine/postProcessing/IPostProcessingEffect.java
  15. 9 2
      src/main/java/eu/tankernn/gameEngine/postProcessing/ImageRenderer.java
  16. 3 3
      src/main/java/eu/tankernn/gameEngine/postProcessing/MultisampleMultitargetFbo.java
  17. 23 31
      src/main/java/eu/tankernn/gameEngine/postProcessing/PostProcessing.java
  18. 3 2
      src/main/java/eu/tankernn/gameEngine/postProcessing/bloom/BrightFilter.java
  19. 1 1
      src/main/java/eu/tankernn/gameEngine/postProcessing/bloom/CombineFilter.java
  20. 1 1
      src/main/java/eu/tankernn/gameEngine/postProcessing/gaussianBlur/HorizontalBlur.java
  21. 1 1
      src/main/java/eu/tankernn/gameEngine/postProcessing/gaussianBlur/VerticalBlur.java
  22. 0 1
      src/main/java/eu/tankernn/gameEngine/renderEngine/DisplayManager.java
  23. 14 2
      src/main/java/eu/tankernn/gameEngine/renderEngine/RawModel.java
  24. 26 16
      src/main/java/eu/tankernn/gameEngine/renderEngine/font/TextMaster.java
  25. 5 1
      src/main/java/eu/tankernn/gameEngine/renderEngine/shaders/ShaderProgram.java
  26. 1 1
      src/main/java/eu/tankernn/gameEngine/renderEngine/shadows/ShadowMapMasterRenderer.java
  27. 1 0
      src/main/java/eu/tankernn/gameEngine/settings/Settings.java
  28. 16 18
      src/main/java/eu/tankernn/gameEngine/terrains/TerrainPack.java

+ 2 - 1
TODO.txt

@@ -1,4 +1,5 @@
-Infinite terrain
+All Masters, Renderers, etc. should be objects, not static
+Reflectivity uniform vars
 Multiplayer
 Modular GUIs
  - Make text variables uniform/ change text rendering method

+ 31 - 25
src/main/java/eu/tankernn/gameEngine/MainLoop.java

@@ -62,7 +62,7 @@ public class MainLoop {
 	public static final String DUDV_MAP = "waterDUDV.png";
 	public static final String NORMAL_MAP = "waterNormalMap.png";
 
-	private static final boolean DEBUG = true;
+	public static final boolean DEBUG = true;
 
 	static List<Entity> entities = new ArrayList<Entity>();
 	static List<Entity> normalMapEntities = new ArrayList<Entity>();
@@ -107,12 +107,14 @@ public class MainLoop {
 		Skybox skybox = new Skybox(Texture.newCubeMap(dayTextures, 500), Texture.newCubeMap(nightTextures, 500), 500);
 
 		MasterRenderer renderer = new MasterRenderer(loader, camera, skybox);
-		ParticleMaster.init(loader, camera.getProjectionMatrix());
-		TextMaster.init(loader);
+		ParticleMaster particleMaster = new ParticleMaster(loader, camera.getProjectionMatrix());
+		TextMaster textMaster = new TextMaster(loader);
 
 		FontType font = new FontType(loader.loadTexture("arial.png"), "arial.fnt");
-		GUIText text = new GUIText("Sample text", 3, font, new Vector2f(0.5f, 0.5f), 0.5f, true).setColor(1, 1, 1);
-		TextMaster.loadText(text);
+		GUIText text = new GUIText("Sample text", 1, font, new Vector2f(0.5f, 0.0f), 0.5f, false).setColor(0, 1, 0);
+		GUIText fpsText = new GUIText("FPS: ", 1, font, new Vector2f(0.0f, 0.0f), 0.5f, false).setColor(1, 1, 1);
+		textMaster.loadText(fpsText);
+		textMaster.loadText(text);
 
 		// Barrel
 		TexturedModel barrelModel = new TexturedModel(loader.loadNormalMappedOBJ(new InternalFile("barrel.obj")),
@@ -130,14 +132,11 @@ public class MainLoop {
 		lights.add(sun);
 		lights.add(flashLight);
 
-		terrainPack.update(player);
-
 		// ### Random grass generation ###
 
 		ModelTexture textureAtlas = new ModelTexture(Texture.newTexture(new InternalFile("lantern.png")).create());
 		textureAtlas.setNumberOfRows(1);
-		TexturedModel grassModel = new TexturedModel(
-				loader.loadToVAO(OBJFileLoader.loadOBJ(new InternalFile("lantern.obj"))), textureAtlas);
+		TexturedModel grassModel = new TexturedModel(loader.loadOBJ(new InternalFile("lantern.obj")), textureAtlas);
 		grassModel.getModelTexture().setHasTransparency(true);
 		grassModel.getModelTexture().setShineDamper(10);
 		grassModel.getModelTexture().setReflectivity(0.5f);
@@ -152,7 +151,7 @@ public class MainLoop {
 			entities.add(new Entity(grassModel, rand.nextInt(4),
 					new Vector3f(x, terrainPack.getTerrainHeightByWorldPos(x, z), z), new Vector3f(), 1));
 		}
-		
+
 		terrainPack.addWaitingForTerrainHeight(entities.toArray(new Entity[entities.size()]));
 
 		// #### Water rendering ####
@@ -166,7 +165,8 @@ public class MainLoop {
 
 		ParticleTexture particleTexture = new ParticleTexture(loader.loadTexture("particles/cosmic.png"), 4, true);
 		ParticleSystem ps = new ParticleSystem(particleTexture, 50, 10, 0.3f, 4);
-
+		particleMaster.addSystem(ps);
+		
 		MultisampleMultitargetFbo multisampleFbo = new MultisampleMultitargetFbo(Display.getWidth(),
 				Display.getHeight());
 		Fbo outputFbo = new Fbo(Display.getWidth(), Display.getHeight(), Fbo.DEPTH_TEXTURE);
@@ -185,16 +185,18 @@ public class MainLoop {
 
 			if (picker.getCurrentTerrainPoint() != null) {
 				Vector3f currentPoint = picker.getCurrentTerrainPoint();
-				flashLight.getPosition().x = currentPoint.x;
-				flashLight.getPosition().z = currentPoint.z;
+				flashLight.getPosition().set(currentPoint);
 				flashLight.getPosition().y = terrainPack.getTerrainHeightByWorldPos(currentPoint.x, currentPoint.z)
 						+ 1.0f;
 			}
+			
+			if (picker.getCurrentEntity() != null) {
+				picker.getCurrentEntity().setScale(2);
+			}
 
 			if (picker.getCurrentGui() != null) {
 				if (Mouse.isButtonDown(0)) {
 					System.out.println("Clicked gui.");
-					picker.getCurrentGui().getPosition().x += 0.1f;
 				}
 			}
 
@@ -203,22 +205,22 @@ public class MainLoop {
 				Terrain currentTerrain = terrainPack.getTerrainByWorldPos(player.getPosition().x,
 						player.getPosition().z);
 				if (currentTerrain != null) {
-					text.remove();
 					Vector3f pos = player.getPosition();
 					String textString = "X: " + Math.floor(pos.x) + " Y: " + Math.floor(pos.y) + " Z: "
 							+ Math.floor(pos.z) + " Current terrain: " + currentTerrain.getX() / Settings.TERRAIN_SIZE
 							+ ":" + currentTerrain.getZ() / Settings.TERRAIN_SIZE;
-					text = new GUIText(textString, 1, font, new Vector2f(0.5f, 0f), 0.5f, false);
+					text.setText(textString);
+					fpsText.setText(String.format("FPS: %.2f", getFps()));
 				}
 			}
 
 			// Sort list of lights
 			DistanceSorter.sort(lights, camera);
-
+			
 			renderer.renderShadowMap(entities, sun);
-
-			ps.generateParticles(player.getPosition());
-			ParticleMaster.update(camera);
+			
+			ps.setPosition(player.getPosition());
+			particleMaster.update(camera);
 
 			Scene scene = new Scene(entities, normalMapEntities, terrainPack, lights, camera, skybox);
 
@@ -231,16 +233,16 @@ public class MainLoop {
 
 			renderer.renderScene(scene, new Vector4f(0, 1, 0, Float.MAX_VALUE));
 			waterMaster.renderWater(camera, lights);
-			ParticleMaster.renderParticles(camera);
+			particleMaster.renderParticles(camera);
 
 			multisampleFbo.unbindFrameBuffer();
 
 			multisampleFbo.resolveToFbo(GL30.GL_COLOR_ATTACHMENT0, outputFbo);
 			multisampleFbo.resolveToFbo(GL30.GL_COLOR_ATTACHMENT1, outputFbo2);
 			PostProcessing.doPostProcessing(outputFbo.getColourTexture(), outputFbo2.getColourTexture());
-
+			
 			guiRenderer.render(guis);
-			TextMaster.render();
+			textMaster.render();
 
 			DisplayManager.updateDisplay();
 		}
@@ -249,8 +251,8 @@ public class MainLoop {
 		outputFbo.cleanUp();
 		outputFbo2.cleanUp();
 		multisampleFbo.cleanUp();
-		ParticleMaster.cleanUp();
-		TextMaster.cleanUp();
+		particleMaster.cleanUp();
+		textMaster.cleanUp();
 		waterMaster.cleanUp();
 		guiRenderer.cleanUp();
 		renderer.cleanUp();
@@ -258,4 +260,8 @@ public class MainLoop {
 		terrainPack.cleanUp();
 		DisplayManager.closeDisplay();
 	}
+
+	private static double getFps() {
+		return 1 / DisplayManager.getFrameTimeSeconds();
+	}
 }

+ 0 - 2
src/main/java/eu/tankernn/gameEngine/entities/Car.java

@@ -73,8 +73,6 @@ public class Car extends Player {
 
 		this.currentTurnSpeed = Math.min(currentTurnSpeed, TURN_MAX);
 		this.currentTurnSpeed = Math.max(currentTurnSpeed, -TURN_MAX);
-
-		// TODO Nitro
 	}
 
 }

+ 5 - 9
src/main/java/eu/tankernn/gameEngine/entities/Entity.java

@@ -7,8 +7,6 @@ import eu.tankernn.gameEngine.loader.models.TexturedModel;
 import eu.tankernn.gameEngine.util.IPositionable;
 
 public class Entity implements IPositionable {
-	private static final Vector3f SIZE = new Vector3f(2, 4, 2);
-	
 	private TexturedModel model;
 	private Vector3f position;
 	private Vector3f rotation;
@@ -22,16 +20,14 @@ public class Entity implements IPositionable {
 		this.position = position;
 		this.rotation = rotation;
 		this.scale = scale;
-		this.boundingBox = new AABB(position, SIZE);
+		this.boundingBox = model.getRawModel().getBoundingBox();
+		this.boundingBox.updatePosition(position);
+		this.boundingBox = this.boundingBox.copy();
 	}
 	
 	public Entity(TexturedModel model, int index, Vector3f position, Vector3f rotation, float scale) {
-		this.model = model;
+		this(model, position, rotation, scale);
 		this.textureIndex = index;
-		this.position = position;
-		this.rotation = rotation;
-		this.scale = scale;
-		this.boundingBox = new AABB(position, SIZE);
 	}
 	
 	public float getTextureXOffset() {
@@ -56,7 +52,7 @@ public class Entity implements IPositionable {
 	}
 	
 	private void updateBoundingBox() {
-		this.boundingBox = new AABB(this.position, SIZE); //TODO Fix model size
+		this.boundingBox.updatePosition(this.position);
 	}
 	
 	public TexturedModel getModel() {

+ 11 - 11
src/main/java/eu/tankernn/gameEngine/font/meshCreator/GUIText.java

@@ -3,8 +3,6 @@ package eu.tankernn.gameEngine.font.meshCreator;
 import org.lwjgl.util.vector.Vector2f;
 import org.lwjgl.util.vector.Vector3f;
 
-import eu.tankernn.gameEngine.renderEngine.font.TextMaster;
-
 /**
  * Represents a piece of text in the game.
  * 
@@ -14,6 +12,8 @@ import eu.tankernn.gameEngine.renderEngine.font.TextMaster;
 public class GUIText {
 
 	private String textString;
+	private boolean dirty;
+	
 	private float fontSize;
 
 	private int textMeshVao;
@@ -61,14 +61,6 @@ public class GUIText {
 		this.position = position;
 		this.lineMaxSize = maxLineLength;
 		this.centerText = centered;
-		TextMaster.loadText(this);
-	}
-
-	/**
-	 * Remove the text from the screen.
-	 */
-	public void remove() {
-		TextMaster.removeText(this);
 	}
 
 	/**
@@ -184,5 +176,13 @@ public class GUIText {
 	protected String getTextString() {
 		return textString;
 	}
-
+	
+	public void setText(String text) {
+		this.textString = text;
+		this.dirty = true;
+	}
+	
+	public boolean isDirty() {
+		return this.dirty;
+	}
 }

+ 4 - 2
src/main/java/eu/tankernn/gameEngine/loader/Loader.java

@@ -171,10 +171,12 @@ public class Loader {
 	}
 	
 	public RawModel loadOBJ(InternalFile objFile) {
-		return this.loadToVAO(OBJFileLoader.loadOBJ(objFile));
+		ModelData data = OBJFileLoader.loadOBJ(objFile);
+		return this.loadToVAO(data).withBoundingBox(data);
 	}
 	
 	public RawModel loadNormalMappedOBJ(InternalFile objFile) {
-		return this.loadToVAO(NormalMappedObjLoader.loadOBJ(objFile));
+		ModelDataNM data = NormalMappedObjLoader.loadOBJ(objFile);
+		return this.loadToVAO(data).withBoundingBox(data);
 	}
 }

+ 55 - 29
src/main/java/eu/tankernn/gameEngine/loader/models/AABB.java

@@ -2,55 +2,81 @@ package eu.tankernn.gameEngine.loader.models;
 
 import org.lwjgl.util.vector.Vector3f;
 
+import eu.tankernn.gameEngine.loader.obj.ModelData;
+
 public class AABB {
 	protected Vector3f middlePos, halfSize;
-	
-	public AABB(Vector3f middlePos, Vector3f halfSize)
-	{
+
+	public AABB(Vector3f middlePos, Vector3f halfSize) {
 		this.middlePos = middlePos;
 		this.halfSize = halfSize;
 	}
+
+	public AABB(ModelData model) {
+		Vector3f max = new Vector3f(), min = new Vector3f();
+		float[] vertexArray = model.getVertices();
+
+		for (int i = 0; i < vertexArray.length; i += 3) {
+			if (vertexArray[i] > max.x)
+				max.setX(vertexArray[i]);
+			if (vertexArray[i] < min.x)
+				min.setX(vertexArray[i]);
+		}
+
+		for (int i = 1; i < vertexArray.length; i += 3) {
+			if (vertexArray[i] > max.y)
+				max.setY(vertexArray[i]);
+			if (vertexArray[i] < min.y)
+				min.setY(vertexArray[i]);
+		}
+
+		for (int i = 2; i < vertexArray.length; i += 3) {
+			if (vertexArray[i] > max.z)
+				max.setZ(vertexArray[i]);
+			if (vertexArray[i] < min.z)
+				min.setZ(vertexArray[i]);
+		}
+
+		Vector3f fullSize = Vector3f.sub(max, min, null);
+		this.halfSize = new Vector3f(fullSize.x / 2, fullSize.y / 2, fullSize.z / 2);
+	}
 	
-//	public AABB(Vector3f middlePos, RawModel model) {
-//		float maxX, maxY, maxZ;
-//		
-//	}
-	
-	public static boolean collides(AABB a, AABB b)
-	{
-		if (Math.abs(a.middlePos.x - b.middlePos.x) < a.halfSize.x + b.halfSize.x)
-		{
-			if (Math.abs(a.middlePos.y - b.middlePos.y) < a.halfSize.y + b.halfSize.y)
-			{
-				if (Math.abs(a.middlePos.z - b.middlePos.z) < a.halfSize.z + b.halfSize.z)
-				{
+	public AABB copy() {
+		return new AABB(new Vector3f(this.middlePos), new Vector3f(this.halfSize));
+	}
+
+	public void updatePosition(Vector3f pos) {
+		this.middlePos = new Vector3f(pos);
+		this.middlePos.setY(pos.y + halfSize.y);
+	}
+
+	public static boolean collides(AABB a, AABB b) {
+		if (Math.abs(a.middlePos.x - b.middlePos.x) < a.halfSize.x + b.halfSize.x) {
+			if (Math.abs(a.middlePos.y - b.middlePos.y) < a.halfSize.y + b.halfSize.y) {
+				if (Math.abs(a.middlePos.z - b.middlePos.z) < a.halfSize.z + b.halfSize.z) {
 					return true;
 				}
 			}
 		}
-		
+
 		return false;
 	}
-	
-	public static boolean inside(AABB a, Vector3f b)
-	{
-		if (Math.abs(a.middlePos.x - b.x) < a.halfSize.x)
-		{
-			if (Math.abs(a.middlePos.y - b.y) < a.halfSize.y)
-			{
-				if (Math.abs(a.middlePos.z - b.z) < a.halfSize.z)
-				{
+
+	public static boolean inside(AABB a, Vector3f b) {
+		if (Math.abs(a.middlePos.x - b.x) < a.halfSize.x) {
+			if (Math.abs(a.middlePos.y - b.y) < a.halfSize.y) {
+				if (Math.abs(a.middlePos.z - b.z) < a.halfSize.z) {
 					return true;
 				}
 			}
 		}
 		return false;
 	}
-	
+
 	public Vector3f getLb() {
-		return new Vector3f(middlePos.x - halfSize.x, middlePos.y/* - halfSize.y*/, middlePos.z - halfSize.z);
+		return new Vector3f(middlePos.x - halfSize.x, middlePos.y - halfSize.y, middlePos.z - halfSize.z);
 	}
-	
+
 	public Vector3f getRt() {
 		return new Vector3f(middlePos.x + halfSize.x, middlePos.y + halfSize.y, middlePos.z + halfSize.z);
 	}

+ 3 - 31
src/main/java/eu/tankernn/gameEngine/loader/obj/normalMapped/ModelDataNM.java

@@ -1,46 +1,18 @@
 package eu.tankernn.gameEngine.loader.obj.normalMapped;
 
-public class ModelDataNM {
+import eu.tankernn.gameEngine.loader.obj.ModelData;
 
-	private float[] vertices;
-	private float[] textureCoords;
-	private float[] normals;
+public class ModelDataNM extends ModelData {
 	private float[] tangents;
-	private int[] indices;
-	private float furthestPoint;
 
 	public ModelDataNM(float[] vertices, float[] textureCoords, float[] normals, float[] tangents, int[] indices,
 			float furthestPoint) {
-		this.vertices = vertices;
-		this.textureCoords = textureCoords;
-		this.normals = normals;
-		this.indices = indices;
-		this.furthestPoint = furthestPoint;
+		super(vertices, textureCoords, normals, indices, furthestPoint);
 		this.tangents = tangents;
 	}
 
-	public float[] getVertices() {
-		return vertices;
-	}
-
-	public float[] getTextureCoords() {
-		return textureCoords;
-	}
-	
 	public float[] getTangents(){
 		return tangents;
 	}
 
-	public float[] getNormals() {
-		return normals;
-	}
-
-	public int[] getIndices() {
-		return indices;
-	}
-
-	public float getFurthestPoint() {
-		return furthestPoint;
-	}
-
 }

+ 0 - 1
src/main/java/eu/tankernn/gameEngine/particles/Particle.java

@@ -36,7 +36,6 @@ public class Particle implements IPositionable {
 		this.lifeLength = lifeLength;
 		this.rotation = rotation;
 		this.scale = scale;
-		ParticleMaster.addParticle(this);
 	}
 
 	public ParticleTexture getTexture() {

+ 23 - 12
src/main/java/eu/tankernn/gameEngine/particles/ParticleMaster.java

@@ -14,14 +14,21 @@ import eu.tankernn.gameEngine.loader.Loader;
 import eu.tankernn.gameEngine.util.DistanceSorter;
 
 public class ParticleMaster {
-	private static Map<ParticleTexture, List<Particle>> particles = new HashMap<ParticleTexture, List<Particle>>();
-	private static ParticleRenderer renderer;
-	
-	public static void init(Loader loader, Matrix4f projectionMatrix) {
+	private Map<ParticleTexture, List<Particle>> particles = new HashMap<ParticleTexture, List<Particle>>();
+	private List<ParticleSystem> systems = new ArrayList<ParticleSystem>();
+	private ParticleRenderer renderer;
+
+	public ParticleMaster(Loader loader, Matrix4f projectionMatrix) {
 		renderer = new ParticleRenderer(loader, projectionMatrix);
 	}
-	
-	public static void update(Camera camera) {
+
+	public void update(Camera camera) {
+		for (ParticleSystem sys : systems) {
+			for (Particle particle : sys.generateParticles()) {
+				addParticle(particle);
+			}
+		}
+
 		Iterator<Entry<ParticleTexture, List<Particle>>> mapIterator = particles.entrySet().iterator();
 		while (mapIterator.hasNext()) {
 			Entry<ParticleTexture, List<Particle>> entry = mapIterator.next();
@@ -41,16 +48,16 @@ public class ParticleMaster {
 				DistanceSorter.sort(list, camera);
 		}
 	}
-	
-	public static void renderParticles(Camera camera) {
+
+	public void renderParticles(Camera camera) {
 		renderer.render(particles, camera);
 	}
-	
-	public static void cleanUp() {
+
+	public void cleanUp() {
 		renderer.cleanUp();
 	}
-	
-	public static void addParticle(Particle particle) {
+
+	public void addParticle(Particle particle) {
 		List<Particle> list = particles.get(particle.getTexture());
 		if (list == null) {
 			list = new ArrayList<Particle>();
@@ -58,4 +65,8 @@ public class ParticleMaster {
 		}
 		list.add(particle);
 	}
+
+	public void addSystem(ParticleSystem system) {
+		this.systems.add(system);
+	}
 }

+ 3 - 2
src/main/java/eu/tankernn/gameEngine/particles/ParticleShader.java

@@ -13,8 +13,9 @@ public class ParticleShader extends ShaderProgram {
 	protected UniformMatrix projectionMatrix = new UniformMatrix("projectionMatrix");
 
 	public ParticleShader() {
-		//																 0,					1,						5,				6
-		super(VERTEX_FILE, FRAGMENT_FILE, "position", "modelViewMatrix", "texOffsets", "blendFactor");
+		super(VERTEX_FILE, FRAGMENT_FILE, "position", "modelViewMatrix");
+		super.bindAttribute("texOffsets", 5);
+		super.bindAttribute("blendFactor", 6);
 		super.storeAllUniformLocations(numberOfRows, projectionMatrix);
 	}
 

+ 15 - 5
src/main/java/eu/tankernn/gameEngine/particles/ParticleSystem.java

@@ -1,11 +1,15 @@
 package eu.tankernn.gameEngine.particles;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.lwjgl.util.vector.Vector3f;
 
 import eu.tankernn.gameEngine.renderEngine.DisplayManager;
 
 public class ParticleSystem {
 	private float pps, speed, gravityComplient, lifeLength;
+	private Vector3f position;
 	
 	private ParticleTexture texture;
 	
@@ -17,25 +21,31 @@ public class ParticleSystem {
 		this.lifeLength = lifeLength;
 	}
 	
-	public void generateParticles(Vector3f systemCenter) {
+	public void setPosition(Vector3f systemCenter) {
+		this.position = systemCenter;
+	}
+	
+	public List<Particle> generateParticles() {
+		List<Particle> particles = new ArrayList<Particle>();
 		float delta = DisplayManager.getFrameTimeSeconds();
 		float particlesToCreate = pps * delta;
 		int count = (int) Math.floor(particlesToCreate);
 		float partialParticle = particlesToCreate % 1;
 		for (int i = 0; i < count; i++) {
-			emitParticle(systemCenter);
+			particles.add(createParticle(position));
 		}
 		if (Math.random() < partialParticle) {
-			emitParticle(systemCenter);
+			particles.add(createParticle(position));
 		}
+		return particles;
 	}
 	
-	private void emitParticle(Vector3f center) {
+	private Particle createParticle(Vector3f center) {
 		float dirX = (float) Math.random() * 2f - 1f;
 		float dirZ = (float) Math.random() * 2f - 1f;
 		Vector3f velocity = new Vector3f(dirX, 1, dirZ);
 		velocity.normalise();
 		velocity.scale(speed);
-		new Particle(texture, new Vector3f(center), velocity, gravityComplient, lifeLength, 0, 1);
+		return new Particle(texture, new Vector3f(center), velocity, gravityComplient, lifeLength, 0, 1);
 	}
 }

+ 7 - 2
src/main/java/eu/tankernn/gameEngine/postProcessing/ContrastChanger.java

@@ -11,9 +11,9 @@ public class ContrastChanger implements IPostProcessingEffect {
 		renderer = new ImageRenderer();
 	}
 	
-	public void render(Texture texture) {
+	public void render(Texture colorTexture, Texture brightTexture) {
 		shader.start();
-		texture.bindToUnit(0);
+		brightTexture.bindToUnit(0);
 		renderer.renderQuad();
 		shader.stop();
 	}
@@ -22,4 +22,9 @@ public class ContrastChanger implements IPostProcessingEffect {
 		renderer.cleanUp();
 		shader.cleanUp();
 	}
+
+	@Override
+	public Texture getOutputTexture() {
+		return renderer.getOutputTexture();
+	}
 }

+ 2 - 1
src/main/java/eu/tankernn/gameEngine/postProcessing/IPostProcessingEffect.java

@@ -3,6 +3,7 @@ package eu.tankernn.gameEngine.postProcessing;
 import eu.tankernn.gameEngine.loader.textures.Texture;
 
 public interface IPostProcessingEffect {
-	public void render(Texture texture);
+	public void render(Texture colorTexture, Texture brightTexture);
 	public void cleanUp();
+	public Texture getOutputTexture();
 }

+ 9 - 2
src/main/java/eu/tankernn/gameEngine/postProcessing/ImageRenderer.java

@@ -1,5 +1,6 @@
 package eu.tankernn.gameEngine.postProcessing;
 
+import org.lwjgl.opengl.Display;
 import org.lwjgl.opengl.GL11;
 
 import eu.tankernn.gameEngine.loader.textures.Texture;
@@ -9,10 +10,16 @@ public class ImageRenderer {
 	private Fbo fbo;
 
 	public ImageRenderer(int width, int height) {
-		this.fbo = new Fbo(width, height, Fbo.NONE);
+		this(new Fbo(width, height, Fbo.NONE));
 	}
 
-	public ImageRenderer() {}
+	public ImageRenderer() {
+		this(Display.getWidth(), Display.getHeight());
+	}
+	
+	public ImageRenderer(Fbo fbo) {
+		this.fbo = fbo;
+	}
 
 	public void renderQuad() {
 		if (fbo != null) {

+ 3 - 3
src/main/java/eu/tankernn/gameEngine/postProcessing/MultisampleMultitargetFbo.java

@@ -10,7 +10,7 @@ import org.lwjgl.opengl.GL20;
 import org.lwjgl.opengl.GL30;
 
 import eu.tankernn.gameEngine.loader.textures.TextureUtils;
-import eu.tankernn.gameEngine.renderEngine.DisplayManager;
+import eu.tankernn.gameEngine.settings.Settings;
 
 public class MultisampleMultitargetFbo extends Fbo {
 	
@@ -46,7 +46,7 @@ public class MultisampleMultitargetFbo extends Fbo {
 	protected int createMultisampleColorAttachment(int attachment) {
 		int colorBuffer = GL30.glGenRenderbuffers();
 		GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, colorBuffer);
-		GL30.glRenderbufferStorageMultisample(GL30.GL_RENDERBUFFER, DisplayManager.MULTISAMPLING, GL11.GL_RGBA8, width, height);
+		GL30.glRenderbufferStorageMultisample(GL30.GL_RENDERBUFFER, Settings.MULTISAMPLING, GL11.GL_RGBA8, width, height);
 		GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, attachment, GL30.GL_RENDERBUFFER,
 				colorBuffer);
 		return colorBuffer;
@@ -56,7 +56,7 @@ public class MultisampleMultitargetFbo extends Fbo {
 	protected void createDepthBufferAttachment() {
 		depthBuffer = GL30.glGenRenderbuffers();
 		GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBuffer);
-		GL30.glRenderbufferStorageMultisample(GL30.GL_RENDERBUFFER, DisplayManager.MULTISAMPLING, GL14.GL_DEPTH_COMPONENT24, width, height);
+		GL30.glRenderbufferStorageMultisample(GL30.GL_RENDERBUFFER, Settings.MULTISAMPLING, GL14.GL_DEPTH_COMPONENT24, width, height);
 		GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER,
 				depthBuffer);
 	}

+ 23 - 31
src/main/java/eu/tankernn/gameEngine/postProcessing/PostProcessing.java

@@ -1,5 +1,8 @@
 package eu.tankernn.gameEngine.postProcessing;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.lwjgl.opengl.Display;
 import org.lwjgl.opengl.GL11;
 
@@ -12,61 +15,50 @@ import eu.tankernn.gameEngine.postProcessing.gaussianBlur.VerticalBlur;
 import eu.tankernn.gameEngine.renderEngine.RawModel;
 
 public class PostProcessing {
-	
+
 	private static final int blurFactor = 2;
-	
-	private static final float[] POSITIONS = {-1, 1, -1, -1, 1, 1, 1, -1};
+
+	private static final float[] POSITIONS = { -1, 1, -1, -1, 1, 1, 1, -1 };
 	private static RawModel quad;
-	private static ContrastChanger contrastChanger;
-	private static HorizontalBlur hBlur[] = new HorizontalBlur[blurFactor];
-	private static VerticalBlur vBlur[] = new VerticalBlur[blurFactor];
-	private static BrightFilter brightFilter;
+	private static List<IPostProcessingEffect> effects = new ArrayList<IPostProcessingEffect>();
 	private static CombineFilter combineFilter;
 	
 	public static void init(Loader loader) {
 		quad = loader.loadToVAO(POSITIONS, 2);
-		contrastChanger = new ContrastChanger();
+		effects.add(new ContrastChanger());
 		for (int i = 0; i < blurFactor; i++) {
 			int temp = i + 1;
-			hBlur[i] = new HorizontalBlur(Display.getWidth() / temp, Display.getHeight() / temp);
-			vBlur[i] = new VerticalBlur(Display.getWidth() / temp, Display.getHeight() / temp);
+			effects.add(new HorizontalBlur(Display.getWidth() / temp, Display.getHeight() / temp));
+			effects.add(new VerticalBlur(Display.getWidth() / temp, Display.getHeight() / temp));
 		}
-		brightFilter = new BrightFilter(Display.getWidth() / 2, Display.getHeight() / 2);
+		effects.add(new BrightFilter(Display.getWidth() / 2, Display.getHeight() / 2));
 		combineFilter = new CombineFilter();
 	}
-	
+
 	public static void doPostProcessing(Texture colorTexture, Texture brightTexture) {
-		start();
-		//brightFilter.render(colorTexture);
-		Texture bloomTexture = brightTexture;
-		for (int i = 0; i < blurFactor; i++) {
-			hBlur[i].render(bloomTexture);
-			vBlur[i].render(hBlur[i].getOutputTexture());
-			bloomTexture = vBlur[i].getOutputTexture();
+		for (IPostProcessingEffect effect : effects) {
+			effect.render(colorTexture, brightTexture);
+			brightTexture = effect.getOutputTexture();
 		}
-		combineFilter.render(colorTexture, bloomTexture);
-		//contrastChanger.render(bloomTexture);
+		
+		start();
+		combineFilter.render(colorTexture, brightTexture);
 		end();
 	}
-	
+
 	public static void cleanUp() {
-		contrastChanger.cleanUp();
-		for (int i = 0; i < blurFactor; i++) {
-			hBlur[i].cleanUp();
-			vBlur[i].cleanUp();
-		}
-		brightFilter.cleanUp();
+		effects.forEach(p -> p.cleanUp());
 		combineFilter.cleanUp();
 	}
-	
+
 	private static void start() {
 		quad.bind(0);
 		GL11.glDisable(GL11.GL_DEPTH_TEST);
 	}
-	
+
 	private static void end() {
 		GL11.glEnable(GL11.GL_DEPTH_TEST);
 		quad.unbind(0);
 	}
-	
+
 }

+ 3 - 2
src/main/java/eu/tankernn/gameEngine/postProcessing/bloom/BrightFilter.java

@@ -14,9 +14,10 @@ public class BrightFilter implements IPostProcessingEffect {
 		renderer = new ImageRenderer(width, height);
 	}
 	
-	public void render(Texture texture){
+	@Override
+	public void render(Texture colorTexture, Texture brightTexture) {
 		shader.start();
-		texture.bindToUnit(0);
+		colorTexture.bindToUnit(0);
 		renderer.renderQuad();
 		shader.stop();
 	}

+ 1 - 1
src/main/java/eu/tankernn/gameEngine/postProcessing/bloom/CombineFilter.java

@@ -13,7 +13,7 @@ public class CombineFilter {
 		shader.start();
 		shader.connectTextureUnits();
 		shader.stop();
-		renderer = new ImageRenderer();
+		renderer = new ImageRenderer(null);
 	}
 	
 	public void render(Texture colorTexture, Texture bloomTexture){

+ 1 - 1
src/main/java/eu/tankernn/gameEngine/postProcessing/gaussianBlur/HorizontalBlur.java

@@ -17,7 +17,7 @@ public class HorizontalBlur implements IPostProcessingEffect {
 		renderer = new ImageRenderer(targetFboWidth, targetFboHeight);
 	}
 	
-	public void render(Texture texture){
+	public void render(Texture colorTexture, Texture texture){
 		shader.start();
 		texture.bindToUnit(0);
 		renderer.renderQuad();

+ 1 - 1
src/main/java/eu/tankernn/gameEngine/postProcessing/gaussianBlur/VerticalBlur.java

@@ -17,7 +17,7 @@ public class VerticalBlur implements IPostProcessingEffect {
 		shader.stop();
 	}
 	
-	public void render(Texture texture){
+	public void render(Texture colorTexture, Texture texture){
 		shader.start();
 		texture.bindToUnit(0);
 		renderer.renderQuad();

+ 0 - 1
src/main/java/eu/tankernn/gameEngine/renderEngine/DisplayManager.java

@@ -23,7 +23,6 @@ public class DisplayManager {
 	private static final int WIDTH = 1600;
 	private static final int HEIGHT = 900;
 	private static final int FPS_CAP = 60;
-	public static final int MULTISAMPLING = 8;
 	
 	private static long lastFrameTime;
 	private static float delta;

+ 14 - 2
src/main/java/eu/tankernn/gameEngine/renderEngine/RawModel.java

@@ -5,14 +5,18 @@ import org.lwjgl.opengl.GL15;
 import org.lwjgl.opengl.GL20;
 import org.lwjgl.opengl.GL30;
 
+import eu.tankernn.gameEngine.loader.models.AABB;
+import eu.tankernn.gameEngine.loader.obj.ModelData;
+
 public class RawModel {
 	
 	private static final int BYTES_PER_FLOAT = 4;
-
+	
 	public final int id;
 	private Vbo dataVbo;
 	private Vbo indexVbo;
 	private int indexCount;
+	private AABB boundingBox;
 
 	public static RawModel create() {
 		int id = GL30.glGenVertexArrays();
@@ -62,6 +66,11 @@ public class RawModel {
 		return this;
 	}
 	
+	public RawModel withBoundingBox(ModelData data) {
+		this.boundingBox = new AABB(data);
+		return this;
+	}
+	
 	public void delete() {
 		GL30.glDeleteVertexArrays(id);
 		dataVbo.delete();
@@ -134,5 +143,8 @@ public class RawModel {
 		}
 		return interleavedBuffer;
 	}
-
+	
+	public AABB getBoundingBox() {
+		return this.boundingBox;
+	}
 }

+ 26 - 16
src/main/java/eu/tankernn/gameEngine/renderEngine/font/TextMaster.java

@@ -11,42 +11,52 @@ import eu.tankernn.gameEngine.font.meshCreator.TextMeshData;
 import eu.tankernn.gameEngine.loader.Loader;
 
 public class TextMaster {
-	
-	private static Loader loader;
-	private static Map<FontType, List<GUIText>> texts = new HashMap<FontType, List<GUIText>>();
-	private static FontRenderer renderer;
-	
-	public static void init(Loader load) {
+
+	private Loader loader;
+	private Map<FontType, List<GUIText>> texts = new HashMap<FontType, List<GUIText>>();
+	private FontRenderer renderer;
+
+	public TextMaster(Loader load) {
 		renderer = new FontRenderer();
 		loader = load;
 	}
-	
-	public static void render() {
+
+	public void render() {
+		for (List<GUIText> l : texts.values()) {
+			for (GUIText t : l) {
+				if (t.isDirty())
+					updateText(t);
+			}
+		}
 		renderer.render(texts);
 	}
-	
-	public static void loadText(GUIText text) {
+
+	public void updateText(GUIText text) {
 		FontType font = text.getFont();
 		TextMeshData data = font.loadText(text);
 		int vao = loader.loadToVAO(data.getVertexPositions(), data.getTextureCoords());
 		text.setMeshInfo(vao, data.getVertexCount());
-		List<GUIText> textBatch = texts.get(font);
+	}
+
+	public void loadText(GUIText text) {
+		updateText(text);
+		List<GUIText> textBatch = texts.get(text.getFont());
 		if (textBatch == null) {
 			textBatch = new ArrayList<GUIText>();
-			texts.put(font, textBatch);
+			texts.put(text.getFont(), textBatch);
 		}
 		textBatch.add(text);
 	}
-	
-	public static void removeText(GUIText text) {
+
+	public void removeText(GUIText text) {
 		List<GUIText> textBatch = texts.get(text.getFont());
 		textBatch.remove(text);
 		if (textBatch.isEmpty()) {
 			texts.remove(text.getFont());
 		}
 	}
-	
-	public static void cleanUp() {
+
+	public void cleanUp() {
 		renderer.cleanUp();
 	}
 }

+ 5 - 1
src/main/java/eu/tankernn/gameEngine/renderEngine/shaders/ShaderProgram.java

@@ -89,10 +89,14 @@ public class ShaderProgram {
 
 	private void bindAttributes(String[] inVariables) {
 		for (int i = 0; i < inVariables.length; i++) {
-			GL20.glBindAttribLocation(programID, i, inVariables[i]);
+			bindAttribute(inVariables[i], i);
 		}
 	}
 
+	protected void bindAttribute(String variable, int attributeId) {
+		GL20.glBindAttribLocation(programID, attributeId, variable);
+	}
+
 	private int loadShader(String file, int type) {
 		StringBuilder shaderSource = new StringBuilder();
 		try {

+ 1 - 1
src/main/java/eu/tankernn/gameEngine/renderEngine/shadows/ShadowMapMasterRenderer.java

@@ -25,7 +25,7 @@ import eu.tankernn.gameEngine.loader.textures.Texture;
  */
 public class ShadowMapMasterRenderer {
 
-	public static final int SHADOW_MAP_SIZE = 1024 * 16;
+	public static final int SHADOW_MAP_SIZE = 1024 * 4;
 
 	private ShadowFrameBuffer shadowFbo;
 	private ShadowShader shader;

+ 1 - 0
src/main/java/eu/tankernn/gameEngine/settings/Settings.java

@@ -14,4 +14,5 @@ public class Settings {
 	public static final float TERRAIN_SIZE = 800;
 	
 	public static final float ANISOTROPIC_FILTERING_AMOUNT = 4f;
+	public static final int MULTISAMPLING = 2;
 }

+ 16 - 18
src/main/java/eu/tankernn/gameEngine/terrains/TerrainPack.java

@@ -15,6 +15,7 @@ import java.util.concurrent.Future;
 
 import org.apache.commons.lang3.tuple.Pair;
 
+import eu.tankernn.gameEngine.MainLoop;
 import eu.tankernn.gameEngine.loader.Loader;
 import eu.tankernn.gameEngine.loader.textures.TerrainTexturePack;
 import eu.tankernn.gameEngine.loader.textures.Texture;
@@ -23,7 +24,7 @@ import eu.tankernn.gameEngine.util.IPositionable;
 
 public class TerrainPack {
 	private Map<Pair<Integer, Integer>, Terrain> terrains = new HashMap<Pair<Integer, Integer>, Terrain>();
-	private List<Future<TerrainModelData>> waitingData = new ArrayList<Future<TerrainModelData>>();
+	private Map<Pair<Integer, Integer>, Future<TerrainModelData>> waitingData = new HashMap<Pair<Integer, Integer>, Future<TerrainModelData>>();
 	private List<IPositionable> waitingForHeight = new ArrayList<IPositionable>();
 	private ExecutorService executor = Executors.newCachedThreadPool();
 	private int seed;
@@ -88,29 +89,28 @@ public class TerrainPack {
 		int newX = currentTerrain.getLeft();
 		int newZ = currentTerrain.getRight();
 
-		for (Future<TerrainModelData> futureData : waitingData) {
-			if (futureData.isDone()) {
-				System.out.println("Adding terrain.");
+		waitingData.values().removeIf(f -> {
+			if (f.isDone()) {
+				if (MainLoop.DEBUG)
+					System.out.println("Adding terrain");
 				try {
-					TerrainModelData data = futureData.get();
+					TerrainModelData data = f.get();
 					terrains.put(Pair.of(data.getGridX(), data.getGridZ()),
 							new Terrain(data.getGridX(), data.getGridZ(), loader, texturePack, blendMap, data));
 				} catch (InterruptedException | ExecutionException e) {
 					e.printStackTrace();
 				}
-			}
-		}
-		
+				return true;
+			} else
+				return false;
+		});
+
 		waitingForHeight.removeIf(p -> {
 			if (!terrains.containsKey(getGridPosByWorldPos(p.getPosition().x, p.getPosition().z)))
 				return false;
 			p.getPosition().setY(getTerrainHeightByWorldPos(p.getPosition().x, p.getPosition().z));
 			return true;
 		});
-		
-		// FIXME If a task finishes between the loop above and this statement,
-		// the terrain will never be added.
-		waitingData.removeIf(f -> f.isDone());
 
 		if (lastX != newX || lastZ != newZ || terrains.isEmpty()) {
 			List<Pair<Integer, Integer>> toGenerate = new ArrayList<Pair<Integer, Integer>>();
@@ -120,7 +120,7 @@ public class TerrainPack {
 					toGenerate.add(Pair.of(x, z));
 
 			for (Pair<Integer, Integer> pair : toGenerate) {
-				if (terrains.containsKey(pair) | pair.getLeft() < 0 | pair.getRight() < 0)
+				if (waitingData.containsKey(pair) | terrains.containsKey(pair) | pair.getLeft() < 0 | pair.getRight() < 0)
 					continue;
 
 				Callable<TerrainModelData> task = new Callable<TerrainModelData>() {
@@ -130,18 +130,16 @@ public class TerrainPack {
 					}
 				};
 
-				waitingData.add(executor.submit(task));
+				waitingData.put(pair, executor.submit(task));
 			}
-			
+
 			for (Pair<Integer, Integer> pair : terrains.keySet()) {
 				if (!toGenerate.contains(pair)) {
 					terrains.get(pair).delete();
 				}
 			}
-			
+
 			terrains.keySet().retainAll(toGenerate);
-			
-			System.out.println(terrains.size());
 
 			lastX = newX;
 			lastZ = newZ;