Browse Source

Gaussian blur and native exporting

Added guassian blur post processing effect.
Made native libraries get automatically exported when application is
run.
Tankernn 8 years ago
parent
commit
50e70b7fec

+ 38 - 0
src/main/java/eu/tankernn/gameEngine/gaussianBlur/HorizontalBlur.java

@@ -0,0 +1,38 @@
+package eu.tankernn.gameEngine.gaussianBlur;
+
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL13;
+
+import eu.tankernn.gameEngine.postProcessing.ImageRenderer;
+
+public class HorizontalBlur {
+	
+	private ImageRenderer renderer;
+	private HorizontalBlurShader shader;
+	
+	public HorizontalBlur(int targetFboWidth, int targetFboHeight){
+		shader = new HorizontalBlurShader();
+		shader.start();
+		shader.loadTargetWidth(targetFboWidth);
+		shader.stop();
+		renderer = new ImageRenderer(targetFboWidth, targetFboHeight);
+	}
+	
+	public void render(int texture){
+		shader.start();
+		GL13.glActiveTexture(GL13.GL_TEXTURE0);
+		GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
+		renderer.renderQuad();
+		shader.stop();
+	}
+	
+	public int getOutputTexture(){
+		return renderer.getOutputTexture();
+	}
+	
+	public void cleanUp(){
+		renderer.cleanUp();
+		shader.cleanUp();
+	}
+
+}

+ 30 - 0
src/main/java/eu/tankernn/gameEngine/gaussianBlur/HorizontalBlurShader.java

@@ -0,0 +1,30 @@
+package eu.tankernn.gameEngine.gaussianBlur;
+
+import eu.tankernn.gameEngine.shaders.ShaderProgram;
+
+public class HorizontalBlurShader extends ShaderProgram {
+
+	private static final String VERTEX_FILE = "/eu/tankernn/gameEngine/gaussianBlur/horizontalBlurVertex.glsl";
+	private static final String FRAGMENT_FILE = "/eu/tankernn/gameEngine/gaussianBlur/blurFragment.glsl";
+	
+	private int location_targetWidth;
+	
+	protected HorizontalBlurShader() {
+		super(VERTEX_FILE, FRAGMENT_FILE);
+	}
+
+	protected void loadTargetWidth(float width){
+		super.loadFloat(location_targetWidth, width);
+	}
+	
+	@Override
+	protected void getAllUniformLocations() {
+		location_targetWidth = super.getUniformLocation("targetWidth");
+	}
+
+	@Override
+	protected void bindAttributes() {
+		super.bindAttribute(0, "position");
+	}
+	
+}

+ 38 - 0
src/main/java/eu/tankernn/gameEngine/gaussianBlur/VerticalBlur.java

@@ -0,0 +1,38 @@
+package eu.tankernn.gameEngine.gaussianBlur;
+
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL13;
+
+import eu.tankernn.gameEngine.postProcessing.ImageRenderer;
+
+public class VerticalBlur {
+	
+	private ImageRenderer renderer;
+	private VerticalBlurShader shader;
+	
+	public VerticalBlur(int targetFboWidth, int targetFboHeight){
+		shader = new VerticalBlurShader();
+		renderer = new ImageRenderer(targetFboWidth, targetFboHeight);
+		shader.start();
+		shader.loadTargetHeight(targetFboHeight);
+		shader.stop();
+	}
+
+	
+	public void render(int texture){
+		shader.start();
+		GL13.glActiveTexture(GL13.GL_TEXTURE0);
+		GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
+		renderer.renderQuad();
+		shader.stop();
+	}
+	
+	public int getOutputTexture(){
+		return renderer.getOutputTexture();
+	}
+	
+	public void cleanUp(){
+		renderer.cleanUp();
+		shader.cleanUp();
+	}
+}

+ 29 - 0
src/main/java/eu/tankernn/gameEngine/gaussianBlur/VerticalBlurShader.java

