diff --git a/out/production/EPQ 3D renderer/App.class b/out/production/EPQ 3D renderer/App.class
index 488c832..a13221e 100644
--- a/out/production/EPQ 3D renderer/App.class
+++ b/out/production/EPQ 3D renderer/App.class
Binary files differ
diff --git a/out/production/EPQ 3D renderer/Face.class b/out/production/EPQ 3D renderer/Face.class
index b38f9a6..54b5092 100644
--- a/out/production/EPQ 3D renderer/Face.class
+++ b/out/production/EPQ 3D renderer/Face.class
Binary files differ
diff --git a/out/production/EPQ 3D renderer/Matrix.class b/out/production/EPQ 3D renderer/Matrix.class
index c8eecf9..698f676 100644
--- a/out/production/EPQ 3D renderer/Matrix.class
+++ b/out/production/EPQ 3D renderer/Matrix.class
Binary files differ
diff --git a/out/production/EPQ 3D renderer/Object3d.class b/out/production/EPQ 3D renderer/Object3d.class
index 7724b1a..694bbc1 100644
--- a/out/production/EPQ 3D renderer/Object3d.class
+++ b/out/production/EPQ 3D renderer/Object3d.class
Binary files differ
diff --git a/out/production/EPQ 3D renderer/Player.class b/out/production/EPQ 3D renderer/Player.class
index 8b9f9c0..b8bf0db 100644
--- a/out/production/EPQ 3D renderer/Player.class
+++ b/out/production/EPQ 3D renderer/Player.class
Binary files differ
diff --git a/out/production/EPQ 3D renderer/Screen.class b/out/production/EPQ 3D renderer/Screen.class
index bcf7d88..6d7f20a 100644
--- a/out/production/EPQ 3D renderer/Screen.class
+++ b/out/production/EPQ 3D renderer/Screen.class
Binary files differ
diff --git a/out/production/EPQ 3D renderer/Triangle.class b/out/production/EPQ 3D renderer/Triangle.class
index 2cd17e2..5a043b9 100644
--- a/out/production/EPQ 3D renderer/Triangle.class
+++ b/out/production/EPQ 3D renderer/Triangle.class
Binary files differ
diff --git a/out/production/EPQ 3D renderer/Vector3D.class b/out/production/EPQ 3D renderer/Vector3D.class
index c8090a9..79370e5 100644
--- a/out/production/EPQ 3D renderer/Vector3D.class
+++ b/out/production/EPQ 3D renderer/Vector3D.class
Binary files differ
diff --git a/src/App.java b/src/App.java
index bf5ec33..a2131d2 100644
--- a/src/App.java
+++ b/src/App.java
@@ -37,23 +37,46 @@
 
     public static void initObjects(){
         mainCollection = new ObjectCollection();
+//        mainCollection.addObject(new Object3d(new PointComp[]{
+//                new PointComp(-10,-10,-10),
+//                new PointComp(-10,-10,10),
+//                new PointComp(-10,10,-10),
+//                new PointComp(-10,10,10),
+//                new PointComp(10,-10,-10),
+//                new PointComp(10,-10,10),
+//                new PointComp(10,10,-10),
+//                new PointComp(10,10,10)
+//
+//        }, new int[][]{
+//                {0,2,3,1},
+//                {4,5,7,6},
+//                {0,1,5,4},
+//                {1,3,7,5},
+//                {3,2,6,7},
+//                {2,0,4,6},
+//        }, true));
+//        mainCollection.addObject(new Object3d(new PointComp[]{
+//                new PointComp(-10,10,10),
+//                new PointComp(-10,-10,10),
+//                new PointComp(10,10,10),
+//                new PointComp(10,-10,10),
+//                new PointComp(0,0,24)
+//        }, new int[][]{
+//                {0,2,3,1},
+//                {1,0,4},
+//                {0,2,4},
+//                {2,3,4},
+//                {3,1,4}
+//        }, true));
         mainCollection.addObject(new Object3d(new PointComp[]{
-                new PointComp(-10,-10,-10),
-                new PointComp(-10,-10,10),
-                new PointComp(-10,10,-10),
-                new PointComp(-10,10,10),
-                new PointComp(10,-10,-10),
-                new PointComp(10,-10,10),
-                new PointComp(10,10,-10),
-                new PointComp(10,10,10)
-
+                new PointComp(0,0,0),
+                new PointComp(20,0,0),
+                new PointComp(0,10,0),
+                new PointComp(0,0,10),
         }, new int[][]{
-                {0,2,3,1},
-                {4,5,7,6},
-                {0,1,5,4},
-                {1,3,7,5},
-                {3,2,6,7},
-                {2,0,4,6},
+                {0,1,2},
+                {0,2,3},
+                {0,3,1}
         }, true));
     }
 }
