Commits

Roi Atalla committed 90e3d7d

Preliminary work on Chapter 12.

Comments (0)

Files changed (16)

src/main/java/com/ra4king/opengl/GLProgram.java

 		}
 	}
 	
-	public void checkGLError(String after) {
+	public void checkGLError(String event) {
 		int error;
 		while((error = glGetError()) != GL_NO_ERROR)
-			throw new RuntimeException("OpenGL Error during " + after + ": " + gluErrorString(error));
+			throw new RuntimeException("OpenGL Error during " + event + ": " + gluErrorString(error));
 	}
 	
 	public int getWidth() {

src/main/java/com/ra4king/opengl/arcsynthesis/gl33/chapter12/LightManager.java

 package com.ra4king.opengl.arcsynthesis.gl33.chapter12;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.security.auth.x500.X500Principal;
+
+import com.ra4king.opengl.util.Timer;
+import com.ra4king.opengl.util.Timer.Type;
+import com.ra4king.opengl.util.interpolators.ConstVelLinearInterpolatorVector;
+import com.ra4king.opengl.util.interpolators.TimedLinearInterpolatorVector;
+import com.ra4king.opengl.util.interpolators.TimedLinearInterpolatorf;
+import com.ra4king.opengl.util.math.Vector3;
 import com.ra4king.opengl.util.math.Vector4;
 
 public class LightManager {
 	public final int NUMBER_OF_LIGHTS = 4;
 	public final int NUMBER_OF_POINT_LIGHTS = NUMBER_OF_LIGHTS - 1;
 	
+	private Timer sunTimer;
+	private TimedLinearInterpolatorVector<Vector4> ambientInterpolator;
+	private TimedLinearInterpolatorVector<Vector4> backgroundInterpolator;
+	private TimedLinearInterpolatorVector<Vector4> sunlightInterpolator;
+	private TimedLinearInterpolatorf maxIntensityInterpolator;
+	
+	private ArrayList<ConstVelLinearInterpolatorVector<Vector3>> lightPos;
+	private ArrayList<Vector4> lightIntensity;
+	private ArrayList<Timer> lightTimers;
+	private HashMap<String,Timer> extraTimers;
+	
+	private final float halfLightDistance = 70;
+	private float lightAttenuation = 1f / (halfLightDistance * halfLightDistance);
+	
+	private float lightHeight = 10.5f;
+	private float lightRadius = 70;
+	
+	public LightManager() {
+		sunTimer = new Timer(Type.LOOP, 30);
+		ambientInterpolator = new TimedLinearInterpolatorVector<>();
+		backgroundInterpolator = new TimedLinearInterpolatorVector<>();
+		sunlightInterpolator = new TimedLinearInterpolatorVector<>();
+		maxIntensityInterpolator = new TimedLinearInterpolatorf();
+		
+		lightTimers = new ArrayList<>();
+		
+		lightPos = new ArrayList<>();
+		for(int a = 0; a < NUMBER_OF_POINT_LIGHTS; a++)
+			lightPos.add(new ConstVelLinearInterpolatorVector<Vector3>());
+		
+		lightIntensity = new ArrayList<>();
+		for(int a = 0; a < NUMBER_OF_POINT_LIGHTS; a++)
+			lightIntensity.add(new Vector4(0.2f, 0.2f, 0.2f, 1));
+		
+		ArrayList<Vector3> posValues = new ArrayList<>();
+		posValues.add(new Vector3(-50, 30, 70));
+		posValues.add(new Vector3(-70, 30, 50));
+		posValues.add(new Vector3(-70, 30, -50));
+		posValues.add(new Vector3(-50, 30, -70));
+		posValues.add(new Vector3(50, 30, -70));
+		posValues.add(new Vector3(70, 30, -50));
+		posValues.add(new Vector3(70, 30, 50));
+		posValues.add(new Vector3(50, 30, 70));
+		lightPos.get(0).setValues(posValues);
+		lightTimers.add(new Timer(Timer.Type.LOOP, 15));
+		
+		posValues.clear();
+		posValues.add(new Vector3(100, 6, 75));
+		posValues.add(new Vector3(90, 8, 90));
+		posValues.add(new Vector3(75, 10, 100));
+		posValues.add(new Vector3(60, 12, 90));
+		posValues.add(new Vector3(50, 14, 75));
+		posValues.add(new Vector3(60, 16, 60));
+		posValues.add(new Vector3(75, 18, 50));
+		posValues.add(new Vector3(90, 20, 60));
+		posValues.add(new Vector3(100, 22, 75));
+		posValues.add(new Vector3(90, 24, 90));
+		posValues.add(new Vector3(75, 26, 100));
+		posValues.add(new Vector3(60, 28, 90));
+		posValues.add(new Vector3(50, 30, 75));
+		
+		posValues.add(new Vector3(105, 9, -70));
+		posValues.add(new Vector3(105, 10, -90));
+		posValues.add(new Vector3(72, 20, -90));
+		posValues.add(new Vector3(72, 22, -70));
+		posValues.add(new Vector3(105, 32, -70));
+		posValues.add(new Vector3(105, 34, -90));
+		posValues.add(new Vector3(72, 44, -90));
+		
+		lightPos.get(1).setValues(posValues);
+		lightTimers.add(new Timer(Timer.Type.LOOP, 25));
+		
+		posValues.clear();
+		posValues.add(new Vector3(-7, 35, 1));
+		posValues.add(new Vector3(8, 40, -14));
+		posValues.add(new Vector3(-7, 45, -29));
+		posValues.add(new Vector3(-22, 50, -14));
+		posValues.add(new Vector3(-7, 55, 1));
+		posValues.add(new Vector3(8, 60, -14));
+		posValues.add(new Vector3(-7, 65, -29));
+		
+		posValues.add(new Vector3(-83, 30, -92));
+		posValues.add(new Vector3(-98, 27, -77));
+		posValues.add(new Vector3(-83, 24, -62));
+		posValues.add(new Vector3(-68, 21, -77));
+		posValues.add(new Vector3(-83, 18, -92));
+		posValues.add(new Vector3(-98, 15, -77));
+		
+		posValues.add(new Vector3(-50, 8, 25));
+		posValues.add(new Vector3(-59.5f, 4, 65));
+		posValues.add(new Vector3(-59.5f, 4, 78));
+		posValues.add(new Vector3(-45, 4, 82));
+		posValues.add(new Vector3(-40, 4, 50));
+		posValues.add(new Vector3(-70, 20, 40));
+		posValues.add(new Vector3(-60, 20, 90));
+		posValues.add(new Vector3(-40, 25, 90));
+		
+		lightPos.get(2).setValues(posValues);
+		lightTimers.add(new Timer(Timer.Type.LOOP, 15));
+	}
+	
+	public Vector4 calcLightPosition(Timer timer, float alphaOffset) {
+		float currTime = timer.getAlpha() + alphaOffset;
+		
+		Vector4 ret = new Vector4(0, lightHeight, 0, 1);
+		ret.x((float)Math.cos(currTime * 2 * Math.PI) * lightRadius);
+		ret.z((float)Math.sin(currTime * 2 * Math.PI) * lightRadius);
+		
+		return ret;
+	}
+	
+	public Vector4 getMaxIntensityValue(Pair<Vector4, Float> data) {
+		return data.first;
+	}
+	
+	public float getMaxIntensityTime(Pair<Vector4, Float> data) {
+		return data.second;
+	}
+	
+	public float getLightVectorValue(Pair<Float, Float> data) {
+		return data.first;
+	}
+	
+	public float getLightVectorTime(Pair<Float, Float> data) {
+		return data.second;
+	}
+	
+	public void setSunlightValues(SunlightValue[] values) {
+		ArrayList<TimedLinearInterpolatorVector<Vector4>.Data> ambient = new ArrayList<>();
+		ArrayList<TimedLinearInterpolatorVector<Vector4>.Data> light = new ArrayList<>();
+		ArrayList<TimedLinearInterpolatorVector<Vector4>.Data> background = new ArrayList<>();
+		
+		for(SunlightValue v : values) {
+			ambient.add(ambientInterpolator.new Data(v.ambient, v.normTime));
+			light.add(sunlightInterpolator.new Data(v.sunlightIntensity, v.normTime));
+			background.add(backgroundInterpolator.new Data(v.backgroundColor, v.normTime));
+		}
+		
+		ambientInterpolator.setValues(ambient);
+		sunlightInterpolator.setValues(light);
+		backgroundInterpolator.setValues(background);
+		
+		ArrayList<TimedLinearInterpolatorf.Data> maxIntensity = new ArrayList<>();
+		maxIntensity.add(maxIntensityInterpolator.new Data(1, 0));
+		maxIntensityInterpolator.setValues(maxIntensity, false);
+	}
+	
+	public void setSunlightValues(SunlightValueHDR[] values) {
+		ArrayList<TimedLinearInterpolatorVector<Vector4>.Data> ambient = new ArrayList<>();
+		ArrayList<TimedLinearInterpolatorVector<Vector4>.Data> light = new ArrayList<>();
+		ArrayList<TimedLinearInterpolatorVector<Vector4>.Data> background = new ArrayList<>();
+		ArrayList<TimedLinearInterpolatorf.Data> maxIntensity = new ArrayList<>();
+		
+		for(SunlightValueHDR v : values) {
+			ambient.add(ambientInterpolator.new Data(v.ambient, v.normTime));
+			light.add(sunlightInterpolator.new Data(v.sunlightIntensity, v.normTime));
+			background.add(backgroundInterpolator.new Data(v.backgroundColor, v.normTime));
+			maxIntensity.add(maxIntensityInterpolator.new Data(v.maxIntensity, v.normTime));
+		}
+		
+		ambientInterpolator.setValues(ambient);
+		sunlightInterpolator.setValues(light);
+		backgroundInterpolator.setValues(background);
+		maxIntensityInterpolator.setValues(maxIntensity);
+	}
+	
+	
+	
+	private static class Pair<F, S> {
+		private F first;
+		private S second;
+		
+		public Pair(F first, S second) {
+			this.first = first;
+			this.second = second;
+		}
+	}
+	
 	private class PerLight {
 		private Vector4 cameraSpaceLightPos;
 		private Vector4 lightIntensity;
+		
+		public PerLight(Vector4 cameraSpaceLightPos, Vector4 lightIntensity) {
+			this.cameraSpaceLightPos = cameraSpaceLightPos;
+			this.lightIntensity = lightIntensity;
+		}
 	}
 	
 	private class LightBlock {
 		private Vector4 ambientIntensity;
 		private float lightAttenuation;
-		private float[] padding = new float[3];
 		private PerLight[] lights = new PerLight[NUMBER_OF_LIGHTS];
+		
+		public LightBlock(Vector4 ambientIntensity, float lightAttenuation) {
+			this.ambientIntensity = ambientIntensity;
+			this.lightAttenuation = lightAttenuation;
+		}
 	}
 	
 	private class LightBlockHDR {
 		private Vector4 ambientIntensity;
 		private float lightAttenuation;
 		private float maxIntensity;
-		private float[] padding = new float[2];
 		private PerLight[] lights = new PerLight[NUMBER_OF_LIGHTS];
+		
+		public LightBlockHDR(Vector4 ambientIntensity, float lightAttenuation, float maxIntensity) {
+			this.ambientIntensity = ambientIntensity;
+			this.lightAttenuation = lightAttenuation;
+			this.maxIntensity = maxIntensity;
+		}
 	}
 	
 	private class LightBlockGamma {
 		private float lightAttenuation;
 		private float maxIntensity;
 		private float gamma;
-		private float padding;
 		private PerLight[] lights = new PerLight[NUMBER_OF_LIGHTS];
+		
+		public LightBlockGamma(Vector4 ambientIntensity, float lightAttenuation, float maxIntensity, float gamma) {
+			this.ambientIntensity = ambientIntensity;
+			this.lightAttenuation = lightAttenuation;
+			this.maxIntensity = maxIntensity;
+			this.gamma = gamma;
+		}
 	}
 	
 	private class SunlightValue {
 		private Vector4 ambient;
 		private Vector4 sunlightIntensity;
 		private Vector4 backgroundColor;
+		
+		public SunlightValue(float normTime, Vector3 ambient, Vector4 sunlightIntensity, Vector4 backgroundColor) {
+			this.normTime = normTime;
+			this.ambient = this.ambient;
+			this.sunlightIntensity = sunlightIntensity;
+			this.backgroundColor = backgroundColor;
+		}
 	}
 	
 	private class SunlightValueHDR {
 		private Vector4 sunlightIntensity;
 		private Vector4 backgroundColor;
 		private float maxIntensity;
+		
+		public SunlightValueHDR(float normTime, Vector4 ambient, Vector4 sunlightIntensity, Vector4 backgroundColor, float maxIntensity) {
+			this.normTime = normTime;
+			this.ambient = ambient;
+			this.sunlightIntensity = sunlightIntensity;
+			this.backgroundColor = backgroundColor;
+			this.maxIntensity = maxIntensity;
+		}
 	}
 	
 	private enum TimerTypes {

src/main/java/com/ra4king/opengl/superbible/osb5/chapter2/example1/Example2_1.java

 		
 		glCompileShader(vs);
 		
-		if(glGetShader(vs, GL_COMPILE_STATUS) == GL_FALSE) {
-			System.err.println("Failure in compiling vertex shader. Error log:\n" + glGetShaderInfoLog(vs, glGetShader(vs, GL_INFO_LOG_LENGTH)));
+		if(glGetShaderi(vs, GL_COMPILE_STATUS) == GL_FALSE) {
+			System.err.println("Failure in compiling vertex shader. Error log:\n" + glGetShaderInfoLog(vs, glGetShaderi(vs, GL_INFO_LOG_LENGTH)));
 			System.exit(0);
 		}
 		
 		
 		glCompileShader(fs);
 		
-		if(glGetShader(fs, GL_COMPILE_STATUS) == GL_FALSE) {
-			System.err.println("Failure in compiling fragment shader. Error log:\n" + glGetShaderInfoLog(fs, glGetShader(fs, GL_INFO_LOG_LENGTH)));
+		if(glGetShaderi(fs, GL_COMPILE_STATUS) == GL_FALSE) {
+			System.err.println("Failure in compiling fragment shader. Error log:\n" + glGetShaderInfoLog(fs, glGetShaderi(fs, GL_INFO_LOG_LENGTH)));
 			destroy();
 		}
 		
 		
 		glLinkProgram(program);
 		
-		if(glGetProgram(program, GL_LINK_STATUS) == GL_FALSE) {
-			System.err.println("Failure in linking program. Error log:\n" + glGetProgramInfoLog(program, glGetProgram(program, GL_INFO_LOG_LENGTH)));
+		if(glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE) {
+			System.err.println("Failure in linking program. Error log:\n" + glGetProgramInfoLog(program, glGetProgrami(program, GL_INFO_LOG_LENGTH)));
 			destroy();
 		}
 		

src/main/java/com/ra4king/opengl/util/ShaderProgram.java

 		glAttachShader(program, fs);
 		
 		if(attributes != null)
-			for(Integer i : attributes.keySet())
+			for(int i : attributes.keySet())
 				glBindAttribLocation(program, i, attributes.get(i));
 		
 		glLinkProgram(program);

src/main/java/com/ra4king/opengl/util/interpolators/ConstVelLinearInterpolatorVector.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+import com.ra4king.opengl.util.math.Vector;
+
+public class ConstVelLinearInterpolatorVector<T extends Vector<T>> extends WeightedLinearInterpolatorVector<T> {
+	private float totalDist;
+	
+	public float getDistance() {
+		return totalDist;
+	}
+	
+	public void setValues(ArrayList<T> data) {
+		setValues(data, true);
+	}
+	
+	public void setValues(ArrayList<T> data, boolean isLooping) {
+		values.clear();
+		
+		for(T d : data)
+			values.add(new Data(d, 0));
+		
+		if(isLooping)
+			values.add(values.get(0));
+		
+		totalDist = 0;
+		for(int a = 0; a < values.size(); a++) {
+			totalDist += values.get(a).data.copy().sub(values.get(a-1).data).length();
+			values.get(a).weight = totalDist;
+		}
+		
+		for(Data d : values)
+			d.weight /= totalDist;
+	}
+}

src/main/java/com/ra4king/opengl/util/interpolators/ConstVelLinearInterpolatorf.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+public class ConstVelLinearInterpolatorf extends WeightedLinearInterpolatorf {
+	private float totalDist;
+	
+	public float getDistance() {
+		return totalDist;
+	}
+	
+	public void setValues(ArrayList<Float> data) {
+		setValues(data, true);
+	}
+	
+	public void setValues(ArrayList<Float> data, boolean isLooping) {
+		values.clear();
+		
+		for(Float d : data)
+			values.add(new Data(d, 0));
+		
+		if(isLooping)
+			values.add(values.get(0));
+		
+		totalDist = 0;
+		for(int a = 0; a < values.size(); a++) {
+			totalDist += Math.abs(values.get(a).data - values.get(a-1).data);
+			values.get(a).weight = totalDist;
+		}
+		
+		for(Data d : values)
+			d.weight /= totalDist;
+	}
+}

src/main/java/com/ra4king/opengl/util/interpolators/LinearInterpolatorVector.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+import com.ra4king.opengl.util.math.Vector;
+
+public class LinearInterpolatorVector<T extends Vector<T>> extends WeightedLinearInterpolatorVector<T> {
+	public void setValues(ArrayList<T> data) {
+		setValues(data, true);
+	}
+	
+	public void setValues(ArrayList<T> data, boolean isLooping) {
+		values.clear();
+		
+		for(T d : data)
+			values.add(new Data(d, 0));
+		
+		if(isLooping && !values.isEmpty())
+			values.add(values.get(values.size()-1));
+		
+		for(int a = 0; a < values.size(); a++)
+			values.get(a).weight = a / (float)(values.size()-1);
+	}
+}

src/main/java/com/ra4king/opengl/util/interpolators/LinearInterpolatorf.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+public class LinearInterpolatorf extends WeightedLinearInterpolatorf {
+	public void setValues(ArrayList<Float> data) {
+		setValues(data, true);
+	}
+	
+	public void setValues(ArrayList<Float> data, boolean isLooping) {
+		values.clear();
+		
+		for(Float d : data)
+			values.add(new Data(d, 0));
+		
+		if(isLooping && !values.isEmpty())
+			values.add(values.get(values.size()-1));
+		
+		for(int a = 0; a < values.size(); a++)
+			values.get(a).weight = a / (float)(values.size()-1);
+	}
+}

src/main/java/com/ra4king/opengl/util/interpolators/TimedLinearInterpolatorVector.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+import com.ra4king.opengl.util.math.Vector;
+
+public class TimedLinearInterpolatorVector<T extends Vector<T>> extends WeightedLinearInterpolatorVector<T> {
+	public void setValues(ArrayList<Data> data) {
+		setValues(data, true);
+	}
+	
+	public void setValues(ArrayList<Data> data, boolean isLooping) {
+		values.clear();
+		for(Data d : data) {
+			if(d.weight < 0 || d.weight > 1)
+				throw new IllegalArgumentException("weight is out of bounds.");
+			values.add(d);
+		}
+		
+		if(isLooping && !values.isEmpty())
+			values.add(values.get(0));
+		
+		if(!values.isEmpty()) {
+			values.get(0).weight = 0;
+			values.get(values.size()-1).weight = 1;
+		}
+	}
+}

src/main/java/com/ra4king/opengl/util/interpolators/TimedLinearInterpolatorf.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+public class TimedLinearInterpolatorf extends WeightedLinearInterpolatorf {
+	public void setValues(ArrayList<Data> data) {
+		setValues(data, true);
+	}
+	
+	public void setValues(ArrayList<Data> data, boolean isLooping) {
+		values.clear();
+		for(Data d : data) {
+			if(d.weight < 0 || d.weight > 1)
+				throw new IllegalArgumentException("weight is out of bounds.");
+			values.add(d);
+		}
+		
+		if(isLooping && !values.isEmpty())
+			values.add(values.get(0));
+		
+		if(!values.isEmpty()) {
+			values.get(0).weight = 0;
+			values.get(values.size()-1).weight = 1;
+		}
+	}
+}

src/main/java/com/ra4king/opengl/util/interpolators/WeightedLinearInterpolatorVector.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+import com.ra4king.opengl.util.math.Vector;
+
+public class WeightedLinearInterpolatorVector<T extends Vector<T>> {
+	public class Data {
+		public T data;
+		public float weight;
+		
+		public Data(T data, float weight) {
+			this.data = data;
+			this.weight = weight;
+		}
+	}
+	
+	protected ArrayList<Data> values = new ArrayList<>();
+	
+	public int numSegments() {
+		return values.isEmpty() ? 0 : values.size() - 1;
+	}
+	
+	public T interpolate(float alpha) {
+		if(values.isEmpty())
+			return null;
+		if(values.size() == 1)
+			return values.get(0).data;
+		
+		int segment = 1;
+		for(; segment < values.size(); segment++)
+			if(alpha < values.get(segment).weight)
+				break;
+		
+		if(segment == values.size())
+			return values.get(values.size()-1).data;
+		
+		float sectionAlpha = alpha - values.get(segment-1).weight;
+		sectionAlpha /= values.get(segment).weight - values.get(segment-1).weight;
+		
+		float invSecAlpha = 1 - sectionAlpha;
+		
+		return values.get(segment-1).data.mult(invSecAlpha).add(values.get(segment).data.mult(sectionAlpha));
+	}
+}

src/main/java/com/ra4king/opengl/util/interpolators/WeightedLinearInterpolatorf.java

+package com.ra4king.opengl.util.interpolators;
+
+import java.util.ArrayList;
+
+public class WeightedLinearInterpolatorf {
+	public class Data {
+		public float data;
+		public float weight;
+		
+		public Data(float data, float weight) {
+			this.data = data;
+			this.weight = weight;
+		}
+	}
+	
+	protected ArrayList<Data> values = new ArrayList<>();
+	
+	public int numSegments() {
+		return values.isEmpty() ? 0 : values.size() - 1;
+	}
+	
+	public float interpolate(float alpha) {
+		if(values.isEmpty())
+			return 0;
+		if(values.size() == 1)
+			return values.get(0).data;
+		
+		int segment = 1;
+		for(; segment < values.size(); segment++)
+			if(alpha < values.get(segment).weight)
+				break;
+		
+		if(segment == values.size())
+			return values.get(values.size()-1).data;
+		
+		float sectionAlpha = alpha - values.get(segment-1).weight;
+		sectionAlpha /= values.get(segment).weight - values.get(segment-1).weight;
+		
+		float invSecAlpha = 1 - sectionAlpha;
+		
+		return values.get(segment-1).data * invSecAlpha + values.get(segment).data * sectionAlpha;
+	}
+}

src/main/java/com/ra4king/opengl/util/math/Vector.java

+package com.ra4king.opengl.util.math;
+
+import java.nio.FloatBuffer;
+
+public interface Vector<V> {
+	V add(V v);
+	V sub(V v);
+	V mult(V v);
+	V mult(float f);
+	float length();
+	V copy();
+	FloatBuffer toBuffer();
+}

src/main/java/com/ra4king/opengl/util/math/Vector2.java

 
 import org.lwjgl.BufferUtils;
 
-public class Vector2 {
+public class Vector2 implements Vector<Vector2> {
 	private float x, y;
 	
 	public Vector2() {
 		set(vec);
 	}
 	
+	public Vector2 copy() {
+		return new Vector2(this);
+	}
+	
 	public float x() {
 		return x;
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector2 add(Vector2 vec) {
 		return add(vec.x, vec.y);
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector2 sub(Vector2 vec) {
 		return sub(vec.x, vec.y);
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector2 mult(Vector2 vec) {
 		return mult(vec.x, vec.y);
 	}

src/main/java/com/ra4king/opengl/util/math/Vector3.java

 
 import org.lwjgl.BufferUtils;
 
-public class Vector3 {
+public class Vector3 implements Vector<Vector3> {
 	private float x, y, z;
 	
 	public Vector3() {
 		set(vec);
 	}
 	
+	public Vector3 copy() {
+		return new Vector3(this);
+	}
+	
 	public float x() {
 		return x;
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector3 add(Vector3 vec) {
 		return add(vec.x, vec.y, vec.z);
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector3 sub(Vector3 vec) {
 		return sub(vec.x, vec.y, vec.z);
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector3 mult(Vector3 vec) {
 		return mult(vec.x, vec.y, vec.z);
 	}

src/main/java/com/ra4king/opengl/util/math/Vector4.java

 
 import org.lwjgl.BufferUtils;
 
-public class Vector4 {
+public class Vector4 implements Vector<Vector4> {
 	private float x, y, z, w;
 	
 	public Vector4() {
 		set(vec);
 	}
 	
+	public Vector4 copy() {
+		return new Vector4(this);
+	}
+	
 	public float x() {
 		return x;
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector4 add(Vector4 vec) {
 		return add(vec.x, vec.y, vec.z, vec.w);
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector4 sub(Vector4 vec) {
 		return sub(vec.x, vec.y, vec.z, vec.w);
 	}
 		return this;
 	}
 	
+	@Override
 	public Vector4 mult(Vector4 vec) {
 		return mult(vec.x, vec.y, vec.z, vec.w);
 	}