@@ -0,0 +1,29 @@
+package eu.tankernn.gameEngine.gaussianBlur;
+
+import eu.tankernn.gameEngine.shaders.ShaderProgram;
+
+public class VerticalBlurShader extends ShaderProgram{
+
+	private static final String VERTEX_FILE = "/eu/tankernn/gameEngine/gaussianBlur/verticalBlurVertex.glsl";
+	private static final String FRAGMENT_FILE = "/eu/tankernn/gameEngine/gaussianBlur/blurFragment.glsl";
+	
+	private int location_targetHeight;
+	
+	protected VerticalBlurShader() {
+		super(VERTEX_FILE, FRAGMENT_FILE);
+	}
+	
+	protected void loadTargetHeight(float height){
+		super.loadFloat(location_targetHeight, height);
+	}
+
+	@Override
+	protected void getAllUniformLocations() {	
+		location_targetHeight = super.getUniformLocation("targetHeight");
+	}
+
+	@Override
+	protected void bindAttributes() {
+		super.bindAttribute(0, "position");
+	}
+}

+ 26 - 0
src/main/java/eu/tankernn/gameEngine/gaussianBlur/blurFragment.glsl

@@ -0,0 +1,26 @@
+#version 150
+
+out vec4 out_colour;
+
+const int blurFactor = 11;
+
+in vec2 blurTextureCoords[blurFactor];
+
+uniform sampler2D originalTexture;
+
+void main(void){
+	
+	out_colour = vec4(0.0);
+	
+	out_colour += texture(originalTexture, blurTextureCoords[0]) * 0.0093;
+    out_colour += texture(originalTexture, blurTextureCoords[1]) * 0.028002;
+    out_colour += texture(originalTexture, blurTextureCoords[2]) * 0.065984;
+    out_colour += texture(originalTexture, blurTextureCoords[3]) * 0.121703;
+    out_colour += texture(originalTexture, blurTextureCoords[4]) * 0.175713;
+    out_colour += texture(originalTexture, blurTextureCoords[5]) * 0.198596;
+    out_colour += texture(originalTexture, blurTextureCoords[6]) * 0.175713;
+    out_colour += texture(originalTexture, blurTextureCoords[7]) * 0.121703;
+    out_colour += texture(originalTexture, blurTextureCoords[8]) * 0.065984;
+    out_colour += texture(originalTexture, blurTextureCoords[9]) * 0.028002;
+    out_colour += texture(originalTexture, blurTextureCoords[10]) * 0.0093;
+}

+ 23 - 0
src/main/java/eu/tankernn/gameEngine/gaussianBlur/horizontalBlurVertex.glsl

@@ -0,0 +1,23 @@
+#version 150
+
+in vec2 position;
+
+const int blurFactor = 11;
+
+out vec2 blurTextureCoords[blurFactor]; //11 is number of samples
+
+uniform float targetWidth;
+
+void main(void){
+
+	gl_Position = vec4(position, 0.0, 1.0);
+	vec2 centerTexCoords = position * 0.5 + 0.5;
+	float pixelSize = 1.0 / targetWidth;
+	
+	int offset = (blurFactor-1) / 2;
+	
+	for (int i = -offset; i <= offset; i++) {
+		blurTextureCoords[i + offset] = centerTexCoords + vec2(pixelSize * i, 0.0);
+	}
+	
+}

+ 24 - 0
src/main/java/eu/tankernn/gameEngine/gaussianBlur/verticalBlurVertex.glsl

@@ -0,0 +1,24 @@
+#version 150
+
+in vec2 position;
+
+const int blurFactor = 11; // This cannot be changed
+
+out vec2 blurTextureCoords[blurFactor];
+
+uniform float targetHeight;
+
+void main(void){
+
+	gl_Position = vec4(position, 0.0, 1.0);
+	vec2 centerTexCoords = position * 0.5 + 0.5;
+	
+	float pixelSize = 1.0 / targetHeight;
+	
+	int offset = (blurFactor-1) / 2;
+	
+	for (int i = -offset; i <= offset; i++) {
+		blurTextureCoords[i + offset] = centerTexCoords + vec2(0.0, pixelSize * i);
+	}
+
+}