diff --git a/src/Face.java b/src/Face.java
index d027d53..2ad549d 100644
--- a/src/Face.java
+++ b/src/Face.java
@@ -28,7 +28,7 @@
             point.setRotatedPoint(camMatrix);
             point.setProjectedPoint(FPDis, scrX, scrY);
             // skip rendering if any points are behind the camera
-            if(point.getRotatedPoint().z < 0){
+            if(point.getRotatedPoint().z < 0.1){
                 valid = false;
                 break;
             }
@@ -68,9 +68,6 @@
                 valid = true;
             }}
         if(!valid){throw new RuntimeException("Could not calculate normal of face");}
-        normal = new Vector3D(
-                vec1.y*vec2.z - vec1.z*vec2.y,
-                vec1.z*vec2.x - vec1.x*vec2.z,
-                vec1.x*vec2.y - vec1.y*vec2.x);
+        normal = vec1.cross(vec2);
     }
 }
diff --git a/src/Matrix.java b/src/Matrix.java
index 81cc3b2..7202d29 100644
--- a/src/Matrix.java
+++ b/src/Matrix.java
@@ -7,7 +7,7 @@
         x = _x; y= _y;
         items = new double[y][x];
     }
-    public double item(int _x, int _y){
+    public double getItem(int _x, int _y){
         return items[_y][_x];
     }
     public void setItem(int _x, int _y, double val){
@@ -27,7 +27,7 @@
                 for(int ry = 0; ry< result.y; ry+=1){
                     newItem = 0;
                     for(int i = 0; i<x; i+=1){
-                        newItem += this.item(i, ry)*mult.item(rx, i);
+                        newItem += this.getItem(i, ry)*mult.getItem(rx, i);
                     }
                     result.setItem(rx, ry, newItem);
             }}
@@ -38,22 +38,22 @@
     }
     public void multiplyPoint3to(Point3D point, Point3D result) {
         if(x==3){
-            result.x = point.x * item(0,0) + point.y*item(1,0) + point.z*item(2,0);
-            result.y = point.x * item(0,1) + point.y*item(1,1) + point.z*item(2,1);
-            result.z = point.x * item(0,2) + point.y*item(1,2) + point.z*item(2,2);
+            result.x = point.x * getItem(0,0) + point.y* getItem(1,0) + point.z* getItem(2,0);
+            result.y = point.x * getItem(0,1) + point.y* getItem(1,1) + point.z* getItem(2,1);
+            result.z = point.x * getItem(0,2) + point.y* getItem(1,2) + point.z* getItem(2,2);
         } else if(x == 4){
-            result.x = point.x * item(0,0) + point.y*item(1,0) + point.z*item(2,0) + item(3,0);
-            result.y = point.x * item(0,1) + point.y*item(1,1) + point.z*item(2,1) + item(3,1);
-            result.z = point.x * item(0,2) + point.y*item(1,2) + point.z*item(2,2) + item(3,2);
+            result.x = point.x * getItem(0,0) + point.y* getItem(1,0) + point.z* getItem(2,0) + getItem(3,0);
+            result.y = point.x * getItem(0,1) + point.y* getItem(1,1) + point.z* getItem(2,1) + getItem(3,1);
+            result.z = point.x * getItem(0,2) + point.y* getItem(1,2) + point.z* getItem(2,2) + getItem(3,2);
         } else {throw new RuntimeException("wrong-dimensions");}
     }
     public void multiplyPoint2to(Point2D point, Point2D result) throws Exception {
         if(x==2){
-            result.x = (int)(point.x * item(0,0) + point.y*item(0,1));
-            result.y = (int)(point.x * item(1,0) + point.y*item(1,1));
+            result.x = (int)(point.x * getItem(0,0) + point.y* getItem(0,1));
+            result.y = (int)(point.x * getItem(1,0) + point.y* getItem(1,1));
         } else if(x == 3){
-            result.x = (int)(point.x * item(0,0) + point.y*item(0,1) + item(0,2));
-            result.y = (int)(point.x * item(1,0) + point.y*item(1,1) + item(1,2));
+            result.x = (int)(point.x * getItem(0,0) + point.y* getItem(0,1) + getItem(0,2));
+            result.y = (int)(point.x * getItem(1,0) + point.y* getItem(1,1) + getItem(1,2));
         } else {throw new Exception("wrong-dimensions");}
     }
 }