+ 0 - 1
src/main/java/eu/tankernn/gameEngine/postProcessing/Fbo.java

@@ -60,7 +60,6 @@ public class Fbo {
 	 * rendered after this will be rendered to this FBO, and not to the screen.
 	 */
 	public void bindFrameBuffer() {
-		GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
 		GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, frameBuffer);
 		GL11.glViewport(0, 0, width, height);
 	}

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

@@ -6,13 +6,13 @@ public class ImageRenderer {
 
 	private Fbo fbo;
 
-	protected ImageRenderer(int width, int height) {
+	public ImageRenderer(int width, int height) {
 		this.fbo = new Fbo(width, height, Fbo.NONE);
 	}
 
-	protected ImageRenderer() {}
+	public ImageRenderer() {}
 
-	protected void renderQuad() {
+	public void renderQuad() {
 		if (fbo != null) {
 			fbo.bindFrameBuffer();
 		}
@@ -23,11 +23,11 @@ public class ImageRenderer {
 		}
 	}
 
-	protected int getOutputTexture() {
+	public int getOutputTexture() {
 		return fbo.getColourTexture();
 	}
 
-	protected void cleanUp() {
+	public void cleanUp() {
 		if (fbo != null) {
 			fbo.cleanUp();
 		}

+ 24 - 2
src/main/java/eu/tankernn/gameEngine/postProcessing/PostProcessing.java

@@ -1,31 +1,53 @@
 package eu.tankernn.gameEngine.postProcessing;
 
+import org.lwjgl.opengl.Display;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.opengl.GL20;
 import org.lwjgl.opengl.GL30;
 
+import eu.tankernn.gameEngine.gaussianBlur.HorizontalBlur;
+import eu.tankernn.gameEngine.gaussianBlur.VerticalBlur;
 import eu.tankernn.gameEngine.models.RawModel;
 import eu.tankernn.gameEngine.renderEngine.Loader;
 
 public class PostProcessing {
 	
+	private static final int blurFactor = 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];
 	
 	public static void init(Loader loader) {
 		quad = loader.loadToVAO(POSITIONS, 2);
 		contrastChanger = 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);
+		}
 	}
 	
 	public static void doPostProcessing(int colorTexture) {
 		start();
-		contrastChanger.render(colorTexture);
+		int currentTexture = colorTexture;
+		for (int i = 0; i < blurFactor; i++) {
+			hBlur[i].render(currentTexture);
+			vBlur[i].render(hBlur[i].getOutputTexture());
+			currentTexture = vBlur[i].getOutputTexture();
+		}
+		contrastChanger.render(currentTexture);
 		end();
 	}
 	
 	public static void cleanUp() {
-		
+		contrastChanger.cleanUp();
+		for (int i = 0; i < blurFactor; i++) {
+			hBlur[i].cleanUp();
+			vBlur[i].cleanUp();
+		}
 	}
 	
 	private static void start() {

+ 79 - 9
src/main/java/eu/tankernn/gameEngine/tester/MainLoop.java

@@ -1,9 +1,19 @@
 package eu.tankernn.gameEngine.tester;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
 import java.util.Random;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import javax.swing.JOptionPane;
 
 import org.lwjgl.opengl.Display;
 import org.lwjgl.util.vector.Vector2f;
@@ -49,12 +59,8 @@ public class MainLoop {
 	private static final int SEED = 1235;
 	
 	public static void main(String[] args) {
-		File nativeDir = new File("natives");
-		if (nativeDir.exists()) {
-			System.setProperty("org.lwjgl.librarypath", nativeDir.getAbsolutePath());
-		}
+		exportNatives();
 		
-			
 		List<Entity> entities = new ArrayList<Entity>();
 		List<Entity> normalMapEntities = new ArrayList<Entity>();
 		TerrainPack terrainPack = new TerrainPack();
@@ -99,10 +105,10 @@ public class MainLoop {
 		List<Light> lights = new ArrayList<Light>();
 		lights.add(sun);
 		lights.add(flashLight);
-		lights.add(new Light(new Vector3f(10, 100,0), new Vector3f(0,1,0)));
-		lights.add(new Light(new Vector3f(20, 100,0), new Vector3f(0,0,1)));
-		lights.add(new Light(new Vector3f(30, 100,0), new Vector3f(1,0,0)));
-		lights.add(new Light(new Vector3f(40, 100,0), new Vector3f(1,1,0)));
+		lights.add(new Light(new Vector3f(10, 100, 0), new Vector3f(0, 1, 0)));
+		lights.add(new Light(new Vector3f(20, 100, 0), new Vector3f(0, 0, 1)));
+		lights.add(new Light(new Vector3f(30, 100, 0), new Vector3f(1, 0, 0)));
+		lights.add(new Light(new Vector3f(40, 100, 0), new Vector3f(1, 1, 0)));
 		
 		// ### Terrain textures ###
 		
@@ -219,4 +225,68 @@ public class MainLoop {
 		loader.cleanUp();
 		DisplayManager.closeDisplay();
 	}
+	
+	private static void exportNatives() {
+		File nativeDir = new File("natives");
+		if (!nativeDir.isDirectory() || nativeDir.list().length == 0) {
+			try {
+				nativeDir.mkdir();
+				
+				File jarFile = null;
+				try {
+					jarFile = new File(MainLoop.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
+				} catch (URISyntaxException e1) {
+					e1.printStackTrace();
+				}
+				
+				if (jarFile != null && jarFile.isFile()) { // Run with JAR file
+					final JarFile jar = new JarFile(jarFile);
+					final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
+					while (entries.hasMoreElements()) {
+						final String name = entries.nextElement().getName();
+						if (name.endsWith(".dll") || name.endsWith(".so") || name.endsWith(".dylib") || name.endsWith(".jnilb")) { //filter according to the path
+							System.out.println(name);
+							try {
+								exportFile(name, "natives");
+							} catch (Exception e) {
+								e.printStackTrace();
+							}
+						}
+					}
+					jar.close();
+					System.setProperty("org.lwjgl.librarypath", nativeDir.getAbsolutePath());
+				} else { // Run with IDE
+				}
+			} catch (IOException e) {
+				JOptionPane.showMessageDialog(null, "Could not export natives. Execute in terminal to see full error output.", "Export natives", JOptionPane.ERROR_MESSAGE);
+				e.printStackTrace();
+			}
+		}
+	}
+	
+	private static String exportFile(String classPath, String targetDir) throws Exception {
+		InputStream stream = null;
+		OutputStream resStreamOut = null;
+		try {
+			stream = MainLoop.class.getResourceAsStream("/" + classPath);//note that each / is a directory down in the "jar tree" been the jar the root of the tree
+			if (stream == null) {
+				throw new Exception("Cannot get resource \"" + classPath + "\" from Jar file.");
+			}
+			
+			int readBytes;
+			byte[] buffer = new byte[4096];
+			File outFile = new File(targetDir + "/" + classPath);
+			outFile.getParentFile().mkdirs();
+			resStreamOut = new FileOutputStream(outFile);
+			while ((readBytes = stream.read(buffer)) > 0) {
+				resStreamOut.write(buffer, 0, readBytes);
+			}
+			stream.close();
+			resStreamOut.close();
+		} catch (Exception ex) {
+			throw ex;
+		}
+		
+		return classPath;
+	}
 }