diff --git a/src/Object3d.java b/src/Object3d.java
index 976859a..9382d8b 100644
--- a/src/Object3d.java
+++ b/src/Object3d.java
@@ -25,19 +25,13 @@
              faces) {
             // check whether faces are pointing towards or away from the camera
             // TODO figure out angle
-            Vector3D camVec = new Vector3D(
-                    face.points[0].point.x - playerPos.x,
-                    face.points[0].point.y - playerPos.y,
-                    face.points[0].point.z - playerPos.z
-            );
-            double ang = face.normal.angleTo(camVec);
-            //debugimg.getGraphics().drawString(Math.round(Math.toDegrees(ang)) + " angle " + iterator, 10, 20 + 10*iterator);
+            Vector3D camVec = new Vector3D(0,0,0);
+            camVec.createFrom2Points(playerPos, face.points[0].point);
             int numberOfPixels = 0;
-            if(ang <= Math.PI/2-0.01){
+            if(face.normal.angleTo(camVec) <= Math.PI/2-0.01){
                 numberOfPixels = face.draw(img, debugimg, camMatrix, FPDis, scrX, scrY);
             }
             debugimg.getGraphics().drawString(iterator + ": " +numberOfPixels , 10, 20 + 10*iterator);
-
             iterator += 1;
         }
     }
@@ -73,9 +67,20 @@
                 pointB = point.point;
                 distance = newDis;}}
         boundingSphereC = new Point3D(
-                (pointA.x+ pointB.x) / 2,
+                (pointA.x + pointB.x) / 2,
                 (pointA.y + pointB.y)/2,
-                (pointA.y + pointB.y)/2);
+                (pointA.z + pointB.z)/2);
         boundingSphereR = Math.sqrt(distance)/2;
+        boolean valid = false;
+        for (PointComp point:
+                points) {
+            distance = Math.sqrt(
+                    Math.pow(boundingSphereC.x - point.point.x, 2)+
+                    Math.pow(boundingSphereC.y - point.point.y, 2)+
+                    Math.pow(boundingSphereC.z - point.point.z, 2));
+            if(distance > boundingSphereR){
+                boundingSphereR = distance;
+            }
+        }
     }
 }
diff --git a/src/ObjectCollection.java b/src/ObjectCollection.java
index efe60cc..fb9de3f 100644
--- a/src/ObjectCollection.java
+++ b/src/ObjectCollection.java
@@ -11,7 +11,7 @@
     public ArrayList<Object3d> objects = new ArrayList<Object3d>();
 
     public void invalidate(boolean invalidatePoints){
-        // the first level of object collections should contain all the points for the sub-levels.
+        // the first level of object collections should contain all the points for the sublevels.
         // this means that we only need to invalidate them at the top level
         if(invalidatePoints){for (PointComp point:
              points) {
@@ -27,16 +27,26 @@
         }
     }
 
-    public void draw(BufferedImage img, BufferedImage debugimg, Matrix camMatrix, double FPDis, int scrX, int scrY, Point3D playerPos){
-        // todo check for frustum culling
+    public void draw(BufferedImage img, BufferedImage debugImg, Matrix camMatrix, Point3D playerPos, Plane[] frustumPlanes, double FPDis, int scrX, int scrY){
         for (Object3d object:
              objects) {
-            object.draw(img, debugimg, camMatrix, FPDis, scrX, scrY, playerPos);
+            boolean draw = true;
+            int i = 0;
+            for (Plane plane:
+                 frustumPlanes) {
+                    debugImg.getGraphics().drawString(
+                            "Dis: " + String.format("%.1f", plane.getDistance(object.boundingSphereC)), 500, 10 + 20*i);
+                if(plane.getDistance(object.boundingSphereC) < -object.boundingSphereR){
+                    draw = false;
+                    break;}
+                i += 1;
+            }
+            if(draw){object.draw(img, debugImg, camMatrix, FPDis, scrX, scrY, playerPos);}
         }
         // todo check for frustum culling
         for(ObjectCollection collection:
         subCollections){
-            collection.draw(img, debugimg, camMatrix, FPDis, scrX, scrY, playerPos);
+            collection.draw(img, debugImg, camMatrix, playerPos, frustumPlanes, FPDis, scrX, scrY);
         }
     }
     public void addCollection(int[] pointList){
diff --git a/src/Plane.java b/src/Plane.java
new file mode 100644
index 0000000..fa525cf
--- /dev/null
+++ b/src/Plane.java
@@ -0,0 +1,27 @@
+public class Plane {
+    public Point3D mainPoint;
+    public Vector3D normalVector;
+
+    public double getDistance(Point3D point){
+        Vector3D vec = new Vector3D(0,0,0);
+        vec.createFrom2Points(mainPoint, point);
+        return normalVector.dot(vec);
+    }
+    public void initFrom3Points(Point3D _mainPoint, Point3D point1, Point3D point2){
+        // find normal vector to 3 points
+        Vector3D vec1 = new Vector3D(0,0,0);
+        Vector3D vec2 = new Vector3D(0,0,0);
+        vec1.createFrom2Points(_mainPoint, point1);
+        vec2.createFrom2Points(point1, point2);
+        initFromPointAndVector(_mainPoint, vec1.cross(vec2));
+    }
+    public void initFromPointAndVector(Point3D _mainPoint, Vector3D _normalVector){
+        // convert to unit vector
+        mainPoint = _mainPoint;
+        double len = _normalVector.getLength();
+        normalVector = new Vector3D(
+                _normalVector.x / len,
+                _normalVector.y / len,
+                _normalVector.z / len);
+    }
+}
diff --git a/src/Player.java b/src/Player.java
index 25215e5..cb16b47 100644
--- a/src/Player.java
+++ b/src/Player.java
@@ -5,20 +5,35 @@
 
 public class Player {
 
+    public Plane[] frustumPlanes = new Plane[6];
     // image that represents the player's position on the board
     private BufferedImage image;
     // current position of the player on the board grid
+    private Matrix rotMatrix;
     public Matrix camMatrix;
+    private Matrix invRotMatrix;
+    private Matrix invCamMatrix;
     public double FOV = 100;
     protected double Fpdis;
-    private Point3D position = new Point3D(-30,0,0);
+    protected Point3D FPWorldPos;
+    protected PointComp[] ScreenCornerPosS = new PointComp[4];
+    private Point3D position = new Point3D(0,0,0);
     private Point3D rotation = new Point3D(0,Math.PI / 2, 0);
     private Point3D direction = new Point3D(0,0,0);
     public Vector3D viewVector = new Vector3D(0,0,0);
     public double mouseSensitivity = 0.005; // radians per pixel
     // called when the player is initialised
-    public Player() {
-        Fpdis = Math.tanh(Math.toRadians(FOV)/2d);
+    public Player(int scrX, int scrY) {
+        Fpdis = 1/Math.tan(Math.toRadians(FOV)/2d);
+        for(int i = 0; i < 6; i+=1){
+            frustumPlanes[i] = new Plane();
+        }
+        double yVal = (double)scrY / (double)scrX;
+        // flip x and y because reasons
+        ScreenCornerPosS[0] = new PointComp(-yVal,-1,  0);
+        ScreenCornerPosS[1] = new PointComp(yVal,-1,  0);
+        ScreenCornerPosS[2] = new PointComp(-yVal,1,  0);
+        ScreenCornerPosS[3] = new PointComp(yVal,1,  0);
     }
 
     // unused because the player should not be drawn
@@ -43,9 +58,9 @@
             direction.x += 1;
         } else if (key == KeyEvent.VK_S && -direction.x < 1) {
             direction.x += -1;
-        } else if (key == KeyEvent.VK_D && direction.y < 1) {
+        } else if (key == KeyEvent.VK_A && direction.y < 1) {
             direction.y += 1;
-        } else if (key == KeyEvent.VK_A && -direction.y < 1) {
+        } else if (key == KeyEvent.VK_D && -direction.y < 1) {
             direction.y += -1;
         } else if (key == KeyEvent.VK_SPACE && direction.z < 1) {
             direction.z += 1;
@@ -58,9 +73,9 @@
             direction.x -= 1;
         } else if (key == KeyEvent.VK_S && -direction.x > -1) {
             direction.x -= -1;
-        } else if (key == KeyEvent.VK_D && direction.y > -1) {
+        } else if (key == KeyEvent.VK_A && direction.y > -1) {
             direction.y -= 1;
-        } else if (key == KeyEvent.VK_A && -direction.y > -1) {
+        } else if (key == KeyEvent.VK_D && -direction.y > -1) {
             direction.y -= -1;
         } else if (key == KeyEvent.VK_SPACE && direction.z > -1) {
             direction.z -= 1;
@@ -71,7 +86,7 @@
     public void tick(Point2D mouseRel) {
         // gets called once every tick, before the repainting process happens.
         // change rotation depending on mouse movement
-        rotation.z += mouseRel.x * mouseSensitivity;
+        rotation.z -= mouseRel.x * mouseSensitivity;
         // force z rotation to wrap around
         if(rotation.z<-Math.PI){
             rotation.z = Math.PI;
@@ -79,13 +94,13 @@
             rotation.z = -Math.PI;
         }
         rotation.y += mouseRel.y * mouseSensitivity;
-        // max out y rotation at 0 and 90 degrees
+        // max out y rotation at 0 and -90 degrees
         if(rotation.y < 0){
             rotation.y = 0;
         } else if(rotation.y > Math.PI){
             rotation.y = Math.PI;
         }
-        // calculate direction vector to translate position by
+        // define rotation and translation matrices
         Matrix zMat = new Matrix(3, 3);
         zMat.setItems(new double[][]{
                 {Math.cos(rotation.z),  Math.sin(rotation.z), 0},
@@ -104,13 +119,25 @@
                 {0, Math.cos(rotation.x), Math.sin(rotation.x)},
                 {0, -Math.sin(rotation.x), Math.cos(rotation.x)}}
         );
-        // calculate inverse Z mat for player movement
+        // calculate inverse matrices
         Matrix izMat = new Matrix(3, 3);
         izMat.setItems(new double[][]{
                 {Math.cos(-rotation.z),  Math.sin(-rotation.z), 0},
                 {-Math.sin(-rotation.z), Math.cos(-rotation.z), 0},
                 {0,                      0,                     1}}
         );
+        Matrix iyMat = new Matrix(3, 3);
+        iyMat.setItems(new double[][]{
+                {Math.cos(-rotation.y), 0, -Math.sin(-rotation.y)},
+                {0,                    1, 0                    },
+                {Math.sin(-rotation.y), 0, Math.cos(-rotation.y) }}
+        );
+        Matrix ixMat = new Matrix(3, 3);
+        ixMat.setItems(new double[][]{
+                {1, 0,                    0                   },
+                {0, Math.cos(-rotation.x), Math.sin(-rotation.x)},
+                {0, -Math.sin(-rotation.x), Math.cos(-rotation.x)}}
+        );
         // apply izMat to direction vector
         try {
             Point3D dirvec = new Point3D(0,0,0);
@@ -125,15 +152,64 @@
                  {0, 1, 0, -position.y},
                  {0, 0, 1, -position.z}}
         );
-        // multiply out camera matrix for rotation
-        camMatrix = xMat.multiply(yMat).multiply(zMat);
-        // calculate view vector
-        /*Point3D viewPoint = new Point3D(0,0,0);
-        camMatrix.multiplyPoint3to(new Point3D(0,0,1), viewPoint);
-        viewVector.x = viewPoint.x;viewVector.y=viewPoint.y;viewVector.z=viewPoint.z;*/
+        // multiply out matrices
+        rotMatrix = xMat.multiply(yMat).multiply(zMat);
+        camMatrix = rotMatrix.multiply(traMat);
+        invRotMatrix = izMat.multiply(iyMat).multiply(ixMat);
+        // I really don't want to do it like this, but I don't think there's any other way without messing up
+        // all my other matrices :(
+        invCamMatrix = new Matrix(4, 3);
+        for(int x = 0; x<3; x+=1){
+            for(int y = 0; y<3; y+=1){
+                invCamMatrix.setItem(x, y, invRotMatrix.getItem(x, y));
+            }}
+        for(int y = 0; y<3; y+=1){
+            invCamMatrix.setItem(3, y, -traMat.getItem(3, y));
+        }
 
-        // add translation to camMatrix
-        camMatrix = camMatrix.multiply(traMat);
+        // calculate view vector
+        Point3D viewPoint = new Point3D(0,0,0);
+        invRotMatrix.multiplyPoint3to(new Point3D(0,0,1), viewPoint);
+        // todo - work out why i need to reverse this
+        viewVector.x = viewPoint.x;viewVector.y=viewPoint.y;viewVector.z=viewPoint.z;
+
+        // calculate camera focal point and edges in world coordinates
+        FPWorldPos = new Point3D(
+                position.x - viewVector.x*Fpdis,
+                position.y - viewVector.y*Fpdis,
+                position.z - viewVector.z*Fpdis);
+        for (PointComp point:
+             ScreenCornerPosS) {
+            point.invalidate();
+            point.setRotatedPoint(invCamMatrix);
+        }
+        // find frustum planes
+        // near plane
+        //frustumPlanes[0].initFromPointAndVector(position, viewVector);
+        frustumPlanes[0].initFrom3Points(ScreenCornerPosS[0].getRotatedPoint(),
+                ScreenCornerPosS[1].getRotatedPoint(), ScreenCornerPosS[2].getRotatedPoint());
+        // far plane
+        int farPlaneDis = 1000;
+        frustumPlanes[1].initFromPointAndVector(
+                new Point3D(
+                        position.x + viewVector.x*farPlaneDis,
+                        position.y + viewVector.y*farPlaneDis,
+                        position.z + viewVector.z*farPlaneDis),
+                // invert the view vector because the normal needs to point the other way
+                new Vector3D(-viewVector.x, -viewVector.y, -viewVector.z));
+        // mid planes
+        // left plane
+        frustumPlanes[2].initFrom3Points(FPWorldPos,
+                ScreenCornerPosS[0].getRotatedPoint(), ScreenCornerPosS[1].getRotatedPoint());
+        // right plane
+        frustumPlanes[3].initFrom3Points(FPWorldPos,
+                ScreenCornerPosS[3].getRotatedPoint(), ScreenCornerPosS[2].getRotatedPoint());
+        // top plane
+        frustumPlanes[4].initFrom3Points(FPWorldPos,
+                ScreenCornerPosS[1].getRotatedPoint(), ScreenCornerPosS[3].getRotatedPoint());
+        // bottom plane
+        frustumPlanes[5].initFrom3Points(FPWorldPos,
+                ScreenCornerPosS[2].getRotatedPoint(), ScreenCornerPosS[0].getRotatedPoint());
     }
 
     // returnValue Functions
diff --git a/src/Point3D.java b/src/Point3D.java
index 595db2d..81ef356 100644
--- a/src/Point3D.java
+++ b/src/Point3D.java
@@ -20,15 +20,17 @@
     }
     public Point2D project(double fpdis, int scrX, int scrY){
         return new Point2D(
-                (int)(((fpdis*y)/z + .5)*scrX),
-                (int)(((fpdis*x)/z + .5)*scrY)
+                (int)(((fpdis*y)/(z) + .5)*scrX),
+                (int)(((fpdis*x)/(z) + .5)*scrY)
                 // multiply by scrX both times such that the projected screen always projects points between -1<x<1.
                 // this means that there isn't any weird scaling, and the FOV is in terms of horizontal.. ness.
         );
     }
     public void projectOn(double fpdis, int scrX, int scrY, Point2D point){
-        point.x = (int)(scrX*((fpdis*y)/z + .5));
-        point.y = (int)(scrX*((fpdis*x)/z + .5));
+        // this is a mess of random fixes because none of my coordinates are correct. :(
+        // sorry
+        point.x = scrX - (int)(scrX*0.5*((fpdis*y)/(z) + 1));
+        point.y = (int)(scrX*0.5*((fpdis*x)/(z) + ((double)scrY/(double)scrX)));
     }
     public double[] get(){
         return new double[]{x, y, z};
diff --git a/src/Screen.java b/src/Screen.java
index 4192a73..05594fc 100644
--- a/src/Screen.java
+++ b/src/Screen.java
@@ -1,7 +1,6 @@
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.image.BufferedImage;
-import java.util.ArrayList;
 import javax.swing.*;
 
 public class Screen extends JPanel implements ActionListener, KeyListener, MouseListener, MouseMotionListener {
@@ -10,7 +9,7 @@
         // mouse
     private boolean captured = false;
     private final Point2D mouseRel = new Point2D(0,0);
-    private Cursor invisibleCursor;
+    private final Cursor invisibleCursor;
 
     public ObjectCollection mainCollection;
 
@@ -52,7 +51,7 @@
         invisibleCursor = toolkit.createCustomCursor(cursorImage, hotSpot, "InvisibleCursor");
 
         // initialize the game state
-        player = new Player();
+        player = new Player(TILE_SIZE*COLUMNS, TILE_SIZE*ROWS);
         // this timer will call the actionPerformed() method every DELAY ms
         timer = new Timer(DELAY, this);
         timer.start();
@@ -86,8 +85,8 @@
     }
     private void drawScreen(Graphics g) {
         BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB );
-        BufferedImage debugimg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
-        debugimg.createGraphics();
+        BufferedImage debugImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
+        debugImg.createGraphics();
         g.setColor(Color.white);
 //        line.point2.x = 100*Math.sin(ang) + 200;
 //        line.point2.y = 100*Math.cos(ang) + 200;
@@ -108,26 +107,60 @@
         Triangle t2 = null;
         try {
             t1 = new Triangle(
-                    newPoints.get(0).project(player.Fpdis, getWidth(), getHeight()),
-                    newPoints.get(1).project(player.Fpdis, getWidth(), getHeight()),
-                    newPoints.get(2).project(player.Fpdis, getWidth(), getHeight()));
+                    newPoints.get(0).project(player.FPDis, getWidth(), getHeight()),
+                    newPoints.get(1).project(player.FPDis, getWidth(), getHeight()),
+                    newPoints.get(2).project(player.FPDis, getWidth(), getHeight()));
         } catch(NullPointerException ignored){}
         try{
             t2 = new Triangle(
-                newPoints.get(0).project(player.Fpdis, getWidth(), getHeight()),
-                newPoints.get(2).project(player.Fpdis, getWidth(), getHeight()),
-                newPoints.get(3).project(player.Fpdis, getWidth(), getHeight()));
+                newPoints.get(0).project(player.FPDis, getWidth(), getHeight()),
+                newPoints.get(2).project(player.FPDis, getWidth(), getHeight()),
+                newPoints.get(3).project(player.FPDis, getWidth(), getHeight()));
         } catch(NullPointerException ignored){}
 
         try{t1.draw(img);}catch (NullPointerException ignored){}
         try{t2.draw(img);}catch (NullPointerException ignored){}
         ang += 0.02;*/
         mainCollection.invalidate(true);
-        mainCollection.draw(img, debugimg, player.camMatrix, player.Fpdis, getWidth(), getHeight(), player.getPos());
+        mainCollection.draw(img, debugImg, player.camMatrix, player.getPos(), player.frustumPlanes, player.Fpdis, getWidth(), getHeight());
         g.drawImage(img, 0, 0, this);
-        g.drawImage(debugimg, 0, 0, this);
+
         // DEBUG DRAWING
-        g.drawString(Math.round(1000/(float)(System.currentTimeMillis() - lastTime)) + " fps" , 10, 10);
+        debugImg.getGraphics().drawString(Math.round(1000/(float)(System.currentTimeMillis() - lastTime)) + " fps" , 10, 10);
+        debugImg.getGraphics().drawString("fpPos: " +
+                String.format("%.2f", player.FPWorldPos.x) + " " +
+                String.format("%.2f", player.FPWorldPos.y) + " " +
+                String.format("%.2f", player.FPWorldPos.z) + " ", 100, 30);
+        g.drawImage(debugImg, 0, 0, this);
+        debugImg.getGraphics().drawString("playerPos: " +
+                String.format("%.2f", player.getPos().x) + " " +
+                String.format("%.2f", player.getPos().y) + " " +
+                String.format("%.2f", player.getPos().z) + " ", 100, 50);
+        debugImg.getGraphics().drawString("rotation: " +
+                Math.round(Math.toDegrees(player.getRot().x)) + " " +
+                Math.round(Math.toDegrees(player.getRot().y)) + " " +
+                Math.round(Math.toDegrees(player.getRot().z)) + " ", 300, 50);
+        debugImg.getGraphics().drawString("viewVec: " +
+                String.format("%.2f",player.viewVector.x) + " " +
+                String.format("%.2f",player.viewVector.y) + " " +
+                String.format("%.2f",player.viewVector.z) + " ", 100, 70);
+        for(int i = 0; i<4; i+=1){
+            debugImg.getGraphics().drawString("camPoint " + i + ": " +
+                    String.format("%.2f", player.ScreenCornerPosS[i].getRotatedPoint().x) + " " +
+                    String.format("%.2f", player.ScreenCornerPosS[i].getRotatedPoint().y) + " " +
+                    String.format("%.2f", player.ScreenCornerPosS[i].getRotatedPoint().z), 10, 90 + 20 * i);
+        }
+        for(int i = 0; i<6; i+=1){
+            debugImg.getGraphics().drawString("plane " + i + ": " +
+                    String.format("%.2f", player.frustumPlanes[i].mainPoint.x) + " " +
+                    String.format("%.2f", player.frustumPlanes[i].mainPoint.y) + " " +
+                    String.format("%.2f", player.frustumPlanes[i].mainPoint.z) + ", normal: " +
+                    String.format("%.2f", player.frustumPlanes[i].normalVector.x) + " " +
+                    String.format("%.2f", player.frustumPlanes[i].normalVector.y) + " " +
+                    String.format("%.2f", player.frustumPlanes[i].normalVector.z), 10, 170 + 20 * i);
+        }
+
+        g.drawImage(debugImg, 0, 0, this);
         lastTime = System.currentTimeMillis();
 
     }
diff --git a/src/Triangle.java b/src/Triangle.java
index 77dbada..08c5c43 100644
--- a/src/Triangle.java
+++ b/src/Triangle.java
@@ -25,7 +25,6 @@
     }
     //  returns int for debug
     public int draw(BufferedImage img){
-        int numberOfPixels = 0; // debug
         long lastMillis;
 
         if (!is_initialised){initialise();}
diff --git a/src/Vector3D.java b/src/Vector3D.java
index 55457f4..6680548 100644
--- a/src/Vector3D.java
+++ b/src/Vector3D.java
@@ -1,5 +1,7 @@
 // technically not required as vectors have the same information as points, but it's useful to have separate vector and point things..
 
+import java.util.Vector;
+
 public class Vector3D {
     public double x;
     public double y;
@@ -10,6 +12,14 @@
         y = _y;
         z = _z;
     }
+    public void createFrom2Points(Point3D start, Point3D end){
+        x = end.x - start.x;
+        y = end.y - start.y;
+        z = end.z - start.z;
+    }
+    public double getLength(){
+        return Math.sqrt(x*x + y*y + z*z);
+    }
     public double angleTo(Vector3D vec2){
         return Math.acos(
                 (x*vec2.x + y*vec2.y + z*vec2.z)
@@ -17,4 +27,13 @@
                         Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2)) *
                         Math.sqrt(Math.pow(vec2.x,  2) + Math.pow(vec2.y, 2) + Math.pow(vec2.z, 2))));
     }
+    public Vector3D cross(Vector3D vec2){
+        return new Vector3D(
+                y*vec2.z - z*vec2.y,
+                z*vec2.x - x*vec2.z,
+                x*vec2.y - y*vec2.x);
+    }
+    public double dot(Vector3D vec2){
+        return x*vec2.x + y* vec2.y+z* vec2.z;
+    }
 }